aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/spongycastle/pkix
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2014-01-27 14:00:22 +0100
committerDominik Schürmann <dominik@dominikschuermann.de>2014-01-27 14:00:22 +0100
commit5aec25ac0501352e4cb6645c86869dde6e91f0d0 (patch)
treeee9adfd55cddf25f098e5e028d585a72de7cd70c /libraries/spongycastle/pkix
parent8ca42b9bf953c6195ee0c17ef48a3154c126cc04 (diff)
downloadopen-keychain-5aec25ac0501352e4cb6645c86869dde6e91f0d0.tar.gz
open-keychain-5aec25ac0501352e4cb6645c86869dde6e91f0d0.tar.bz2
open-keychain-5aec25ac0501352e4cb6645c86869dde6e91f0d0.zip
Add spongy castle sources to libraries folder
Diffstat (limited to 'libraries/spongycastle/pkix')
-rw-r--r--libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/CertUtils.java246
-rw-r--r--libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/X509AttributeCertificateHolder.java366
-rw-r--r--libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/X509CertificateHolder.java327
-rw-r--r--libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/crmf/EncryptedValueParser.java103
-rw-r--r--libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/crmf/FixedLengthMGF1Padder.java120
-rw-r--r--libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cms/CMSTypedStream.java85
-rw-r--r--libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/operator/bc/OperatorUtils.java16
-rw-r--r--libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/TimeStampToken.java391
-rw-r--r--libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/TimeStampTokenInfo.java112
-rw-r--r--libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/cms/CMSTimeStampedData.java201
-rw-r--r--libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/cms/CMSTimeStampedDataParser.java204
-rw-r--r--libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/cms/CMSTimeStampedGenerator.java88
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/AttributeCertificateHolder.java357
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/AttributeCertificateIssuer.java147
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/CertException.java27
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/CertIOException.java29
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/CertRuntimeException.java19
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/CertUtils.java244
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509AttributeCertificateHolder.java366
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509CRLEntryHolder.java144
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509CRLHolder.java317
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509CertificateHolder.java327
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509ContentVerifierProviderBuilder.java14
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509ExtensionUtils.java126
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509v1CertificateBuilder.java66
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509v2AttributeCertificateBuilder.java109
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509v2CRLBuilder.java182
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509v3CertificateBuilder.java142
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/bc/BcX509ExtensionUtils.java91
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/bc/BcX509v1CertificateBuilder.java33
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/bc/BcX509v3CertificateBuilder.java51
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CMPException.java24
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CMPRuntimeException.java19
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CMPUtil.java26
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateConfirmationContent.java41
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateConfirmationContentBuilder.java78
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateStatus.java60
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/GeneralPKIMessage.java82
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessage.java198
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessageBuilder.java306
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/RevocationDetails.java36
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/RevocationDetailsBuilder.java59
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/AuthenticatorControl.java57
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFException.java19
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFRuntimeException.java19
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFUtil.java42
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CertificateRequestMessage.java309
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CertificateRequestMessageBuilder.java279
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/Control.java24
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValueBuilder.java133
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValuePadder.java24
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValueParser.java103
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/FixedLengthMGF1Padder.java120
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKIArchiveControl.java104
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKIArchiveControlBuilder.java78
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACBuilder.java199
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValueGenerator.java41
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValueVerifier.java43
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValuesCalculator.java15
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/ProofOfPossessionSigningKeyBuilder.java75
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/RegTokenControl.java57
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/ValueDecryptorGenerator.java10
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/CRMFHelper.java450
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessage.java84
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessageBuilder.java57
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaEncryptedValueBuilder.java26
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaPKIArchiveControlBuilder.java29
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JceAsymmetricValueDecryptorGenerator.java120
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JceCRMFEncryptorBuilder.java136
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcePKMACValuesCalculator.java69
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/CertHelper.java17
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/DefaultCertHelper.java14
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaAttrCertStore.java62
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCRLStore.java63
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCertStore.java64
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCertStoreBuilder.java148
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX500NameUtil.java29
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509AttributeCertificateHolder.java26
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CRLConverter.java103
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CRLHolder.java26
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CertificateConverter.java116
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CertificateHolder.java26
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509ContentVerifierProviderBuilder.java50
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509ExtensionUtils.java129
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v1CertificateBuilder.java48
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v2CRLBuilder.java23
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v3CertificateBuilder.java103
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/NamedCertHelper.java22
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/ProviderCertHelper.java22
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/BasicOCSPResp.java212
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/BasicOCSPRespBuilder.java264
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/CertificateID.java156
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/CertificateStatus.java6
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPException.java27
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPReq.java259
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPReqBuilder.java199
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPResp.java141
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPRespBuilder.java59
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPUtils.java64
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/Req.java25
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/RespData.java52
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/RespID.java89
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/RevokedStatus.java55
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/SingleResp.java102
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/UnknownStatus.java12
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaBasicOCSPRespBuilder.java18
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaCertificateID.java20
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaRespID.java26
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPath.java80
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathUtils.java21
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidation.java11
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationContext.java61
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationException.java24
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationResult.java66
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationResultBuilder.java14
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/BasicConstraintsValidation.java103
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/CRLValidation.java78
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/CertificatePoliciesValidation.java146
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/CertificatePoliciesValidationBuilder.java35
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/KeyUsageValidation.java63
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/ParentCertIssuedValidation.java127
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/ValidationUtils.java11
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/MSOutlookKeyIdCalculator.java33
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelector.java268
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelectorBuilder.java194
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/X509CertificateHolderSelector.java152
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaSelectorConverter.java35
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java57
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertificateHolderSelector.java72
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/AuthAttributesProvider.java8
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAbsentContent.java49
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAlgorithm.java51
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAttributeTableGenerationException.java32
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAttributeTableGenerator.java19
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthEnvelopedData.java78
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthEnvelopedGenerator.java13
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedData.java260
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataGenerator.java181
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataParser.java348
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataStreamGenerator.java310
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedGenerator.java40
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSCompressedData.java107
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataGenerator.java74
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataParser.java72
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataStreamGenerator.java165
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSConfig.java34
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSContentInfoParser.java45
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSDigestedData.java136
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedData.java62
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedDataGenerator.java109
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedGenerator.java21
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedData.java206
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataGenerator.java131
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataParser.java208
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataStreamGenerator.java305
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedGenerator.java75
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedHelper.java203
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSException.java32
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSProcessable.java21
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSProcessableByteArray.java55
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSProcessableFile.java80
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSProcessableInputStream.java50
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSReadable.java10
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSRuntimeException.java32
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSecureReadable.java10
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignatureAlgorithmNameGenerator.java15
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignatureEncryptionAlgorithmFinder.java17
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedData.java543
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataGenerator.java232
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataParser.java624
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataStreamGenerator.java486
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedGenerator.java239
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedHelper.java253
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignerDigestMismatchException.java11
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSStreamException.java26
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSTypedData.java9
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSTypedStream.java86
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSUtils.java253
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSVerifierCertificateNotValidException.java11
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/DefaultAuthenticatedAttributeTableGenerator.java91
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java154
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java46
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/DefaultSignedAttributeTableGenerator.java121
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KEKRecipient.java10
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KEKRecipientId.java63
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KEKRecipientInfoGenerator.java39
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KEKRecipientInformation.java38
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipient.java14
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientId.java89
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientInfoGenerator.java80
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientInformation.java131
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipient.java10
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientId.java102
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientInfoGenerator.java58
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientInformation.java50
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/NullOutputStream.java28
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/OriginatorId.java118
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/OriginatorInfoGenerator.java54
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/OriginatorInformation.java95
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/PasswordRecipient.java17
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientId.java44
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientInfoGenerator.java138
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientInformation.java135
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/Recipient.java5
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientId.java31
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientInfoGenerator.java10
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientInformation.java181
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientInformationStore.java115
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientOperator.java48
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerId.java104
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInfoGenerator.java291
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInfoGeneratorBuilder.java139
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInformation.java680
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInformationStore.java109
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInformationVerifier.java50
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInformationVerifierProvider.java16
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SimpleAttributeTableGenerator.java25
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcCMSContentEncryptorBuilder.java124
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKEnvelopedRecipient.java49
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKRecipient.java33
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKRecipientInfoGenerator.java19
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKeyTransRecipient.java36
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKeyTransRecipientInfoGenerator.java20
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordEnvelopedRecipient.java49
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordRecipient.java61
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordRecipientInfoGenerator.java31
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcRSAKeyTransEnvelopedRecipient.java50
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcRSAKeyTransRecipientInfoGenerator.java23
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcRSASignerInfoVerifierBuilder.java39
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/CMSUtils.java23
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/EnvelopedDataHelper.java378
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/CMSUtils.java99
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/DefaultJcaJceExtHelper.java26
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/EnvelopedDataHelper.java668
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaJceExtHelper.java18
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSelectorConverter.java55
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerId.java56
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerInfoGeneratorBuilder.java68
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerInfoVerifierBuilder.java180
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSimpleSignerInfoGeneratorBuilder.java202
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSimpleSignerInfoVerifierBuilder.java150
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaX509CertSelectorConverter.java24
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceAlgorithmIdentifierConverter.java64
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java160
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java155
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKAuthenticatedRecipient.java61
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKEnvelopedRecipient.java43
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKRecipient.java119
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKRecipientInfoGenerator.java45
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeAuthenticatedRecipient.java57
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeEnvelopedRecipient.java45
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipient.java184
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientId.java23
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java215
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransAuthenticatedRecipient.java60
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransEnvelopedRecipient.java43
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipient.java156
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipientId.java57
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipientInfoGenerator.java87
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordAuthenticatedRecipient.java54
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordEnvelopedRecipient.java42
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordRecipient.java82
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordRecipientInfoGenerator.java61
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/NamedJcaJceExtHelper.java31
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/ProviderJcaJceExtHelper.java32
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/ZlibCompressor.java24
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/ZlibExpanderProvider.java116
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestBuilder.java32
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestData.java48
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestBuilder.java34
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestData.java40
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSConstructionException.java20
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSException.java28
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSMessage.java22
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSParsingException.java20
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequest.java134
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestBuilder.java131
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestData.java38
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestInfo.java237
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSResponse.java74
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/MessageImprint.java38
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/MessageImprintBuilder.java35
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/SignedDVCSMessageGenerator.java45
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/TargetChain.java18
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestBuilder.java76
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestData.java51
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestBuilder.java49
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestData.java66
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACCertificateBuilder.java83
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACCertificateHolder.java88
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACCertificateRequestHolder.java88
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACException.java27
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACIOException.java29
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/DefaultEACHelper.java14
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/EACHelper.java11
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/JcaPublicKeyConverter.java168
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/NamedEACHelper.java22
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/ProviderEACHelper.java22
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/EACSignatureVerifier.java30
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/EACSigner.java27
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/DefaultEACHelper.java14
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/EACHelper.java39
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/EACUtil.java5
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/JcaEACSignatureVerifierBuilder.java181
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/JcaEACSignerBuilder.java234
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/NamedEACHelper.java22
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/ProviderEACHelper.java22
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/mozilla/SignedPublicKeyAndChallenge.java139
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/EncryptionException.java23
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/MiscPEMGenerator.java211
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMDecryptor.java7
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMDecryptorProvider.java9
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMEncryptedKeyPair.java44
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMEncryptor.java11
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMException.java34
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMKeyPair.java26
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMKeyPairParser.java9
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMParser.java509
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMUtilities.java65
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMWriter.java60
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PKCS8Generator.java87
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PasswordException.java10
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PasswordFinder.java9
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaMiscPEMGenerator.java98
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPEMKeyConverter.java115
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPKCS8Generator.java18
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8DecryptorProviderBuilder.java141
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java221
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMDecryptorProviderBuilder.java54
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMEncryptorBuilder.java78
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/PEMUtilities.java258
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyUnwrapper.java19
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyWrapper.java19
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/BufferingContentSigner.java70
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/ContentSigner.java27
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/ContentVerifier.java31
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/ContentVerifierProvider.java34
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java97
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DefaultSecretKeySizeProvider.java69
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java212
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DigestAlgorithmIdentifierFinder.java24
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DigestCalculator.java36
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DigestCalculatorProvider.java9
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/GenericKey.java41
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/InputDecryptor.java29
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/InputDecryptorProvider.java9
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/InputExpander.java29
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/InputExpanderProvider.java8
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/KeyUnwrapper.java11
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/KeyWrapper.java11
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/MacCalculator.java34
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/MacCalculatorProvider.java8
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OperatorCreationException.java15
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OperatorException.java24
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OperatorStreamException.java21
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OutputCompressor.java29
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OutputEncryptor.java36
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/RawContentVerifier.java17
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/RuntimeOperatorException.java24
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/SecretKeySizeProvider.java17
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/SignatureAlgorithmIdentifierFinder.java15
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyUnwrapper.java19
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyWrapper.java19
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/AESUtil.java34
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyUnwrapper.java13
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyWrapper.java13
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyUnwrapper.java51
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyWrapper.java60
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcContentSignerBuilder.java82
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcContentVerifierProviderBuilder.java144
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentSignerBuilder.java25
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentVerifierProviderBuilder.java40
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDefaultDigestProvider.java144
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestCalculatorProvider.java82
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestProvider.java11
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyUnwrapper.java22
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyWrapper.java32
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentSignerBuilder.java24
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentVerifierProviderBuilder.java39
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcSignerOutputStream.java47
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyUnwrapper.java49
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyWrapper.java51
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/CamelliaUtil.java36
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/OperatorUtils.java23
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/SEEDUtil.java14
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaAlgorithmParametersConverter.java73
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentSignerBuilder.java160
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java312
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java114
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java133
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyWrapper.java157
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceGenericKey.java33
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyUnwrapper.java65
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyWrapper.java154
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorHelper.java469
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorUtils.java25
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/MacDataGenerator.java49
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS10CertificationRequest.java236
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS10CertificationRequestBuilder.java156
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12MacCalculatorBuilder.java13
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12MacCalculatorBuilderProvider.java8
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12PfxPdu.java161
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12PfxPduBuilder.java179
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBag.java93
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBagBuilder.java76
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBagFactory.java58
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS8EncryptedPrivateKeyInfo.java76
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS8EncryptedPrivateKeyInfoBuilder.java54
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCSException.java27
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCSIOException.java29
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS10CertificationRequest.java42
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS10CertificationRequestBuilder.java28
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12MacCalculatorBuilder.java54
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12MacCalculatorBuilderProvider.java40
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12PBEInputDecryptorProviderBuilder.java66
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12PBEOutputEncryptorBuilder.java77
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/PKCS12PBEUtils.java153
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS10CertificationRequest.java115
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS10CertificationRequestBuilder.java38
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS12SafeBagBuilder.java45
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS8EncryptedPrivateKeyInfoBuilder.java15
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilder.java122
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilderProvider.java108
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCSPBEInputDecryptorProviderBuilder.java177
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCSPBEOutputEncryptorBuilder.java179
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/GenTimeAccuracy.java60
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPAlgorithms.java35
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPException.java28
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPIOException.java30
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPUtil.java209
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPValidationException.java34
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampRequest.java268
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampRequestGenerator.java163
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampResponse.java189
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampResponseGenerator.java353
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampToken.java393
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampTokenGenerator.java356
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampTokenInfo.java121
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedData.java204
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedDataGenerator.java70
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedDataParser.java207
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedGenerator.java88
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/ImprintDigestInvalidException.java21
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/MetaDataUtil.java76
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/TimeStampDataUtil.java256
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/voms/VOMSAttribute.java242
-rw-r--r--libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/cmp/package.html7
-rw-r--r--libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/crmf/jcajce/package.html7
-rw-r--r--libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/crmf/package.html7
-rw-r--r--libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/jcajce/package.html7
-rw-r--r--libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/ocsp/jcajce/package.html7
-rw-r--r--libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/ocsp/package.html7
-rw-r--r--libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/package.html5
-rw-r--r--libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/selector/package.html7
-rw-r--r--libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cms/package.html5
-rw-r--r--libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/dvcs/package.html5
-rw-r--r--libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/eac/package.html5
-rw-r--r--libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/mozilla/package.html5
-rw-r--r--libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/openssl/package.html5
-rw-r--r--libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/operator/package.html5
-rw-r--r--libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/pkcs/jcajce/package.html7
-rw-r--r--libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/pkcs/package.html7
-rw-r--r--libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/tsp/cms/package.html5
-rw-r--r--libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/tsp/package.html5
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/cmp/GeneralPKIMessage.java82
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/CertificateRequestMessage.java309
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/FixedLengthMGF1Padder.java120
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/jcajce/CRMFHelper.java485
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/jcajce/JceAsymmetricValueDecryptorGenerator.java121
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/jcajce/JceCRMFEncryptorBuilder.java140
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/jcajce/JcePKMACValuesCalculator.java70
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/jcajce/JcaCertStoreBuilder.java149
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/path/CertPathValidationException.java24
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/selector/jcajce/JcaSelectorConverter.java34
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java57
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/CMSAbsentContent.java49
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/CMSProcessableByteArray.java55
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/CMSProcessableFile.java80
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/CMSTypedStream.java86
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/OriginatorInfoGenerator.java54
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/RecipientId.java31
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/SignerInfoGenerator.java291
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/EnvelopedDataHelper.java671
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JcaSelectorConverter.java54
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JcaX509CertSelectorConverter.java24
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java166
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JceKeyAgreeRecipient.java184
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java212
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JcePasswordRecipient.java92
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JcePasswordRecipientInfoGenerator.java66
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/ZlibExpanderProvider.java113
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8DecryptorProviderBuilder.java156
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java240
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/JcaContentSignerBuilder.java166
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java312
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java128
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/JceSymmetricKeyWrapper.java159
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/OperatorHelper.java478
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cert/crmf/jcajce/JceCRMFEncryptorBuilder.java135
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cert/jcajce/JcaAttrCertStore.java72
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cms/bc/BcCMSContentEncryptorBuilder.java124
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java161
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java155
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessage.java55
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessageBuilder.java25
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/crmf/jcajce/JcaPKIArchiveControlBuilder.java22
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaCertStoreBuilder.java151
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaX500NameUtil.java58
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaX509v1CertificateBuilder.java31
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaX509v2CRLBuilder.java15
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaX509v3CertificateBuilder.java54
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/ProviderCertHelper.java30
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/ocsp/jcajce/JcaRespID.java19
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/selector/jcajce/JcaSelectorConverter.java34
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java57
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/selector/jcajce/JcaX509CertificateHolderSelector.java57
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JcaSelectorConverter.java54
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JcaSignerId.java36
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JcaX509CertSelectorConverter.java24
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientId.java32
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JceKeyTransRecipientId.java30
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/eac/jcajce/ProviderEACHelper.java23
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/eac/operator/jcajce/ProviderEACHelper.java23
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/operator/jcajce/JcaAlgorithmParametersConverter.java44
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/operator/jcajce/OperatorHelper.java471
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/pkcs/jcajce/JcaPKCS10CertificationRequestBuilder.java25
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/tsp/cms/CMSTimeStampedData.java204
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/tsp/cms/CMSTimeStampedDataParser.java207
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/tsp/cms/CMSTimeStampedGenerator.java90
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.4/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java215
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.4/org/spongycastle/eac/jcajce/JcaPublicKeyConverter.java141
-rw-r--r--libraries/spongycastle/pkix/src/main/jdk1.4/org/spongycastle/operator/jcajce/JcaAlgorithmParametersConverter.java44
-rw-r--r--libraries/spongycastle/pkix/src/test/data/org/spongycastle/tsp/test/FileDaFirmare.data3
-rw-r--r--libraries/spongycastle/pkix/src/test/data/org/spongycastle/tsp/test/FileDaFirmare.txt.tsd.derbin0 -> 6207 bytes
-rw-r--r--libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/AttrCertSelectorTest.java217
-rw-r--r--libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/AttrCertTest.java639
-rw-r--r--libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/CertTest.java1157
-rw-r--r--libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/PKCS10Test.java159
-rw-r--r--libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/RegressionTest.java31
-rw-r--r--libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cms/test/BcEnvelopedDataTest.java119
-rw-r--r--libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cms/test/BcSignedDataTest.java536
-rw-r--r--libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cms/test/CMSTestUtil.java206
-rw-r--r--libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cms/test/RegressionTest.java29
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/cmp/test/AllTests.java317
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/crmf/test/AllTests.java384
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/ocsp/test/AllTests.java44
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/ocsp/test/OCSPTest.java973
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/path/test/CertPathTest.java369
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/path/test/CertPathValidationTest.java403
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/AllTests.java57
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/AttrCertSelectorTest.java243
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/AttrCertTest.java667
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/BcAttrCertSelectorTest.java212
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/BcAttrCertTest.java636
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/BcCertTest.java1435
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/BcPKCS10Test.java230
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/CertTest.java2997
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/ConverterTest.java66
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/PEMData.java114
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/PKCS10Test.java616
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/SHA1DigestCalculator.java44
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/X509ExtensionUtilsTest.java55
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/AllTests.java51
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/BcEnvelopedDataTest.java969
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/BcSignedDataTest.java1835
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/CMSSampleMessages.java147
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/CMSTestSetup.java24
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/CMSTestUtil.java503
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/ConverterTest.java111
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/MiscDataStreamTest.java265
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewAuthenticatedDataStreamTest.java251
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewAuthenticatedDataTest.java473
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewCompressedDataStreamTest.java127
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewCompressedDataTest.java151
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewEnvelopedDataStreamTest.java760
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewEnvelopedDataTest.java1488
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewSignedDataStreamTest.java1311
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewSignedDataTest.java2060
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NullProviderTest.java281
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/Rfc4134Test.java445
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/SHA1DigestCalculator.java44
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/SunProviderTest.java284
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/dvcs/test/AllTests.java239
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/dvcs/test/DVCSParseTest.java393
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/dvcs/test/DVCSTestSetup.java28
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/dvcs/test/SHA1DigestCalculator.java44
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/eac/test/AllTests.java201
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/eac/test/EACTestSetup.java28
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/mozilla/test/AllTests.java43
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/mozilla/test/SPKACTest.java113
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/ocsp/test/AllTests.java45
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/ocsp/test/OCSPTest.java865
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/ocsp/test/OCSPTestUtil.java181
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/openssl/test/AllTests.java151
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/openssl/test/ParserTest.java500
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/openssl/test/WriterTest.java248
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/pkcs/test/AllTests.java24
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/pkcs/test/BCTestSetup.java26
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/pkcs/test/PKCS10Test.java78
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/pkcs/test/PfxPduTest.java1255
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/GenTimeAccuracyUnitTest.java105
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/TimeStampTokenInfoUnitTest.java144
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/AllTests.java32
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/CMSTimeStampedDataGeneratorTest.java309
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/CMSTimeStampedDataParserTest.java91
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/CMSTimeStampedDataTest.java84
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/NewTSPTest.java833
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/ParseTest.java417
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/SHA1DigestCalculator.java44
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/SHA256DigestCalculator.java44
-rw-r--r--libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/TSPTestUtil.java229
-rw-r--r--libraries/spongycastle/pkix/src/test/jdk1.1/org/spongycastle/cert/path/test/CertPathTest.java370
-rw-r--r--libraries/spongycastle/pkix/src/test/jdk1.1/org/spongycastle/cert/test/CertTest.java2812
-rw-r--r--libraries/spongycastle/pkix/src/test/jdk1.1/org/spongycastle/cert/test/PKCS10Test.java420
-rw-r--r--libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/crmf/test/AllTests.java355
-rw-r--r--libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/AllTests.java56
-rw-r--r--libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/AttrCertTest.java665
-rw-r--r--libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/CertTest.java2875
-rw-r--r--libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/ConverterTest.java66
-rw-r--r--libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/PKCS10Test.java578
-rw-r--r--libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/AllTests.java32
-rw-r--r--libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/ConverterTest.java111
-rw-r--r--libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/Rfc4134Test.java430
-rw-r--r--libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/SignedDataStreamTest.java1158
-rw-r--r--libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/SignedDataTest.java1573
-rw-r--r--libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/openssl/test/ParserTest.java492
-rw-r--r--libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/openssl/test/ReaderTest.java323
-rw-r--r--libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/tsp/test/TSPTest.java603
-rw-r--r--libraries/spongycastle/pkix/src/test/jdk1.4/org/spongycastle/cert/test/CertTest.java2984
-rw-r--r--libraries/spongycastle/pkix/src/test/jdk1.4/org/spongycastle/cms/test/NewEnvelopedDataTest.java1317
-rw-r--r--libraries/spongycastle/pkix/src/test/org/spongycastle/tsp/test/FileDaFirmare.data3
-rw-r--r--libraries/spongycastle/pkix/src/test/org/spongycastle/tsp/test/FileDaFirmare.txt.tsd.derbin0 -> 6207 bytes
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignData.data1
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA1.sigbin0 -> 3345 bytes
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA1Enc.sigbin0 -> 3371 bytes
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA256.sigbin0 -> 3417 bytes
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA256Enc.sigbin0 -> 3443 bytes
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA512.sigbin0 -> 3450 bytes
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA512Enc.sigbin0 -> 3476 bytes
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/counterSig.p7mbin0 -> 5647 bytes
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/eac/test/Belgique CVCA-02032010.7816.cvcertbin0 -> 433 bytes
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/eac/test/REQ_18102010.csrbin0 -> 346 bytes
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/eac/test/at_cert_19a.cvcertbin0 -> 363 bytes
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/eac/test/dv_cer_BEDVBUZABE006_7816.cvcertbin0 -> 225 bytes
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/README.txt8
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes128_cbc.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes128_cfb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes128_ecb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes128_ofb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes192_cbc.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes192_cfb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes192_ecb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes192_ofb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes256_cbc.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes256_cfb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes256_ecb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes256_ofb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_blowfish_cbc.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_blowfish_cfb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_blowfish_ecb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_blowfish_ofb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des1_cbc.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des1_cfb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des1_ecb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des1_ofb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des2_cbc.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des2_cfb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des2_ecb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des2_ofb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des3_cbc.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des3_cfb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des3_ecb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des3_ofb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_128_cbc.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_128_cfb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_128_ecb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_128_ofb.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_40_cbc.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_64_cbc.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_unencrypted.pem20
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/pkcs8/openssl_pkcs8_rsa.pem28
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/pkcs8/openssl_pkcs8_rsa_enc.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes128_cbc.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes128_cfb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes128_ecb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes128_ofb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes192_cbc.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes192_cfb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes192_ecb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes192_ofb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes256_cbc.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes256_cfb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes256_ecb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes256_ofb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_blowfish_cbc.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_blowfish_cfb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_blowfish_ecb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_blowfish_ofb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des1_cbc.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des1_cfb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des1_ecb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des1_ofb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des2_cbc.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des2_cfb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des2_ecb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des2_ofb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des3_cbc.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des3_cfb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des3_ecb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des3_ofb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_128_cbc.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_128_cfb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_128_ecb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_128_ofb.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_40_cbc.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_64_cbc.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_unencrypted.pem27
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/ecexpparam.pem23
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/eckey.pem9
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/enckey.pem30
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/extratest.pem110
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/pkcs7.pem54
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/pkcs8test.pem175
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/smimenopw.pem29
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/test.pem133
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/tsp/test/FileDaFirmare.data3
-rw-r--r--libraries/spongycastle/pkix/src/test/resources/org/spongycastle/tsp/test/FileDaFirmare.txt.tsd.derbin0 -> 6207 bytes
727 files changed, 101482 insertions, 0 deletions
diff --git a/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/CertUtils.java b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/CertUtils.java
new file mode 100644
index 000000000..73d093a0f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/CertUtils.java
@@ -0,0 +1,246 @@
+package org.spongycastle.cert;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERGeneralizedTime;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AttributeCertificate;
+import org.spongycastle.asn1.x509.AttributeCertificateInfo;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.ExtensionsGenerator;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.asn1.x509.TBSCertificate;
+import org.spongycastle.operator.ContentSigner;
+
+class CertUtils
+{
+ private static Set EMPTY_SET = Collections.unmodifiableSet(new HashSet());
+ private static List EMPTY_LIST = Collections.unmodifiableList(new ArrayList());
+
+ static X509CertificateHolder generateFullCert(ContentSigner signer, TBSCertificate tbsCert)
+ {
+ try
+ {
+ return new X509CertificateHolder(generateStructure(tbsCert, signer.getAlgorithmIdentifier(), generateSig(signer, tbsCert)));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("cannot produce certificate signature");
+ }
+ }
+
+ static X509AttributeCertificateHolder generateFullAttrCert(ContentSigner signer, AttributeCertificateInfo attrInfo)
+ {
+ try
+ {
+ return new X509AttributeCertificateHolder(generateAttrStructure(attrInfo, signer.getAlgorithmIdentifier(), generateSig(signer, attrInfo)));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("cannot produce attribute certificate signature");
+ }
+ }
+
+ static X509CRLHolder generateFullCRL(ContentSigner signer, TBSCertList tbsCertList)
+ {
+ try
+ {
+ return new X509CRLHolder(generateCRLStructure(tbsCertList, signer.getAlgorithmIdentifier(), generateSig(signer, tbsCertList)));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("cannot produce certificate signature");
+ }
+ }
+
+ private static byte[] generateSig(ContentSigner signer, ASN1Encodable tbsObj)
+ throws IOException
+ {
+ OutputStream sOut = signer.getOutputStream();
+ DEROutputStream dOut = new DEROutputStream(sOut);
+
+ dOut.writeObject(tbsObj);
+
+ sOut.close();
+
+ return signer.getSignature();
+ }
+
+ private static Certificate generateStructure(TBSCertificate tbsCert, AlgorithmIdentifier sigAlgId, byte[] signature)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCert);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ return Certificate.getInstance(new DERSequence(v));
+ }
+
+ private static AttributeCertificate generateAttrStructure(AttributeCertificateInfo attrInfo, AlgorithmIdentifier sigAlgId, byte[] signature)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(attrInfo);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ return AttributeCertificate.getInstance(new DERSequence(v));
+ }
+
+ private static CertificateList generateCRLStructure(TBSCertList tbsCertList, AlgorithmIdentifier sigAlgId, byte[] signature)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCertList);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ return CertificateList.getInstance(new DERSequence(v));
+ }
+
+ static Set getCriticalExtensionOIDs(Extensions extensions)
+ {
+ if (extensions == null)
+ {
+ return EMPTY_SET;
+ }
+
+ return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getCriticalExtensionOIDs())));
+ }
+
+ static Set getNonCriticalExtensionOIDs(Extensions extensions)
+ {
+ if (extensions == null)
+ {
+ return EMPTY_SET;
+ }
+
+ // TODO: should probably produce a set that imposes correct ordering
+ return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getNonCriticalExtensionOIDs())));
+ }
+
+ static List getExtensionOIDs(Extensions extensions)
+ {
+ if (extensions == null)
+ {
+ return EMPTY_LIST;
+ }
+
+ return Collections.unmodifiableList(Arrays.asList(extensions.getExtensionOIDs()));
+ }
+
+ static void addExtension(ExtensionsGenerator extGenerator, ASN1ObjectIdentifier oid, boolean isCritical, ASN1Encodable value)
+ throws CertIOException
+ {
+ try
+ {
+ extGenerator.addExtension(oid, isCritical, value);
+ }
+ catch (IOException e)
+ {
+ throw new CertIOException("cannot encode extension: " + e.getMessage(), e);
+ }
+ }
+
+ static 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);
+ }
+ }
+
+ static boolean[] bitStringToBoolean(DERBitString bitString)
+ {
+ if (bitString != null)
+ {
+ byte[] bytes = bitString.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - bitString.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ static Date recoverDate(DERGeneralizedTime time)
+ {
+ return time.getDate();
+ }
+
+ static boolean dateBefore(Date d1, Date d2)
+ {
+ return d1.getTime() < d2.getTime();
+ }
+
+ static boolean dateAfter(Date d1, Date d2)
+ {
+ return d1.getTime() > d2.getTime();
+ }
+
+ static 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());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/X509AttributeCertificateHolder.java b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/X509AttributeCertificateHolder.java
new file mode 100644
index 000000000..e58587a70
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/X509AttributeCertificateHolder.java
@@ -0,0 +1,366 @@
+package org.spongycastle.cert;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AttCertValidityPeriod;
+import org.spongycastle.asn1.x509.Attribute;
+import org.spongycastle.asn1.x509.AttributeCertificate;
+import org.spongycastle.asn1.x509.AttributeCertificateInfo;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.operator.ContentVerifier;
+import org.spongycastle.operator.ContentVerifierProvider;
+
+/**
+ * Holding class for an X.509 AttributeCertificate structure.
+ */
+public class X509AttributeCertificateHolder
+{
+ private static Attribute[] EMPTY_ARRAY = new Attribute[0];
+
+ private AttributeCertificate attrCert;
+ private Extensions extensions;
+
+ private static AttributeCertificate parseBytes(byte[] certEncoding)
+ throws IOException
+ {
+ try
+ {
+ return AttributeCertificate.getInstance(ASN1Primitive.fromByteArray(certEncoding));
+ }
+ catch (ClassCastException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Create a X509AttributeCertificateHolder from the passed in bytes.
+ *
+ * @param certEncoding BER/DER encoding of the certificate.
+ * @throws IOException in the event of corrupted data, or an incorrect structure.
+ */
+ public X509AttributeCertificateHolder(byte[] certEncoding)
+ throws IOException
+ {
+ this(parseBytes(certEncoding));
+ }
+
+ /**
+ * Create a X509AttributeCertificateHolder from the passed in ASN.1 structure.
+ *
+ * @param attrCert an ASN.1 AttributeCertificate structure.
+ */
+ public X509AttributeCertificateHolder(AttributeCertificate attrCert)
+ {
+ this.attrCert = attrCert;
+ this.extensions = attrCert.getAcinfo().getExtensions();
+ }
+
+ /**
+ * Return the ASN.1 encoding of this holder's attribute certificate.
+ *
+ * @return a DER encoded byte array.
+ * @throws IOException if an encoding cannot be generated.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return attrCert.getEncoded();
+ }
+
+ public int getVersion()
+ {
+ return attrCert.getAcinfo().getVersion().getValue().intValue() + 1;
+ }
+
+ /**
+ * Return the serial number of this attribute certificate.
+ *
+ * @return the serial number.
+ */
+ public BigInteger getSerialNumber()
+ {
+ return attrCert.getAcinfo().getSerialNumber().getValue();
+ }
+
+ /**
+ * Return the holder details for this attribute certificate.
+ *
+ * @return this attribute certificate's holder structure.
+ */
+ public AttributeCertificateHolder getHolder()
+ {
+ return new AttributeCertificateHolder((ASN1Sequence)attrCert.getAcinfo().getHolder().toASN1Primitive());
+ }
+
+ /**
+ * Return the issuer details for this attribute certificate.
+ *
+ * @return this attribute certificate's issuer structure,
+ */
+ public AttributeCertificateIssuer getIssuer()
+ {
+ return new AttributeCertificateIssuer(attrCert.getAcinfo().getIssuer());
+ }
+
+ /**
+ * Return the date before which this attribute certificate is not valid.
+ *
+ * @return the start date for the attribute certificate's validity period.
+ */
+ public Date getNotBefore()
+ {
+ return CertUtils.recoverDate(attrCert.getAcinfo().getAttrCertValidityPeriod().getNotBeforeTime());
+ }
+
+ /**
+ * Return the date after which this attribute certificate is not valid.
+ *
+ * @return the final date for the attribute certificate's validity period.
+ */
+ public Date getNotAfter()
+ {
+ return CertUtils.recoverDate(attrCert.getAcinfo().getAttrCertValidityPeriod().getNotAfterTime());
+ }
+
+ /**
+ * Return the attributes, if any associated with this request.
+ *
+ * @return an array of Attribute, zero length if none present.
+ */
+ public Attribute[] getAttributes()
+ {
+ ASN1Sequence seq = attrCert.getAcinfo().getAttributes();
+ Attribute[] attrs = new Attribute[seq.size()];
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ attrs[i] = Attribute.getInstance(seq.getObjectAt(i));
+ }
+
+ return attrs;
+ }
+
+ /**
+ * Return an array of attributes matching the passed in type OID.
+ *
+ * @param type the type of the attribute being looked for.
+ * @return an array of Attribute of the requested type, zero length if none present.
+ */
+ public Attribute[] getAttributes(ASN1ObjectIdentifier type)
+ {
+ ASN1Sequence seq = attrCert.getAcinfo().getAttributes();
+ List list = new ArrayList();
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ Attribute attr = Attribute.getInstance(seq.getObjectAt(i));
+ if (attr.getAttrType().equals(type))
+ {
+ list.add(attr);
+ }
+ }
+
+ if (list.size() == 0)
+ {
+ return EMPTY_ARRAY;
+ }
+
+ return (Attribute[])list.toArray(new Attribute[list.size()]);
+ }
+
+ /**
+ * Return whether or not the holder's attribute certificate contains extensions.
+ *
+ * @return true if extension are present, false otherwise.
+ */
+ public boolean hasExtensions()
+ {
+ return extensions != null;
+ }
+
+ /**
+ * Look up the extension associated with the passed in OID.
+ *
+ * @param oid the OID of the extension of interest.
+ *
+ * @return the extension if present, null otherwise.
+ */
+ public Extension getExtension(ASN1ObjectIdentifier oid)
+ {
+ if (extensions != null)
+ {
+ return extensions.getExtension(oid);
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the extensions block associated with this certificate if there is one.
+ *
+ * @return the extensions block, null otherwise.
+ */
+ public Extensions getExtensions()
+ {
+ return extensions;
+ }
+
+ /**
+ * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the
+ * extensions contained in this holder's attribute certificate.
+ *
+ * @return a list of extension OIDs.
+ */
+ public List getExtensionOIDs()
+ {
+ return CertUtils.getExtensionOIDs(extensions);
+ }
+
+ /**
+ * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the
+ * critical extensions contained in this holder's attribute certificate.
+ *
+ * @return a set of critical extension OIDs.
+ */
+ public Set getCriticalExtensionOIDs()
+ {
+ return CertUtils.getCriticalExtensionOIDs(extensions);
+ }
+
+ /**
+ * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the
+ * non-critical extensions contained in this holder's attribute certificate.
+ *
+ * @return a set of non-critical extension OIDs.
+ */
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return CertUtils.getNonCriticalExtensionOIDs(extensions);
+ }
+
+ public boolean[] getIssuerUniqueID()
+ {
+ return CertUtils.bitStringToBoolean(attrCert.getAcinfo().getIssuerUniqueID());
+ }
+
+ /**
+ * Return the details of the signature algorithm used to create this attribute certificate.
+ *
+ * @return the AlgorithmIdentifier describing the signature algorithm used to create this attribute certificate.
+ */
+ public AlgorithmIdentifier getSignatureAlgorithm()
+ {
+ return attrCert.getSignatureAlgorithm();
+ }
+
+ /**
+ * Return the bytes making up the signature associated with this attribute certificate.
+ *
+ * @return the attribute certificate signature bytes.
+ */
+ public byte[] getSignature()
+ {
+ return attrCert.getSignatureValue().getBytes();
+ }
+
+ /**
+ * Return the underlying ASN.1 structure for the attribute certificate in this holder.
+ *
+ * @return a AttributeCertificate object.
+ */
+ public AttributeCertificate toASN1Structure()
+ {
+ return attrCert;
+ }
+
+ /**
+ * Return whether or not this attribute certificate is valid on a particular date.
+ *
+ * @param date the date of interest.
+ * @return true if the attribute certificate is valid, false otherwise.
+ */
+ public boolean isValidOn(Date date)
+ {
+ AttCertValidityPeriod certValidityPeriod = attrCert.getAcinfo().getAttrCertValidityPeriod();
+
+ return !CertUtils.dateBefore(date, CertUtils.recoverDate(certValidityPeriod.getNotBeforeTime())) && !CertUtils.dateAfter(date, CertUtils.recoverDate(certValidityPeriod.getNotAfterTime()));
+ }
+
+ /**
+ * Validate the signature on the attribute certificate in this holder.
+ *
+ * @param verifierProvider a ContentVerifierProvider that can generate a verifier for the signature.
+ * @return true if the signature is valid, false otherwise.
+ * @throws CertException if the signature cannot be processed or is inappropriate.
+ */
+ public boolean isSignatureValid(ContentVerifierProvider verifierProvider)
+ throws CertException
+ {
+ AttributeCertificateInfo acinfo = attrCert.getAcinfo();
+
+ if (!CertUtils.isAlgIdEqual(acinfo.getSignature(), attrCert.getSignatureAlgorithm()))
+ {
+ throw new CertException("signature invalid - algorithm identifier mismatch");
+ }
+
+ ContentVerifier verifier;
+
+ try
+ {
+ verifier = verifierProvider.get((acinfo.getSignature()));
+
+ OutputStream sOut = verifier.getOutputStream();
+ DEROutputStream dOut = new DEROutputStream(sOut);
+
+ dOut.writeObject(acinfo);
+
+ sOut.close();
+ }
+ catch (Exception e)
+ {
+ throw new CertException("unable to process signature: " + e.getMessage(), e);
+ }
+
+ return verifier.verify(attrCert.getSignatureValue().getBytes());
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof X509AttributeCertificateHolder))
+ {
+ return false;
+ }
+
+ X509AttributeCertificateHolder other = (X509AttributeCertificateHolder)o;
+
+ return this.attrCert.equals(other.attrCert);
+ }
+
+ public int hashCode()
+ {
+ return this.attrCert.hashCode();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/X509CertificateHolder.java b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/X509CertificateHolder.java
new file mode 100644
index 000000000..0cf147f6e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/X509CertificateHolder.java
@@ -0,0 +1,327 @@
+package org.spongycastle.cert;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.TBSCertificate;
+import org.spongycastle.operator.ContentVerifier;
+import org.spongycastle.operator.ContentVerifierProvider;
+
+/**
+ * Holding class for an X.509 Certificate structure.
+ */
+public class X509CertificateHolder
+{
+ private Certificate x509Certificate;
+ private Extensions extensions;
+
+ private static Certificate parseBytes(byte[] certEncoding)
+ throws IOException
+ {
+ try
+ {
+ return Certificate.getInstance(ASN1Primitive.fromByteArray(certEncoding));
+ }
+ catch (ClassCastException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Create a X509CertificateHolder from the passed in bytes.
+ *
+ * @param certEncoding BER/DER encoding of the certificate.
+ * @throws IOException in the event of corrupted data, or an incorrect structure.
+ */
+ public X509CertificateHolder(byte[] certEncoding)
+ throws IOException
+ {
+ this(parseBytes(certEncoding));
+ }
+
+ /**
+ * Create a X509CertificateHolder from the passed in ASN.1 structure.
+ *
+ * @param x509Certificate an ASN.1 Certificate structure.
+ */
+ public X509CertificateHolder(Certificate x509Certificate)
+ {
+ this.x509Certificate = x509Certificate;
+ this.extensions = x509Certificate.getTBSCertificate().getExtensions();
+ }
+
+ public int getVersionNumber()
+ {
+ return x509Certificate.getVersionNumber();
+ }
+
+ /**
+ * @deprecated use getVersionNumber
+ */
+ public int getVersion()
+ {
+ return x509Certificate.getVersionNumber();
+ }
+
+ /**
+ * Return whether or not the holder's certificate contains extensions.
+ *
+ * @return true if extension are present, false otherwise.
+ */
+ public boolean hasExtensions()
+ {
+ return extensions != null;
+ }
+
+ /**
+ * Look up the extension associated with the passed in OID.
+ *
+ * @param oid the OID of the extension of interest.
+ *
+ * @return the extension if present, null otherwise.
+ */
+ public Extension getExtension(ASN1ObjectIdentifier oid)
+ {
+ if (extensions != null)
+ {
+ return extensions.getExtension(oid);
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the extensions block associated with this certificate if there is one.
+ *
+ * @return the extensions block, null otherwise.
+ */
+ public Extensions getExtensions()
+ {
+ return extensions;
+ }
+
+ /**
+ * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the
+ * extensions contained in this holder's certificate.
+ *
+ * @return a list of extension OIDs.
+ */
+ public List getExtensionOIDs()
+ {
+ return CertUtils.getExtensionOIDs(extensions);
+ }
+
+ /**
+ * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the
+ * critical extensions contained in this holder's certificate.
+ *
+ * @return a set of critical extension OIDs.
+ */
+ public Set getCriticalExtensionOIDs()
+ {
+ return CertUtils.getCriticalExtensionOIDs(extensions);
+ }
+
+ /**
+ * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the
+ * non-critical extensions contained in this holder's certificate.
+ *
+ * @return a set of non-critical extension OIDs.
+ */
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return CertUtils.getNonCriticalExtensionOIDs(extensions);
+ }
+
+ /**
+ * Return the serial number of this attribute certificate.
+ *
+ * @return the serial number.
+ */
+ public BigInteger getSerialNumber()
+ {
+ return x509Certificate.getSerialNumber().getValue();
+ }
+
+ /**
+ * Return the issuer of this certificate.
+ *
+ * @return the certificate issuer.
+ */
+ public X500Name getIssuer()
+ {
+ return X500Name.getInstance(x509Certificate.getIssuer());
+ }
+
+ /**
+ * Return the subject this certificate is for.
+ *
+ * @return the subject for the certificate.
+ */
+ public X500Name getSubject()
+ {
+ return X500Name.getInstance(x509Certificate.getSubject());
+ }
+
+ /**
+ * Return the date before which this certificate is not valid.
+ *
+ * @return the start time for the certificate's validity period.
+ */
+ public Date getNotBefore()
+ {
+ return x509Certificate.getStartDate().getDate();
+ }
+
+ /**
+ * Return the date after which this certificate is not valid.
+ *
+ * @return the final time for the certificate's validity period.
+ */
+ public Date getNotAfter()
+ {
+ return x509Certificate.getEndDate().getDate();
+ }
+
+ /**
+ * Return the SubjectPublicKeyInfo describing the public key this certificate is carrying.
+ *
+ * @return the public key ASN.1 structure contained in the certificate.
+ */
+ public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+ {
+ return x509Certificate.getSubjectPublicKeyInfo();
+ }
+
+ /**
+ * Return the underlying ASN.1 structure for the certificate in this holder.
+ *
+ * @return a X509CertificateStructure object.
+ */
+ public Certificate toASN1Structure()
+ {
+ return x509Certificate;
+ }
+
+ /**
+ * Return the details of the signature algorithm used to create this attribute certificate.
+ *
+ * @return the AlgorithmIdentifier describing the signature algorithm used to create this attribute certificate.
+ */
+ public AlgorithmIdentifier getSignatureAlgorithm()
+ {
+ return x509Certificate.getSignatureAlgorithm();
+ }
+
+ /**
+ * Return the bytes making up the signature associated with this attribute certificate.
+ *
+ * @return the attribute certificate signature bytes.
+ */
+ public byte[] getSignature()
+ {
+ return x509Certificate.getSignature().getBytes();
+ }
+
+ /**
+ * Return whether or not this certificate is valid on a particular date.
+ *
+ * @param date the date of interest.
+ * @return true if the certificate is valid, false otherwise.
+ */
+ public boolean isValidOn(Date date)
+ {
+ return !CertUtils.dateBefore(date, x509Certificate.getStartDate().getDate()) && !CertUtils.dateAfter(date, x509Certificate.getEndDate().getDate());
+ }
+
+ /**
+ * Validate the signature on the certificate in this holder.
+ *
+ * @param verifierProvider a ContentVerifierProvider that can generate a verifier for the signature.
+ * @return true if the signature is valid, false otherwise.
+ * @throws CertException if the signature cannot be processed or is inappropriate.
+ */
+ public boolean isSignatureValid(ContentVerifierProvider verifierProvider)
+ throws CertException
+ {
+ TBSCertificate tbsCert = x509Certificate.getTBSCertificate();
+
+ if (!CertUtils.isAlgIdEqual(tbsCert.getSignature(), x509Certificate.getSignatureAlgorithm()))
+ {
+ throw new CertException("signature invalid - algorithm identifier mismatch");
+ }
+
+ ContentVerifier verifier;
+
+ try
+ {
+ verifier = verifierProvider.get((tbsCert.getSignature()));
+
+ OutputStream sOut = verifier.getOutputStream();
+ DEROutputStream dOut = new DEROutputStream(sOut);
+
+ dOut.writeObject(tbsCert);
+
+ sOut.close();
+ }
+ catch (Exception e)
+ {
+ throw new CertException("unable to process signature: " + e.getMessage(), e);
+ }
+
+ return verifier.verify(x509Certificate.getSignature().getBytes());
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof X509CertificateHolder))
+ {
+ return false;
+ }
+
+ X509CertificateHolder other = (X509CertificateHolder)o;
+
+ return this.x509Certificate.equals(other.x509Certificate);
+ }
+
+ public int hashCode()
+ {
+ return this.x509Certificate.hashCode();
+ }
+
+ /**
+ * Return the ASN.1 encoding of this holder's certificate.
+ *
+ * @return a DER encoded byte array.
+ * @throws IOException if an encoding cannot be generated.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return x509Certificate.getEncoded();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/crmf/EncryptedValueParser.java b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/crmf/EncryptedValueParser.java
new file mode 100644
index 000000000..0a0b19507
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/crmf/EncryptedValueParser.java
@@ -0,0 +1,103 @@
+package org.spongycastle.cert.crmf;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.crmf.EncryptedValue;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.operator.InputDecryptor;
+import org.spongycastle.util.Strings;
+import org.spongycastle.util.io.Streams;
+
+/**
+ * Parser for EncryptedValue structures.
+ */
+public class EncryptedValueParser
+{
+ private EncryptedValue value;
+ private EncryptedValuePadder padder;
+
+ /**
+ * Basic constructor - create a parser to read the passed in value.
+ *
+ * @param value the value to be parsed.
+ */
+ public EncryptedValueParser(EncryptedValue value)
+ {
+ this.value = value;
+ }
+
+ /**
+ * Create a parser to read the passed in value, assuming the padder was
+ * applied to the data prior to encryption.
+ *
+ * @param value the value to be parsed.
+ * @param padder the padder to be used to remove padding from the decrypted value..
+ */
+ public EncryptedValueParser(EncryptedValue value, EncryptedValuePadder padder)
+ {
+ this.value = value;
+ this.padder = padder;
+ }
+
+ private byte[] decryptValue(ValueDecryptorGenerator decGen)
+ throws CRMFException
+ {
+ if (value.getIntendedAlg() != null)
+ {
+ throw new IllegalStateException("unsupported operation");
+ }
+ if (value.getValueHint() != null)
+ {
+ throw new IllegalStateException("unsupported operation");
+ }
+
+ InputDecryptor decryptor = decGen.getValueDecryptor(value.getKeyAlg(),
+ value.getSymmAlg(), value.getEncSymmKey().getBytes());
+ InputStream dataIn = decryptor.getInputStream(new ByteArrayInputStream(
+ value.getEncValue().getBytes()));
+ try
+ {
+ byte[] data = Streams.readAll(dataIn);
+
+ if (padder != null)
+ {
+ return padder.getUnpaddedData(data);
+ }
+
+ return data;
+ }
+ catch (IOException e)
+ {
+ throw new CRMFException("Cannot parse decrypted data: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Read a X.509 certificate.
+ *
+ * @param decGen the decryptor generator to decrypt the encrypted value.
+ * @return an X509CertificateHolder containing the certificate read.
+ * @throws CRMFException if the decrypted data cannot be parsed, or a decryptor cannot be generated.
+ */
+ public X509CertificateHolder readCertificateHolder(ValueDecryptorGenerator decGen)
+ throws CRMFException
+ {
+ return new X509CertificateHolder(Certificate.getInstance(decryptValue(decGen)));
+ }
+
+ /**
+ * Read a pass phrase.
+ *
+ * @param decGen the decryptor generator to decrypt the encrypted value.
+ * @return a pass phrase as recovered from the encrypted value.
+ * @throws CRMFException if the decrypted data cannot be parsed, or a decryptor cannot be generated.
+ */
+ public char[] readPassphrase(ValueDecryptorGenerator decGen)
+ throws CRMFException
+ {
+ return Strings.fromUTF8ByteArray(decryptValue(decGen)).toCharArray();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/crmf/FixedLengthMGF1Padder.java b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/crmf/FixedLengthMGF1Padder.java
new file mode 100644
index 000000000..3335b7de1
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cert/crmf/FixedLengthMGF1Padder.java
@@ -0,0 +1,120 @@
+package org.spongycastle.cert.crmf;
+
+import java.security.SecureRandom;
+
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.generators.MGF1BytesGenerator;
+import org.spongycastle.crypto.params.MGFParameters;
+
+/**
+ * An encrypted value padder that uses MGF1 as the basis of the padding.
+ */
+public class FixedLengthMGF1Padder
+ implements EncryptedValuePadder
+{
+ private int length;
+ private SecureRandom random;
+ private Digest dig = new SHA1Digest();
+
+ /**
+ * Create a padder to so that padded output will always be at least
+ * length bytes long.
+ *
+ * @param length fixed length for padded output.
+ */
+ public FixedLengthMGF1Padder(int length)
+ {
+ this(length, null);
+ }
+
+ /**
+ * Create a padder to so that padded output will always be at least
+ * length bytes long, using the passed in source of randomness to
+ * provide the random material for the padder.
+ *
+ * @param length fixed length for padded output.
+ * @param random a source of randomness.
+ */
+ public FixedLengthMGF1Padder(int length, SecureRandom random)
+ {
+ this.length = length;
+ this.random = random;
+ }
+
+ public byte[] getPaddedData(byte[] data)
+ {
+ byte[] bytes = new byte[length];
+ byte[] seed = new byte[dig.getDigestSize()];
+ byte[] mask = new byte[length - dig.getDigestSize()];
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(seed);
+
+ MGF1BytesGenerator maskGen = new MGF1BytesGenerator(dig);
+
+ maskGen.init(new MGFParameters(seed));
+
+ maskGen.generateBytes(mask, 0, mask.length);
+
+ System.arraycopy(seed, 0, bytes, 0, seed.length);
+ System.arraycopy(data, 0, bytes, seed.length, data.length);
+
+ for (int i = seed.length + data.length + 1; i != bytes.length; i++)
+ {
+ bytes[i] = (byte)(1 | (random.nextInt() & 0xff));
+ }
+
+ for (int i = 0; i != mask.length; i++)
+ {
+ bytes[i + seed.length] ^= mask[i];
+ }
+
+ return bytes;
+ }
+
+ public byte[] getUnpaddedData(byte[] paddedData)
+ {
+ byte[] seed = new byte[dig.getDigestSize()];
+ byte[] mask = new byte[length - dig.getDigestSize()];
+
+ System.arraycopy(paddedData, 0, seed, 0, seed.length);
+
+ MGF1BytesGenerator maskGen = new MGF1BytesGenerator(dig);
+
+ maskGen.init(new MGFParameters(seed));
+
+ maskGen.generateBytes(mask, 0, mask.length);
+
+ for (int i = 0; i != mask.length; i++)
+ {
+ paddedData[i + seed.length] ^= mask[i];
+ }
+
+ int end = 0;
+
+ for (int i = paddedData.length - 1; i != seed.length; i--)
+ {
+ if (paddedData[i] == 0)
+ {
+ end = i;
+ break;
+ }
+ }
+
+ if (end == 0)
+ {
+ throw new IllegalStateException("bad padding in encoding");
+ }
+
+ byte[] data = new byte[end - seed.length];
+
+ System.arraycopy(paddedData, seed.length, data, 0, data.length);
+
+ return data;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cms/CMSTypedStream.java b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cms/CMSTypedStream.java
new file mode 100644
index 000000000..5c79012ba
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/cms/CMSTypedStream.java
@@ -0,0 +1,85 @@
+package org.spongycastle.cms;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.util.io.Streams;
+
+public class CMSTypedStream
+{
+ private static final int BUF_SIZ = 32 * 1024;
+
+ private final ASN1ObjectIdentifier _oid;
+ private final InputStream _in;
+
+ public CMSTypedStream(
+ InputStream in)
+ {
+ this(PKCSObjectIdentifiers.data.getId(), in, BUF_SIZ);
+ }
+
+ public CMSTypedStream(
+ String oid,
+ InputStream in)
+ {
+ this(new ASN1ObjectIdentifier(oid), in, BUF_SIZ);
+ }
+
+ public CMSTypedStream(
+ String oid,
+ InputStream in,
+ int bufSize)
+ {
+ this(new ASN1ObjectIdentifier(oid), in, bufSize);
+ }
+
+ public CMSTypedStream(
+ ASN1ObjectIdentifier oid,
+ InputStream in)
+ {
+ this(oid, in, BUF_SIZ);
+ }
+
+ public CMSTypedStream(
+ ASN1ObjectIdentifier oid,
+ InputStream in,
+ int bufSize)
+ {
+ _oid = oid;
+ _in = new FullReaderStream(in);
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return _oid;
+ }
+
+ public InputStream getContentStream()
+ {
+ return _in;
+ }
+
+ public void drain()
+ throws IOException
+ {
+ Streams.drain(_in);
+ _in.close();
+ }
+
+ private static class FullReaderStream extends FilterInputStream
+ {
+ FullReaderStream(InputStream in)
+ {
+ super(in);
+ }
+
+ public int read(byte[] buf, int off, int len) throws IOException
+ {
+ int totalRead = Streams.readFully(super.in, buf, off, len);
+ return totalRead > 0 ? totalRead : -1;
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/operator/bc/OperatorUtils.java b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/operator/bc/OperatorUtils.java
new file mode 100644
index 000000000..d0eae576b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/operator/bc/OperatorUtils.java
@@ -0,0 +1,16 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.operator.GenericKey;
+
+class OperatorUtils
+{
+ static byte[] getKeyBytes(GenericKey key)
+ {
+ if (key.getRepresentation() instanceof byte[])
+ {
+ return (byte[])key.getRepresentation();
+ }
+
+ throw new IllegalArgumentException("unknown generic key type");
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/TimeStampToken.java b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/TimeStampToken.java
new file mode 100644
index 000000000..d51a07fed
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/TimeStampToken.java
@@ -0,0 +1,391 @@
+package org.spongycastle.tsp;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.Date;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.cms.Attribute;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.IssuerAndSerialNumber;
+import org.spongycastle.asn1.ess.ESSCertID;
+import org.spongycastle.asn1.ess.ESSCertIDv2;
+import org.spongycastle.asn1.ess.SigningCertificate;
+import org.spongycastle.asn1.ess.SigningCertificateV2;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.tsp.TSTInfo;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.IssuerSerial;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.CMSProcessable;
+import org.spongycastle.cms.CMSSignedData;
+import org.spongycastle.cms.SignerId;
+import org.spongycastle.cms.SignerInformation;
+import org.spongycastle.cms.SignerInformationVerifier;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Store;
+
+public class TimeStampToken
+{
+ CMSSignedData tsToken;
+
+ SignerInformation tsaSignerInfo;
+
+ Date genTime;
+
+ TimeStampTokenInfo tstInfo;
+
+ CertID certID;
+
+ public TimeStampToken(ContentInfo contentInfo)
+ throws TSPException, IOException
+ {
+ this(getSignedData(contentInfo));
+ }
+
+ private static CMSSignedData getSignedData(ContentInfo contentInfo)
+ throws TSPException
+ {
+ try
+ {
+ return new CMSSignedData(contentInfo);
+ }
+ catch (CMSException e)
+ {
+ throw new TSPException("TSP parsing error: " + e.getMessage(), e.getCause());
+ }
+ }
+
+ public TimeStampToken(CMSSignedData signedData)
+ throws TSPException, IOException
+ {
+ this.tsToken = signedData;
+
+ if (!this.tsToken.getSignedContentTypeOID().equals(PKCSObjectIdentifiers.id_ct_TSTInfo.getId()))
+ {
+ throw new TSPValidationException("ContentInfo object not for a time stamp.");
+ }
+
+ Collection signers = tsToken.getSignerInfos().getSigners();
+
+ if (signers.size() != 1)
+ {
+ throw new IllegalArgumentException("Time-stamp token signed by "
+ + signers.size()
+ + " signers, but it must contain just the TSA signature.");
+ }
+
+ tsaSignerInfo = (SignerInformation)signers.iterator().next();
+
+ try
+ {
+ CMSProcessable content = tsToken.getSignedContent();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ content.write(bOut);
+
+ ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(bOut.toByteArray()));
+
+ this.tstInfo = new TimeStampTokenInfo(TSTInfo.getInstance(aIn.readObject()));
+
+ Attribute attr = tsaSignerInfo.getSignedAttributes().get(PKCSObjectIdentifiers.id_aa_signingCertificate);
+
+ if (attr != null)
+ {
+ SigningCertificate signCert = SigningCertificate.getInstance(attr.getAttrValues().getObjectAt(0));
+
+ this.certID = new CertID(ESSCertID.getInstance(signCert.getCerts()[0]));
+ }
+ else
+ {
+ attr = tsaSignerInfo.getSignedAttributes().get(PKCSObjectIdentifiers.id_aa_signingCertificateV2);
+
+ if (attr == null)
+ {
+ throw new TSPValidationException("no signing certificate attribute found, time stamp invalid.");
+ }
+
+ SigningCertificateV2 signCertV2 = SigningCertificateV2.getInstance(attr.getAttrValues().getObjectAt(0));
+
+ this.certID = new CertID(ESSCertIDv2.getInstance(signCertV2.getCerts()[0]));
+ }
+ }
+ catch (CMSException e)
+ {
+ throw new TSPException(e.getMessage(), e.getUnderlyingException());
+ }
+ }
+
+ public TimeStampTokenInfo getTimeStampInfo()
+ {
+ return tstInfo;
+ }
+
+ public SignerId getSID()
+ {
+ return tsaSignerInfo.getSID();
+ }
+
+ public AttributeTable getSignedAttributes()
+ {
+ return tsaSignerInfo.getSignedAttributes();
+ }
+
+ public AttributeTable getUnsignedAttributes()
+ {
+ return tsaSignerInfo.getUnsignedAttributes();
+ }
+
+ public Store getCertificates()
+ {
+ return tsToken.getCertificates();
+ }
+
+ public Store getCRLs()
+ {
+ return tsToken.getCRLs();
+ }
+
+ public Store getAttributeCertificates()
+ {
+ return tsToken.getAttributeCertificates();
+ }
+
+ /**
+ * Validate the time stamp token.
+ * <p>
+ * To be valid the token must be signed by the passed in certificate and
+ * the certificate must be the one referred to by the SigningCertificate
+ * attribute included in the hashed attributes of the token. The
+ * certificate must also have the ExtendedKeyUsageExtension with only
+ * KeyPurposeId.id_kp_timeStamping and have been valid at the time the
+ * timestamp was created.
+ * </p>
+ * <p>
+ * A successful call to validate means all the above are true.
+ * </p>
+ *
+ * @param sigVerifier the content verifier create the objects required to verify the CMS object in the timestamp.
+ * @throws TSPException if an exception occurs in processing the token.
+ * @throws TSPValidationException if the certificate or signature fail to be valid.
+ * @throws IllegalArgumentException if the sigVerifierProvider has no associated certificate.
+ */
+ public void validate(
+ SignerInformationVerifier sigVerifier)
+ throws TSPException, TSPValidationException
+ {
+ if (!sigVerifier.hasAssociatedCertificate())
+ {
+ throw new IllegalArgumentException("verifier provider needs an associated certificate");
+ }
+
+ try
+ {
+ X509CertificateHolder certHolder = sigVerifier.getAssociatedCertificate();
+ DigestCalculator calc = sigVerifier.getDigestCalculator(certID.getHashAlgorithm());
+
+ OutputStream cOut = calc.getOutputStream();
+
+ cOut.write(certHolder.getEncoded());
+ cOut.close();
+
+ if (!Arrays.constantTimeAreEqual(certID.getCertHash(), calc.getDigest()))
+ {
+ throw new TSPValidationException("certificate hash does not match certID hash.");
+ }
+
+ if (certID.getIssuerSerial() != null)
+ {
+ IssuerAndSerialNumber issuerSerial = new IssuerAndSerialNumber(certHolder.toASN1Structure());
+
+ if (!certID.getIssuerSerial().getSerial().equals(issuerSerial.getSerialNumber()))
+ {
+ throw new TSPValidationException("certificate serial number does not match certID for signature.");
+ }
+
+ GeneralName[] names = certID.getIssuerSerial().getIssuer().getNames();
+ boolean found = false;
+
+ for (int i = 0; i != names.length; i++)
+ {
+ if (names[i].getTagNo() == 4 && X500Name.getInstance(names[i].getName()).equals(X500Name.getInstance(issuerSerial.getName())))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ throw new TSPValidationException("certificate name does not match certID for signature. ");
+ }
+ }
+
+ TSPUtil.validateCertificate(certHolder);
+
+ if (!certHolder.isValidOn(tstInfo.getGenTime()))
+ {
+ throw new TSPValidationException("certificate not valid when time stamp created.");
+ }
+
+ if (!tsaSignerInfo.verify(sigVerifier))
+ {
+ throw new TSPValidationException("signature not created by certificate.");
+ }
+ }
+ catch (CMSException e)
+ {
+ if (e.getUnderlyingException() != null)
+ {
+ throw new TSPException(e.getMessage(), e.getUnderlyingException());
+ }
+ else
+ {
+ throw new TSPException("CMS exception: " + e, e);
+ }
+ }
+ catch (IOException e)
+ {
+ throw new TSPException("problem processing certificate: " + e, e);
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new TSPException("unable to create digest: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Return true if the signature on time stamp token is valid.
+ * <p>
+ * Note: this is a much weaker proof of correctness than calling validate().
+ * </p>
+ *
+ * @param sigVerifier the content verifier create the objects required to verify the CMS object in the timestamp.
+ * @return true if the signature matches, false otherwise.
+ * @throws TSPException if the signature cannot be processed or the provider cannot match the algorithm.
+ */
+ public boolean isSignatureValid(
+ SignerInformationVerifier sigVerifier)
+ throws TSPException
+ {
+ try
+ {
+ return tsaSignerInfo.verify(sigVerifier);
+ }
+ catch (CMSException e)
+ {
+ if (e.getUnderlyingException() != null)
+ {
+ throw new TSPException(e.getMessage(), e.getUnderlyingException());
+ }
+ else
+ {
+ throw new TSPException("CMS exception: " + e, e);
+ }
+ }
+ }
+
+ /**
+ * Return the underlying CMSSignedData object.
+ *
+ * @return the underlying CMS structure.
+ */
+ public CMSSignedData toCMSSignedData()
+ {
+ return tsToken;
+ }
+
+ /**
+ * Return a ASN.1 encoded byte stream representing the encoded object.
+ *
+ * @throws IOException if encoding fails.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return tsToken.getEncoded();
+ }
+
+ // perhaps this should be done using an interface on the ASN.1 classes...
+ private class CertID
+ {
+ private ESSCertID certID;
+ private ESSCertIDv2 certIDv2;
+
+ CertID(ESSCertID certID)
+ {
+ this.certID = certID;
+ this.certIDv2 = null;
+ }
+
+ CertID(ESSCertIDv2 certID)
+ {
+ this.certIDv2 = certID;
+ this.certID = null;
+ }
+
+ public String getHashAlgorithmName()
+ {
+ if (certID != null)
+ {
+ return "SHA-1";
+ }
+ else
+ {
+ if (NISTObjectIdentifiers.id_sha256.equals(certIDv2.getHashAlgorithm().getAlgorithm()))
+ {
+ return "SHA-256";
+ }
+ return certIDv2.getHashAlgorithm().getAlgorithm().getId();
+ }
+ }
+
+ public AlgorithmIdentifier getHashAlgorithm()
+ {
+ if (certID != null)
+ {
+ return new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1);
+ }
+ else
+ {
+ return certIDv2.getHashAlgorithm();
+ }
+ }
+
+ public byte[] getCertHash()
+ {
+ if (certID != null)
+ {
+ return certID.getCertHash();
+ }
+ else
+ {
+ return certIDv2.getCertHash();
+ }
+ }
+
+ public IssuerSerial getIssuerSerial()
+ {
+ if (certID != null)
+ {
+ return certID.getIssuerSerial();
+ }
+ else
+ {
+ return certIDv2.getIssuerSerial();
+ }
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/TimeStampTokenInfo.java b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/TimeStampTokenInfo.java
new file mode 100644
index 000000000..0b3b33523
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/TimeStampTokenInfo.java
@@ -0,0 +1,112 @@
+package org.spongycastle.tsp;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Date;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.tsp.Accuracy;
+import org.spongycastle.asn1.tsp.TSTInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.GeneralName;
+
+public class TimeStampTokenInfo
+{
+ TSTInfo tstInfo;
+ Date genTime;
+
+ TimeStampTokenInfo(TSTInfo tstInfo)
+ throws TSPException, IOException
+ {
+ this.tstInfo = tstInfo;
+ this.genTime = tstInfo.getGenTime().getDate();
+ }
+
+ public boolean isOrdered()
+ {
+ return tstInfo.getOrdering().isTrue();
+ }
+
+ public Accuracy getAccuracy()
+ {
+ return tstInfo.getAccuracy();
+ }
+
+ public Date getGenTime()
+ {
+ return genTime;
+ }
+
+ public GenTimeAccuracy getGenTimeAccuracy()
+ {
+ if (this.getAccuracy() != null)
+ {
+ return new GenTimeAccuracy(this.getAccuracy());
+ }
+
+ return null;
+ }
+
+ public ASN1ObjectIdentifier getPolicy()
+ {
+ return tstInfo.getPolicy();
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return tstInfo.getSerialNumber().getValue();
+ }
+
+ public GeneralName getTsa()
+ {
+ return tstInfo.getTsa();
+ }
+
+ /**
+ * @return the nonce value, null if there isn't one.
+ */
+ public BigInteger getNonce()
+ {
+ if (tstInfo.getNonce() != null)
+ {
+ return tstInfo.getNonce().getValue();
+ }
+
+ return null;
+ }
+
+ public AlgorithmIdentifier getHashAlgorithm()
+ {
+ return tstInfo.getMessageImprint().getHashAlgorithm();
+ }
+
+ public ASN1ObjectIdentifier getMessageImprintAlgOID()
+ {
+ return tstInfo.getMessageImprint().getHashAlgorithm().getAlgorithm();
+ }
+
+ public byte[] getMessageImprintDigest()
+ {
+ return tstInfo.getMessageImprint().getHashedMessage();
+ }
+
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return tstInfo.getEncoded();
+ }
+
+ /**
+ * @deprecated use toASN1Structure
+ * @return
+ */
+ public TSTInfo toTSTInfo()
+ {
+ return tstInfo;
+ }
+
+ public TSTInfo toASN1Structure()
+ {
+ return tstInfo;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/cms/CMSTimeStampedData.java b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/cms/CMSTimeStampedData.java
new file mode 100644
index 000000000..4d9c1653f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/cms/CMSTimeStampedData.java
@@ -0,0 +1,201 @@
+package org.spongycastle.tsp.cms;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.Evidence;
+import org.spongycastle.asn1.cms.TimeStampAndCRL;
+import org.spongycastle.asn1.cms.TimeStampTokenEvidence;
+import org.spongycastle.asn1.cms.TimeStampedData;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.tsp.TimeStampToken;
+
+public class CMSTimeStampedData
+{
+ private TimeStampedData timeStampedData;
+ private ContentInfo contentInfo;
+ private TimeStampDataUtil util;
+
+ public CMSTimeStampedData(ContentInfo contentInfo)
+ {
+ this.initialize(contentInfo);
+ }
+
+ public CMSTimeStampedData(InputStream in)
+ throws IOException
+ {
+ try
+ {
+ initialize(ContentInfo.getInstance(new ASN1InputStream(in).readObject()));
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Malformed content: " + e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new IOException("Malformed content: " + e);
+ }
+ }
+
+ public CMSTimeStampedData(byte[] baseData)
+ throws IOException
+ {
+ this(new ByteArrayInputStream(baseData));
+ }
+
+ private void initialize(ContentInfo contentInfo)
+ {
+ this.contentInfo = contentInfo;
+
+ if (CMSObjectIdentifiers.timestampedData.equals(contentInfo.getContentType()))
+ {
+ this.timeStampedData = TimeStampedData.getInstance(contentInfo.getContent());
+ }
+ else
+ {
+ throw new IllegalArgumentException("Malformed content - type must be " + CMSObjectIdentifiers.timestampedData.getId());
+ }
+
+ util = new TimeStampDataUtil(this.timeStampedData);
+ }
+
+ public byte[] calculateNextHash(DigestCalculator calculator)
+ throws CMSException
+ {
+ return util.calculateNextHash(calculator);
+ }
+
+ /**
+ * Return a new timeStampedData object with the additional token attached.
+ *
+ * @throws CMSException
+ */
+ public CMSTimeStampedData addTimeStamp(TimeStampToken token)
+ throws CMSException
+ {
+ TimeStampAndCRL[] timeStamps = util.getTimeStamps();
+ TimeStampAndCRL[] newTimeStamps = new TimeStampAndCRL[timeStamps.length + 1];
+
+ System.arraycopy(timeStamps, 0, newTimeStamps, 0, timeStamps.length);
+
+ newTimeStamps[timeStamps.length] = new TimeStampAndCRL(token.toCMSSignedData().toASN1Structure());
+
+ return new CMSTimeStampedData(new ContentInfo(CMSObjectIdentifiers.timestampedData, new TimeStampedData(timeStampedData.getDataUri(), timeStampedData.getMetaData(), timeStampedData.getContent(), new Evidence(new TimeStampTokenEvidence(newTimeStamps)))));
+ }
+
+ public byte[] getContent()
+ {
+ if (timeStampedData.getContent() != null)
+ {
+ return timeStampedData.getContent().getOctets();
+ }
+
+ return null;
+ }
+
+ public String getDataUri()
+ {
+ DERIA5String dataURI = this.timeStampedData.getDataUri();
+
+ if (dataURI != null)
+ {
+ return dataURI.getString();
+ }
+
+ return null;
+ }
+
+ public String getFileName()
+ {
+ return util.getFileName();
+ }
+
+ public String getMediaType()
+ {
+ return util.getMediaType();
+ }
+
+ public AttributeTable getOtherMetaData()
+ {
+ return util.getOtherMetaData();
+ }
+
+ public TimeStampToken[] getTimeStampTokens()
+ throws CMSException
+ {
+ return util.getTimeStampTokens();
+ }
+
+ /**
+ * Initialise the passed in calculator with the MetaData for this message, if it is
+ * required as part of the initial message imprint calculation.
+ *
+ * @param calculator the digest calculator to be initialised.
+ * @throws CMSException if the MetaData is required and cannot be processed
+ */
+ public void initialiseMessageImprintDigestCalculator(DigestCalculator calculator)
+ throws CMSException
+ {
+ util.initialiseMessageImprintDigestCalculator(calculator);
+ }
+
+ /**
+ * Returns an appropriately initialised digest calculator based on the message imprint algorithm
+ * described in the first time stamp in the TemporalData for this message. If the metadata is required
+ * to be included in the digest calculation, the returned calculator will be pre-initialised.
+ *
+ * @param calculatorProvider a provider of DigestCalculator objects.
+ * @return an initialised digest calculator.
+ * @throws OperatorCreationException if the provider is unable to create the calculator.
+ */
+ public DigestCalculator getMessageImprintDigestCalculator(DigestCalculatorProvider calculatorProvider)
+ throws OperatorCreationException
+ {
+ return util.getMessageImprintDigestCalculator(calculatorProvider);
+ }
+
+ /**
+ * Validate the digests present in the TimeStampTokens contained in the CMSTimeStampedData.
+ *
+ * @param calculatorProvider provider for digest calculators
+ * @param dataDigest the calculated data digest for the message
+ * @throws ImprintDigestInvalidException if an imprint digest fails to compare
+ * @throws CMSException if an exception occurs processing the message.
+ */
+ public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest)
+ throws ImprintDigestInvalidException, CMSException
+ {
+ util.validate(calculatorProvider, dataDigest);
+ }
+
+ /**
+ * Validate the passed in timestamp token against the tokens and data present in the message.
+ *
+ * @param calculatorProvider provider for digest calculators
+ * @param dataDigest the calculated data digest for the message.
+ * @param timeStampToken the timestamp token of interest.
+ * @throws ImprintDigestInvalidException if the token is not present in the message, or an imprint digest fails to compare.
+ * @throws CMSException if an exception occurs processing the message.
+ */
+ public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest, TimeStampToken timeStampToken)
+ throws ImprintDigestInvalidException, CMSException
+ {
+ util.validate(calculatorProvider, dataDigest, timeStampToken);
+ }
+
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return contentInfo.getEncoded();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/cms/CMSTimeStampedDataParser.java b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/cms/CMSTimeStampedDataParser.java
new file mode 100644
index 000000000..f64396336
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/cms/CMSTimeStampedDataParser.java
@@ -0,0 +1,204 @@
+package org.spongycastle.tsp.cms;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.BERTags;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.ContentInfoParser;
+import org.spongycastle.asn1.cms.TimeStampedDataParser;
+import org.spongycastle.cms.CMSContentInfoParser;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.tsp.TimeStampToken;
+import org.spongycastle.util.io.Streams;
+
+public class CMSTimeStampedDataParser
+ extends CMSContentInfoParser
+{
+ private TimeStampedDataParser timeStampedData;
+ private TimeStampDataUtil util;
+
+ public CMSTimeStampedDataParser(InputStream in)
+ throws CMSException
+ {
+ super(in);
+
+ initialize(_contentInfo);
+ }
+
+ public CMSTimeStampedDataParser(byte[] baseData)
+ throws CMSException
+ {
+ this(new ByteArrayInputStream(baseData));
+ }
+
+ private void initialize(ContentInfoParser contentInfo)
+ throws CMSException
+ {
+ try
+ {
+ if (CMSObjectIdentifiers.timestampedData.equals(contentInfo.getContentType()))
+ {
+ this.timeStampedData = TimeStampedDataParser.getInstance(contentInfo.getContent(BERTags.SEQUENCE));
+ }
+ else
+ {
+ throw new IllegalArgumentException("Malformed content - type must be " + CMSObjectIdentifiers.timestampedData.getId());
+ }
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("parsing exception: " + e.getMessage(), e);
+ }
+ }
+
+ public byte[] calculateNextHash(DigestCalculator calculator)
+ throws CMSException
+ {
+ return util.calculateNextHash(calculator);
+ }
+
+ public InputStream getContent()
+ {
+ if (timeStampedData.getContent() != null)
+ {
+ return timeStampedData.getContent().getOctetStream();
+ }
+
+ return null;
+ }
+
+ public String getDataUri()
+ {
+ DERIA5String dataURI = this.timeStampedData.getDataUri();
+
+ if (dataURI != null)
+ {
+ return dataURI.getString();
+ }
+
+ return null;
+ }
+
+ public String getFileName()
+ {
+ return util.getFileName();
+ }
+
+ public String getMediaType()
+ {
+ return util.getMediaType();
+ }
+
+ public AttributeTable getOtherMetaData()
+ {
+ return util.getOtherMetaData();
+ }
+
+ /**
+ * Initialise the passed in calculator with the MetaData for this message, if it is
+ * required as part of the initial message imprint calculation.
+ *
+ * @param calculator the digest calculator to be initialised.
+ * @throws CMSException if the MetaData is required and cannot be processed
+ */
+ public void initialiseMessageImprintDigestCalculator(DigestCalculator calculator)
+ throws CMSException
+ {
+ util.initialiseMessageImprintDigestCalculator(calculator);
+ }
+
+ /**
+ * Returns an appropriately initialised digest calculator based on the message imprint algorithm
+ * described in the first time stamp in the TemporalData for this message. If the metadata is required
+ * to be included in the digest calculation, the returned calculator will be pre-initialised.
+ *
+ * @param calculatorProvider a provider of DigestCalculator objects.
+ * @return an initialised digest calculator.
+ * @throws OperatorCreationException if the provider is unable to create the calculator.
+ */
+ public DigestCalculator getMessageImprintDigestCalculator(DigestCalculatorProvider calculatorProvider)
+ throws OperatorCreationException
+ {
+ try
+ {
+ parseTimeStamps();
+ }
+ catch (CMSException e)
+ {
+ throw new OperatorCreationException("unable to extract algorithm ID: " + e.getMessage(), e);
+ }
+
+ return util.getMessageImprintDigestCalculator(calculatorProvider);
+ }
+
+ public TimeStampToken[] getTimeStampTokens()
+ throws CMSException
+ {
+ parseTimeStamps();
+
+ return util.getTimeStampTokens();
+ }
+
+ /**
+ * Validate the digests present in the TimeStampTokens contained in the CMSTimeStampedData.
+ *
+ * @param calculatorProvider provider for digest calculators
+ * @param dataDigest the calculated data digest for the message
+ * @throws ImprintDigestInvalidException if an imprint digest fails to compare
+ * @throws CMSException if an exception occurs processing the message.
+ */
+ public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest)
+ throws ImprintDigestInvalidException, CMSException
+ {
+ parseTimeStamps();
+
+ util.validate(calculatorProvider, dataDigest);
+ }
+
+ /**
+ * Validate the passed in timestamp token against the tokens and data present in the message.
+ *
+ * @param calculatorProvider provider for digest calculators
+ * @param dataDigest the calculated data digest for the message.
+ * @param timeStampToken the timestamp token of interest.
+ * @throws ImprintDigestInvalidException if the token is not present in the message, or an imprint digest fails to compare.
+ * @throws CMSException if an exception occurs processing the message.
+ */
+ public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest, TimeStampToken timeStampToken)
+ throws ImprintDigestInvalidException, CMSException
+ {
+ parseTimeStamps();
+
+ util.validate(calculatorProvider, dataDigest, timeStampToken);
+ }
+
+ private void parseTimeStamps()
+ throws CMSException
+ {
+ try
+ {
+ if (util == null)
+ {
+ InputStream cont = this.getContent();
+
+ if (cont != null)
+ {
+ Streams.drain(cont);
+ }
+
+ util = new TimeStampDataUtil(timeStampedData);
+ }
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("unable to parse evidence block: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/cms/CMSTimeStampedGenerator.java b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/cms/CMSTimeStampedGenerator.java
new file mode 100644
index 000000000..ca6190dee
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/j2me/org/spongycastle/tsp/cms/CMSTimeStampedGenerator.java
@@ -0,0 +1,88 @@
+package org.spongycastle.tsp.cms;
+
+import org.spongycastle.asn1.ASN1Boolean;
+import org.spongycastle.asn1.DERBoolean;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DERUTF8String;
+import org.spongycastle.asn1.cms.Attributes;
+import org.spongycastle.asn1.cms.MetaData;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.util.Integers;
+
+public class CMSTimeStampedGenerator
+{
+ protected MetaData metaData;
+ protected String dataUri;
+
+ /**
+ * Set the dataURI to be included in message.
+ *
+ * @param dataUri URI for the data the initial message imprint digest is based on.
+ */
+ public void setDataUri(String dataUri)
+ {
+ this.dataUri = dataUri;
+ }
+
+ /**
+ * Set the MetaData for the generated message.
+ *
+ * @param hashProtected true if the MetaData should be included in first imprint calculation, false otherwise.
+ * @param fileName optional file name, may be null.
+ * @param mediaType optional media type, may be null.
+ */
+ public void setMetaData(boolean hashProtected, String fileName, String mediaType)
+ {
+ setMetaData(hashProtected, fileName, mediaType, null);
+ }
+
+ /**
+ * Set the MetaData for the generated message.
+ *
+ * @param hashProtected true if the MetaData should be included in first imprint calculation, false otherwise.
+ * @param fileName optional file name, may be null.
+ * @param mediaType optional media type, may be null.
+ * @param attributes optional attributes, may be null.
+ */
+ public void setMetaData(boolean hashProtected, String fileName, String mediaType, Attributes attributes)
+ {
+ DERUTF8String asn1FileName = null;
+
+ if (fileName != null)
+ {
+ asn1FileName = new DERUTF8String(fileName);
+ }
+
+ DERIA5String asn1MediaType = null;
+
+ if (mediaType != null)
+ {
+ asn1MediaType = new DERIA5String(mediaType);
+ }
+
+ setMetaData(hashProtected, asn1FileName, asn1MediaType, attributes);
+ }
+
+ private void setMetaData(boolean hashProtected, DERUTF8String fileName, DERIA5String mediaType, Attributes attributes)
+ {
+ this.metaData = new MetaData(ASN1Boolean.getInstance(hashProtected), fileName, mediaType, attributes);
+ }
+
+ /**
+ * Initialise the passed in calculator with the MetaData for this message, if it is
+ * required as part of the initial message imprint calculation. After initialisation the
+ * calculator can then be used to calculate the initial message imprint digest for the first
+ * timestamp.
+ *
+ * @param calculator the digest calculator to be initialised.
+ * @throws CMSException if the MetaData is required and cannot be processed
+ */
+ public void initialiseMessageImprintDigestCalculator(DigestCalculator calculator)
+ throws CMSException
+ {
+ MetaDataUtil util = new MetaDataUtil(metaData);
+
+ util.initialiseMessageImprintDigestCalculator(calculator);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/AttributeCertificateHolder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/AttributeCertificateHolder.java
new file mode 100644
index 000000000..610cdbe73
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/AttributeCertificateHolder.java
@@ -0,0 +1,357 @@
+package org.spongycastle.cert;
+
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.x500.X500Name;
+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.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+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>
+ * <p>
+ * <b>Note:</b> If objectDigestInfo comparisons are to be carried out the static
+ * method setDigestCalculatorProvider <b>must</b> be called once to configure the class
+ * to do the necessary calculations.
+ * </p>
+ */
+public class AttributeCertificateHolder
+ implements Selector
+{
+ private static DigestCalculatorProvider digestCalculatorProvider;
+
+ final Holder holder;
+
+ AttributeCertificateHolder(ASN1Sequence seq)
+ {
+ holder = Holder.getInstance(seq);
+ }
+
+ public AttributeCertificateHolder(X500Name issuerName,
+ BigInteger serialNumber)
+ {
+ holder = new Holder(new IssuerSerial(
+ new GeneralNames(new GeneralName(issuerName)),
+ new ASN1Integer(serialNumber)));
+ }
+
+ public AttributeCertificateHolder(X509CertificateHolder cert)
+ {
+ holder = new Holder(new IssuerSerial(generateGeneralNames(cert.getIssuer()),
+ new ASN1Integer(cert.getSerialNumber())));
+ }
+
+ public AttributeCertificateHolder(X500Name 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,
+ ASN1ObjectIdentifier digestAlgorithm, ASN1ObjectIdentifier otherObjectTypeID, byte[] objectDigest)
+ {
+ holder = new Holder(new ObjectDigestInfo(digestedObjectType,
+ 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 algorithm identifier for the digest used if ObjectDigestInfo is present.
+ *
+ * @return digest AlgorithmIdentifier or <code>null</code> if ObjectDigestInfo is absent.
+ */
+ public AlgorithmIdentifier getDigestAlgorithm()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ return holder.getObjectDigestInfo().getDigestAlgorithm();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the hash if an object digest info is used.
+ *
+ * @return The hash or <code>null</code> if ObjectDigestInfo is absent.
+ */
+ 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 ASN1ObjectIdentifier getOtherObjectTypeID()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ new ASN1ObjectIdentifier(holder.getObjectDigestInfo().getOtherObjectTypeID().getId());
+ }
+ return null;
+ }
+
+ private GeneralNames generateGeneralNames(X500Name principal)
+ {
+ return new GeneralNames(new GeneralName(principal));
+ }
+
+ private boolean matchesDN(X500Name subject, GeneralNames targets)
+ {
+ GeneralName[] names = targets.getNames();
+
+ for (int i = 0; i != names.length; i++)
+ {
+ GeneralName gn = names[i];
+
+ if (gn.getTagNo() == GeneralName.directoryName)
+ {
+ if (X500Name.getInstance(gn.getName()).equals(subject))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private X500Name[] getPrincipals(GeneralName[] names)
+ {
+ List l = new ArrayList(names.length);
+
+ for (int i = 0; i != names.length; i++)
+ {
+ if (names[i].getTagNo() == GeneralName.directoryName)
+ {
+ l.add(X500Name.getInstance(names[i].getName()));
+ }
+ }
+
+ return (X500Name[])l.toArray(new X500Name[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 X500Name[] getEntityNames()
+ {
+ if (holder.getEntityName() != null)
+ {
+ return getPrincipals(holder.getEntityName().getNames());
+ }
+
+ 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 X500Name[] getIssuer()
+ {
+ if (holder.getBaseCertificateID() != null)
+ {
+ return getPrincipals(holder.getBaseCertificateID().getIssuer().getNames());
+ }
+
+ 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.toASN1Primitive());
+ }
+
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509CertificateHolder))
+ {
+ return false;
+ }
+
+ X509CertificateHolder x509Cert = (X509CertificateHolder)obj;
+
+ if (holder.getBaseCertificateID() != null)
+ {
+ return holder.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber())
+ && matchesDN(x509Cert.getIssuer(), holder.getBaseCertificateID().getIssuer());
+ }
+
+ if (holder.getEntityName() != null)
+ {
+ if (matchesDN(x509Cert.getSubject(),
+ holder.getEntityName()))
+ {
+ return true;
+ }
+ }
+
+ if (holder.getObjectDigestInfo() != null)
+ {
+ try
+ {
+ DigestCalculator digCalc = digestCalculatorProvider.get(holder.getObjectDigestInfo().getDigestAlgorithm());
+ OutputStream digOut = digCalc.getOutputStream();
+
+ switch (getDigestedObjectType())
+ {
+ case ObjectDigestInfo.publicKey:
+ // TODO: DSA Dss-parms
+ digOut.write(x509Cert.getSubjectPublicKeyInfo().getEncoded());
+ break;
+ case ObjectDigestInfo.publicKeyCert:
+ digOut.write(x509Cert.getEncoded());
+ break;
+ }
+
+ digOut.close();
+
+ if (!Arrays.areEqual(digCalc.getDigest(), getObjectDigest()))
+ {
+ return false;
+ }
+ }
+ catch (Exception 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();
+ }
+
+ /**
+ * Set a digest calculator provider to be used if matches are attempted using
+ * ObjectDigestInfo,
+ *
+ * @param digCalcProvider a provider of digest calculators.
+ */
+ public static void setDigestCalculatorProvider(DigestCalculatorProvider digCalcProvider)
+ {
+ digestCalculatorProvider = digCalcProvider;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/AttributeCertificateIssuer.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/AttributeCertificateIssuer.java
new file mode 100644
index 000000000..e659e5924
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/AttributeCertificateIssuer.java
@@ -0,0 +1,147 @@
+package org.spongycastle.cert;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.x500.X500Name;
+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.util.Selector;
+
+/**
+ * Carrying class for an attribute certificate issuer.
+ */
+public class AttributeCertificateIssuer
+ implements 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(X500Name principal)
+ {
+ form = new V2Form(new GeneralNames(new GeneralName(principal)));
+ }
+
+ public X500Name[] 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)
+ {
+ l.add(X500Name.getInstance(names[i].getName()));
+ }
+ }
+
+ return (X500Name[])l.toArray(new X500Name[l.size()]);
+ }
+
+ private boolean matchesDN(X500Name subject, GeneralNames targets)
+ {
+ GeneralName[] names = targets.getNames();
+
+ for (int i = 0; i != names.length; i++)
+ {
+ GeneralName gn = names[i];
+
+ if (gn.getTagNo() == GeneralName.directoryName)
+ {
+ if (X500Name.getInstance(gn.getName()).equals(subject))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public Object clone()
+ {
+ return new AttributeCertificateIssuer(AttCertIssuer.getInstance(form));
+ }
+
+ 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 X509CertificateHolder))
+ {
+ return false;
+ }
+
+ X509CertificateHolder x509Cert = (X509CertificateHolder)obj;
+
+ if (form instanceof V2Form)
+ {
+ V2Form issuer = (V2Form)form;
+ if (issuer.getBaseCertificateID() != null)
+ {
+ return issuer.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber())
+ && matchesDN(x509Cert.getIssuer(), issuer.getBaseCertificateID().getIssuer());
+ }
+
+ GeneralNames name = issuer.getIssuerName();
+ if (matchesDN(x509Cert.getSubject(), name))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ GeneralNames name = (GeneralNames)form;
+ if (matchesDN(x509Cert.getSubject(), name))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/CertException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/CertException.java
new file mode 100644
index 000000000..b394ec895
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/CertException.java
@@ -0,0 +1,27 @@
+package org.spongycastle.cert;
+
+/**
+ * General checked Exception thrown in the cert package and its sub-packages.
+ */
+public class CertException
+ extends Exception
+{
+ private Throwable cause;
+
+ public CertException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public CertException(String msg)
+ {
+ super(msg);
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/CertIOException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/CertIOException.java
new file mode 100644
index 000000000..f21641d62
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/CertIOException.java
@@ -0,0 +1,29 @@
+package org.spongycastle.cert;
+
+import java.io.IOException;
+
+/**
+ * General IOException thrown in the cert package and its sub-packages.
+ */
+public class CertIOException
+ extends IOException
+{
+ private Throwable cause;
+
+ public CertIOException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public CertIOException(String msg)
+ {
+ super(msg);
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/CertRuntimeException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/CertRuntimeException.java
new file mode 100644
index 000000000..a797083e6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/CertRuntimeException.java
@@ -0,0 +1,19 @@
+package org.spongycastle.cert;
+
+public class CertRuntimeException
+ extends RuntimeException
+{
+ private Throwable cause;
+
+ public CertRuntimeException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/CertUtils.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/CertUtils.java
new file mode 100644
index 000000000..d03f78437
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/CertUtils.java
@@ -0,0 +1,244 @@
+package org.spongycastle.cert;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AttributeCertificate;
+import org.spongycastle.asn1.x509.AttributeCertificateInfo;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.ExtensionsGenerator;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.asn1.x509.TBSCertificate;
+import org.spongycastle.operator.ContentSigner;
+
+class CertUtils
+{
+ private static Set EMPTY_SET = Collections.unmodifiableSet(new HashSet());
+ private static List EMPTY_LIST = Collections.unmodifiableList(new ArrayList());
+
+ static X509CertificateHolder generateFullCert(ContentSigner signer, TBSCertificate tbsCert)
+ {
+ try
+ {
+ return new X509CertificateHolder(generateStructure(tbsCert, signer.getAlgorithmIdentifier(), generateSig(signer, tbsCert)));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("cannot produce certificate signature");
+ }
+ }
+
+ static X509AttributeCertificateHolder generateFullAttrCert(ContentSigner signer, AttributeCertificateInfo attrInfo)
+ {
+ try
+ {
+ return new X509AttributeCertificateHolder(generateAttrStructure(attrInfo, signer.getAlgorithmIdentifier(), generateSig(signer, attrInfo)));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("cannot produce attribute certificate signature");
+ }
+ }
+
+ static X509CRLHolder generateFullCRL(ContentSigner signer, TBSCertList tbsCertList)
+ {
+ try
+ {
+ return new X509CRLHolder(generateCRLStructure(tbsCertList, signer.getAlgorithmIdentifier(), generateSig(signer, tbsCertList)));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("cannot produce certificate signature");
+ }
+ }
+
+ private static byte[] generateSig(ContentSigner signer, ASN1Encodable tbsObj)
+ throws IOException
+ {
+ OutputStream sOut = signer.getOutputStream();
+ DEROutputStream dOut = new DEROutputStream(sOut);
+
+ dOut.writeObject(tbsObj);
+
+ sOut.close();
+
+ return signer.getSignature();
+ }
+
+ private static Certificate generateStructure(TBSCertificate tbsCert, AlgorithmIdentifier sigAlgId, byte[] signature)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCert);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ return Certificate.getInstance(new DERSequence(v));
+ }
+
+ private static AttributeCertificate generateAttrStructure(AttributeCertificateInfo attrInfo, AlgorithmIdentifier sigAlgId, byte[] signature)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(attrInfo);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ return AttributeCertificate.getInstance(new DERSequence(v));
+ }
+
+ private static CertificateList generateCRLStructure(TBSCertList tbsCertList, AlgorithmIdentifier sigAlgId, byte[] signature)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCertList);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ return CertificateList.getInstance(new DERSequence(v));
+ }
+
+ static Set getCriticalExtensionOIDs(Extensions extensions)
+ {
+ if (extensions == null)
+ {
+ return EMPTY_SET;
+ }
+
+ return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getCriticalExtensionOIDs())));
+ }
+
+ static Set getNonCriticalExtensionOIDs(Extensions extensions)
+ {
+ if (extensions == null)
+ {
+ return EMPTY_SET;
+ }
+
+ // TODO: should probably produce a set that imposes correct ordering
+ return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getNonCriticalExtensionOIDs())));
+ }
+
+ static List getExtensionOIDs(Extensions extensions)
+ {
+ if (extensions == null)
+ {
+ return EMPTY_LIST;
+ }
+
+ return Collections.unmodifiableList(Arrays.asList(extensions.getExtensionOIDs()));
+ }
+
+ static void addExtension(ExtensionsGenerator extGenerator, ASN1ObjectIdentifier oid, boolean isCritical, ASN1Encodable value)
+ throws CertIOException
+ {
+ try
+ {
+ extGenerator.addExtension(oid, isCritical, value);
+ }
+ catch (IOException e)
+ {
+ throw new CertIOException("cannot encode extension: " + e.getMessage(), e);
+ }
+ }
+
+ static 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);
+ }
+ }
+
+ static boolean[] bitStringToBoolean(DERBitString bitString)
+ {
+ if (bitString != null)
+ {
+ byte[] bytes = bitString.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - bitString.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ static Date recoverDate(ASN1GeneralizedTime time)
+ {
+ try
+ {
+ return time.getDate();
+ }
+ catch (ParseException e)
+ {
+ throw new IllegalStateException("unable to recover date: " + e.getMessage());
+ }
+ }
+
+ static 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());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509AttributeCertificateHolder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509AttributeCertificateHolder.java
new file mode 100644
index 000000000..76c0cdf95
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509AttributeCertificateHolder.java
@@ -0,0 +1,366 @@
+package org.spongycastle.cert;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AttCertValidityPeriod;
+import org.spongycastle.asn1.x509.Attribute;
+import org.spongycastle.asn1.x509.AttributeCertificate;
+import org.spongycastle.asn1.x509.AttributeCertificateInfo;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.operator.ContentVerifier;
+import org.spongycastle.operator.ContentVerifierProvider;
+
+/**
+ * Holding class for an X.509 AttributeCertificate structure.
+ */
+public class X509AttributeCertificateHolder
+{
+ private static Attribute[] EMPTY_ARRAY = new Attribute[0];
+
+ private AttributeCertificate attrCert;
+ private Extensions extensions;
+
+ private static AttributeCertificate parseBytes(byte[] certEncoding)
+ throws IOException
+ {
+ try
+ {
+ return AttributeCertificate.getInstance(ASN1Primitive.fromByteArray(certEncoding));
+ }
+ catch (ClassCastException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Create a X509AttributeCertificateHolder from the passed in bytes.
+ *
+ * @param certEncoding BER/DER encoding of the certificate.
+ * @throws IOException in the event of corrupted data, or an incorrect structure.
+ */
+ public X509AttributeCertificateHolder(byte[] certEncoding)
+ throws IOException
+ {
+ this(parseBytes(certEncoding));
+ }
+
+ /**
+ * Create a X509AttributeCertificateHolder from the passed in ASN.1 structure.
+ *
+ * @param attrCert an ASN.1 AttributeCertificate structure.
+ */
+ public X509AttributeCertificateHolder(AttributeCertificate attrCert)
+ {
+ this.attrCert = attrCert;
+ this.extensions = attrCert.getAcinfo().getExtensions();
+ }
+
+ /**
+ * Return the ASN.1 encoding of this holder's attribute certificate.
+ *
+ * @return a DER encoded byte array.
+ * @throws IOException if an encoding cannot be generated.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return attrCert.getEncoded();
+ }
+
+ public int getVersion()
+ {
+ return attrCert.getAcinfo().getVersion().getValue().intValue() + 1;
+ }
+
+ /**
+ * Return the serial number of this attribute certificate.
+ *
+ * @return the serial number.
+ */
+ public BigInteger getSerialNumber()
+ {
+ return attrCert.getAcinfo().getSerialNumber().getValue();
+ }
+
+ /**
+ * Return the holder details for this attribute certificate.
+ *
+ * @return this attribute certificate's holder structure.
+ */
+ public AttributeCertificateHolder getHolder()
+ {
+ return new AttributeCertificateHolder((ASN1Sequence)attrCert.getAcinfo().getHolder().toASN1Primitive());
+ }
+
+ /**
+ * Return the issuer details for this attribute certificate.
+ *
+ * @return this attribute certificate's issuer structure,
+ */
+ public AttributeCertificateIssuer getIssuer()
+ {
+ return new AttributeCertificateIssuer(attrCert.getAcinfo().getIssuer());
+ }
+
+ /**
+ * Return the date before which this attribute certificate is not valid.
+ *
+ * @return the start date for the attribute certificate's validity period.
+ */
+ public Date getNotBefore()
+ {
+ return CertUtils.recoverDate(attrCert.getAcinfo().getAttrCertValidityPeriod().getNotBeforeTime());
+ }
+
+ /**
+ * Return the date after which this attribute certificate is not valid.
+ *
+ * @return the final date for the attribute certificate's validity period.
+ */
+ public Date getNotAfter()
+ {
+ return CertUtils.recoverDate(attrCert.getAcinfo().getAttrCertValidityPeriod().getNotAfterTime());
+ }
+
+ /**
+ * Return the attributes, if any associated with this request.
+ *
+ * @return an array of Attribute, zero length if none present.
+ */
+ public Attribute[] getAttributes()
+ {
+ ASN1Sequence seq = attrCert.getAcinfo().getAttributes();
+ Attribute[] attrs = new Attribute[seq.size()];
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ attrs[i] = Attribute.getInstance(seq.getObjectAt(i));
+ }
+
+ return attrs;
+ }
+
+ /**
+ * Return an array of attributes matching the passed in type OID.
+ *
+ * @param type the type of the attribute being looked for.
+ * @return an array of Attribute of the requested type, zero length if none present.
+ */
+ public Attribute[] getAttributes(ASN1ObjectIdentifier type)
+ {
+ ASN1Sequence seq = attrCert.getAcinfo().getAttributes();
+ List list = new ArrayList();
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ Attribute attr = Attribute.getInstance(seq.getObjectAt(i));
+ if (attr.getAttrType().equals(type))
+ {
+ list.add(attr);
+ }
+ }
+
+ if (list.size() == 0)
+ {
+ return EMPTY_ARRAY;
+ }
+
+ return (Attribute[])list.toArray(new Attribute[list.size()]);
+ }
+
+ /**
+ * Return whether or not the holder's attribute certificate contains extensions.
+ *
+ * @return true if extension are present, false otherwise.
+ */
+ public boolean hasExtensions()
+ {
+ return extensions != null;
+ }
+
+ /**
+ * Look up the extension associated with the passed in OID.
+ *
+ * @param oid the OID of the extension of interest.
+ *
+ * @return the extension if present, null otherwise.
+ */
+ public Extension getExtension(ASN1ObjectIdentifier oid)
+ {
+ if (extensions != null)
+ {
+ return extensions.getExtension(oid);
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the extensions block associated with this certificate if there is one.
+ *
+ * @return the extensions block, null otherwise.
+ */
+ public Extensions getExtensions()
+ {
+ return extensions;
+ }
+
+ /**
+ * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the
+ * extensions contained in this holder's attribute certificate.
+ *
+ * @return a list of extension OIDs.
+ */
+ public List getExtensionOIDs()
+ {
+ return CertUtils.getExtensionOIDs(extensions);
+ }
+
+ /**
+ * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the
+ * critical extensions contained in this holder's attribute certificate.
+ *
+ * @return a set of critical extension OIDs.
+ */
+ public Set getCriticalExtensionOIDs()
+ {
+ return CertUtils.getCriticalExtensionOIDs(extensions);
+ }
+
+ /**
+ * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the
+ * non-critical extensions contained in this holder's attribute certificate.
+ *
+ * @return a set of non-critical extension OIDs.
+ */
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return CertUtils.getNonCriticalExtensionOIDs(extensions);
+ }
+
+ public boolean[] getIssuerUniqueID()
+ {
+ return CertUtils.bitStringToBoolean(attrCert.getAcinfo().getIssuerUniqueID());
+ }
+
+ /**
+ * Return the details of the signature algorithm used to create this attribute certificate.
+ *
+ * @return the AlgorithmIdentifier describing the signature algorithm used to create this attribute certificate.
+ */
+ public AlgorithmIdentifier getSignatureAlgorithm()
+ {
+ return attrCert.getSignatureAlgorithm();
+ }
+
+ /**
+ * Return the bytes making up the signature associated with this attribute certificate.
+ *
+ * @return the attribute certificate signature bytes.
+ */
+ public byte[] getSignature()
+ {
+ return attrCert.getSignatureValue().getBytes();
+ }
+
+ /**
+ * Return the underlying ASN.1 structure for the attribute certificate in this holder.
+ *
+ * @return a AttributeCertificate object.
+ */
+ public AttributeCertificate toASN1Structure()
+ {
+ return attrCert;
+ }
+
+ /**
+ * Return whether or not this attribute certificate is valid on a particular date.
+ *
+ * @param date the date of interest.
+ * @return true if the attribute certificate is valid, false otherwise.
+ */
+ public boolean isValidOn(Date date)
+ {
+ AttCertValidityPeriod certValidityPeriod = attrCert.getAcinfo().getAttrCertValidityPeriod();
+
+ return !date.before(CertUtils.recoverDate(certValidityPeriod.getNotBeforeTime())) && !date.after(CertUtils.recoverDate(certValidityPeriod.getNotAfterTime()));
+ }
+
+ /**
+ * Validate the signature on the attribute certificate in this holder.
+ *
+ * @param verifierProvider a ContentVerifierProvider that can generate a verifier for the signature.
+ * @return true if the signature is valid, false otherwise.
+ * @throws CertException if the signature cannot be processed or is inappropriate.
+ */
+ public boolean isSignatureValid(ContentVerifierProvider verifierProvider)
+ throws CertException
+ {
+ AttributeCertificateInfo acinfo = attrCert.getAcinfo();
+
+ if (!CertUtils.isAlgIdEqual(acinfo.getSignature(), attrCert.getSignatureAlgorithm()))
+ {
+ throw new CertException("signature invalid - algorithm identifier mismatch");
+ }
+
+ ContentVerifier verifier;
+
+ try
+ {
+ verifier = verifierProvider.get((acinfo.getSignature()));
+
+ OutputStream sOut = verifier.getOutputStream();
+ DEROutputStream dOut = new DEROutputStream(sOut);
+
+ dOut.writeObject(acinfo);
+
+ sOut.close();
+ }
+ catch (Exception e)
+ {
+ throw new CertException("unable to process signature: " + e.getMessage(), e);
+ }
+
+ return verifier.verify(attrCert.getSignatureValue().getBytes());
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof X509AttributeCertificateHolder))
+ {
+ return false;
+ }
+
+ X509AttributeCertificateHolder other = (X509AttributeCertificateHolder)o;
+
+ return this.attrCert.equals(other.attrCert);
+ }
+
+ public int hashCode()
+ {
+ return this.attrCert.hashCode();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509CRLEntryHolder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509CRLEntryHolder.java
new file mode 100644
index 000000000..da542c0e6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509CRLEntryHolder.java
@@ -0,0 +1,144 @@
+package org.spongycastle.cert;
+
+import java.math.BigInteger;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.TBSCertList;
+
+/**
+ * Holding class for an X.509 CRL Entry structure.
+ */
+public class X509CRLEntryHolder
+{
+ private TBSCertList.CRLEntry entry;
+ private GeneralNames ca;
+
+ X509CRLEntryHolder(TBSCertList.CRLEntry entry, boolean isIndirect, GeneralNames previousCA)
+ {
+ this.entry = entry;
+ this.ca = previousCA;
+
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ ca = GeneralNames.getInstance(currentCaName.getParsedValue());
+ }
+ }
+ }
+
+ /**
+ * Return the serial number of the certificate associated with this CRLEntry.
+ *
+ * @return the revoked certificate's serial number.
+ */
+ public BigInteger getSerialNumber()
+ {
+ return entry.getUserCertificate().getValue();
+ }
+
+ /**
+ * Return the date on which the certificate associated with this CRLEntry was revoked.
+ *
+ * @return the revocation date for the revoked certificate.
+ */
+ public Date getRevocationDate()
+ {
+ return entry.getRevocationDate().getDate();
+ }
+
+ /**
+ * Return whether or not the holder's CRL entry contains extensions.
+ *
+ * @return true if extension are present, false otherwise.
+ */
+ public boolean hasExtensions()
+ {
+ return entry.hasExtensions();
+ }
+
+ /**
+ * Return the available names for the certificate issuer for the certificate referred to by this CRL entry.
+ * <p>
+ * Note: this will be the issuer of the CRL unless it has been specified that the CRL is indirect
+ * in the IssuingDistributionPoint extension and either a previous entry, or the current one,
+ * has specified a different CA via the certificateIssuer extension.
+ * </p>
+ *
+ * @return the revoked certificate's issuer.
+ */
+ public GeneralNames getCertificateIssuer()
+ {
+ return this.ca;
+ }
+
+ /**
+ * Look up the extension associated with the passed in OID.
+ *
+ * @param oid the OID of the extension of interest.
+ *
+ * @return the extension if present, null otherwise.
+ */
+ public Extension getExtension(ASN1ObjectIdentifier oid)
+ {
+ Extensions extensions = entry.getExtensions();
+
+ if (extensions != null)
+ {
+ return extensions.getExtension(oid);
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the extensions block associated with this CRL entry if there is one.
+ *
+ * @return the extensions block, null otherwise.
+ */
+ public Extensions getExtensions()
+ {
+ return entry.getExtensions();
+ }
+
+ /**
+ * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the
+ * extensions contained in this holder's CRL entry.
+ *
+ * @return a list of extension OIDs.
+ */
+ public List getExtensionOIDs()
+ {
+ return CertUtils.getExtensionOIDs(entry.getExtensions());
+ }
+
+ /**
+ * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the
+ * critical extensions contained in this holder's CRL entry.
+ *
+ * @return a set of critical extension OIDs.
+ */
+ public Set getCriticalExtensionOIDs()
+ {
+ return CertUtils.getCriticalExtensionOIDs(entry.getExtensions());
+ }
+
+ /**
+ * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the
+ * non-critical extensions contained in this holder's CRL entry.
+ *
+ * @return a set of non-critical extension OIDs.
+ */
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return CertUtils.getNonCriticalExtensionOIDs(entry.getExtensions());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509CRLHolder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509CRLHolder.java
new file mode 100644
index 000000000..e94c2c1b4
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509CRLHolder.java
@@ -0,0 +1,317 @@
+package org.spongycastle.cert;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.CertificateList;
+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.IssuingDistributionPoint;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.operator.ContentVerifier;
+import org.spongycastle.operator.ContentVerifierProvider;
+
+/**
+ * Holding class for an X.509 CRL structure.
+ */
+public class X509CRLHolder
+{
+ private CertificateList x509CRL;
+ private boolean isIndirect;
+ private Extensions extensions;
+ private GeneralNames issuerName;
+
+ private static CertificateList parseStream(InputStream stream)
+ throws IOException
+ {
+ try
+ {
+ return CertificateList.getInstance(new ASN1InputStream(stream, true).readObject());
+ }
+ catch (ClassCastException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ }
+
+ private static boolean isIndirectCRL(Extensions extensions)
+ {
+ if (extensions == null)
+ {
+ return false;
+ }
+
+ Extension ext = extensions.getExtension(Extension.issuingDistributionPoint);
+
+ return ext != null && IssuingDistributionPoint.getInstance(ext.getParsedValue()).isIndirectCRL();
+ }
+
+ /**
+ * Create a X509CRLHolder from the passed in bytes.
+ *
+ * @param crlEncoding BER/DER encoding of the CRL
+ * @throws IOException in the event of corrupted data, or an incorrect structure.
+ */
+ public X509CRLHolder(byte[] crlEncoding)
+ throws IOException
+ {
+ this(parseStream(new ByteArrayInputStream(crlEncoding)));
+ }
+
+ /**
+ * Create a X509CRLHolder from the passed in InputStream.
+ *
+ * @param crlStream BER/DER encoded InputStream of the CRL
+ * @throws IOException in the event of corrupted data, or an incorrect structure.
+ */
+ public X509CRLHolder(InputStream crlStream)
+ throws IOException
+ {
+ this(parseStream(crlStream));
+ }
+
+ /**
+ * Create a X509CRLHolder from the passed in ASN.1 structure.
+ *
+ * @param x509CRL an ASN.1 CertificateList structure.
+ */
+ public X509CRLHolder(CertificateList x509CRL)
+ {
+ this.x509CRL = x509CRL;
+ this.extensions = x509CRL.getTBSCertList().getExtensions();
+ this.isIndirect = isIndirectCRL(extensions);
+ this.issuerName = new GeneralNames(new GeneralName(x509CRL.getIssuer()));
+ }
+
+ /**
+ * Return the ASN.1 encoding of this holder's CRL.
+ *
+ * @return a DER encoded byte array.
+ * @throws IOException if an encoding cannot be generated.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return x509CRL.getEncoded();
+ }
+
+ /**
+ * Return the issuer of this holder's CRL.
+ *
+ * @return the CRL issuer.
+ */
+ public X500Name getIssuer()
+ {
+ return X500Name.getInstance(x509CRL.getIssuer());
+ }
+
+ public X509CRLEntryHolder getRevokedCertificate(BigInteger serialNumber)
+ {
+ GeneralNames currentCA = issuerName;
+ for (Enumeration en = x509CRL.getRevokedCertificateEnumeration(); en.hasMoreElements();)
+ {
+ TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)en.nextElement();
+
+ if (entry.getUserCertificate().getValue().equals(serialNumber))
+ {
+ return new X509CRLEntryHolder(entry, isIndirect, currentCA);
+ }
+
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ currentCA = GeneralNames.getInstance(currentCaName.getParsedValue());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Return a collection of X509CRLEntryHolder objects, giving the details of the
+ * revoked certificates that appear on this CRL.
+ *
+ * @return the revoked certificates as a collection of X509CRLEntryHolder objects.
+ */
+ public Collection getRevokedCertificates()
+ {
+ TBSCertList.CRLEntry[] entries = x509CRL.getRevokedCertificates();
+ List l = new ArrayList(entries.length);
+ GeneralNames currentCA = issuerName;
+
+ for (Enumeration en = x509CRL.getRevokedCertificateEnumeration(); en.hasMoreElements();)
+ {
+ TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)en.nextElement();
+ X509CRLEntryHolder crlEntry = new X509CRLEntryHolder(entry, isIndirect, currentCA);
+
+ l.add(crlEntry);
+
+ currentCA = crlEntry.getCertificateIssuer();
+ }
+
+ return l;
+ }
+
+ /**
+ * Return whether or not the holder's CRL contains extensions.
+ *
+ * @return true if extension are present, false otherwise.
+ */
+ public boolean hasExtensions()
+ {
+ return extensions != null;
+ }
+
+ /**
+ * Look up the extension associated with the passed in OID.
+ *
+ * @param oid the OID of the extension of interest.
+ *
+ * @return the extension if present, null otherwise.
+ */
+ public Extension getExtension(ASN1ObjectIdentifier oid)
+ {
+ if (extensions != null)
+ {
+ return extensions.getExtension(oid);
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the extensions block associated with this CRL if there is one.
+ *
+ * @return the extensions block, null otherwise.
+ */
+ public Extensions getExtensions()
+ {
+ return extensions;
+ }
+
+ /**
+ * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the
+ * extensions contained in this holder's CRL.
+ *
+ * @return a list of extension OIDs.
+ */
+ public List getExtensionOIDs()
+ {
+ return CertUtils.getExtensionOIDs(extensions);
+ }
+
+ /**
+ * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the
+ * critical extensions contained in this holder's CRL.
+ *
+ * @return a set of critical extension OIDs.
+ */
+ public Set getCriticalExtensionOIDs()
+ {
+ return CertUtils.getCriticalExtensionOIDs(extensions);
+ }
+
+ /**
+ * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the
+ * non-critical extensions contained in this holder's CRL.
+ *
+ * @return a set of non-critical extension OIDs.
+ */
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return CertUtils.getNonCriticalExtensionOIDs(extensions);
+ }
+
+ /**
+ * Return the underlying ASN.1 structure for the CRL in this holder.
+ *
+ * @return a CertificateList object.
+ */
+ public CertificateList toASN1Structure()
+ {
+ return x509CRL;
+ }
+
+ /**
+ * Validate the signature on the CRL.
+ *
+ * @param verifierProvider a ContentVerifierProvider that can generate a verifier for the signature.
+ * @return true if the signature is valid, false otherwise.
+ * @throws CertException if the signature cannot be processed or is inappropriate.
+ */
+ public boolean isSignatureValid(ContentVerifierProvider verifierProvider)
+ throws CertException
+ {
+ TBSCertList tbsCRL = x509CRL.getTBSCertList();
+
+ if (!CertUtils.isAlgIdEqual(tbsCRL.getSignature(), x509CRL.getSignatureAlgorithm()))
+ {
+ throw new CertException("signature invalid - algorithm identifier mismatch");
+ }
+
+ ContentVerifier verifier;
+
+ try
+ {
+ verifier = verifierProvider.get((tbsCRL.getSignature()));
+
+ OutputStream sOut = verifier.getOutputStream();
+ DEROutputStream dOut = new DEROutputStream(sOut);
+
+ dOut.writeObject(tbsCRL);
+
+ sOut.close();
+ }
+ catch (Exception e)
+ {
+ throw new CertException("unable to process signature: " + e.getMessage(), e);
+ }
+
+ return verifier.verify(x509CRL.getSignature().getBytes());
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof X509CRLHolder))
+ {
+ return false;
+ }
+
+ X509CRLHolder other = (X509CRLHolder)o;
+
+ return this.x509CRL.equals(other.x509CRL);
+ }
+
+ public int hashCode()
+ {
+ return this.x509CRL.hashCode();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509CertificateHolder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509CertificateHolder.java
new file mode 100644
index 000000000..fd53b92ca
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509CertificateHolder.java
@@ -0,0 +1,327 @@
+package org.spongycastle.cert;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.TBSCertificate;
+import org.spongycastle.operator.ContentVerifier;
+import org.spongycastle.operator.ContentVerifierProvider;
+
+/**
+ * Holding class for an X.509 Certificate structure.
+ */
+public class X509CertificateHolder
+{
+ private Certificate x509Certificate;
+ private Extensions extensions;
+
+ private static Certificate parseBytes(byte[] certEncoding)
+ throws IOException
+ {
+ try
+ {
+ return Certificate.getInstance(ASN1Primitive.fromByteArray(certEncoding));
+ }
+ catch (ClassCastException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Create a X509CertificateHolder from the passed in bytes.
+ *
+ * @param certEncoding BER/DER encoding of the certificate.
+ * @throws IOException in the event of corrupted data, or an incorrect structure.
+ */
+ public X509CertificateHolder(byte[] certEncoding)
+ throws IOException
+ {
+ this(parseBytes(certEncoding));
+ }
+
+ /**
+ * Create a X509CertificateHolder from the passed in ASN.1 structure.
+ *
+ * @param x509Certificate an ASN.1 Certificate structure.
+ */
+ public X509CertificateHolder(Certificate x509Certificate)
+ {
+ this.x509Certificate = x509Certificate;
+ this.extensions = x509Certificate.getTBSCertificate().getExtensions();
+ }
+
+ public int getVersionNumber()
+ {
+ return x509Certificate.getVersionNumber();
+ }
+
+ /**
+ * @deprecated use getVersionNumber
+ */
+ public int getVersion()
+ {
+ return x509Certificate.getVersionNumber();
+ }
+
+ /**
+ * Return whether or not the holder's certificate contains extensions.
+ *
+ * @return true if extension are present, false otherwise.
+ */
+ public boolean hasExtensions()
+ {
+ return extensions != null;
+ }
+
+ /**
+ * Look up the extension associated with the passed in OID.
+ *
+ * @param oid the OID of the extension of interest.
+ *
+ * @return the extension if present, null otherwise.
+ */
+ public Extension getExtension(ASN1ObjectIdentifier oid)
+ {
+ if (extensions != null)
+ {
+ return extensions.getExtension(oid);
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the extensions block associated with this certificate if there is one.
+ *
+ * @return the extensions block, null otherwise.
+ */
+ public Extensions getExtensions()
+ {
+ return extensions;
+ }
+
+ /**
+ * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the
+ * extensions contained in this holder's certificate.
+ *
+ * @return a list of extension OIDs.
+ */
+ public List getExtensionOIDs()
+ {
+ return CertUtils.getExtensionOIDs(extensions);
+ }
+
+ /**
+ * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the
+ * critical extensions contained in this holder's certificate.
+ *
+ * @return a set of critical extension OIDs.
+ */
+ public Set getCriticalExtensionOIDs()
+ {
+ return CertUtils.getCriticalExtensionOIDs(extensions);
+ }
+
+ /**
+ * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the
+ * non-critical extensions contained in this holder's certificate.
+ *
+ * @return a set of non-critical extension OIDs.
+ */
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return CertUtils.getNonCriticalExtensionOIDs(extensions);
+ }
+
+ /**
+ * Return the serial number of this attribute certificate.
+ *
+ * @return the serial number.
+ */
+ public BigInteger getSerialNumber()
+ {
+ return x509Certificate.getSerialNumber().getValue();
+ }
+
+ /**
+ * Return the issuer of this certificate.
+ *
+ * @return the certificate issuer.
+ */
+ public X500Name getIssuer()
+ {
+ return X500Name.getInstance(x509Certificate.getIssuer());
+ }
+
+ /**
+ * Return the subject this certificate is for.
+ *
+ * @return the subject for the certificate.
+ */
+ public X500Name getSubject()
+ {
+ return X500Name.getInstance(x509Certificate.getSubject());
+ }
+
+ /**
+ * Return the date before which this certificate is not valid.
+ *
+ * @return the start time for the certificate's validity period.
+ */
+ public Date getNotBefore()
+ {
+ return x509Certificate.getStartDate().getDate();
+ }
+
+ /**
+ * Return the date after which this certificate is not valid.
+ *
+ * @return the final time for the certificate's validity period.
+ */
+ public Date getNotAfter()
+ {
+ return x509Certificate.getEndDate().getDate();
+ }
+
+ /**
+ * Return the SubjectPublicKeyInfo describing the public key this certificate is carrying.
+ *
+ * @return the public key ASN.1 structure contained in the certificate.
+ */
+ public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+ {
+ return x509Certificate.getSubjectPublicKeyInfo();
+ }
+
+ /**
+ * Return the underlying ASN.1 structure for the certificate in this holder.
+ *
+ * @return a X509CertificateStructure object.
+ */
+ public Certificate toASN1Structure()
+ {
+ return x509Certificate;
+ }
+
+ /**
+ * Return the details of the signature algorithm used to create this attribute certificate.
+ *
+ * @return the AlgorithmIdentifier describing the signature algorithm used to create this attribute certificate.
+ */
+ public AlgorithmIdentifier getSignatureAlgorithm()
+ {
+ return x509Certificate.getSignatureAlgorithm();
+ }
+
+ /**
+ * Return the bytes making up the signature associated with this attribute certificate.
+ *
+ * @return the attribute certificate signature bytes.
+ */
+ public byte[] getSignature()
+ {
+ return x509Certificate.getSignature().getBytes();
+ }
+
+ /**
+ * Return whether or not this certificate is valid on a particular date.
+ *
+ * @param date the date of interest.
+ * @return true if the certificate is valid, false otherwise.
+ */
+ public boolean isValidOn(Date date)
+ {
+ return !date.before(x509Certificate.getStartDate().getDate()) && !date.after(x509Certificate.getEndDate().getDate());
+ }
+
+ /**
+ * Validate the signature on the certificate in this holder.
+ *
+ * @param verifierProvider a ContentVerifierProvider that can generate a verifier for the signature.
+ * @return true if the signature is valid, false otherwise.
+ * @throws CertException if the signature cannot be processed or is inappropriate.
+ */
+ public boolean isSignatureValid(ContentVerifierProvider verifierProvider)
+ throws CertException
+ {
+ TBSCertificate tbsCert = x509Certificate.getTBSCertificate();
+
+ if (!CertUtils.isAlgIdEqual(tbsCert.getSignature(), x509Certificate.getSignatureAlgorithm()))
+ {
+ throw new CertException("signature invalid - algorithm identifier mismatch");
+ }
+
+ ContentVerifier verifier;
+
+ try
+ {
+ verifier = verifierProvider.get((tbsCert.getSignature()));
+
+ OutputStream sOut = verifier.getOutputStream();
+ DEROutputStream dOut = new DEROutputStream(sOut);
+
+ dOut.writeObject(tbsCert);
+
+ sOut.close();
+ }
+ catch (Exception e)
+ {
+ throw new CertException("unable to process signature: " + e.getMessage(), e);
+ }
+
+ return verifier.verify(x509Certificate.getSignature().getBytes());
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof X509CertificateHolder))
+ {
+ return false;
+ }
+
+ X509CertificateHolder other = (X509CertificateHolder)o;
+
+ return this.x509Certificate.equals(other.x509Certificate);
+ }
+
+ public int hashCode()
+ {
+ return this.x509Certificate.hashCode();
+ }
+
+ /**
+ * Return the ASN.1 encoding of this holder's certificate.
+ *
+ * @return a DER encoded byte array.
+ * @throws IOException if an encoding cannot be generated.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return x509Certificate.getEncoded();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509ContentVerifierProviderBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509ContentVerifierProviderBuilder.java
new file mode 100644
index 000000000..d8429912f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509ContentVerifierProviderBuilder.java
@@ -0,0 +1,14 @@
+package org.spongycastle.cert;
+
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.OperatorCreationException;
+
+public interface X509ContentVerifierProviderBuilder
+{
+ ContentVerifierProvider build(SubjectPublicKeyInfo validatingKeyInfo)
+ throws OperatorCreationException;
+
+ ContentVerifierProvider build(X509CertificateHolder validatingKeyInfo)
+ throws OperatorCreationException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509ExtensionUtils.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509ExtensionUtils.java
new file mode 100644
index 000000000..54f56adb8
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509ExtensionUtils.java
@@ -0,0 +1,126 @@
+package org.spongycastle.cert;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1OctetString;
+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.SubjectKeyIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.operator.DigestCalculator;
+
+/**
+ * General utility class for creating calculated extensions using the standard methods.
+ * <p>
+ * <b>Note:</b> This class is not thread safe!
+ * </p>
+ */
+public class X509ExtensionUtils
+{
+ private DigestCalculator calculator;
+
+ public X509ExtensionUtils(DigestCalculator calculator)
+ {
+ this.calculator = calculator;
+ }
+
+ public AuthorityKeyIdentifier createAuthorityKeyIdentifier(
+ X509CertificateHolder certHolder)
+ {
+ if (certHolder.getVersionNumber() != 3)
+ {
+ GeneralName genName = new GeneralName(certHolder.getIssuer());
+ SubjectPublicKeyInfo info = certHolder.getSubjectPublicKeyInfo();
+
+ return new AuthorityKeyIdentifier(
+ calculateIdentifier(info), new GeneralNames(genName), certHolder.getSerialNumber());
+ }
+ else
+ {
+ GeneralName genName = new GeneralName(certHolder.getIssuer());
+ Extension ext = certHolder.getExtension(Extension.subjectKeyIdentifier);
+
+ if (ext != null)
+ {
+ ASN1OctetString str = ASN1OctetString.getInstance(ext.getParsedValue());
+
+ return new AuthorityKeyIdentifier(
+ str.getOctets(), new GeneralNames(genName), certHolder.getSerialNumber());
+ }
+ else
+ {
+ SubjectPublicKeyInfo info = certHolder.getSubjectPublicKeyInfo();
+
+ return new AuthorityKeyIdentifier(
+ calculateIdentifier(info), new GeneralNames(genName), certHolder.getSerialNumber());
+ }
+ }
+ }
+
+ public AuthorityKeyIdentifier createAuthorityKeyIdentifier(SubjectPublicKeyInfo publicKeyInfo)
+ {
+ return new AuthorityKeyIdentifier(calculateIdentifier(publicKeyInfo));
+ }
+
+ /**
+ * Return a RFC 3280 type 1 key identifier. As in:
+ * <pre>
+ * (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the
+ * value of the BIT STRING subjectPublicKey (excluding the tag,
+ * length, and number of unused bits).
+ * </pre>
+ * @param publicKeyInfo the key info object containing the subjectPublicKey field.
+ * @return the key identifier.
+ */
+ public SubjectKeyIdentifier createSubjectKeyIdentifier(
+ SubjectPublicKeyInfo publicKeyInfo)
+ {
+ return new SubjectKeyIdentifier(calculateIdentifier(publicKeyInfo));
+ }
+
+ /**
+ * Return a RFC 3280 type 2 key identifier. As in:
+ * <pre>
+ * (2) The keyIdentifier is composed of a four bit type field with
+ * the value 0100 followed by the least significant 60 bits of the
+ * SHA-1 hash of the value of the BIT STRING subjectPublicKey.
+ * </pre>
+ * @param publicKeyInfo the key info object containing the subjectPublicKey field.
+ * @return the key identifier.
+ */
+ public SubjectKeyIdentifier createTruncatedSubjectKeyIdentifier(SubjectPublicKeyInfo publicKeyInfo)
+ {
+ byte[] digest = calculateIdentifier(publicKeyInfo);
+ byte[] id = new byte[8];
+
+ System.arraycopy(digest, digest.length - 8, id, 0, id.length);
+
+ id[0] &= 0x0f;
+ id[0] |= 0x40;
+
+ return new SubjectKeyIdentifier(id);
+ }
+
+ private byte[] calculateIdentifier(SubjectPublicKeyInfo publicKeyInfo)
+ {
+ byte[] bytes = publicKeyInfo.getPublicKeyData().getBytes();
+
+ OutputStream cOut = calculator.getOutputStream();
+
+ try
+ {
+ cOut.write(bytes);
+
+ cOut.close();
+ }
+ catch (IOException e)
+ { // it's hard to imagine this happening, but yes it does!
+ throw new CertRuntimeException("unable to calculate identifier: " + e.getMessage(), e);
+ }
+
+ return calculator.getDigest();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509v1CertificateBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509v1CertificateBuilder.java
new file mode 100644
index 000000000..b0a9b497f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509v1CertificateBuilder.java
@@ -0,0 +1,66 @@
+package org.spongycastle.cert;
+
+import java.math.BigInteger;
+import java.util.Date;
+
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.Time;
+import org.spongycastle.asn1.x509.V1TBSCertificateGenerator;
+import org.spongycastle.operator.ContentSigner;
+
+
+/**
+ * class to produce an X.509 Version 1 certificate.
+ */
+public class X509v1CertificateBuilder
+{
+ private V1TBSCertificateGenerator tbsGen;
+
+ /**
+ * Create a builder for a version 1 certificate.
+ *
+ * @param issuer the certificate issuer
+ * @param serial the certificate serial number
+ * @param notBefore the date before which the certificate is not valid
+ * @param notAfter the date after which the certificate is not valid
+ * @param subject the certificate subject
+ * @param publicKeyInfo the info structure for the public key to be associated with this certificate.
+ */
+ public X509v1CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, SubjectPublicKeyInfo publicKeyInfo)
+ {
+ if (issuer == null)
+ {
+ throw new IllegalArgumentException("issuer must not be null");
+ }
+
+ if (publicKeyInfo == null)
+ {
+ throw new IllegalArgumentException("publicKeyInfo must not be null");
+ }
+
+ tbsGen = new V1TBSCertificateGenerator();
+ tbsGen.setSerialNumber(new ASN1Integer(serial));
+ tbsGen.setIssuer(issuer);
+ tbsGen.setStartDate(new Time(notBefore));
+ tbsGen.setEndDate(new Time(notAfter));
+ tbsGen.setSubject(subject);
+ tbsGen.setSubjectPublicKeyInfo(publicKeyInfo);
+ }
+
+ /**
+ * Generate an X509 certificate, based on the current issuer and subject
+ * using the passed in signer.
+ *
+ * @param signer the content signer to be used to generate the signature validating the certificate.
+ * @return a holder containing the resulting signed certificate.
+ */
+ public X509CertificateHolder build(
+ ContentSigner signer)
+ {
+ tbsGen.setSignature(signer.getAlgorithmIdentifier());
+
+ return CertUtils.generateFullCert(signer, tbsGen.generateTBSCertificate());
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509v2AttributeCertificateBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509v2AttributeCertificateBuilder.java
new file mode 100644
index 000000000..199bb9b4d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509v2AttributeCertificateBuilder.java
@@ -0,0 +1,109 @@
+package org.spongycastle.cert;
+
+import java.math.BigInteger;
+import java.util.Date;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.x509.AttCertIssuer;
+import org.spongycastle.asn1.x509.Attribute;
+import org.spongycastle.asn1.x509.ExtensionsGenerator;
+import org.spongycastle.asn1.x509.V2AttributeCertificateInfoGenerator;
+import org.spongycastle.operator.ContentSigner;
+
+/**
+ * class to produce an X.509 Version 2 AttributeCertificate.
+ */
+public class X509v2AttributeCertificateBuilder
+{
+ private V2AttributeCertificateInfoGenerator acInfoGen;
+ private ExtensionsGenerator extGenerator;
+
+ public X509v2AttributeCertificateBuilder(AttributeCertificateHolder holder, AttributeCertificateIssuer issuer, BigInteger serialNumber, Date notBefore, Date notAfter)
+ {
+ acInfoGen = new V2AttributeCertificateInfoGenerator();
+ extGenerator = new ExtensionsGenerator();
+
+ acInfoGen.setHolder(holder.holder);
+ acInfoGen.setIssuer(AttCertIssuer.getInstance(issuer.form));
+ acInfoGen.setSerialNumber(new ASN1Integer(serialNumber));
+ acInfoGen.setStartDate(new ASN1GeneralizedTime(notBefore));
+ acInfoGen.setEndDate(new ASN1GeneralizedTime(notAfter));
+ }
+
+ /**
+ * Add an attribute to the certification request we are building.
+ *
+ * @param attrType the OID giving the type of the attribute.
+ * @param attrValue the ASN.1 structure that forms the value of the attribute.
+ * @return this builder object.
+ */
+ public X509v2AttributeCertificateBuilder addAttribute(ASN1ObjectIdentifier attrType, ASN1Encodable attrValue)
+ {
+ acInfoGen.addAttribute(new Attribute(attrType, new DERSet(attrValue)));
+
+ return this;
+ }
+
+ /**
+ * Add an attribute with multiple values to the certification request we are building.
+ *
+ * @param attrType the OID giving the type of the attribute.
+ * @param attrValues an array of ASN.1 structures that form the value of the attribute.
+ * @return this builder object.
+ */
+ public X509v2AttributeCertificateBuilder addAttribute(ASN1ObjectIdentifier attrType, ASN1Encodable[] attrValues)
+ {
+ acInfoGen.addAttribute(new Attribute(attrType, new DERSet(attrValues)));
+
+ return this;
+ }
+
+ public void setIssuerUniqueId(
+ boolean[] iui)
+ {
+ acInfoGen.setIssuerUniqueID(CertUtils.booleanToBitString(iui));
+ }
+
+ /**
+ * Add a given extension field for the standard extensions tag
+ *
+ * @param oid the OID defining the extension type.
+ * @param isCritical true if the extension is critical, false otherwise.
+ * @param value the ASN.1 structure that forms the extension's value.
+ * @return this builder object.
+ */
+ public X509v2AttributeCertificateBuilder addExtension(
+ ASN1ObjectIdentifier oid,
+ boolean isCritical,
+ ASN1Encodable value)
+ throws CertIOException
+ {
+ CertUtils.addExtension(extGenerator, oid, isCritical, value);
+
+ return this;
+ }
+
+ /**
+ * Generate an X509 certificate, based on the current issuer and subject
+ * using the passed in signer.
+ *
+ * @param signer the content signer to be used to generate the signature validating the certificate.
+ * @return a holder containing the resulting signed certificate.
+ */
+ public X509AttributeCertificateHolder build(
+ ContentSigner signer)
+ {
+ acInfoGen.setSignature(signer.getAlgorithmIdentifier());
+
+ if (!extGenerator.isEmpty())
+ {
+ acInfoGen.setExtensions(extGenerator.generate());
+ }
+
+ return CertUtils.generateFullAttrCert(signer, acInfoGen.generateAttributeCertificateInfo());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509v2CRLBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509v2CRLBuilder.java
new file mode 100644
index 000000000..d4b211cab
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509v2CRLBuilder.java
@@ -0,0 +1,182 @@
+package org.spongycastle.cert;
+
+import java.math.BigInteger;
+import java.util.Date;
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.ExtensionsGenerator;
+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.operator.ContentSigner;
+
+/**
+ * class to produce an X.509 Version 2 CRL.
+ */
+public class X509v2CRLBuilder
+{
+ private V2TBSCertListGenerator tbsGen;
+ private ExtensionsGenerator extGenerator;
+
+ /**
+ * Basic constructor.
+ *
+ * @param issuer the issuer this CRL is associated with.
+ * @param thisUpdate the date of this update.
+ */
+ public X509v2CRLBuilder(
+ X500Name issuer,
+ Date thisUpdate)
+ {
+ tbsGen = new V2TBSCertListGenerator();
+ extGenerator = new ExtensionsGenerator();
+
+ tbsGen.setIssuer(issuer);
+ tbsGen.setThisUpdate(new Time(thisUpdate));
+ }
+
+ /**
+ * Set the date by which the next CRL will become available.
+ *
+ * @param date date of next CRL update.
+ * @return the current builder.
+ */
+ public X509v2CRLBuilder setNextUpdate(
+ Date date)
+ {
+ tbsGen.setNextUpdate(new Time(date));
+
+ return this;
+ }
+
+ /**
+ * Add a CRL entry with the just reasonCode extension.
+ *
+ * @param userCertificateSerial serial number of revoked certificate.
+ * @param revocationDate date of certificate revocation.
+ * @param reason the reason code, as indicated in CRLReason, i.e CRLReason.keyCompromise, or 0 if not to be used.
+ * @return the current builder.
+ */
+ public X509v2CRLBuilder addCRLEntry(BigInteger userCertificateSerial, Date revocationDate, int reason)
+ {
+ tbsGen.addCRLEntry(new ASN1Integer(userCertificateSerial), new Time(revocationDate), reason);
+
+ return this;
+ }
+
+ /**
+ * Add a CRL entry with an invalidityDate extension as well as a reasonCode extension. This is used
+ * where the date of revocation might be after issues with the certificate may have occurred.
+ *
+ * @param userCertificateSerial serial number of revoked certificate.
+ * @param revocationDate date of certificate revocation.
+ * @param reason the reason code, as indicated in CRLReason, i.e CRLReason.keyCompromise, or 0 if not to be used.
+ * @param invalidityDate the date on which the private key for the certificate became compromised or the certificate otherwise became invalid.
+ * @return the current builder.
+ */
+ public X509v2CRLBuilder addCRLEntry(BigInteger userCertificateSerial, Date revocationDate, int reason, Date invalidityDate)
+ {
+ tbsGen.addCRLEntry(new ASN1Integer(userCertificateSerial), new Time(revocationDate), reason, new ASN1GeneralizedTime(invalidityDate));
+
+ return this;
+ }
+
+ /**
+ * Add a CRL entry with extensions.
+ *
+ * @param userCertificateSerial serial number of revoked certificate.
+ * @param revocationDate date of certificate revocation.
+ * @param extensions extension set to be associated with this CRLEntry.
+ * @return the current builder.
+ * @deprecated use method taking Extensions
+ */
+ public X509v2CRLBuilder addCRLEntry(BigInteger userCertificateSerial, Date revocationDate, X509Extensions extensions)
+ {
+ tbsGen.addCRLEntry(new ASN1Integer(userCertificateSerial), new Time(revocationDate), Extensions.getInstance(extensions));
+
+ return this;
+ }
+
+ /**
+ * Add a CRL entry with extensions.
+ *
+ * @param userCertificateSerial serial number of revoked certificate.
+ * @param revocationDate date of certificate revocation.
+ * @param extensions extension set to be associated with this CRLEntry.
+ * @return the current builder.
+ */
+ public X509v2CRLBuilder addCRLEntry(BigInteger userCertificateSerial, Date revocationDate, Extensions extensions)
+ {
+ tbsGen.addCRLEntry(new ASN1Integer(userCertificateSerial), new Time(revocationDate), extensions);
+
+ return this;
+ }
+
+ /**
+ * Add the CRLEntry objects contained in a previous CRL.
+ *
+ * @param other the X509CRLHolder to source the other entries from.
+ * @return the current builder.
+ */
+ public X509v2CRLBuilder addCRL(X509CRLHolder other)
+ {
+ TBSCertList revocations = other.toASN1Structure().getTBSCertList();
+
+ if (revocations != null)
+ {
+ for (Enumeration en = revocations.getRevokedCertificateEnumeration(); en.hasMoreElements();)
+ {
+ tbsGen.addCRLEntry(ASN1Sequence.getInstance(((ASN1Encodable)en.nextElement()).toASN1Primitive()));
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Add a given extension field for the standard extensions tag (tag 3)
+ *
+ * @param oid the OID defining the extension type.
+ * @param isCritical true if the extension is critical, false otherwise.
+ * @param value the ASN.1 structure that forms the extension's value.
+ * @return this builder object.
+ */
+ public X509v2CRLBuilder addExtension(
+ ASN1ObjectIdentifier oid,
+ boolean isCritical,
+ ASN1Encodable value)
+ throws CertIOException
+ {
+ CertUtils.addExtension(extGenerator, oid, isCritical, value);
+
+ return this;
+ }
+
+ /**
+ * Generate an X.509 CRL, based on the current issuer and subject
+ * using the passed in signer.
+ *
+ * @param signer the content signer to be used to generate the signature validating the certificate.
+ * @return a holder containing the resulting signed certificate.
+ */
+ public X509CRLHolder build(
+ ContentSigner signer)
+ {
+ tbsGen.setSignature(signer.getAlgorithmIdentifier());
+
+ if (!extGenerator.isEmpty())
+ {
+ tbsGen.setExtensions(extGenerator.generate());
+ }
+
+ return CertUtils.generateFullCRL(signer, tbsGen.generateTBSCertList());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509v3CertificateBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509v3CertificateBuilder.java
new file mode 100644
index 000000000..c2082293d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509v3CertificateBuilder.java
@@ -0,0 +1,142 @@
+package org.spongycastle.cert;
+
+import java.math.BigInteger;
+import java.util.Date;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.ExtensionsGenerator;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.Time;
+import org.spongycastle.asn1.x509.V3TBSCertificateGenerator;
+import org.spongycastle.operator.ContentSigner;
+
+
+/**
+ * class to produce an X.509 Version 3 certificate.
+ */
+public class X509v3CertificateBuilder
+{
+ private V3TBSCertificateGenerator tbsGen;
+ private ExtensionsGenerator extGenerator;
+
+ /**
+ * Create a builder for a version 3 certificate.
+ *
+ * @param issuer the certificate issuer
+ * @param serial the certificate serial number
+ * @param notBefore the date before which the certificate is not valid
+ * @param notAfter the date after which the certificate is not valid
+ * @param subject the certificate subject
+ * @param publicKeyInfo the info structure for the public key to be associated with this certificate.
+ */
+ public X509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, SubjectPublicKeyInfo publicKeyInfo)
+ {
+ tbsGen = new V3TBSCertificateGenerator();
+ tbsGen.setSerialNumber(new ASN1Integer(serial));
+ tbsGen.setIssuer(issuer);
+ tbsGen.setStartDate(new Time(notBefore));
+ tbsGen.setEndDate(new Time(notAfter));
+ tbsGen.setSubject(subject);
+ tbsGen.setSubjectPublicKeyInfo(publicKeyInfo);
+
+ extGenerator = new ExtensionsGenerator();
+ }
+
+ /**
+ * Set the subjectUniqueID - note: it is very rare that it is correct to do this.
+ *
+ * @param uniqueID a boolean array representing the bits making up the subjectUniqueID.
+ * @return this builder object.
+ */
+ public X509v3CertificateBuilder setSubjectUniqueID(boolean[] uniqueID)
+ {
+ tbsGen.setSubjectUniqueID(CertUtils.booleanToBitString(uniqueID));
+
+ return this;
+ }
+
+ /**
+ * Set the issuerUniqueID - note: it is very rare that it is correct to do this.
+ *
+ * @param uniqueID a boolean array representing the bits making up the issuerUniqueID.
+ * @return this builder object.
+ */
+ public X509v3CertificateBuilder setIssuerUniqueID(boolean[] uniqueID)
+ {
+ tbsGen.setIssuerUniqueID(CertUtils.booleanToBitString(uniqueID));
+
+ return this;
+ }
+
+ /**
+ * Add a given extension field for the standard extensions tag (tag 3)
+ *
+ * @param oid the OID defining the extension type.
+ * @param isCritical true if the extension is critical, false otherwise.
+ * @param value the ASN.1 structure that forms the extension's value.
+ * @return this builder object.
+ */
+ public X509v3CertificateBuilder addExtension(
+ ASN1ObjectIdentifier oid,
+ boolean isCritical,
+ ASN1Encodable value)
+ throws CertIOException
+ {
+ CertUtils.addExtension(extGenerator, oid, isCritical, value);
+
+ return this;
+ }
+
+ /**
+ * Add a given extension field for the standard extensions tag (tag 3)
+ * copying the extension value from another certificate.
+ *
+ * @param oid the OID defining the extension type.
+ * @param isCritical true if the copied extension is to be marked as critical, false otherwise.
+ * @param certHolder the holder for the certificate that the extension is to be copied from.
+ * @return this builder object.
+ */
+ public X509v3CertificateBuilder copyAndAddExtension(
+ ASN1ObjectIdentifier oid,
+ boolean isCritical,
+ X509CertificateHolder certHolder)
+ {
+ Certificate cert = certHolder.toASN1Structure();
+
+ Extension extension = cert.getTBSCertificate().getExtensions().getExtension(oid);
+
+ if (extension == null)
+ {
+ throw new NullPointerException("extension " + oid + " not present");
+ }
+
+ extGenerator.addExtension(oid, isCritical, extension.getExtnValue().getOctets());
+
+ return this;
+ }
+
+ /**
+ * Generate an X.509 certificate, based on the current issuer and subject
+ * using the passed in signer.
+ *
+ * @param signer the content signer to be used to generate the signature validating the certificate.
+ * @return a holder containing the resulting signed certificate.
+ */
+ public X509CertificateHolder build(
+ ContentSigner signer)
+ {
+ tbsGen.setSignature(signer.getAlgorithmIdentifier());
+
+ if (!extGenerator.isEmpty())
+ {
+ tbsGen.setExtensions(extGenerator.generate());
+ }
+
+ return CertUtils.generateFullCert(signer, tbsGen.generateTBSCertificate());
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/bc/BcX509ExtensionUtils.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/bc/BcX509ExtensionUtils.java
new file mode 100644
index 000000000..6d4dc217d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/bc/BcX509ExtensionUtils.java
@@ -0,0 +1,91 @@
+package org.spongycastle.cert.bc;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
+import org.spongycastle.cert.X509ExtensionUtils;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.util.SubjectPublicKeyInfoFactory;
+import org.spongycastle.operator.DigestCalculator;
+
+public class BcX509ExtensionUtils
+ extends X509ExtensionUtils
+{
+ /**
+ * Create a utility class pre-configured with a SHA-1 digest calculator based on the
+ * BC implementation.
+ */
+ public BcX509ExtensionUtils()
+ {
+ super(new SHA1DigestCalculator());
+ }
+
+ public BcX509ExtensionUtils(DigestCalculator calculator)
+ {
+ super(calculator);
+ }
+
+ public AuthorityKeyIdentifier createAuthorityKeyIdentifier(
+ AsymmetricKeyParameter publicKey)
+ throws IOException
+ {
+ return super.createAuthorityKeyIdentifier(SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey));
+ }
+
+ /**
+ * Return a RFC 3280 type 1 key identifier. As in:
+ * <pre>
+ * (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the
+ * value of the BIT STRING subjectPublicKey (excluding the tag,
+ * length, and number of unused bits).
+ * </pre>
+ * @param publicKey the key object containing the key identifier is to be based on.
+ * @return the key identifier.
+ */
+ public SubjectKeyIdentifier createSubjectKeyIdentifier(
+ AsymmetricKeyParameter publicKey)
+ throws IOException
+ {
+ return super.createSubjectKeyIdentifier(SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey));
+ }
+
+ private static class SHA1DigestCalculator
+ implements DigestCalculator
+ {
+ private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1);
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return bOut;
+ }
+
+ public byte[] getDigest()
+ {
+ byte[] bytes = bOut.toByteArray();
+
+ bOut.reset();
+
+ Digest sha1 = new SHA1Digest();
+
+ sha1.update(bytes, 0, bytes.length);
+
+ byte[] digest = new byte[sha1.getDigestSize()];
+
+ sha1.doFinal(digest, 0);
+
+ return digest;
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/bc/BcX509v1CertificateBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/bc/BcX509v1CertificateBuilder.java
new file mode 100644
index 000000000..2036d5d52
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/bc/BcX509v1CertificateBuilder.java
@@ -0,0 +1,33 @@
+package org.spongycastle.cert.bc;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Date;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cert.X509v1CertificateBuilder;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.util.SubjectPublicKeyInfoFactory;
+
+/**
+ * JCA helper class to allow BC lightweight objects to be used in the construction of a Version 1 certificate.
+ */
+public class BcX509v1CertificateBuilder
+ extends X509v1CertificateBuilder
+{
+ /**
+ * Initialise the builder using an AsymmetricKeyParameter.
+ *
+ * @param issuer X500Name representing the issuer of this certificate.
+ * @param serial the serial number for the certificate.
+ * @param notBefore date before which the certificate is not valid.
+ * @param notAfter date after which the certificate is not valid.
+ * @param subject X500Name representing the subject of this certificate.
+ * @param publicKey the public key to be associated with the certificate.
+ */
+ public BcX509v1CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, AsymmetricKeyParameter publicKey)
+ throws IOException
+ {
+ super(issuer, serial, notBefore, notAfter, subject, SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/bc/BcX509v3CertificateBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/bc/BcX509v3CertificateBuilder.java
new file mode 100644
index 000000000..282641013
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/bc/BcX509v3CertificateBuilder.java
@@ -0,0 +1,51 @@
+package org.spongycastle.cert.bc;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Date;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509v3CertificateBuilder;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.util.SubjectPublicKeyInfoFactory;
+
+/**
+ * JCA helper class to allow BC lightweight objects to be used in the construction of a Version 3 certificate.
+ */
+public class BcX509v3CertificateBuilder
+ extends X509v3CertificateBuilder
+{
+ /**
+ * Initialise the builder using a PublicKey.
+ *
+ * @param issuer X500Name representing the issuer of this certificate.
+ * @param serial the serial number for the certificate.
+ * @param notBefore date before which the certificate is not valid.
+ * @param notAfter date after which the certificate is not valid.
+ * @param subject X500Name representing the subject of this certificate.
+ * @param publicKey the public key to be associated with the certificate.
+ */
+ public BcX509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, AsymmetricKeyParameter publicKey)
+ throws IOException
+ {
+ super(issuer, serial, notBefore, notAfter, subject, SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey));
+ }
+
+ /**
+ * Initialise the builder using the subject from the passed in issuerCert as the issuer, as well as
+ * passing through and converting the other objects provided.
+ *
+ * @param issuerCert holder for certificate who's subject is the issuer of the certificate we are building.
+ * @param serial the serial number for the certificate.
+ * @param notBefore date before which the certificate is not valid.
+ * @param notAfter date after which the certificate is not valid.
+ * @param subject principal representing the subject of this certificate.
+ * @param publicKey the public key to be associated with the certificate.
+ */
+ public BcX509v3CertificateBuilder(X509CertificateHolder issuerCert, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, AsymmetricKeyParameter publicKey)
+ throws IOException
+ {
+ super(issuerCert.getSubject(), serial, notBefore, notAfter, subject, SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CMPException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CMPException.java
new file mode 100644
index 000000000..dc02a03bd
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CMPException.java
@@ -0,0 +1,24 @@
+package org.spongycastle.cert.cmp;
+
+public class CMPException
+ extends Exception
+{
+ private Throwable cause;
+
+ public CMPException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public CMPException(String msg)
+ {
+ super(msg);
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CMPRuntimeException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CMPRuntimeException.java
new file mode 100644
index 000000000..07f5b819f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CMPRuntimeException.java
@@ -0,0 +1,19 @@
+package org.spongycastle.cert.cmp;
+
+public class CMPRuntimeException
+ extends RuntimeException
+{
+ private Throwable cause;
+
+ public CMPRuntimeException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CMPUtil.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CMPUtil.java
new file mode 100644
index 000000000..6198ca84d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CMPUtil.java
@@ -0,0 +1,26 @@
+package org.spongycastle.cert.cmp;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.DEROutputStream;
+
+class CMPUtil
+{
+ static void derEncodeToStream(ASN1Encodable obj, OutputStream stream)
+ {
+ DEROutputStream dOut = new DEROutputStream(stream);
+
+ try
+ {
+ dOut.writeObject(obj);
+
+ dOut.close();
+ }
+ catch (IOException e)
+ {
+ throw new CMPRuntimeException("unable to DER encode object: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateConfirmationContent.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateConfirmationContent.java
new file mode 100644
index 000000000..0f8603414
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateConfirmationContent.java
@@ -0,0 +1,41 @@
+package org.spongycastle.cert.cmp;
+
+import org.spongycastle.asn1.cmp.CertConfirmContent;
+import org.spongycastle.asn1.cmp.CertStatus;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DigestAlgorithmIdentifierFinder;
+
+public class CertificateConfirmationContent
+{
+ private DigestAlgorithmIdentifierFinder digestAlgFinder;
+ private CertConfirmContent content;
+
+ public CertificateConfirmationContent(CertConfirmContent content)
+ {
+ this(content, new DefaultDigestAlgorithmIdentifierFinder());
+ }
+
+ public CertificateConfirmationContent(CertConfirmContent content, DigestAlgorithmIdentifierFinder digestAlgFinder)
+ {
+ this.digestAlgFinder = digestAlgFinder;
+ this.content = content;
+ }
+
+ public CertConfirmContent toASN1Structure()
+ {
+ return content;
+ }
+
+ public CertificateStatus[] getStatusMessages()
+ {
+ CertStatus[] statusArray = content.toCertStatusArray();
+ CertificateStatus[] ret = new CertificateStatus[statusArray.length];
+
+ for (int i = 0; i != ret.length; i++)
+ {
+ ret[i] = new CertificateStatus(digestAlgFinder, statusArray[i]);
+ }
+
+ return ret;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateConfirmationContentBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateConfirmationContentBuilder.java
new file mode 100644
index 000000000..106b3e24f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateConfirmationContentBuilder.java
@@ -0,0 +1,78 @@
+package org.spongycastle.cert.cmp;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.cmp.CertConfirmContent;
+import org.spongycastle.asn1.cmp.CertStatus;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+
+public class CertificateConfirmationContentBuilder
+{
+ private DigestAlgorithmIdentifierFinder digestAlgFinder;
+ private List acceptedCerts = new ArrayList();
+ private List acceptedReqIds = new ArrayList();
+
+ public CertificateConfirmationContentBuilder()
+ {
+ this(new DefaultDigestAlgorithmIdentifierFinder());
+ }
+
+ public CertificateConfirmationContentBuilder(DigestAlgorithmIdentifierFinder digestAlgFinder)
+ {
+ this.digestAlgFinder = digestAlgFinder;
+ }
+
+ public CertificateConfirmationContentBuilder addAcceptedCertificate(X509CertificateHolder certHolder, BigInteger certReqID)
+ {
+ acceptedCerts.add(certHolder);
+ acceptedReqIds.add(certReqID);
+
+ return this;
+ }
+
+ public CertificateConfirmationContent build(DigestCalculatorProvider digesterProvider)
+ throws CMPException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ for (int i = 0; i != acceptedCerts.size(); i++)
+ {
+ X509CertificateHolder certHolder = (X509CertificateHolder)acceptedCerts.get(i);
+ BigInteger reqID = (BigInteger)acceptedReqIds.get(i);
+
+ AlgorithmIdentifier digAlg = digestAlgFinder.find(certHolder.toASN1Structure().getSignatureAlgorithm());
+ if (digAlg == null)
+ {
+ throw new CMPException("cannot find algorithm for digest from signature");
+ }
+
+ DigestCalculator digester;
+
+ try
+ {
+ digester = digesterProvider.get(digAlg);
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new CMPException("unable to create digest: " + e.getMessage(), e);
+ }
+
+ CMPUtil.derEncodeToStream(certHolder.toASN1Structure(), digester.getOutputStream());
+
+ v.add(new CertStatus(digester.getDigest(), reqID));
+ }
+
+ return new CertificateConfirmationContent(CertConfirmContent.getInstance(new DERSequence(v)), digestAlgFinder);
+ }
+
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateStatus.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateStatus.java
new file mode 100644
index 000000000..f2923878a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/CertificateStatus.java
@@ -0,0 +1,60 @@
+package org.spongycastle.cert.cmp;
+
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.cmp.CertStatus;
+import org.spongycastle.asn1.cmp.PKIStatusInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.operator.DigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.util.Arrays;
+
+public class CertificateStatus
+{
+ private DigestAlgorithmIdentifierFinder digestAlgFinder;
+ private CertStatus certStatus;
+
+ CertificateStatus(DigestAlgorithmIdentifierFinder digestAlgFinder, CertStatus certStatus)
+ {
+ this.digestAlgFinder = digestAlgFinder;
+ this.certStatus = certStatus;
+ }
+
+ public PKIStatusInfo getStatusInfo()
+ {
+ return certStatus.getStatusInfo();
+ }
+
+ public BigInteger getCertRequestID()
+ {
+ return certStatus.getCertReqId().getValue();
+ }
+
+ public boolean isVerified(X509CertificateHolder certHolder, DigestCalculatorProvider digesterProvider)
+ throws CMPException
+ {
+ AlgorithmIdentifier digAlg = digestAlgFinder.find(certHolder.toASN1Structure().getSignatureAlgorithm());
+ if (digAlg == null)
+ {
+ throw new CMPException("cannot find algorithm for digest from signature");
+ }
+
+ DigestCalculator digester;
+
+ try
+ {
+ digester = digesterProvider.get(digAlg);
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new CMPException("unable to create digester: " + e.getMessage(), e);
+ }
+
+ CMPUtil.derEncodeToStream(certHolder.toASN1Structure(), digester.getOutputStream());
+
+ return Arrays.areEqual(certStatus.getCertHash().getOctets(), digester.getDigest());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/GeneralPKIMessage.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/GeneralPKIMessage.java
new file mode 100644
index 000000000..5bd499071
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/GeneralPKIMessage.java
@@ -0,0 +1,82 @@
+package org.spongycastle.cert.cmp;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.cmp.PKIBody;
+import org.spongycastle.asn1.cmp.PKIHeader;
+import org.spongycastle.asn1.cmp.PKIMessage;
+import org.spongycastle.cert.CertIOException;
+
+/**
+ * General wrapper for a generic PKIMessage
+ */
+public class GeneralPKIMessage
+{
+ private final PKIMessage pkiMessage;
+
+ private static PKIMessage parseBytes(byte[] encoding)
+ throws IOException
+ {
+ try
+ {
+ return PKIMessage.getInstance(ASN1Primitive.fromByteArray(encoding));
+ }
+ catch (ClassCastException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Create a PKIMessage from the passed in bytes.
+ *
+ * @param encoding BER/DER encoding of the PKIMessage
+ * @throws IOException in the event of corrupted data, or an incorrect structure.
+ */
+ public GeneralPKIMessage(byte[] encoding)
+ throws IOException
+ {
+ this(parseBytes(encoding));
+ }
+
+ /**
+ * Wrap a PKIMessage ASN.1 structure.
+ *
+ * @param pkiMessage base PKI message.
+ */
+ public GeneralPKIMessage(PKIMessage pkiMessage)
+ {
+ this.pkiMessage = pkiMessage;
+ }
+
+ public PKIHeader getHeader()
+ {
+ return pkiMessage.getHeader();
+ }
+
+ public PKIBody getBody()
+ {
+ return pkiMessage.getBody();
+ }
+
+ /**
+ * Return true if this message has protection bits on it. A return value of true
+ * indicates the message can be used to construct a ProtectedPKIMessage.
+ *
+ * @return true if message has protection, false otherwise.
+ */
+ public boolean hasProtection()
+ {
+ return pkiMessage.getHeader().getProtectionAlg() != null;
+ }
+
+ public PKIMessage toASN1Structure()
+ {
+ return pkiMessage;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessage.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessage.java
new file mode 100644
index 000000000..b5dbb9804
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessage.java
@@ -0,0 +1,198 @@
+package org.spongycastle.cert.cmp;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.cmp.CMPCertificate;
+import org.spongycastle.asn1.cmp.CMPObjectIdentifiers;
+import org.spongycastle.asn1.cmp.PBMParameter;
+import org.spongycastle.asn1.cmp.PKIBody;
+import org.spongycastle.asn1.cmp.PKIHeader;
+import org.spongycastle.asn1.cmp.PKIMessage;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.crmf.PKMACBuilder;
+import org.spongycastle.operator.ContentVerifier;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.MacCalculator;
+import org.spongycastle.util.Arrays;
+
+/**
+ * Wrapper for a PKIMessage with protection attached to it.
+ */
+public class ProtectedPKIMessage
+{
+ private PKIMessage pkiMessage;
+
+ /**
+ * Base constructor.
+ *
+ * @param pkiMessage a GeneralPKIMessage with
+ */
+ public ProtectedPKIMessage(GeneralPKIMessage pkiMessage)
+ {
+ if (!pkiMessage.hasProtection())
+ {
+ throw new IllegalArgumentException("PKIMessage not protected");
+ }
+
+ this.pkiMessage = pkiMessage.toASN1Structure();
+ }
+
+ ProtectedPKIMessage(PKIMessage pkiMessage)
+ {
+ if (pkiMessage.getHeader().getProtectionAlg() == null)
+ {
+ throw new IllegalArgumentException("PKIMessage not protected");
+ }
+
+ this.pkiMessage = pkiMessage;
+ }
+
+ /**
+ * Return the message header.
+ *
+ * @return the message's PKIHeader structure.
+ */
+ public PKIHeader getHeader()
+ {
+ return pkiMessage.getHeader();
+ }
+
+ /**
+ * Return the message body.
+ *
+ * @return the message's PKIBody structure.
+ */
+ public PKIBody getBody()
+ {
+ return pkiMessage.getBody();
+ }
+
+ /**
+ * Return the underlying ASN.1 structure contained in this object.
+ *
+ * @return a PKIMessage structure.
+ */
+ public PKIMessage toASN1Structure()
+ {
+ return pkiMessage;
+ }
+
+ /**
+ * Determine whether the message is protected by a password based MAC. Use verify(PKMACBuilder, char[])
+ * to verify the message if this method returns true.
+ *
+ * @return true if protection MAC PBE based, false otherwise.
+ */
+ public boolean hasPasswordBasedMacProtection()
+ {
+ return pkiMessage.getHeader().getProtectionAlg().getAlgorithm().equals(CMPObjectIdentifiers.passwordBasedMac);
+ }
+
+ /**
+ * Return the extra certificates associated with this message.
+ *
+ * @return an array of extra certificates, zero length if none present.
+ */
+ public X509CertificateHolder[] getCertificates()
+ {
+ CMPCertificate[] certs = pkiMessage.getExtraCerts();
+
+ if (certs == null)
+ {
+ return new X509CertificateHolder[0];
+ }
+
+ X509CertificateHolder[] res = new X509CertificateHolder[certs.length];
+ for (int i = 0; i != certs.length; i++)
+ {
+ res[i] = new X509CertificateHolder(certs[i].getX509v3PKCert());
+ }
+
+ return res;
+ }
+
+ /**
+ * Verify a message with a public key based signature attached.
+ *
+ * @param verifierProvider a provider of signature verifiers.
+ * @return true if the provider is able to create a verifier that validates
+ * the signature, false otherwise.
+ * @throws CMPException if an exception is thrown trying to verify the signature.
+ */
+ public boolean verify(ContentVerifierProvider verifierProvider)
+ throws CMPException
+ {
+ ContentVerifier verifier;
+ try
+ {
+ verifier = verifierProvider.get(pkiMessage.getHeader().getProtectionAlg());
+
+ return verifySignature(pkiMessage.getProtection().getBytes(), verifier);
+ }
+ catch (Exception e)
+ {
+ throw new CMPException("unable to verify signature: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Verify a message with password based MAC protection.
+ *
+ * @param pkMacBuilder MAC builder that can be used to construct the appropriate MacCalculator
+ * @param password the MAC password
+ * @return true if the passed in password and MAC builder verify the message, false otherwise.
+ * @throws CMPException if algorithm not MAC based, or an exception is thrown verifying the MAC.
+ */
+ public boolean verify(PKMACBuilder pkMacBuilder, char[] password)
+ throws CMPException
+ {
+ if (!CMPObjectIdentifiers.passwordBasedMac.equals(pkiMessage.getHeader().getProtectionAlg().getAlgorithm()))
+ {
+ throw new CMPException("protection algorithm not mac based");
+ }
+
+ try
+ {
+ pkMacBuilder.setParameters(PBMParameter.getInstance(pkiMessage.getHeader().getProtectionAlg().getParameters()));
+ MacCalculator calculator = pkMacBuilder.build(password);
+
+ OutputStream macOut = calculator.getOutputStream();
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(pkiMessage.getHeader());
+ v.add(pkiMessage.getBody());
+
+ macOut.write(new DERSequence(v).getEncoded(ASN1Encoding.DER));
+
+ macOut.close();
+
+ return Arrays.areEqual(calculator.getMac(), pkiMessage.getProtection().getBytes());
+ }
+ catch (Exception e)
+ {
+ throw new CMPException("unable to verify MAC: " + e.getMessage(), e);
+ }
+ }
+
+ private boolean verifySignature(byte[] signature, ContentVerifier verifier)
+ throws IOException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(pkiMessage.getHeader());
+ v.add(pkiMessage.getBody());
+
+ OutputStream sOut = verifier.getOutputStream();
+
+ sOut.write(new DERSequence(v).getEncoded(ASN1Encoding.DER));
+
+ sOut.close();
+
+ return verifier.verify(signature);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessageBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessageBuilder.java
new file mode 100644
index 000000000..8d5228d17
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessageBuilder.java
@@ -0,0 +1,306 @@
+package org.spongycastle.cert.cmp;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.cmp.CMPCertificate;
+import org.spongycastle.asn1.cmp.InfoTypeAndValue;
+import org.spongycastle.asn1.cmp.PKIBody;
+import org.spongycastle.asn1.cmp.PKIFreeText;
+import org.spongycastle.asn1.cmp.PKIHeader;
+import org.spongycastle.asn1.cmp.PKIHeaderBuilder;
+import org.spongycastle.asn1.cmp.PKIMessage;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.MacCalculator;
+
+/**
+ * Builder for creating a protected PKI message.
+ */
+public class ProtectedPKIMessageBuilder
+{
+ private PKIHeaderBuilder hdrBuilder;
+ private PKIBody body;
+ private List generalInfos = new ArrayList();
+ private List extraCerts = new ArrayList();
+
+ /**
+ * Commence a message with the header version CMP_2000.
+ *
+ * @param sender message sender.
+ * @param recipient intended recipient.
+ */
+ public ProtectedPKIMessageBuilder(GeneralName sender, GeneralName recipient)
+ {
+ this(PKIHeader.CMP_2000, sender, recipient);
+ }
+
+ /**
+ * Commence a message with a specific header type.
+ *
+ * @param pvno the version CMP_1999 or CMP_2000.
+ * @param sender message sender.
+ * @param recipient intended recipient.
+ */
+ public ProtectedPKIMessageBuilder(int pvno, GeneralName sender, GeneralName recipient)
+ {
+ hdrBuilder = new PKIHeaderBuilder(pvno, sender, recipient);
+ }
+
+ /**
+ * Set the identifier for the transaction the new message will belong to.
+ *
+ * @param tid the transaction ID.
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder setTransactionID(byte[] tid)
+ {
+ hdrBuilder.setTransactionID(tid);
+
+ return this;
+ }
+
+ /**
+ * Include a human-readable message in the new message.
+ *
+ * @param freeText the contents of the human readable message,
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder setFreeText(PKIFreeText freeText)
+ {
+ hdrBuilder.setFreeText(freeText);
+
+ return this;
+ }
+
+ /**
+ * Add a generalInfo data record to the header of the new message.
+ *
+ * @param genInfo the generalInfo data to be added.
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder addGeneralInfo(InfoTypeAndValue genInfo)
+ {
+ generalInfos.add(genInfo);
+
+ return this;
+ }
+
+ /**
+ * Set the creation time for the new message.
+ *
+ * @param time the message creation time.
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder setMessageTime(Date time)
+ {
+ hdrBuilder.setMessageTime(new ASN1GeneralizedTime(time));
+
+ return this;
+ }
+
+ /**
+ * Set the recipient key identifier for the key to be used to verify the new message.
+ *
+ * @param kid a key identifier.
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder setRecipKID(byte[] kid)
+ {
+ hdrBuilder.setRecipKID(kid);
+
+ return this;
+ }
+
+ /**
+ * Set the recipient nonce field on the new message.
+ *
+ * @param nonce a NONCE, typically copied from the sender nonce of the previous message.
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder setRecipNonce(byte[] nonce)
+ {
+ hdrBuilder.setRecipNonce(nonce);
+
+ return this;
+ }
+
+ /**
+ * Set the sender key identifier for the key used to protect the new message.
+ *
+ * @param kid a key identifier.
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder setSenderKID(byte[] kid)
+ {
+ hdrBuilder.setSenderKID(kid);
+
+ return this;
+ }
+
+ /**
+ * Set the sender nonce field on the new message.
+ *
+ * @param nonce a NONCE, typically 128 bits of random data.
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder setSenderNonce(byte[] nonce)
+ {
+ hdrBuilder.setSenderNonce(nonce);
+
+ return this;
+ }
+
+ /**
+ * Set the body for the new message
+ *
+ * @param body the message body.
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder setBody(PKIBody body)
+ {
+ this.body = body;
+
+ return this;
+ }
+
+ /**
+ * Add an "extra certificate" to the message.
+ *
+ * @param extraCert the extra certificate to add.
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder addCMPCertificate(X509CertificateHolder extraCert)
+ {
+ extraCerts.add(extraCert);
+
+ return this;
+ }
+
+ /**
+ * Build a protected PKI message which has MAC based integrity protection.
+ *
+ * @param macCalculator MAC calculator.
+ * @return the resulting protected PKI message.
+ * @throws CMPException if the protection MAC cannot be calculated.
+ */
+ public ProtectedPKIMessage build(MacCalculator macCalculator)
+ throws CMPException
+ {
+ finaliseHeader(macCalculator.getAlgorithmIdentifier());
+
+ PKIHeader header = hdrBuilder.build();
+
+ try
+ {
+ DERBitString protection = new DERBitString(calculateMac(macCalculator, header, body));
+
+ return finaliseMessage(header, protection);
+ }
+ catch (IOException e)
+ {
+ throw new CMPException("unable to encode MAC input: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Build a protected PKI message which has MAC based integrity protection.
+ *
+ * @param signer the ContentSigner to be used to calculate the signature.
+ * @return the resulting protected PKI message.
+ * @throws CMPException if the protection signature cannot be calculated.
+ */
+ public ProtectedPKIMessage build(ContentSigner signer)
+ throws CMPException
+ {
+ finaliseHeader(signer.getAlgorithmIdentifier());
+
+ PKIHeader header = hdrBuilder.build();
+
+ try
+ {
+ DERBitString protection = new DERBitString(calculateSignature(signer, header, body));
+
+ return finaliseMessage(header, protection);
+ }
+ catch (IOException e)
+ {
+ throw new CMPException("unable to encode signature input: " + e.getMessage(), e);
+ }
+ }
+
+ private void finaliseHeader(AlgorithmIdentifier algorithmIdentifier)
+ {
+ hdrBuilder.setProtectionAlg(algorithmIdentifier);
+
+ if (!generalInfos.isEmpty())
+ {
+ InfoTypeAndValue[] genInfos = new InfoTypeAndValue[generalInfos.size()];
+
+ hdrBuilder.setGeneralInfo((InfoTypeAndValue[])generalInfos.toArray(genInfos));
+ }
+ }
+
+ private ProtectedPKIMessage finaliseMessage(PKIHeader header, DERBitString protection)
+ {
+ if (!extraCerts.isEmpty())
+ {
+ CMPCertificate[] cmpCerts = new CMPCertificate[extraCerts.size()];
+
+ for (int i = 0; i != cmpCerts.length; i++)
+ {
+ cmpCerts[i] = new CMPCertificate(((X509CertificateHolder)extraCerts.get(i)).toASN1Structure());
+ }
+
+ return new ProtectedPKIMessage(new PKIMessage(header, body, protection, cmpCerts));
+ }
+ else
+ {
+ return new ProtectedPKIMessage(new PKIMessage(header, body, protection));
+ }
+ }
+
+ private byte[] calculateSignature(ContentSigner signer, PKIHeader header, PKIBody body)
+ throws IOException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(header);
+ v.add(body);
+
+ OutputStream sOut = signer.getOutputStream();
+
+ sOut.write(new DERSequence(v).getEncoded(ASN1Encoding.DER));
+
+ sOut.close();
+
+ return signer.getSignature();
+ }
+
+ private byte[] calculateMac(MacCalculator macCalculator, PKIHeader header, PKIBody body)
+ throws IOException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(header);
+ v.add(body);
+
+ OutputStream sOut = macCalculator.getOutputStream();
+
+ sOut.write(new DERSequence(v).getEncoded(ASN1Encoding.DER));
+
+ sOut.close();
+
+ return macCalculator.getMac();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/RevocationDetails.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/RevocationDetails.java
new file mode 100644
index 000000000..a9c4993c1
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/RevocationDetails.java
@@ -0,0 +1,36 @@
+package org.spongycastle.cert.cmp;
+
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.cmp.RevDetails;
+import org.spongycastle.asn1.x500.X500Name;
+
+public class RevocationDetails
+{
+ private RevDetails revDetails;
+
+ public RevocationDetails(RevDetails revDetails)
+ {
+ this.revDetails = revDetails;
+ }
+
+ public X500Name getSubject()
+ {
+ return revDetails.getCertDetails().getSubject();
+ }
+
+ public X500Name getIssuer()
+ {
+ return revDetails.getCertDetails().getIssuer();
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return revDetails.getCertDetails().getSerialNumber().getValue();
+ }
+
+ public RevDetails toASN1Structure()
+ {
+ return revDetails;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/RevocationDetailsBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/RevocationDetailsBuilder.java
new file mode 100644
index 000000000..bc7eaa042
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/RevocationDetailsBuilder.java
@@ -0,0 +1,59 @@
+package org.spongycastle.cert.cmp;
+
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.cmp.RevDetails;
+import org.spongycastle.asn1.crmf.CertTemplateBuilder;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+
+public class RevocationDetailsBuilder
+{
+ private CertTemplateBuilder templateBuilder = new CertTemplateBuilder();
+
+ public RevocationDetailsBuilder setPublicKey(SubjectPublicKeyInfo publicKey)
+ {
+ if (publicKey != null)
+ {
+ templateBuilder.setPublicKey(publicKey);
+ }
+
+ return this;
+ }
+
+ public RevocationDetailsBuilder setIssuer(X500Name issuer)
+ {
+ if (issuer != null)
+ {
+ templateBuilder.setIssuer(issuer);
+ }
+
+ return this;
+ }
+
+ public RevocationDetailsBuilder setSerialNumber(BigInteger serialNumber)
+ {
+ if (serialNumber != null)
+ {
+ templateBuilder.setSerialNumber(new ASN1Integer(serialNumber));
+ }
+
+ return this;
+ }
+
+ public RevocationDetailsBuilder setSubject(X500Name subject)
+ {
+ if (subject != null)
+ {
+ templateBuilder.setSubject(subject);
+ }
+
+ return this;
+ }
+
+ public RevocationDetails build()
+ {
+ return new RevocationDetails(new RevDetails(templateBuilder.build()));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/AuthenticatorControl.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/AuthenticatorControl.java
new file mode 100644
index 000000000..58e6c63a5
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/AuthenticatorControl.java
@@ -0,0 +1,57 @@
+package org.spongycastle.cert.crmf;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERUTF8String;
+import org.spongycastle.asn1.crmf.CRMFObjectIdentifiers;
+
+/**
+ * Carrier for an authenticator control.
+ */
+public class AuthenticatorControl
+ implements Control
+{
+ private static final ASN1ObjectIdentifier type = CRMFObjectIdentifiers.id_regCtrl_authenticator;
+
+ private final DERUTF8String token;
+
+ /**
+ * Basic constructor - build from a UTF-8 string representing the token.
+ *
+ * @param token UTF-8 string representing the token.
+ */
+ public AuthenticatorControl(DERUTF8String token)
+ {
+ this.token = token;
+ }
+
+ /**
+ * Basic constructor - build from a string representing the token.
+ *
+ * @param token string representing the token.
+ */
+ public AuthenticatorControl(String token)
+ {
+ this.token = new DERUTF8String(token);
+ }
+
+ /**
+ * Return the type of this control.
+ *
+ * @return CRMFObjectIdentifiers.id_regCtrl_authenticator
+ */
+ public ASN1ObjectIdentifier getType()
+ {
+ return type;
+ }
+
+ /**
+ * Return the token associated with this control (a UTF8String).
+ *
+ * @return a UTF8String.
+ */
+ public ASN1Encodable getValue()
+ {
+ return token;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFException.java
new file mode 100644
index 000000000..14aa0ad2b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFException.java
@@ -0,0 +1,19 @@
+package org.spongycastle.cert.crmf;
+
+public class CRMFException
+ extends Exception
+{
+ private Throwable cause;
+
+ public CRMFException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFRuntimeException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFRuntimeException.java
new file mode 100644
index 000000000..cde484c4c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFRuntimeException.java
@@ -0,0 +1,19 @@
+package org.spongycastle.cert.crmf;
+
+public class CRMFRuntimeException
+ extends RuntimeException
+{
+ private Throwable cause;
+
+ public CRMFRuntimeException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFUtil.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFUtil.java
new file mode 100644
index 000000000..eb6771e62
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CRMFUtil.java
@@ -0,0 +1,42 @@
+package org.spongycastle.cert.crmf;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.x509.ExtensionsGenerator;
+import org.spongycastle.cert.CertIOException;
+
+class CRMFUtil
+{
+ static void derEncodeToStream(ASN1Encodable obj, OutputStream stream)
+ {
+ DEROutputStream dOut = new DEROutputStream(stream);
+
+ try
+ {
+ dOut.writeObject(obj);
+
+ dOut.close();
+ }
+ catch (IOException e)
+ {
+ throw new CRMFRuntimeException("unable to DER encode object: " + e.getMessage(), e);
+ }
+ }
+
+ static void addExtension(ExtensionsGenerator extGenerator, ASN1ObjectIdentifier oid, boolean isCritical, ASN1Encodable value)
+ throws CertIOException
+ {
+ try
+ {
+ extGenerator.addExtension(oid, isCritical, value);
+ }
+ catch (IOException e)
+ {
+ throw new CertIOException("cannot encode extension: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CertificateRequestMessage.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CertificateRequestMessage.java
new file mode 100644
index 000000000..987b6b376
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CertificateRequestMessage.java
@@ -0,0 +1,309 @@
+package org.spongycastle.cert.crmf;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERUTF8String;
+import org.spongycastle.asn1.crmf.AttributeTypeAndValue;
+import org.spongycastle.asn1.crmf.CRMFObjectIdentifiers;
+import org.spongycastle.asn1.crmf.CertReqMsg;
+import org.spongycastle.asn1.crmf.CertTemplate;
+import org.spongycastle.asn1.crmf.Controls;
+import org.spongycastle.asn1.crmf.PKIArchiveOptions;
+import org.spongycastle.asn1.crmf.PKMACValue;
+import org.spongycastle.asn1.crmf.POPOSigningKey;
+import org.spongycastle.asn1.crmf.ProofOfPossession;
+import org.spongycastle.cert.CertIOException;
+import org.spongycastle.operator.ContentVerifier;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.OperatorCreationException;
+
+/**
+ * Carrier for a CRMF CertReqMsg.
+ */
+public class CertificateRequestMessage
+{
+ public static final int popRaVerified = ProofOfPossession.TYPE_RA_VERIFIED;
+ public static final int popSigningKey = ProofOfPossession.TYPE_SIGNING_KEY;
+ public static final int popKeyEncipherment = ProofOfPossession.TYPE_KEY_ENCIPHERMENT;
+ public static final int popKeyAgreement = ProofOfPossession.TYPE_KEY_AGREEMENT;
+
+ private final CertReqMsg certReqMsg;
+ private final Controls controls;
+
+ private static CertReqMsg parseBytes(byte[] encoding)
+ throws IOException
+ {
+ try
+ {
+ return CertReqMsg.getInstance(ASN1Primitive.fromByteArray(encoding));
+ }
+ catch (ClassCastException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Create a CertificateRequestMessage from the passed in bytes.
+ *
+ * @param certReqMsg BER/DER encoding of the CertReqMsg structure.
+ * @throws IOException in the event of corrupted data, or an incorrect structure.
+ */
+ public CertificateRequestMessage(byte[] certReqMsg)
+ throws IOException
+ {
+ this(parseBytes(certReqMsg));
+ }
+
+ public CertificateRequestMessage(CertReqMsg certReqMsg)
+ {
+ this.certReqMsg = certReqMsg;
+ this.controls = certReqMsg.getCertReq().getControls();
+ }
+
+ /**
+ * Return the underlying ASN.1 object defining this CertificateRequestMessage object.
+ *
+ * @return a CertReqMsg.
+ */
+ public CertReqMsg toASN1Structure()
+ {
+ return certReqMsg;
+ }
+
+ /**
+ * Return the certificate template contained in this message.
+ *
+ * @return a CertTemplate structure.
+ */
+ public CertTemplate getCertTemplate()
+ {
+ return this.certReqMsg.getCertReq().getCertTemplate();
+ }
+
+ /**
+ * Return whether or not this request has control values associated with it.
+ *
+ * @return true if there are control values present, false otherwise.
+ */
+ public boolean hasControls()
+ {
+ return controls != null;
+ }
+
+ /**
+ * Return whether or not this request has a specific type of control value.
+ *
+ * @param type the type OID for the control value we are checking for.
+ * @return true if a control value of type is present, false otherwise.
+ */
+ public boolean hasControl(ASN1ObjectIdentifier type)
+ {
+ return findControl(type) != null;
+ }
+
+ /**
+ * Return a control value of the specified type.
+ *
+ * @param type the type OID for the control value we are checking for.
+ * @return the control value if present, null otherwise.
+ */
+ public Control getControl(ASN1ObjectIdentifier type)
+ {
+ AttributeTypeAndValue found = findControl(type);
+
+ if (found != null)
+ {
+ if (found.getType().equals(CRMFObjectIdentifiers.id_regCtrl_pkiArchiveOptions))
+ {
+ return new PKIArchiveControl(PKIArchiveOptions.getInstance(found.getValue()));
+ }
+ if (found.getType().equals(CRMFObjectIdentifiers.id_regCtrl_regToken))
+ {
+ return new RegTokenControl(DERUTF8String.getInstance(found.getValue()));
+ }
+ if (found.getType().equals(CRMFObjectIdentifiers.id_regCtrl_authenticator))
+ {
+ return new AuthenticatorControl(DERUTF8String.getInstance(found.getValue()));
+ }
+ }
+
+ return null;
+ }
+
+ private AttributeTypeAndValue findControl(ASN1ObjectIdentifier type)
+ {
+ if (controls == null)
+ {
+ return null;
+ }
+
+ AttributeTypeAndValue[] tAndVs = controls.toAttributeTypeAndValueArray();
+ AttributeTypeAndValue found = null;
+
+ for (int i = 0; i != tAndVs.length; i++)
+ {
+ if (tAndVs[i].getType().equals(type))
+ {
+ found = tAndVs[i];
+ break;
+ }
+ }
+
+ return found;
+ }
+
+ /**
+ * Return whether or not this request message has a proof-of-possession field in it.
+ *
+ * @return true if proof-of-possession is present, false otherwise.
+ */
+ public boolean hasProofOfPossession()
+ {
+ return this.certReqMsg.getPopo() != null;
+ }
+
+ /**
+ * Return the type of the proof-of-possession this request message provides.
+ *
+ * @return one of: popRaVerified, popSigningKey, popKeyEncipherment, popKeyAgreement
+ */
+ public int getProofOfPossessionType()
+ {
+ return this.certReqMsg.getPopo().getType();
+ }
+
+ /**
+ * Return whether or not the proof-of-possession (POP) is of the type popSigningKey and
+ * it has a public key MAC associated with it.
+ *
+ * @return true if POP is popSigningKey and a PKMAC is present, false otherwise.
+ */
+ public boolean hasSigningKeyProofOfPossessionWithPKMAC()
+ {
+ ProofOfPossession pop = certReqMsg.getPopo();
+
+ if (pop.getType() == popSigningKey)
+ {
+ POPOSigningKey popoSign = POPOSigningKey.getInstance(pop.getObject());
+
+ return popoSign.getPoposkInput().getPublicKeyMAC() != null;
+ }
+
+ return false;
+ }
+
+ /**
+ * Return whether or not a signing key proof-of-possession (POP) is valid.
+ *
+ * @param verifierProvider a provider that can produce content verifiers for the signature contained in this POP.
+ * @return true if the POP is valid, false otherwise.
+ * @throws CRMFException if there is a problem in verification or content verifier creation.
+ * @throws IllegalStateException if POP not appropriate.
+ */
+ public boolean isValidSigningKeyPOP(ContentVerifierProvider verifierProvider)
+ throws CRMFException, IllegalStateException
+ {
+ ProofOfPossession pop = certReqMsg.getPopo();
+
+ if (pop.getType() == popSigningKey)
+ {
+ POPOSigningKey popoSign = POPOSigningKey.getInstance(pop.getObject());
+
+ if (popoSign.getPoposkInput() != null && popoSign.getPoposkInput().getPublicKeyMAC() != null)
+ {
+ throw new IllegalStateException("verification requires password check");
+ }
+
+ return verifySignature(verifierProvider, popoSign);
+ }
+ else
+ {
+ throw new IllegalStateException("not Signing Key type of proof of possession");
+ }
+ }
+
+ /**
+ * Return whether or not a signing key proof-of-possession (POP), with an associated PKMAC, is valid.
+ *
+ * @param verifierProvider a provider that can produce content verifiers for the signature contained in this POP.
+ * @param macBuilder a suitable PKMACBuilder to create the MAC verifier.
+ * @param password the password used to key the MAC calculation.
+ * @return true if the POP is valid, false otherwise.
+ * @throws CRMFException if there is a problem in verification or content verifier creation.
+ * @throws IllegalStateException if POP not appropriate.
+ */
+ public boolean isValidSigningKeyPOP(ContentVerifierProvider verifierProvider, PKMACBuilder macBuilder, char[] password)
+ throws CRMFException, IllegalStateException
+ {
+ ProofOfPossession pop = certReqMsg.getPopo();
+
+ if (pop.getType() == popSigningKey)
+ {
+ POPOSigningKey popoSign = POPOSigningKey.getInstance(pop.getObject());
+
+ if (popoSign.getPoposkInput() == null || popoSign.getPoposkInput().getSender() != null)
+ {
+ throw new IllegalStateException("no PKMAC present in proof of possession");
+ }
+
+ PKMACValue pkMAC = popoSign.getPoposkInput().getPublicKeyMAC();
+ PKMACValueVerifier macVerifier = new PKMACValueVerifier(macBuilder);
+
+ if (macVerifier.isValid(pkMAC, password, this.getCertTemplate().getPublicKey()))
+ {
+ return verifySignature(verifierProvider, popoSign);
+ }
+
+ return false;
+ }
+ else
+ {
+ throw new IllegalStateException("not Signing Key type of proof of possession");
+ }
+ }
+
+ private boolean verifySignature(ContentVerifierProvider verifierProvider, POPOSigningKey popoSign)
+ throws CRMFException
+ {
+ ContentVerifier verifier;
+
+ try
+ {
+ verifier = verifierProvider.get(popoSign.getAlgorithmIdentifier());
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new CRMFException("unable to create verifier: " + e.getMessage(), e);
+ }
+
+ if (popoSign.getPoposkInput() != null)
+ {
+ CRMFUtil.derEncodeToStream(popoSign.getPoposkInput(), verifier.getOutputStream());
+ }
+ else
+ {
+ CRMFUtil.derEncodeToStream(certReqMsg.getCertReq(), verifier.getOutputStream());
+ }
+
+ return verifier.verify(popoSign.getSignature().getBytes());
+ }
+
+ /**
+ * Return the ASN.1 encoding of the certReqMsg we wrap.
+ *
+ * @return a byte array containing the binary encoding of the certReqMsg.
+ * @throws IOException if there is an exception creating the encoding.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return certReqMsg.getEncoded();
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CertificateRequestMessageBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CertificateRequestMessageBuilder.java
new file mode 100644
index 000000000..4bfd6451a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/CertificateRequestMessageBuilder.java
@@ -0,0 +1,279 @@
+package org.spongycastle.cert.crmf;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Null;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.crmf.AttributeTypeAndValue;
+import org.spongycastle.asn1.crmf.CertReqMsg;
+import org.spongycastle.asn1.crmf.CertRequest;
+import org.spongycastle.asn1.crmf.CertTemplate;
+import org.spongycastle.asn1.crmf.CertTemplateBuilder;
+import org.spongycastle.asn1.crmf.OptionalValidity;
+import org.spongycastle.asn1.crmf.POPOPrivKey;
+import org.spongycastle.asn1.crmf.ProofOfPossession;
+import org.spongycastle.asn1.crmf.SubsequentMessage;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.ExtensionsGenerator;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.Time;
+import org.spongycastle.cert.CertIOException;
+import org.spongycastle.operator.ContentSigner;
+
+public class CertificateRequestMessageBuilder
+{
+ private final BigInteger certReqId;
+
+ private ExtensionsGenerator extGenerator;
+ private CertTemplateBuilder templateBuilder;
+ private List controls;
+ private ContentSigner popSigner;
+ private PKMACBuilder pkmacBuilder;
+ private char[] password;
+ private GeneralName sender;
+ private POPOPrivKey popoPrivKey;
+ private ASN1Null popRaVerified;
+
+ public CertificateRequestMessageBuilder(BigInteger certReqId)
+ {
+ this.certReqId = certReqId;
+
+ this.extGenerator = new ExtensionsGenerator();
+ this.templateBuilder = new CertTemplateBuilder();
+ this.controls = new ArrayList();
+ }
+
+ public CertificateRequestMessageBuilder setPublicKey(SubjectPublicKeyInfo publicKey)
+ {
+ if (publicKey != null)
+ {
+ templateBuilder.setPublicKey(publicKey);
+ }
+
+ return this;
+ }
+
+ public CertificateRequestMessageBuilder setIssuer(X500Name issuer)
+ {
+ if (issuer != null)
+ {
+ templateBuilder.setIssuer(issuer);
+ }
+
+ return this;
+ }
+
+ public CertificateRequestMessageBuilder setSubject(X500Name subject)
+ {
+ if (subject != null)
+ {
+ templateBuilder.setSubject(subject);
+ }
+
+ return this;
+ }
+
+ public CertificateRequestMessageBuilder setSerialNumber(BigInteger serialNumber)
+ {
+ if (serialNumber != null)
+ {
+ templateBuilder.setSerialNumber(new ASN1Integer(serialNumber));
+ }
+
+ return this;
+ }
+
+ /**
+ * Request a validity period for the certificate. Either, but not both, of the date parameters may be null.
+ *
+ * @param notBeforeDate not before date for certificate requested.
+ * @param notAfterDate not after date for the certificate requested.
+ *
+ * @return the current builder.
+ */
+ public CertificateRequestMessageBuilder setValidity(Date notBeforeDate, Date notAfterDate)
+ {
+ templateBuilder.setValidity(new OptionalValidity(createTime(notBeforeDate), createTime(notAfterDate)));
+
+ return this;
+ }
+
+ private Time createTime(Date date)
+ {
+ if (date != null)
+ {
+ return new Time(date);
+ }
+
+ return null;
+ }
+
+ public CertificateRequestMessageBuilder addExtension(
+ ASN1ObjectIdentifier oid,
+ boolean critical,
+ ASN1Encodable value)
+ throws CertIOException
+ {
+ CRMFUtil.addExtension(extGenerator, oid, critical, value);
+
+ return this;
+ }
+
+ public CertificateRequestMessageBuilder addExtension(
+ ASN1ObjectIdentifier oid,
+ boolean critical,
+ byte[] value)
+ {
+ extGenerator.addExtension(oid, critical, value);
+
+ return this;
+ }
+
+ public CertificateRequestMessageBuilder addControl(Control control)
+ {
+ controls.add(control);
+
+ return this;
+ }
+
+ public CertificateRequestMessageBuilder setProofOfPossessionSigningKeySigner(ContentSigner popSigner)
+ {
+ if (popoPrivKey != null || popRaVerified != null)
+ {
+ throw new IllegalStateException("only one proof of possession allowed");
+ }
+
+ this.popSigner = popSigner;
+
+ return this;
+ }
+
+ public CertificateRequestMessageBuilder setProofOfPossessionSubsequentMessage(SubsequentMessage msg)
+ {
+ if (popSigner != null || popRaVerified != null)
+ {
+ throw new IllegalStateException("only one proof of possession allowed");
+ }
+
+ this.popoPrivKey = new POPOPrivKey(msg);
+
+ return this;
+ }
+
+ public CertificateRequestMessageBuilder setProofOfPossessionRaVerified()
+ {
+ if (popSigner != null || popoPrivKey != null)
+ {
+ throw new IllegalStateException("only one proof of possession allowed");
+ }
+
+ this.popRaVerified = DERNull.INSTANCE;
+
+ return this;
+ }
+
+ public CertificateRequestMessageBuilder setAuthInfoPKMAC(PKMACBuilder pkmacBuilder, char[] password)
+ {
+ this.pkmacBuilder = pkmacBuilder;
+ this.password = password;
+
+ return this;
+ }
+
+ public CertificateRequestMessageBuilder setAuthInfoSender(X500Name sender)
+ {
+ return setAuthInfoSender(new GeneralName(sender));
+ }
+
+ public CertificateRequestMessageBuilder setAuthInfoSender(GeneralName sender)
+ {
+ this.sender = sender;
+
+ return this;
+ }
+
+ public CertificateRequestMessage build()
+ throws CRMFException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new ASN1Integer(certReqId));
+
+ if (!extGenerator.isEmpty())
+ {
+ templateBuilder.setExtensions(extGenerator.generate());
+ }
+
+ v.add(templateBuilder.build());
+
+ if (!controls.isEmpty())
+ {
+ ASN1EncodableVector controlV = new ASN1EncodableVector();
+
+ for (Iterator it = controls.iterator(); it.hasNext();)
+ {
+ Control control = (Control)it.next();
+
+ controlV.add(new AttributeTypeAndValue(control.getType(), control.getValue()));
+ }
+
+ v.add(new DERSequence(controlV));
+ }
+
+ CertRequest request = CertRequest.getInstance(new DERSequence(v));
+
+ v = new ASN1EncodableVector();
+
+ v.add(request);
+
+ if (popSigner != null)
+ {
+ CertTemplate template = request.getCertTemplate();
+
+ if (template.getSubject() == null || template.getPublicKey() == null)
+ {
+ SubjectPublicKeyInfo pubKeyInfo = request.getCertTemplate().getPublicKey();
+ ProofOfPossessionSigningKeyBuilder builder = new ProofOfPossessionSigningKeyBuilder(pubKeyInfo);
+
+ if (sender != null)
+ {
+ builder.setSender(sender);
+ }
+ else
+ {
+ PKMACValueGenerator pkmacGenerator = new PKMACValueGenerator(pkmacBuilder);
+
+ builder.setPublicKeyMac(pkmacGenerator, password);
+ }
+
+ v.add(new ProofOfPossession(builder.build(popSigner)));
+ }
+ else
+ {
+ ProofOfPossessionSigningKeyBuilder builder = new ProofOfPossessionSigningKeyBuilder(request);
+
+ v.add(new ProofOfPossession(builder.build(popSigner)));
+ }
+ }
+ else if (popoPrivKey != null)
+ {
+ v.add(new ProofOfPossession(ProofOfPossession.TYPE_KEY_ENCIPHERMENT, popoPrivKey));
+ }
+ else if (popRaVerified != null)
+ {
+ v.add(new ProofOfPossession());
+ }
+
+ return new CertificateRequestMessage(CertReqMsg.getInstance(new DERSequence(v)));
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/Control.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/Control.java
new file mode 100644
index 000000000..4454f7e77
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/Control.java
@@ -0,0 +1,24 @@
+package org.spongycastle.cert.crmf;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * Generic interface for a CertificateRequestMessage control value.
+ */
+public interface Control
+{
+ /**
+ * Return the type of this control.
+ *
+ * @return an ASN1ObjectIdentifier representing the type.
+ */
+ ASN1ObjectIdentifier getType();
+
+ /**
+ * Return the value contained in this control object.
+ *
+ * @return the value of the control.
+ */
+ ASN1Encodable getValue();
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValueBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValueBuilder.java
new file mode 100644
index 000000000..6a34f49ce
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValueBuilder.java
@@ -0,0 +1,133 @@
+package org.spongycastle.cert.crmf;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.crmf.EncryptedValue;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.operator.KeyWrapper;
+import org.spongycastle.operator.OperatorException;
+import org.spongycastle.operator.OutputEncryptor;
+import org.spongycastle.util.Strings;
+
+/**
+ * Builder for EncryptedValue structures.
+ */
+public class EncryptedValueBuilder
+{
+ private KeyWrapper wrapper;
+ private OutputEncryptor encryptor;
+ private EncryptedValuePadder padder;
+
+ /**
+ * Create a builder that makes EncryptedValue structures.
+ *
+ * @param wrapper a wrapper for key used to encrypt the actual data contained in the EncryptedValue.
+ * @param encryptor an output encryptor to encrypt the actual data contained in the EncryptedValue.
+ */
+ public EncryptedValueBuilder(KeyWrapper wrapper, OutputEncryptor encryptor)
+ {
+ this(wrapper, encryptor, null);
+ }
+
+ /**
+ * Create a builder that makes EncryptedValue structures with fixed length blocks padded using the passed in padder.
+ *
+ * @param wrapper a wrapper for key used to encrypt the actual data contained in the EncryptedValue.
+ * @param encryptor an output encryptor to encrypt the actual data contained in the EncryptedValue.
+ * @param padder a padder to ensure that the EncryptedValue created will always be a constant length.
+ */
+ public EncryptedValueBuilder(KeyWrapper wrapper, OutputEncryptor encryptor, EncryptedValuePadder padder)
+ {
+ this.wrapper = wrapper;
+ this.encryptor = encryptor;
+ this.padder = padder;
+ }
+
+ /**
+ * Build an EncryptedValue structure containing the passed in pass phrase.
+ *
+ * @param revocationPassphrase a revocation pass phrase.
+ * @return an EncryptedValue containing the encrypted pass phrase.
+ * @throws CRMFException on a failure to encrypt the data, or wrap the symmetric key for this value.
+ */
+ public EncryptedValue build(char[] revocationPassphrase)
+ throws CRMFException
+ {
+ return encryptData(padData(Strings.toUTF8ByteArray(revocationPassphrase)));
+ }
+
+ /**
+ * Build an EncryptedValue structure containing the certificate contained in
+ * the passed in holder.
+ *
+ * @param holder a holder containing a certificate.
+ * @return an EncryptedValue containing the encrypted certificate.
+ * @throws CRMFException on a failure to encrypt the data, or wrap the symmetric key for this value.
+ */
+ public EncryptedValue build(X509CertificateHolder holder)
+ throws CRMFException
+ {
+ try
+ {
+ return encryptData(padData(holder.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new CRMFException("cannot encode certificate: " + e.getMessage(), e);
+ }
+ }
+
+ private EncryptedValue encryptData(byte[] data)
+ throws CRMFException
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ OutputStream eOut = encryptor.getOutputStream(bOut);
+
+ try
+ {
+ eOut.write(data);
+
+ eOut.close();
+ }
+ catch (IOException e)
+ {
+ throw new CRMFException("cannot process data: " + e.getMessage(), e);
+ }
+
+ AlgorithmIdentifier intendedAlg = null;
+ AlgorithmIdentifier symmAlg = encryptor.getAlgorithmIdentifier();
+ DERBitString encSymmKey;
+
+ try
+ {
+ wrapper.generateWrappedKey(encryptor.getKey());
+ encSymmKey = new DERBitString(wrapper.generateWrappedKey(encryptor.getKey()));
+ }
+ catch (OperatorException e)
+ {
+ throw new CRMFException("cannot wrap key: " + e.getMessage(), e);
+ }
+
+ AlgorithmIdentifier keyAlg = wrapper.getAlgorithmIdentifier();
+ ASN1OctetString valueHint = null;
+ DERBitString encValue = new DERBitString(bOut.toByteArray());
+
+ return new EncryptedValue(intendedAlg, symmAlg, encSymmKey, keyAlg, valueHint, encValue);
+ }
+
+ private byte[] padData(byte[] data)
+ {
+ if (padder != null)
+ {
+ return padder.getPaddedData(data);
+ }
+
+ return data;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValuePadder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValuePadder.java
new file mode 100644
index 000000000..d00b5b62c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValuePadder.java
@@ -0,0 +1,24 @@
+package org.spongycastle.cert.crmf;
+
+/**
+ * An encrypted value padder is used to make sure that prior to a value been
+ * encrypted the data is padded to a standard length.
+ */
+public interface EncryptedValuePadder
+{
+ /**
+ * Return a byte array of padded data.
+ *
+ * @param data the data to be padded.
+ * @return a padded byte array containing data.
+ */
+ byte[] getPaddedData(byte[] data);
+
+ /**
+ * Return a byte array of with padding removed.
+ *
+ * @param paddedData the data to be padded.
+ * @return an array containing the original unpadded data.
+ */
+ byte[] getUnpaddedData(byte[] paddedData);
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValueParser.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValueParser.java
new file mode 100644
index 000000000..80804993a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/EncryptedValueParser.java
@@ -0,0 +1,103 @@
+package org.spongycastle.cert.crmf;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.crmf.EncryptedValue;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.operator.InputDecryptor;
+import org.spongycastle.util.Strings;
+import org.spongycastle.util.io.Streams;
+
+/**
+ * Parser for EncryptedValue structures.
+ */
+public class EncryptedValueParser
+{
+ private EncryptedValue value;
+ private EncryptedValuePadder padder;
+
+ /**
+ * Basic constructor - create a parser to read the passed in value.
+ *
+ * @param value the value to be parsed.
+ */
+ public EncryptedValueParser(EncryptedValue value)
+ {
+ this.value = value;
+ }
+
+ /**
+ * Create a parser to read the passed in value, assuming the padder was
+ * applied to the data prior to encryption.
+ *
+ * @param value the value to be parsed.
+ * @param padder the padder to be used to remove padding from the decrypted value..
+ */
+ public EncryptedValueParser(EncryptedValue value, EncryptedValuePadder padder)
+ {
+ this.value = value;
+ this.padder = padder;
+ }
+
+ private byte[] decryptValue(ValueDecryptorGenerator decGen)
+ throws CRMFException
+ {
+ if (value.getIntendedAlg() != null)
+ {
+ throw new UnsupportedOperationException();
+ }
+ if (value.getValueHint() != null)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ InputDecryptor decryptor = decGen.getValueDecryptor(value.getKeyAlg(),
+ value.getSymmAlg(), value.getEncSymmKey().getBytes());
+ InputStream dataIn = decryptor.getInputStream(new ByteArrayInputStream(
+ value.getEncValue().getBytes()));
+ try
+ {
+ byte[] data = Streams.readAll(dataIn);
+
+ if (padder != null)
+ {
+ return padder.getUnpaddedData(data);
+ }
+
+ return data;
+ }
+ catch (IOException e)
+ {
+ throw new CRMFException("Cannot parse decrypted data: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Read a X.509 certificate.
+ *
+ * @param decGen the decryptor generator to decrypt the encrypted value.
+ * @return an X509CertificateHolder containing the certificate read.
+ * @throws CRMFException if the decrypted data cannot be parsed, or a decryptor cannot be generated.
+ */
+ public X509CertificateHolder readCertificateHolder(ValueDecryptorGenerator decGen)
+ throws CRMFException
+ {
+ return new X509CertificateHolder(Certificate.getInstance(decryptValue(decGen)));
+ }
+
+ /**
+ * Read a pass phrase.
+ *
+ * @param decGen the decryptor generator to decrypt the encrypted value.
+ * @return a pass phrase as recovered from the encrypted value.
+ * @throws CRMFException if the decrypted data cannot be parsed, or a decryptor cannot be generated.
+ */
+ public char[] readPassphrase(ValueDecryptorGenerator decGen)
+ throws CRMFException
+ {
+ return Strings.fromUTF8ByteArray(decryptValue(decGen)).toCharArray();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/FixedLengthMGF1Padder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/FixedLengthMGF1Padder.java
new file mode 100644
index 000000000..5dd1ce30f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/FixedLengthMGF1Padder.java
@@ -0,0 +1,120 @@
+package org.spongycastle.cert.crmf;
+
+import java.security.SecureRandom;
+
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.generators.MGF1BytesGenerator;
+import org.spongycastle.crypto.params.MGFParameters;
+
+/**
+ * An encrypted value padder that uses MGF1 as the basis of the padding.
+ */
+public class FixedLengthMGF1Padder
+ implements EncryptedValuePadder
+{
+ private int length;
+ private SecureRandom random;
+ private Digest dig = new SHA1Digest();
+
+ /**
+ * Create a padder to so that padded output will always be at least
+ * length bytes long.
+ *
+ * @param length fixed length for padded output.
+ */
+ public FixedLengthMGF1Padder(int length)
+ {
+ this(length, null);
+ }
+
+ /**
+ * Create a padder to so that padded output will always be at least
+ * length bytes long, using the passed in source of randomness to
+ * provide the random material for the padder.
+ *
+ * @param length fixed length for padded output.
+ * @param random a source of randomness.
+ */
+ public FixedLengthMGF1Padder(int length, SecureRandom random)
+ {
+ this.length = length;
+ this.random = random;
+ }
+
+ public byte[] getPaddedData(byte[] data)
+ {
+ byte[] bytes = new byte[length];
+ byte[] seed = new byte[dig.getDigestSize()];
+ byte[] mask = new byte[length - dig.getDigestSize()];
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(seed);
+
+ MGF1BytesGenerator maskGen = new MGF1BytesGenerator(dig);
+
+ maskGen.init(new MGFParameters(seed));
+
+ maskGen.generateBytes(mask, 0, mask.length);
+
+ System.arraycopy(seed, 0, bytes, 0, seed.length);
+ System.arraycopy(data, 0, bytes, seed.length, data.length);
+
+ for (int i = seed.length + data.length + 1; i != bytes.length; i++)
+ {
+ bytes[i] = (byte)(1 + random.nextInt(255));
+ }
+
+ for (int i = 0; i != mask.length; i++)
+ {
+ bytes[i + seed.length] ^= mask[i];
+ }
+
+ return bytes;
+ }
+
+ public byte[] getUnpaddedData(byte[] paddedData)
+ {
+ byte[] seed = new byte[dig.getDigestSize()];
+ byte[] mask = new byte[length - dig.getDigestSize()];
+
+ System.arraycopy(paddedData, 0, seed, 0, seed.length);
+
+ MGF1BytesGenerator maskGen = new MGF1BytesGenerator(dig);
+
+ maskGen.init(new MGFParameters(seed));
+
+ maskGen.generateBytes(mask, 0, mask.length);
+
+ for (int i = 0; i != mask.length; i++)
+ {
+ paddedData[i + seed.length] ^= mask[i];
+ }
+
+ int end = 0;
+
+ for (int i = paddedData.length - 1; i != seed.length; i--)
+ {
+ if (paddedData[i] == 0)
+ {
+ end = i;
+ break;
+ }
+ }
+
+ if (end == 0)
+ {
+ throw new IllegalStateException("bad padding in encoding");
+ }
+
+ byte[] data = new byte[end - seed.length];
+
+ System.arraycopy(paddedData, seed.length, data, 0, data.length);
+
+ return data;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKIArchiveControl.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKIArchiveControl.java
new file mode 100644
index 000000000..0c9bd985a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKIArchiveControl.java
@@ -0,0 +1,104 @@
+package org.spongycastle.cert.crmf;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.EnvelopedData;
+import org.spongycastle.asn1.crmf.CRMFObjectIdentifiers;
+import org.spongycastle.asn1.crmf.EncryptedKey;
+import org.spongycastle.asn1.crmf.PKIArchiveOptions;
+import org.spongycastle.cms.CMSEnvelopedData;
+import org.spongycastle.cms.CMSException;
+
+/**
+ * Carrier for a PKIArchiveOptions structure.
+ */
+public class PKIArchiveControl
+ implements Control
+{
+ public static final int encryptedPrivKey = PKIArchiveOptions.encryptedPrivKey;
+ public static final int keyGenParameters = PKIArchiveOptions.keyGenParameters;
+ public static final int archiveRemGenPrivKey = PKIArchiveOptions.archiveRemGenPrivKey;
+
+ private static final ASN1ObjectIdentifier type = CRMFObjectIdentifiers.id_regCtrl_pkiArchiveOptions;
+
+ private final PKIArchiveOptions pkiArchiveOptions;
+
+ /**
+ * Basic constructor - build from an PKIArchiveOptions structure.
+ *
+ * @param pkiArchiveOptions the ASN.1 structure that will underlie this control.
+ */
+ public PKIArchiveControl(PKIArchiveOptions pkiArchiveOptions)
+ {
+ this.pkiArchiveOptions = pkiArchiveOptions;
+ }
+
+ /**
+ * Return the type of this control.
+ *
+ * @return CRMFObjectIdentifiers.id_regCtrl_pkiArchiveOptions
+ */
+ public ASN1ObjectIdentifier getType()
+ {
+ return type;
+ }
+
+ /**
+ * Return the underlying ASN.1 object.
+ *
+ * @return a PKIArchiveOptions structure.
+ */
+ public ASN1Encodable getValue()
+ {
+ return pkiArchiveOptions;
+ }
+
+ /**
+ * Return the archive control type, one of: encryptedPrivKey,keyGenParameters,or archiveRemGenPrivKey.
+ *
+ * @return the archive control type.
+ */
+ public int getArchiveType()
+ {
+ return pkiArchiveOptions.getType();
+ }
+
+ /**
+ * Return whether this control contains enveloped data.
+ *
+ * @return true if the control contains enveloped data, false otherwise.
+ */
+ public boolean isEnvelopedData()
+ {
+ EncryptedKey encKey = EncryptedKey.getInstance(pkiArchiveOptions.getValue());
+
+ return !encKey.isEncryptedValue();
+ }
+
+ /**
+ * Return the enveloped data structure contained in this control.
+ *
+ * @return a CMSEnvelopedData object.
+ */
+ public CMSEnvelopedData getEnvelopedData()
+ throws CRMFException
+ {
+ try
+ {
+ EncryptedKey encKey = EncryptedKey.getInstance(pkiArchiveOptions.getValue());
+ EnvelopedData data = EnvelopedData.getInstance(encKey.getValue());
+
+ return new CMSEnvelopedData(new ContentInfo(CMSObjectIdentifiers.envelopedData, data));
+ }
+ catch (CMSException e)
+ {
+ throw new CRMFException("CMS parsing error: " + e.getMessage(), e.getCause());
+ }
+ catch (Exception e)
+ {
+ throw new CRMFException("CRMF parsing error: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKIArchiveControlBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKIArchiveControlBuilder.java
new file mode 100644
index 000000000..1ca860cb1
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKIArchiveControlBuilder.java
@@ -0,0 +1,78 @@
+package org.spongycastle.cert.crmf;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.cms.EnvelopedData;
+import org.spongycastle.asn1.crmf.CRMFObjectIdentifiers;
+import org.spongycastle.asn1.crmf.EncKeyWithID;
+import org.spongycastle.asn1.crmf.EncryptedKey;
+import org.spongycastle.asn1.crmf.PKIArchiveOptions;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.cms.CMSEnvelopedData;
+import org.spongycastle.cms.CMSEnvelopedDataGenerator;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.RecipientInfoGenerator;
+import org.spongycastle.operator.OutputEncryptor;
+
+/**
+ * Builder for a PKIArchiveControl structure.
+ */
+public class PKIArchiveControlBuilder
+{
+ private CMSEnvelopedDataGenerator envGen;
+ private CMSProcessableByteArray keyContent;
+
+ /**
+ * Basic constructor - specify the contents of the PKIArchiveControl structure.
+ *
+ * @param privateKeyInfo the private key to be archived.
+ * @param generalName the general name to be associated with the private key.
+ */
+ public PKIArchiveControlBuilder(PrivateKeyInfo privateKeyInfo, GeneralName generalName)
+ {
+ EncKeyWithID encKeyWithID = new EncKeyWithID(privateKeyInfo, generalName);
+
+ try
+ {
+ this.keyContent = new CMSProcessableByteArray(CRMFObjectIdentifiers.id_ct_encKeyWithID, encKeyWithID.getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("unable to encode key and general name info");
+ }
+
+ this.envGen = new CMSEnvelopedDataGenerator();
+ }
+
+ /**
+ * Add a recipient generator to this control.
+ *
+ * @param recipientGen recipient generator created for a specific recipient.
+ * @return this builder object.
+ */
+ public PKIArchiveControlBuilder addRecipientGenerator(RecipientInfoGenerator recipientGen)
+ {
+ envGen.addRecipientInfoGenerator(recipientGen);
+
+ return this;
+ }
+
+ /**
+ * Build the PKIArchiveControl using the passed in encryptor to encrypt its contents.
+ *
+ * @param contentEncryptor a suitable content encryptor.
+ * @return a PKIArchiveControl object.
+ * @throws CMSException in the event the build fails.
+ */
+ public PKIArchiveControl build(OutputEncryptor contentEncryptor)
+ throws CMSException
+ {
+ CMSEnvelopedData envContent = envGen.generate(keyContent, contentEncryptor);
+
+ EnvelopedData envD = EnvelopedData.getInstance(envContent.toASN1Structure().getContent());
+
+ return new PKIArchiveControl(new PKIArchiveOptions(new EncryptedKey(envD)));
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACBuilder.java
new file mode 100644
index 000000000..54e9cd914
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACBuilder.java
@@ -0,0 +1,199 @@
+package org.spongycastle.cert.crmf;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.security.SecureRandom;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.cmp.CMPObjectIdentifiers;
+import org.spongycastle.asn1.cmp.PBMParameter;
+import org.spongycastle.asn1.iana.IANAObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.MacCalculator;
+import org.spongycastle.operator.RuntimeOperatorException;
+import org.spongycastle.util.Strings;
+
+public class PKMACBuilder
+{
+ private AlgorithmIdentifier owf;
+ private int iterationCount;
+ private AlgorithmIdentifier mac;
+ private int saltLength = 20;
+ private SecureRandom random;
+ private PKMACValuesCalculator calculator;
+ private PBMParameter parameters;
+ private int maxIterations;
+
+ public PKMACBuilder(PKMACValuesCalculator calculator)
+ {
+ this(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1), 1000, new AlgorithmIdentifier(IANAObjectIdentifiers.hmacSHA1, DERNull.INSTANCE), calculator);
+ }
+
+ /**
+ * Create a PKMAC builder enforcing a ceiling on the maximum iteration count.
+ *
+ * @param calculator supporting calculator
+ * @param maxIterations max allowable value for iteration count.
+ */
+ public PKMACBuilder(PKMACValuesCalculator calculator, int maxIterations)
+ {
+ this.maxIterations = maxIterations;
+ this.calculator = calculator;
+ }
+
+ private PKMACBuilder(AlgorithmIdentifier hashAlgorithm, int iterationCount, AlgorithmIdentifier macAlgorithm, PKMACValuesCalculator calculator)
+ {
+ this.owf = hashAlgorithm;
+ this.iterationCount = iterationCount;
+ this.mac = macAlgorithm;
+ this.calculator = calculator;
+ }
+
+ /**
+ * Set the salt length in octets.
+ *
+ * @param saltLength length in octets of the salt to be generated.
+ * @return the generator
+ */
+ public PKMACBuilder setSaltLength(int saltLength)
+ {
+ if (saltLength < 8)
+ {
+ throw new IllegalArgumentException("salt length must be at least 8 bytes");
+ }
+
+ this.saltLength = saltLength;
+
+ return this;
+ }
+
+ public PKMACBuilder setIterationCount(int iterationCount)
+ {
+ if (iterationCount < 100)
+ {
+ throw new IllegalArgumentException("iteration count must be at least 100");
+ }
+ checkIterationCountCeiling(iterationCount);
+
+ this.iterationCount = iterationCount;
+
+ return this;
+ }
+
+ public PKMACBuilder setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public PKMACBuilder setParameters(PBMParameter parameters)
+ {
+ checkIterationCountCeiling(parameters.getIterationCount().getValue().intValue());
+
+ this.parameters = parameters;
+
+ return this;
+ }
+
+ public MacCalculator build(char[] password)
+ throws CRMFException
+ {
+ if (parameters != null)
+ {
+ return genCalculator(parameters, password);
+ }
+ else
+ {
+ byte[] salt = new byte[saltLength];
+
+ if (random == null)
+ {
+ this.random = new SecureRandom();
+ }
+
+ random.nextBytes(salt);
+
+ return genCalculator(new PBMParameter(salt, owf, iterationCount, mac), password);
+ }
+ }
+
+ private void checkIterationCountCeiling(int iterationCount)
+ {
+ if (maxIterations > 0 && iterationCount > maxIterations)
+ {
+ throw new IllegalArgumentException("iteration count exceeds limit (" + iterationCount + " > " + maxIterations + ")");
+ }
+ }
+
+ private MacCalculator genCalculator(final PBMParameter params, char[] password)
+ throws CRMFException
+ {
+ // From RFC 4211
+ //
+ // 1. Generate a random salt value S
+ //
+ // 2. Append the salt to the pw. K = pw || salt.
+ //
+ // 3. Hash the value of K. K = HASH(K)
+ //
+ // 4. Iter = Iter - 1. If Iter is greater than zero. Goto step 3.
+ //
+ // 5. Compute an HMAC as documented in [HMAC].
+ //
+ // MAC = HASH( K XOR opad, HASH( K XOR ipad, data) )
+ //
+ // Where opad and ipad are defined in [HMAC].
+ byte[] pw = Strings.toUTF8ByteArray(password);
+ byte[] salt = params.getSalt().getOctets();
+ byte[] K = new byte[pw.length + salt.length];
+
+ System.arraycopy(pw, 0, K, 0, pw.length);
+ System.arraycopy(salt, 0, K, pw.length, salt.length);
+
+ calculator.setup(params.getOwf(), params.getMac());
+
+ int iter = params.getIterationCount().getValue().intValue();
+ do
+ {
+ K = calculator.calculateDigest(K);
+ }
+ while (--iter > 0);
+
+ final byte[] key = K;
+
+ return new MacCalculator()
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return new AlgorithmIdentifier(CMPObjectIdentifiers.passwordBasedMac, params);
+ }
+
+ public GenericKey getKey()
+ {
+ return new GenericKey(getAlgorithmIdentifier(), key);
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return bOut;
+ }
+
+ public byte[] getMac()
+ {
+ try
+ {
+ return calculator.calculateMac(key, bOut.toByteArray());
+ }
+ catch (CRMFException e)
+ {
+ throw new RuntimeOperatorException("exception calculating mac: " + e.getMessage(), e);
+ }
+ }
+ };
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValueGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValueGenerator.java
new file mode 100644
index 000000000..eaf215ff7
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValueGenerator.java
@@ -0,0 +1,41 @@
+package org.spongycastle.cert.crmf;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.crmf.PKMACValue;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.operator.MacCalculator;
+
+class PKMACValueGenerator
+{
+ private PKMACBuilder builder;
+
+ public PKMACValueGenerator(PKMACBuilder builder)
+ {
+ this.builder = builder;
+ }
+
+ public PKMACValue generate(char[] password, SubjectPublicKeyInfo keyInfo)
+ throws CRMFException
+ {
+ MacCalculator calculator = builder.build(password);
+
+ OutputStream macOut = calculator.getOutputStream();
+
+ try
+ {
+ macOut.write(keyInfo.getEncoded(ASN1Encoding.DER));
+
+ macOut.close();
+ }
+ catch (IOException e)
+ {
+ throw new CRMFException("exception encoding mac input: " + e.getMessage(), e);
+ }
+
+ return new PKMACValue(calculator.getAlgorithmIdentifier(), new DERBitString(calculator.getMac()));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValueVerifier.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValueVerifier.java
new file mode 100644
index 000000000..a65ff61d7
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValueVerifier.java
@@ -0,0 +1,43 @@
+package org.spongycastle.cert.crmf;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.cmp.PBMParameter;
+import org.spongycastle.asn1.crmf.PKMACValue;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.operator.MacCalculator;
+import org.spongycastle.util.Arrays;
+
+class PKMACValueVerifier
+{
+ private final PKMACBuilder builder;
+
+ public PKMACValueVerifier(PKMACBuilder builder)
+ {
+ this.builder = builder;
+ }
+
+ public boolean isValid(PKMACValue value, char[] password, SubjectPublicKeyInfo keyInfo)
+ throws CRMFException
+ {
+ builder.setParameters(PBMParameter.getInstance(value.getAlgId().getParameters()));
+ MacCalculator calculator = builder.build(password);
+
+ OutputStream macOut = calculator.getOutputStream();
+
+ try
+ {
+ macOut.write(keyInfo.getEncoded(ASN1Encoding.DER));
+
+ macOut.close();
+ }
+ catch (IOException e)
+ {
+ throw new CRMFException("exception encoding mac input: " + e.getMessage(), e);
+ }
+
+ return Arrays.areEqual(calculator.getMac(), value.getValue().getBytes());
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValuesCalculator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValuesCalculator.java
new file mode 100644
index 000000000..0b4f14077
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/PKMACValuesCalculator.java
@@ -0,0 +1,15 @@
+package org.spongycastle.cert.crmf;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface PKMACValuesCalculator
+{
+ void setup(AlgorithmIdentifier digestAlg, AlgorithmIdentifier macAlg)
+ throws CRMFException;
+
+ byte[] calculateDigest(byte[] data)
+ throws CRMFException;
+
+ byte[] calculateMac(byte[] pwd, byte[] data)
+ throws CRMFException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/ProofOfPossessionSigningKeyBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/ProofOfPossessionSigningKeyBuilder.java
new file mode 100644
index 000000000..07659593c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/ProofOfPossessionSigningKeyBuilder.java
@@ -0,0 +1,75 @@
+package org.spongycastle.cert.crmf;
+
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.crmf.CertRequest;
+import org.spongycastle.asn1.crmf.PKMACValue;
+import org.spongycastle.asn1.crmf.POPOSigningKey;
+import org.spongycastle.asn1.crmf.POPOSigningKeyInput;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.operator.ContentSigner;
+
+public class ProofOfPossessionSigningKeyBuilder
+{
+ private CertRequest certRequest;
+ private SubjectPublicKeyInfo pubKeyInfo;
+ private GeneralName name;
+ private PKMACValue publicKeyMAC;
+
+ public ProofOfPossessionSigningKeyBuilder(CertRequest certRequest)
+ {
+ this.certRequest = certRequest;
+ }
+
+
+ public ProofOfPossessionSigningKeyBuilder(SubjectPublicKeyInfo pubKeyInfo)
+ {
+ this.pubKeyInfo = pubKeyInfo;
+ }
+
+ public ProofOfPossessionSigningKeyBuilder setSender(GeneralName name)
+ {
+ this.name = name;
+
+ return this;
+ }
+
+ public ProofOfPossessionSigningKeyBuilder setPublicKeyMac(PKMACValueGenerator generator, char[] password)
+ throws CRMFException
+ {
+ this.publicKeyMAC = generator.generate(password, pubKeyInfo);
+
+ return this;
+ }
+
+ public POPOSigningKey build(ContentSigner signer)
+ {
+ if (name != null && publicKeyMAC != null)
+ {
+ throw new IllegalStateException("name and publicKeyMAC cannot both be set.");
+ }
+
+ POPOSigningKeyInput popo;
+
+ if (certRequest != null)
+ {
+ popo = null;
+
+ CRMFUtil.derEncodeToStream(certRequest, signer.getOutputStream());
+ }
+ else if (name != null)
+ {
+ popo = new POPOSigningKeyInput(name, pubKeyInfo);
+
+ CRMFUtil.derEncodeToStream(popo, signer.getOutputStream());
+ }
+ else
+ {
+ popo = new POPOSigningKeyInput(publicKeyMAC, pubKeyInfo);
+
+ CRMFUtil.derEncodeToStream(popo, signer.getOutputStream());
+ }
+
+ return new POPOSigningKey(popo, signer.getAlgorithmIdentifier(), new DERBitString(signer.getSignature()));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/RegTokenControl.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/RegTokenControl.java
new file mode 100644
index 000000000..b1a6eb7ec
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/RegTokenControl.java
@@ -0,0 +1,57 @@
+package org.spongycastle.cert.crmf;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERUTF8String;
+import org.spongycastle.asn1.crmf.CRMFObjectIdentifiers;
+
+/**
+ * Carrier for a registration token control.
+ */
+public class RegTokenControl
+ implements Control
+{
+ private static final ASN1ObjectIdentifier type = CRMFObjectIdentifiers.id_regCtrl_regToken;
+
+ private final DERUTF8String token;
+
+ /**
+ * Basic constructor - build from a UTF-8 string representing the token.
+ *
+ * @param token UTF-8 string representing the token.
+ */
+ public RegTokenControl(DERUTF8String token)
+ {
+ this.token = token;
+ }
+
+ /**
+ * Basic constructor - build from a string representing the token.
+ *
+ * @param token string representing the token.
+ */
+ public RegTokenControl(String token)
+ {
+ this.token = new DERUTF8String(token);
+ }
+
+ /**
+ * Return the type of this control.
+ *
+ * @return CRMFObjectIdentifiers.id_regCtrl_regToken
+ */
+ public ASN1ObjectIdentifier getType()
+ {
+ return type;
+ }
+
+ /**
+ * Return the token associated with this control (a UTF8String).
+ *
+ * @return a UTF8String.
+ */
+ public ASN1Encodable getValue()
+ {
+ return token;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/ValueDecryptorGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/ValueDecryptorGenerator.java
new file mode 100644
index 000000000..3fcee4ebd
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/ValueDecryptorGenerator.java
@@ -0,0 +1,10 @@
+package org.spongycastle.cert.crmf;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.InputDecryptor;
+
+public interface ValueDecryptorGenerator
+{
+ InputDecryptor getValueDecryptor(AlgorithmIdentifier keyAlg, AlgorithmIdentifier symmAlg, byte[] encKey)
+ throws CRMFException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/CRMFHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/CRMFHelper.java
new file mode 100644
index 000000000..212ac914d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/CRMFHelper.java
@@ -0,0 +1,450 @@
+package org.spongycastle.cert.crmf.jcajce;
+
+import java.io.IOException;
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Null;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.iana.IANAObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.cert.crmf.CRMFException;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.jcajce.JcaJceHelper;
+import org.spongycastle.jcajce.JcaJceUtils;
+
+class CRMFHelper
+{
+ protected static final Map BASE_CIPHER_NAMES = new HashMap();
+ protected static final Map CIPHER_ALG_NAMES = new HashMap();
+ protected static final Map DIGEST_ALG_NAMES = new HashMap();
+ protected static final Map KEY_ALG_NAMES = new HashMap();
+ protected static final Map MAC_ALG_NAMES = new HashMap();
+
+ static
+ {
+ BASE_CIPHER_NAMES.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESEDE");
+ BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes128_CBC, "AES");
+ BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes192_CBC, "AES");
+ BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes256_CBC, "AES");
+
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, "AES/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AES/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AES/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(new ASN1ObjectIdentifier(PKCSObjectIdentifiers.rsaEncryption.getId()), "RSA/ECB/PKCS1Padding");
+
+ DIGEST_ALG_NAMES.put(OIWObjectIdentifiers.idSHA1, "SHA1");
+ DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha224, "SHA224");
+ DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha256, "SHA256");
+ DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha384, "SHA384");
+ DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha512, "SHA512");
+
+ MAC_ALG_NAMES.put(IANAObjectIdentifiers.hmacSHA1, "HMACSHA1");
+ MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA1, "HMACSHA1");
+ MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA224, "HMACSHA224");
+ MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA256, "HMACSHA256");
+ MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA384, "HMACSHA384");
+ MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA512, "HMACSHA512");
+
+ KEY_ALG_NAMES.put(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ KEY_ALG_NAMES.put(X9ObjectIdentifiers.id_dsa, "DSA");
+ }
+
+ private JcaJceHelper helper;
+
+ CRMFHelper(JcaJceHelper helper)
+ {
+ this.helper = helper;
+ }
+
+ PublicKey toPublicKey(SubjectPublicKeyInfo subjectPublicKeyInfo)
+ throws CRMFException
+ {
+ try
+ {
+ X509EncodedKeySpec xspec = new X509EncodedKeySpec(subjectPublicKeyInfo.getEncoded());
+ AlgorithmIdentifier keyAlg = subjectPublicKeyInfo.getAlgorithm();
+
+ return createKeyFactory(keyAlg.getAlgorithm()).generatePublic(xspec);
+ }
+ catch (Exception e)
+ {
+ throw new CRMFException("invalid key: " + e.getMessage(), e);
+ }
+ }
+
+ Cipher createCipher(ASN1ObjectIdentifier algorithm)
+ throws CRMFException
+ {
+ try
+ {
+ String cipherName = (String)CIPHER_ALG_NAMES.get(algorithm);
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createCipher(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createCipher(algorithm.getId());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CRMFException("cannot create cipher: " + e.getMessage(), e);
+ }
+ }
+
+ public KeyGenerator createKeyGenerator(ASN1ObjectIdentifier algorithm)
+ throws CRMFException
+ {
+ try
+ {
+ String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createKeyGenerator(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createKeyGenerator(algorithm.getId());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CRMFException("cannot create key generator: " + e.getMessage(), e);
+ }
+ }
+
+
+
+ Cipher createContentCipher(final Key sKey, final AlgorithmIdentifier encryptionAlgID)
+ throws CRMFException
+ {
+ return (Cipher)execute(new JCECallback()
+ {
+ public Object doInJCE()
+ throws CRMFException, InvalidAlgorithmParameterException,
+ InvalidKeyException, InvalidParameterSpecException, NoSuchAlgorithmException,
+ NoSuchPaddingException, NoSuchProviderException
+ {
+ Cipher cipher = createCipher(encryptionAlgID.getAlgorithm());
+ ASN1Primitive sParams = (ASN1Primitive)encryptionAlgID.getParameters();
+ ASN1ObjectIdentifier encAlg = encryptionAlgID.getAlgorithm();
+
+ if (sParams != null && !(sParams instanceof ASN1Null))
+ {
+ try
+ {
+ AlgorithmParameters params = createAlgorithmParameters(encryptionAlgID.getAlgorithm());
+
+ try
+ {
+ JcaJceUtils.loadParameters(params, sParams);
+ }
+ catch (IOException e)
+ {
+ throw new CRMFException("error decoding algorithm parameters.", e);
+ }
+
+ cipher.init(Cipher.DECRYPT_MODE, sKey, params);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ if (encAlg.equals(CMSAlgorithm.DES_EDE3_CBC)
+ || encAlg.equals(CMSAlgorithm.IDEA_CBC)
+ || encAlg.equals(CMSAlgorithm.AES128_CBC)
+ || encAlg.equals(CMSAlgorithm.AES192_CBC)
+ || encAlg.equals(CMSAlgorithm.AES256_CBC))
+ {
+ cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec(
+ ASN1OctetString.getInstance(sParams).getOctets()));
+ }
+ else
+ {
+ throw e;
+ }
+ }
+ }
+ else
+ {
+ if (encAlg.equals(CMSAlgorithm.DES_EDE3_CBC)
+ || encAlg.equals(CMSAlgorithm.IDEA_CBC)
+ || encAlg.equals(CMSAlgorithm.CAST5_CBC))
+ {
+ cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec(new byte[8]));
+ }
+ else
+ {
+ cipher.init(Cipher.DECRYPT_MODE, sKey);
+ }
+ }
+
+ return cipher;
+ }
+ });
+ }
+
+ AlgorithmParameters createAlgorithmParameters(ASN1ObjectIdentifier algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (algorithmName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createAlgorithmParameters(algorithmName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createAlgorithmParameters(algorithm.getId());
+ }
+
+ KeyFactory createKeyFactory(ASN1ObjectIdentifier algorithm)
+ throws CRMFException
+ {
+ try
+ {
+ String algName = (String)KEY_ALG_NAMES.get(algorithm);
+
+ if (algName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createKeyFactory(algName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createKeyFactory(algorithm.getId());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CRMFException("cannot create cipher: " + e.getMessage(), e);
+ }
+ }
+
+ MessageDigest createDigest(ASN1ObjectIdentifier algorithm)
+ throws CRMFException
+ {
+ try
+ {
+ String digestName = (String)DIGEST_ALG_NAMES.get(algorithm);
+
+ if (digestName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createDigest(digestName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createDigest(algorithm.getId());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CRMFException("cannot create cipher: " + e.getMessage(), e);
+ }
+ }
+
+ Mac createMac(ASN1ObjectIdentifier algorithm)
+ throws CRMFException
+ {
+ try
+ {
+ String macName = (String)MAC_ALG_NAMES.get(algorithm);
+
+ if (macName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createMac(macName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createMac(algorithm.getId());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CRMFException("cannot create mac: " + e.getMessage(), e);
+ }
+ }
+
+ AlgorithmParameterGenerator createAlgorithmParameterGenerator(ASN1ObjectIdentifier algorithm)
+ throws GeneralSecurityException
+ {
+ String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (algorithmName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createAlgorithmParameterGenerator(algorithmName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createAlgorithmParameterGenerator(algorithm.getId());
+ }
+
+ AlgorithmParameters generateParameters(ASN1ObjectIdentifier encryptionOID, SecretKey encKey, SecureRandom rand)
+ throws CRMFException
+ {
+ try
+ {
+ AlgorithmParameterGenerator pGen = createAlgorithmParameterGenerator(encryptionOID);
+
+ if (encryptionOID.equals(CMSAlgorithm.RC2_CBC))
+ {
+ byte[] iv = new byte[8];
+
+ rand.nextBytes(iv);
+
+ try
+ {
+ pGen.init(new RC2ParameterSpec(encKey.getEncoded().length * 8, iv), rand);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new CRMFException("parameters generation error: " + e, e);
+ }
+ }
+
+ return pGen.generateParameters();
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ return null;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CRMFException("exception creating algorithm parameter generator: " + e, e);
+ }
+ }
+
+ AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier encryptionOID, AlgorithmParameters params)
+ throws CRMFException
+ {
+ ASN1Encodable asn1Params;
+ if (params != null)
+ {
+ try
+ {
+ asn1Params = JcaJceUtils.extractParameters(params);
+ }
+ catch (IOException e)
+ {
+ throw new CRMFException("cannot encode parameters: " + e.getMessage(), e);
+ }
+ }
+ else
+ {
+ asn1Params = DERNull.INSTANCE;
+ }
+
+ return new AlgorithmIdentifier(
+ encryptionOID,
+ asn1Params);
+ }
+
+ static Object execute(JCECallback callback) throws CRMFException
+ {
+ try
+ {
+ return callback.doInJCE();
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new CRMFException("can't find algorithm.", e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CRMFException("key invalid in message.", e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new CRMFException("can't find provider.", e);
+ }
+ catch (NoSuchPaddingException e)
+ {
+ throw new CRMFException("required padding not supported.", e);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new CRMFException("algorithm parameters invalid.", e);
+ }
+ catch (InvalidParameterSpecException e)
+ {
+ throw new CRMFException("MAC algorithm parameter spec invalid.", e);
+ }
+ }
+
+ static interface JCECallback
+ {
+ Object doInJCE()
+ throws CRMFException, InvalidAlgorithmParameterException, InvalidKeyException, InvalidParameterSpecException,
+ NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessage.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessage.java
new file mode 100644
index 000000000..1aabc3b95
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessage.java
@@ -0,0 +1,84 @@
+package org.spongycastle.cert.crmf.jcajce;
+
+import java.io.IOException;
+import java.security.Provider;
+import java.security.PublicKey;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.crmf.CertReqMsg;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.crmf.CRMFException;
+import org.spongycastle.cert.crmf.CertificateRequestMessage;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+
+public class JcaCertificateRequestMessage
+ extends CertificateRequestMessage
+{
+ private CRMFHelper helper = new CRMFHelper(new DefaultJcaJceHelper());
+
+ public JcaCertificateRequestMessage(byte[] certReqMsg)
+ {
+ this(CertReqMsg.getInstance(certReqMsg));
+ }
+
+ public JcaCertificateRequestMessage(CertificateRequestMessage certReqMsg)
+ {
+ this(certReqMsg.toASN1Structure());
+ }
+
+ public JcaCertificateRequestMessage(CertReqMsg certReqMsg)
+ {
+ super(certReqMsg);
+ }
+
+ public JcaCertificateRequestMessage setProvider(String providerName)
+ {
+ this.helper = new CRMFHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public JcaCertificateRequestMessage setProvider(Provider provider)
+ {
+ this.helper = new CRMFHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public X500Principal getSubjectX500Principal()
+ {
+ X500Name subject = this.getCertTemplate().getSubject();
+
+ if (subject != null)
+ {
+ try
+ {
+ return new X500Principal(subject.getEncoded(ASN1Encoding.DER));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("unable to construct DER encoding of name: " + e.getMessage());
+ }
+ }
+
+ return null;
+ }
+
+ public PublicKey getPublicKey()
+ throws CRMFException
+ {
+ SubjectPublicKeyInfo subjectPublicKeyInfo = getCertTemplate().getPublicKey();
+
+ if (subjectPublicKeyInfo != null)
+ {
+ return helper.toPublicKey(subjectPublicKeyInfo);
+ }
+
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessageBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessageBuilder.java
new file mode 100644
index 000000000..1d9318ddc
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessageBuilder.java
@@ -0,0 +1,57 @@
+package org.spongycastle.cert.crmf.jcajce;
+
+import java.math.BigInteger;
+import java.security.PublicKey;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.crmf.CertificateRequestMessageBuilder;
+
+public class JcaCertificateRequestMessageBuilder
+ extends CertificateRequestMessageBuilder
+{
+ public JcaCertificateRequestMessageBuilder(BigInteger certReqId)
+ {
+ super(certReqId);
+ }
+
+ public JcaCertificateRequestMessageBuilder setIssuer(X500Principal issuer)
+ {
+ if (issuer != null)
+ {
+ setIssuer(X500Name.getInstance(issuer.getEncoded()));
+ }
+
+ return this;
+ }
+
+ public JcaCertificateRequestMessageBuilder setSubject(X500Principal subject)
+ {
+ if (subject != null)
+ {
+ setSubject(X500Name.getInstance(subject.getEncoded()));
+ }
+
+ return this;
+ }
+
+ public JcaCertificateRequestMessageBuilder setAuthInfoSender(X500Principal sender)
+ {
+ if (sender != null)
+ {
+ setAuthInfoSender(new GeneralName(X500Name.getInstance(sender.getEncoded())));
+ }
+
+ return this;
+ }
+
+ public JcaCertificateRequestMessageBuilder setPublicKey(PublicKey publicKey)
+ {
+ setPublicKey(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));
+
+ return this;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaEncryptedValueBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaEncryptedValueBuilder.java
new file mode 100644
index 000000000..bed393dc4
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaEncryptedValueBuilder.java
@@ -0,0 +1,26 @@
+package org.spongycastle.cert.crmf.jcajce;
+
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.crmf.EncryptedValue;
+import org.spongycastle.cert.crmf.CRMFException;
+import org.spongycastle.cert.crmf.EncryptedValueBuilder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.operator.KeyWrapper;
+import org.spongycastle.operator.OutputEncryptor;
+
+public class JcaEncryptedValueBuilder
+ extends EncryptedValueBuilder
+{
+ public JcaEncryptedValueBuilder(KeyWrapper wrapper, OutputEncryptor encryptor)
+ {
+ super(wrapper, encryptor);
+ }
+
+ public EncryptedValue build(X509Certificate certificate)
+ throws CertificateEncodingException, CRMFException
+ {
+ return build(new JcaX509CertificateHolder(certificate));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaPKIArchiveControlBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaPKIArchiveControlBuilder.java
new file mode 100644
index 000000000..de527e07d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcaPKIArchiveControlBuilder.java
@@ -0,0 +1,29 @@
+package org.spongycastle.cert.crmf.jcajce;
+
+import java.security.PrivateKey;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.cert.crmf.PKIArchiveControlBuilder;
+
+public class JcaPKIArchiveControlBuilder
+ extends PKIArchiveControlBuilder
+{
+ public JcaPKIArchiveControlBuilder(PrivateKey privateKey, X500Name name)
+ {
+ this(privateKey, new GeneralName(name));
+ }
+
+ public JcaPKIArchiveControlBuilder(PrivateKey privateKey, X500Principal name)
+ {
+ this(privateKey, X500Name.getInstance(name.getEncoded()));
+ }
+
+ public JcaPKIArchiveControlBuilder(PrivateKey privateKey, GeneralName generalName)
+ {
+ super(PrivateKeyInfo.getInstance(privateKey.getEncoded()), generalName);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JceAsymmetricValueDecryptorGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JceAsymmetricValueDecryptorGenerator.java
new file mode 100644
index 000000000..870c4b3b8
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JceAsymmetricValueDecryptorGenerator.java
@@ -0,0 +1,120 @@
+package org.spongycastle.cert.crmf.jcajce;
+
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.ProviderException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.crmf.CRMFException;
+import org.spongycastle.cert.crmf.ValueDecryptorGenerator;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.InputDecryptor;
+
+public class JceAsymmetricValueDecryptorGenerator
+ implements ValueDecryptorGenerator
+{
+ private PrivateKey recipientKey;
+ private CRMFHelper helper = new CRMFHelper(new DefaultJcaJceHelper());
+
+ public JceAsymmetricValueDecryptorGenerator(PrivateKey recipientKey)
+ {
+ this.recipientKey = recipientKey;
+ }
+
+ public JceAsymmetricValueDecryptorGenerator setProvider(Provider provider)
+ {
+ this.helper = new CRMFHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JceAsymmetricValueDecryptorGenerator setProvider(String providerName)
+ {
+ this.helper = new CRMFHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ private Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey)
+ throws CRMFException
+ {
+ try
+ {
+ Key sKey = null;
+
+ Cipher keyCipher = helper.createCipher(keyEncryptionAlgorithm.getAlgorithm());
+
+ try
+ {
+ keyCipher.init(Cipher.UNWRAP_MODE, recipientKey);
+ sKey = keyCipher.unwrap(encryptedContentEncryptionKey, contentEncryptionAlgorithm.getAlgorithm().getId(), Cipher.SECRET_KEY);
+ }
+ catch (GeneralSecurityException e)
+ {
+ }
+ catch (IllegalStateException e)
+ {
+ }
+ catch (UnsupportedOperationException e)
+ {
+ }
+ catch (ProviderException e)
+ {
+ }
+
+ // some providers do not support UNWRAP (this appears to be only for asymmetric algorithms)
+ if (sKey == null)
+ {
+ keyCipher.init(Cipher.DECRYPT_MODE, recipientKey);
+ sKey = new SecretKeySpec(keyCipher.doFinal(encryptedContentEncryptionKey), contentEncryptionAlgorithm.getAlgorithm().getId());
+ }
+
+ return sKey;
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CRMFException("key invalid in message.", e);
+ }
+ catch (IllegalBlockSizeException e)
+ {
+ throw new CRMFException("illegal blocksize in message.", e);
+ }
+ catch (BadPaddingException e)
+ {
+ throw new CRMFException("bad padding in message.", e);
+ }
+ }
+
+ public InputDecryptor getValueDecryptor(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey)
+ throws CRMFException
+ {
+ Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, encryptedContentEncryptionKey);
+
+ final Cipher dataCipher = helper.createContentCipher(secretKey, contentEncryptionAlgorithm);
+
+ return new InputDecryptor()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return contentEncryptionAlgorithm;
+ }
+
+ public InputStream getInputStream(InputStream dataIn)
+ {
+ return new CipherInputStream(dataIn, dataCipher);
+ }
+ };
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JceCRMFEncryptorBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JceCRMFEncryptorBuilder.java
new file mode 100644
index 000000000..8226bb3b6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JceCRMFEncryptorBuilder.java
@@ -0,0 +1,136 @@
+package org.spongycastle.cert.crmf.jcajce;
+
+import java.io.OutputStream;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.Provider;
+import java.security.SecureRandom;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.crmf.CRMFException;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OutputEncryptor;
+import org.spongycastle.operator.jcajce.JceGenericKey;
+
+public class JceCRMFEncryptorBuilder
+{
+ private final ASN1ObjectIdentifier encryptionOID;
+ private final int keySize;
+
+ private CRMFHelper helper = new CRMFHelper(new DefaultJcaJceHelper());
+ private SecureRandom random;
+
+ public JceCRMFEncryptorBuilder(ASN1ObjectIdentifier encryptionOID)
+ {
+ this(encryptionOID, -1);
+ }
+
+ public JceCRMFEncryptorBuilder(ASN1ObjectIdentifier encryptionOID, int keySize)
+ {
+ this.encryptionOID = encryptionOID;
+ this.keySize = keySize;
+ }
+
+ public JceCRMFEncryptorBuilder setProvider(Provider provider)
+ {
+ this.helper = new CRMFHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JceCRMFEncryptorBuilder setProvider(String providerName)
+ {
+ this.helper = new CRMFHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public JceCRMFEncryptorBuilder setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public OutputEncryptor build()
+ throws CRMFException
+ {
+ return new CRMFOutputEncryptor(encryptionOID, keySize, random);
+ }
+
+ private class CRMFOutputEncryptor
+ implements OutputEncryptor
+ {
+ private SecretKey encKey;
+ private AlgorithmIdentifier algorithmIdentifier;
+ private Cipher cipher;
+
+ CRMFOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, SecureRandom random)
+ throws CRMFException
+ {
+ KeyGenerator keyGen = helper.createKeyGenerator(encryptionOID);
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ if (keySize < 0)
+ {
+ keyGen.init(random);
+ }
+ else
+ {
+ keyGen.init(keySize, random);
+ }
+
+ cipher = helper.createCipher(encryptionOID);
+ encKey = keyGen.generateKey();
+ AlgorithmParameters params = helper.generateParameters(encryptionOID, encKey, random);
+
+ try
+ {
+ cipher.init(Cipher.ENCRYPT_MODE, encKey, params, random);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CRMFException("unable to initialize cipher: " + e.getMessage(), e);
+ }
+
+ //
+ // If params are null we try and second guess on them as some providers don't provide
+ // algorithm parameter generation explicity but instead generate them under the hood.
+ //
+ if (params == null)
+ {
+ params = cipher.getParameters();
+ }
+
+ algorithmIdentifier = helper.getAlgorithmIdentifier(encryptionOID, params);
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmIdentifier;
+ }
+
+ public OutputStream getOutputStream(OutputStream dOut)
+ {
+ return new CipherOutputStream(dOut, cipher);
+ }
+
+ public GenericKey getKey()
+ {
+ return new JceGenericKey(algorithmIdentifier, encKey);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcePKMACValuesCalculator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcePKMACValuesCalculator.java
new file mode 100644
index 000000000..c11f9535e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/crmf/jcajce/JcePKMACValuesCalculator.java
@@ -0,0 +1,69 @@
+package org.spongycastle.cert.crmf.jcajce;
+
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.security.Provider;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.crmf.CRMFException;
+import org.spongycastle.cert.crmf.PKMACValuesCalculator;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+
+public class JcePKMACValuesCalculator
+ implements PKMACValuesCalculator
+{
+ private MessageDigest digest;
+ private Mac mac;
+ private CRMFHelper helper;
+
+ public JcePKMACValuesCalculator()
+ {
+ this.helper = new CRMFHelper(new DefaultJcaJceHelper());
+ }
+
+ public JcePKMACValuesCalculator setProvider(Provider provider)
+ {
+ this.helper = new CRMFHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JcePKMACValuesCalculator setProvider(String providerName)
+ {
+ this.helper = new CRMFHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public void setup(AlgorithmIdentifier digAlg, AlgorithmIdentifier macAlg)
+ throws CRMFException
+ {
+ digest = helper.createDigest(digAlg.getAlgorithm());
+ mac = helper.createMac(macAlg.getAlgorithm());
+ }
+
+ public byte[] calculateDigest(byte[] data)
+ {
+ return digest.digest(data);
+ }
+
+ public byte[] calculateMac(byte[] pwd, byte[] data)
+ throws CRMFException
+ {
+ try
+ {
+ mac.init(new SecretKeySpec(pwd, mac.getAlgorithm()));
+
+ return mac.doFinal(data);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CRMFException("failure in setup: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/CertHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/CertHelper.java
new file mode 100644
index 000000000..1c5679bf3
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/CertHelper.java
@@ -0,0 +1,17 @@
+package org.spongycastle.cert.jcajce;
+
+import java.security.NoSuchProviderException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+abstract class CertHelper
+{
+ public CertificateFactory getCertificateFactory(String type)
+ throws NoSuchProviderException, CertificateException
+ {
+ return createCertificateFactory(type);
+ }
+
+ protected abstract CertificateFactory createCertificateFactory(String type)
+ throws CertificateException, NoSuchProviderException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/DefaultCertHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/DefaultCertHelper.java
new file mode 100644
index 000000000..d8713bf38
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/DefaultCertHelper.java
@@ -0,0 +1,14 @@
+package org.spongycastle.cert.jcajce;
+
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+class DefaultCertHelper
+ extends CertHelper
+{
+ protected CertificateFactory createCertificateFactory(String type)
+ throws CertificateException
+ {
+ return CertificateFactory.getInstance(type);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaAttrCertStore.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaAttrCertStore.java
new file mode 100644
index 000000000..ed3543355
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaAttrCertStore.java
@@ -0,0 +1,62 @@
+package org.spongycastle.cert.jcajce;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.util.CollectionStore;
+import org.spongycastle.x509.X509AttributeCertificate;
+
+/**
+ * Class for storing Attribute Certificates for later lookup.
+ * <p>
+ * The class will convert X509AttributeCertificate objects into X509AttributeCertificateHolder objects.
+ * </p>
+ */
+public class JcaAttrCertStore
+ extends CollectionStore
+{
+ /**
+ * Basic constructor.
+ *
+ * @param collection - initial contents for the store, this is copied.
+ */
+ public JcaAttrCertStore(Collection collection)
+ throws IOException
+ {
+ super(convertCerts(collection));
+ }
+
+ public JcaAttrCertStore(X509AttributeCertificate attrCert)
+ throws IOException
+ {
+ this(Collections.singletonList(attrCert));
+ }
+
+ private static Collection convertCerts(Collection collection)
+ throws IOException
+ {
+ List list = new ArrayList(collection.size());
+
+ for (Iterator it = collection.iterator(); it.hasNext();)
+ {
+ Object o = it.next();
+
+ if (o instanceof X509AttributeCertificate)
+ {
+ X509AttributeCertificate cert = (X509AttributeCertificate)o;
+
+ list.add(new JcaX509AttributeCertificateHolder(cert));
+ }
+ else
+ {
+ list.add(o);
+ }
+ }
+
+ return list;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCRLStore.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCRLStore.java
new file mode 100644
index 000000000..08493d138
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCRLStore.java
@@ -0,0 +1,63 @@
+package org.spongycastle.cert.jcajce;
+
+import java.io.IOException;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.cert.X509CRLHolder;
+import org.spongycastle.util.CollectionStore;
+
+/**
+ * Class for storing CRLs for later lookup.
+ * <p>
+ * The class will convert X509CRL objects into X509CRLHolder objects.
+ * </p>
+ */
+public class JcaCRLStore
+ extends CollectionStore
+{
+ /**
+ * Basic constructor.
+ *
+ * @param collection - initial contents for the store, this is copied.
+ */
+ public JcaCRLStore(Collection collection)
+ throws CRLException
+ {
+ super(convertCRLs(collection));
+ }
+
+ private static Collection convertCRLs(Collection collection)
+ throws CRLException
+ {
+ List list = new ArrayList(collection.size());
+
+ for (Iterator it = collection.iterator(); it.hasNext();)
+ {
+ Object crl = it.next();
+
+ if (crl instanceof X509CRL)
+ {
+ try
+ {
+ list.add(new X509CRLHolder(((X509CRL)crl).getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new CRLException("cannot read encoding: " + e.getMessage());
+
+ }
+ }
+ else
+ {
+ list.add((X509CRLHolder)crl);
+ }
+ }
+
+ return list;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCertStore.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCertStore.java
new file mode 100644
index 000000000..497668142
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCertStore.java
@@ -0,0 +1,64 @@
+package org.spongycastle.cert.jcajce;
+
+import java.io.IOException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.util.CollectionStore;
+
+/**
+ * Class for storing Certificates for later lookup.
+ * <p>
+ * The class will convert X509Certificate objects into X509CertificateHolder objects.
+ * </p>
+ */
+public class JcaCertStore
+ extends CollectionStore
+{
+ /**
+ * Basic constructor.
+ *
+ * @param collection - initial contents for the store, this is copied.
+ */
+ public JcaCertStore(Collection collection)
+ throws CertificateEncodingException
+ {
+ super(convertCerts(collection));
+ }
+
+ private static Collection convertCerts(Collection collection)
+ throws CertificateEncodingException
+ {
+ List list = new ArrayList(collection.size());
+
+ for (Iterator it = collection.iterator(); it.hasNext();)
+ {
+ Object o = it.next();
+
+ if (o instanceof X509Certificate)
+ {
+ X509Certificate cert = (X509Certificate)o;
+
+ try
+ {
+ list.add(new X509CertificateHolder(cert.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException("unable to read encoding: " + e.getMessage());
+ }
+ }
+ else
+ {
+ list.add((X509CertificateHolder)o);
+ }
+ }
+
+ return list;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCertStoreBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCertStoreBuilder.java
new file mode 100644
index 000000000..fbb26cb45
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaCertStoreBuilder.java
@@ -0,0 +1,148 @@
+package org.spongycastle.cert.jcajce;
+
+import java.security.GeneralSecurityException;
+import java.security.Provider;
+import java.security.cert.CRLException;
+import java.security.cert.CertStore;
+import java.security.cert.CertificateException;
+import java.security.cert.CollectionCertStoreParameters;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.cert.X509CRLHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.util.Store;
+
+/**
+ * Builder to create a CertStore from certificate and CRL stores.
+ */
+public class JcaCertStoreBuilder
+{
+ private List certs = new ArrayList();
+ private List crls = new ArrayList();
+ private Object provider;
+ private JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter();
+ private JcaX509CRLConverter crlConverter = new JcaX509CRLConverter();
+ private String type = "Collection";
+
+ /**
+ * Add a store full of X509CertificateHolder objects.
+ *
+ * @param certStore a store of X509CertificateHolder objects.
+ */
+ public JcaCertStoreBuilder addCertificates(Store certStore)
+ {
+ certs.addAll(certStore.getMatches(null));
+
+ return this;
+ }
+
+ /**
+ * Add a single certificate.
+ *
+ * @param cert the X509 certificate holder containing the certificate.
+ */
+ public JcaCertStoreBuilder addCertificate(X509CertificateHolder cert)
+ {
+ certs.add(cert);
+
+ return this;
+ }
+
+ /**
+ * Add a store full of X509CRLHolder objects.
+ * @param crlStore a store of X509CRLHolder objects.
+ */
+ public JcaCertStoreBuilder addCRLs(Store crlStore)
+ {
+ crls.addAll(crlStore.getMatches(null));
+
+ return this;
+ }
+
+ /**
+ * Add a single CRL.
+ *
+ * @param crl the X509 CRL holder containing the CRL.
+ */
+ public JcaCertStoreBuilder addCRL(X509CRLHolder crl)
+ {
+ crls.add(crl);
+
+ return this;
+ }
+
+ public JcaCertStoreBuilder setProvider(String providerName)
+ {
+ certificateConverter.setProvider(providerName);
+ crlConverter.setProvider(providerName);
+ this.provider = providerName;
+
+ return this;
+ }
+
+ public JcaCertStoreBuilder setProvider(Provider provider)
+ {
+ certificateConverter.setProvider(provider);
+ crlConverter.setProvider(provider);
+ this.provider = provider;
+
+ return this;
+ }
+
+ /**
+ * Set the type of the CertStore generated. By default it is "Collection".
+ *
+ * @param type type of CertStore passed to CertStore.getInstance().
+ * @return the current builder.
+ */
+ public JcaCertStoreBuilder setType(String type)
+ {
+ this.type = type;
+
+ return this;
+ }
+
+ /**
+ * Build the CertStore from the current inputs.
+ *
+ * @return a CertStore.
+ * @throws GeneralSecurityException
+ */
+ public CertStore build()
+ throws GeneralSecurityException
+ {
+ CollectionCertStoreParameters params = convertHolders(certificateConverter, crlConverter);
+
+ if (provider instanceof String)
+ {
+ return CertStore.getInstance(type, params, (String)provider);
+ }
+
+ if (provider instanceof Provider)
+ {
+ return CertStore.getInstance(type, params, (Provider)provider);
+ }
+
+ return CertStore.getInstance(type, params);
+ }
+
+ private CollectionCertStoreParameters convertHolders(JcaX509CertificateConverter certificateConverter, JcaX509CRLConverter crlConverter)
+ throws CertificateException, CRLException
+ {
+ List jcaObjs = new ArrayList(certs.size() + crls.size());
+
+ for (Iterator it = certs.iterator(); it.hasNext();)
+ {
+ jcaObjs.add(certificateConverter.getCertificate((X509CertificateHolder)it.next()));
+ }
+
+ for (Iterator it = crls.iterator(); it.hasNext();)
+ {
+ jcaObjs.add(crlConverter.getCRL((X509CRLHolder)it.next()));
+ }
+
+ return new CollectionCertStoreParameters(jcaObjs);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX500NameUtil.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX500NameUtil.java
new file mode 100644
index 000000000..d6b6ae899
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX500NameUtil.java
@@ -0,0 +1,29 @@
+package org.spongycastle.cert.jcajce;
+
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.X500NameStyle;
+
+public class JcaX500NameUtil
+{
+ public static X500Name getIssuer(X509Certificate certificate)
+ {
+ return X500Name.getInstance(certificate.getIssuerX500Principal().getEncoded());
+ }
+
+ public static X500Name getSubject(X509Certificate certificate)
+ {
+ return X500Name.getInstance(certificate.getSubjectX500Principal().getEncoded());
+ }
+
+ public static X500Name getIssuer(X500NameStyle style, X509Certificate certificate)
+ {
+ return X500Name.getInstance(style, certificate.getIssuerX500Principal().getEncoded());
+ }
+
+ public static X500Name getSubject(X500NameStyle style, X509Certificate certificate)
+ {
+ return X500Name.getInstance(style, certificate.getSubjectX500Principal().getEncoded());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509AttributeCertificateHolder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509AttributeCertificateHolder.java
new file mode 100644
index 000000000..350762527
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509AttributeCertificateHolder.java
@@ -0,0 +1,26 @@
+package org.spongycastle.cert.jcajce;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.x509.AttributeCertificate;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.x509.X509AttributeCertificate;
+
+/**
+ * JCA helper class for converting an old style X509AttributeCertificate into a X509AttributeCertificateHolder object.
+ */
+public class JcaX509AttributeCertificateHolder
+ extends X509AttributeCertificateHolder
+{
+ /**
+ * Base constructor.
+ *
+ * @param cert AttributeCertificate to be used a the source for the holder creation.
+ * @throws IOException if there is a problem extracting the attribute certificate information.
+ */
+ public JcaX509AttributeCertificateHolder(X509AttributeCertificate cert)
+ throws IOException
+ {
+ super(AttributeCertificate.getInstance(cert.getEncoded()));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CRLConverter.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CRLConverter.java
new file mode 100644
index 000000000..7040f1aa9
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CRLConverter.java
@@ -0,0 +1,103 @@
+package org.spongycastle.cert.jcajce;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509CRL;
+
+import org.spongycastle.cert.X509CRLHolder;
+
+/**
+ * Class for converting an X509CRLHolder into a corresponding X509CRL object tied to a
+ * particular JCA provider.
+ */
+public class JcaX509CRLConverter
+{
+ private CertHelper helper = new DefaultCertHelper();
+
+ /**
+ * Base constructor, configure with the default provider.
+ */
+ public JcaX509CRLConverter()
+ {
+ this.helper = new DefaultCertHelper();
+ }
+
+ /**
+ * Set the provider to use from a Provider object.
+ *
+ * @param provider the provider to use.
+ * @return the converter instance.
+ */
+ public JcaX509CRLConverter setProvider(Provider provider)
+ {
+ this.helper = new ProviderCertHelper(provider);
+
+ return this;
+ }
+
+ /**
+ * Set the provider to use by name.
+ *
+ * @param providerName name of the provider to use.
+ * @return the converter instance.
+ */
+ public JcaX509CRLConverter setProvider(String providerName)
+ {
+ this.helper = new NamedCertHelper(providerName);
+
+ return this;
+ }
+
+ /**
+ * Use the configured converter to produce a X509CRL object from a X509CRLHolder object.
+ *
+ * @param crlHolder the holder to be converted
+ * @return a X509CRL object
+ * @throws CRLException if the conversion is unable to be made.
+ */
+ public X509CRL getCRL(X509CRLHolder crlHolder)
+ throws CRLException
+ {
+ try
+ {
+ CertificateFactory cFact = helper.getCertificateFactory("X.509");
+
+ return (X509CRL)cFact.generateCRL(new ByteArrayInputStream(crlHolder.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new ExCRLException("exception parsing certificate: " + e.getMessage(), e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new ExCRLException("cannot find required provider:" + e.getMessage(), e);
+ }
+ catch (CertificateException e)
+ {
+ throw new ExCRLException("cannot create factory: " + e.getMessage(), e);
+ }
+ }
+
+ private class ExCRLException
+ extends CRLException
+ {
+ private Throwable cause;
+
+ public ExCRLException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CRLHolder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CRLHolder.java
new file mode 100644
index 000000000..91bcd88db
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CRLHolder.java
@@ -0,0 +1,26 @@
+package org.spongycastle.cert.jcajce;
+
+import java.security.cert.CRLException;
+import java.security.cert.X509CRL;
+
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.cert.X509CRLHolder;
+
+/**
+ * JCA helper class for converting an X509CRL into a X509CRLHolder object.
+ */
+public class JcaX509CRLHolder
+ extends X509CRLHolder
+{
+ /**
+ * Base constructor.
+ *
+ * @param crl CRL to be used a the source for the holder creation.
+ * @throws CRLException if there is a problem extracting the CRL information.
+ */
+ public JcaX509CRLHolder(X509CRL crl)
+ throws CRLException
+ {
+ super(CertificateList.getInstance(crl.getEncoded()));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CertificateConverter.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CertificateConverter.java
new file mode 100644
index 000000000..5e46a17d7
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CertificateConverter.java
@@ -0,0 +1,116 @@
+package org.spongycastle.cert.jcajce;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.cert.X509CertificateHolder;
+
+/**
+ * Converter for producing X509Certificate objects tied to a specific provider from X509CertificateHolder objects.
+ */
+public class JcaX509CertificateConverter
+{
+ private CertHelper helper = new DefaultCertHelper();
+
+ /**
+ * Base constructor, configure with the default provider.
+ */
+ public JcaX509CertificateConverter()
+ {
+ this.helper = new DefaultCertHelper();
+ }
+
+ /**
+ * Set the provider to use from a Provider object.
+ *
+ * @param provider the provider to use.
+ * @return the converter instance.
+ */
+ public JcaX509CertificateConverter setProvider(Provider provider)
+ {
+ this.helper = new ProviderCertHelper(provider);
+
+ return this;
+ }
+
+ /**
+ * Set the provider to use by name.
+ *
+ * @param providerName name of the provider to use.
+ * @return the converter instance.
+ */
+ public JcaX509CertificateConverter setProvider(String providerName)
+ {
+ this.helper = new NamedCertHelper(providerName);
+
+ return this;
+ }
+
+ /**
+ * Use the configured converter to produce a X509Certificate object from a X509CertificateHolder object.
+ *
+ * @param certHolder the holder to be converted
+ * @return a X509Certificate object
+ * @throws CertificateException if the conversion is unable to be made.
+ */
+ public X509Certificate getCertificate(X509CertificateHolder certHolder)
+ throws CertificateException
+ {
+ try
+ {
+ CertificateFactory cFact = helper.getCertificateFactory("X.509");
+
+ return (X509Certificate)cFact.generateCertificate(new ByteArrayInputStream(certHolder.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new ExCertificateParsingException("exception parsing certificate: " + e.getMessage(), e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new ExCertificateException("cannot find required provider:" + e.getMessage(), e);
+ }
+ }
+
+ private class ExCertificateParsingException
+ extends CertificateParsingException
+ {
+ private Throwable cause;
+
+ public ExCertificateParsingException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+
+ private class ExCertificateException
+ extends CertificateException
+ {
+ private Throwable cause;
+
+ public ExCertificateException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CertificateHolder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CertificateHolder.java
new file mode 100644
index 000000000..a523f975e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509CertificateHolder.java
@@ -0,0 +1,26 @@
+package org.spongycastle.cert.jcajce;
+
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.cert.X509CertificateHolder;
+
+/**
+ * JCA helper class for converting an X509Certificate into a X509CertificateHolder object.
+ */
+public class JcaX509CertificateHolder
+ extends X509CertificateHolder
+{
+ /**
+ * Base constructor.
+ *
+ * @param cert certificate to be used a the source for the holder creation.
+ * @throws CertificateEncodingException if there is a problem extracting the certificate information.
+ */
+ public JcaX509CertificateHolder(X509Certificate cert)
+ throws CertificateEncodingException
+ {
+ super(Certificate.getInstance(cert.getEncoded()));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509ContentVerifierProviderBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509ContentVerifierProviderBuilder.java
new file mode 100644
index 000000000..46eb3b432
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509ContentVerifierProviderBuilder.java
@@ -0,0 +1,50 @@
+package org.spongycastle.cert.jcajce;
+
+import java.security.Provider;
+import java.security.cert.CertificateException;
+
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509ContentVerifierProviderBuilder;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+
+public class JcaX509ContentVerifierProviderBuilder
+ implements X509ContentVerifierProviderBuilder
+{
+ private JcaContentVerifierProviderBuilder builder = new JcaContentVerifierProviderBuilder();
+
+ public JcaX509ContentVerifierProviderBuilder setProvider(Provider provider)
+ {
+ this.builder.setProvider(provider);
+
+ return this;
+ }
+
+ public JcaX509ContentVerifierProviderBuilder setProvider(String providerName)
+ {
+ this.builder.setProvider(providerName);
+
+ return this;
+ }
+
+ public ContentVerifierProvider build(SubjectPublicKeyInfo validatingKeyInfo)
+ throws OperatorCreationException
+ {
+ return builder.build(validatingKeyInfo);
+ }
+
+ public ContentVerifierProvider build(X509CertificateHolder validatingKeyInfo)
+ throws OperatorCreationException
+ {
+ try
+ {
+ return builder.build(validatingKeyInfo);
+ }
+ catch (CertificateException e)
+ {
+ throw new OperatorCreationException("Unable to process certificate: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509ExtensionUtils.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509ExtensionUtils.java
new file mode 100644
index 000000000..12f01fbef
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509ExtensionUtils.java
@@ -0,0 +1,129 @@
+package org.spongycastle.cert.jcajce;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.X509ExtensionUtils;
+import org.spongycastle.operator.DigestCalculator;
+
+public class JcaX509ExtensionUtils
+ extends X509ExtensionUtils
+{
+ /**
+ * Create a utility class pre-configured with a SHA-1 digest calculator based on the
+ * default implementation.
+ *
+ * @throws NoSuchAlgorithmException
+ */
+ public JcaX509ExtensionUtils()
+ throws NoSuchAlgorithmException
+ {
+ super(new SHA1DigestCalculator(MessageDigest.getInstance("SHA1")));
+ }
+
+ public JcaX509ExtensionUtils(DigestCalculator calculator)
+ {
+ super(calculator);
+ }
+
+ public AuthorityKeyIdentifier createAuthorityKeyIdentifier(
+ X509Certificate cert)
+ throws CertificateEncodingException
+ {
+ return super.createAuthorityKeyIdentifier(new JcaX509CertificateHolder(cert));
+ }
+
+ public AuthorityKeyIdentifier createAuthorityKeyIdentifier(
+ PublicKey pubKey)
+ {
+ return super.createAuthorityKeyIdentifier(SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()));
+ }
+
+ /**
+ * Return a RFC 3280 type 1 key identifier. As in:
+ * <pre>
+ * (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the
+ * value of the BIT STRING subjectPublicKey (excluding the tag,
+ * length, and number of unused bits).
+ * </pre>
+ * @param publicKey the key object containing the key identifier is to be based on.
+ * @return the key identifier.
+ */
+ public SubjectKeyIdentifier createSubjectKeyIdentifier(
+ PublicKey publicKey)
+ {
+ return super.createSubjectKeyIdentifier(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));
+ }
+
+ /**
+ * Return a RFC 3280 type 2 key identifier. As in:
+ * <pre>
+ * (2) The keyIdentifier is composed of a four bit type field with
+ * the value 0100 followed by the least significant 60 bits of the
+ * SHA-1 hash of the value of the BIT STRING subjectPublicKey.
+ * </pre>
+ * @param publicKey the key object of interest.
+ * @return the key identifier.
+ */
+ public SubjectKeyIdentifier createTruncatedSubjectKeyIdentifier(PublicKey publicKey)
+ {
+ return super.createSubjectKeyIdentifier(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));
+ }
+
+ /**
+ * Return the ASN.1 object contained in a byte[] returned by a getExtensionValue() call.
+ *
+ * @param encExtValue DER encoded OCTET STRING containing the DER encoded extension object.
+ * @return an ASN.1 object
+ * @throws java.io.IOException on a parsing error.
+ */
+ public static ASN1Primitive parseExtensionValue(byte[] encExtValue)
+ throws IOException
+ {
+ return ASN1Primitive.fromByteArray(ASN1OctetString.getInstance(encExtValue).getOctets());
+ }
+
+ private static class SHA1DigestCalculator
+ implements DigestCalculator
+ {
+ private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ private MessageDigest digest;
+
+ public SHA1DigestCalculator(MessageDigest digest)
+ {
+ this.digest = digest;
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1);
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return bOut;
+ }
+
+ public byte[] getDigest()
+ {
+ byte[] bytes = digest.digest(bOut.toByteArray());
+
+ bOut.reset();
+
+ return bytes;
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v1CertificateBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v1CertificateBuilder.java
new file mode 100644
index 000000000..e5e4f83d4
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v1CertificateBuilder.java
@@ -0,0 +1,48 @@
+package org.spongycastle.cert.jcajce;
+
+import java.math.BigInteger;
+import java.security.PublicKey;
+import java.util.Date;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.X509v1CertificateBuilder;
+
+/**
+ * JCA helper class to allow JCA objects to be used in the construction of a Version 1 certificate.
+ */
+public class JcaX509v1CertificateBuilder
+ extends X509v1CertificateBuilder
+{
+ /**
+ * Initialise the builder using a PublicKey.
+ *
+ * @param issuer X500Name representing the issuer of this certificate.
+ * @param serial the serial number for the certificate.
+ * @param notBefore date before which the certificate is not valid.
+ * @param notAfter date after which the certificate is not valid.
+ * @param subject X500Name representing the subject of this certificate.
+ * @param publicKey the public key to be associated with the certificate.
+ */
+ public JcaX509v1CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, PublicKey publicKey)
+ {
+ super(issuer, serial, notBefore, notAfter, subject, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));
+ }
+
+ /**
+ * Initialise the builder using X500Principal objects and a PublicKey.
+ *
+ * @param issuer principal representing the issuer of this certificate.
+ * @param serial the serial number for the certificate.
+ * @param notBefore date before which the certificate is not valid.
+ * @param notAfter date after which the certificate is not valid.
+ * @param subject principal representing the subject of this certificate.
+ * @param publicKey the public key to be associated with the certificate.
+ */
+ public JcaX509v1CertificateBuilder(X500Principal issuer, BigInteger serial, Date notBefore, Date notAfter, X500Principal subject, PublicKey publicKey)
+ {
+ super(X500Name.getInstance(issuer.getEncoded()), serial, notBefore, notAfter, X500Name.getInstance(subject.getEncoded()), SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v2CRLBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v2CRLBuilder.java
new file mode 100644
index 000000000..97d544bd3
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v2CRLBuilder.java
@@ -0,0 +1,23 @@
+package org.spongycastle.cert.jcajce;
+
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cert.X509v2CRLBuilder;
+
+public class JcaX509v2CRLBuilder
+ extends X509v2CRLBuilder
+{
+ public JcaX509v2CRLBuilder(X500Principal issuer, Date now)
+ {
+ super(X500Name.getInstance(issuer.getEncoded()), now);
+ }
+
+ public JcaX509v2CRLBuilder(X509Certificate issuerCert, Date now)
+ {
+ this(issuerCert.getSubjectX500Principal(), now);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v3CertificateBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v3CertificateBuilder.java
new file mode 100644
index 000000000..c61654c1d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/JcaX509v3CertificateBuilder.java
@@ -0,0 +1,103 @@
+package org.spongycastle.cert.jcajce;
+
+import java.math.BigInteger;
+import java.security.PublicKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.X509v3CertificateBuilder;
+
+/**
+ * JCA helper class to allow JCA objects to be used in the construction of a Version 3 certificate.
+ */
+public class JcaX509v3CertificateBuilder
+ extends X509v3CertificateBuilder
+{
+ /**
+ * Initialise the builder using a PublicKey.
+ *
+ * @param issuer X500Name representing the issuer of this certificate.
+ * @param serial the serial number for the certificate.
+ * @param notBefore date before which the certificate is not valid.
+ * @param notAfter date after which the certificate is not valid.
+ * @param subject X500Name representing the subject of this certificate.
+ * @param publicKey the public key to be associated with the certificate.
+ */
+ public JcaX509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, PublicKey publicKey)
+ {
+ super(issuer, serial, notBefore, notAfter, subject, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));
+ }
+
+ /**
+ * Initialise the builder using X500Principal objects and a PublicKey.
+ *
+ * @param issuer principal representing the issuer of this certificate.
+ * @param serial the serial number for the certificate.
+ * @param notBefore date before which the certificate is not valid.
+ * @param notAfter date after which the certificate is not valid.
+ * @param subject principal representing the subject of this certificate.
+ * @param publicKey the public key to be associated with the certificate.
+ */
+ public JcaX509v3CertificateBuilder(X500Principal issuer, BigInteger serial, Date notBefore, Date notAfter, X500Principal subject, PublicKey publicKey)
+ {
+ super(X500Name.getInstance(issuer.getEncoded()), serial, notBefore, notAfter, X500Name.getInstance(subject.getEncoded()), SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));
+ }
+
+ /**
+ * Initialise the builder using the subject from the passed in issuerCert as the issuer, as well as
+ * passing through and converting the other objects provided.
+ *
+ * @param issuerCert certificate who's subject is the issuer of the certificate we are building.
+ * @param serial the serial number for the certificate.
+ * @param notBefore date before which the certificate is not valid.
+ * @param notAfter date after which the certificate is not valid.
+ * @param subject principal representing the subject of this certificate.
+ * @param publicKey the public key to be associated with the certificate.
+ */
+ public JcaX509v3CertificateBuilder(X509Certificate issuerCert, BigInteger serial, Date notBefore, Date notAfter, X500Principal subject, PublicKey publicKey)
+ {
+ this(issuerCert.getSubjectX500Principal(), serial, notBefore, notAfter, subject, publicKey);
+ }
+
+ /**
+ * Initialise the builder using the subject from the passed in issuerCert as the issuer, as well as
+ * passing through and converting the other objects provided.
+ *
+ * @param issuerCert certificate who's subject is the issuer of the certificate we are building.
+ * @param serial the serial number for the certificate.
+ * @param notBefore date before which the certificate is not valid.
+ * @param notAfter date after which the certificate is not valid.
+ * @param subject principal representing the subject of this certificate.
+ * @param publicKey the public key to be associated with the certificate.
+ */
+ public JcaX509v3CertificateBuilder(X509Certificate issuerCert, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, PublicKey publicKey)
+ {
+ this(X500Name.getInstance(issuerCert.getSubjectX500Principal().getEncoded()), serial, notBefore, notAfter, subject, publicKey);
+ }
+
+ /**
+ * Add a given extension field for the standard extensions tag (tag 3)
+ * copying the extension value from another certificate.
+ *
+ * @param oid the type of the extension to be copied.
+ * @param critical true if the extension is to be marked critical, false otherwise.
+ * @param certificate the source of the extension to be copied.
+ * @return the builder instance.
+ */
+ public JcaX509v3CertificateBuilder copyAndAddExtension(
+ ASN1ObjectIdentifier oid,
+ boolean critical,
+ X509Certificate certificate)
+ throws CertificateEncodingException
+ {
+ this.copyAndAddExtension(oid, critical, new JcaX509CertificateHolder(certificate));
+
+ return this;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/NamedCertHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/NamedCertHelper.java
new file mode 100644
index 000000000..89584138e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/NamedCertHelper.java
@@ -0,0 +1,22 @@
+package org.spongycastle.cert.jcajce;
+
+import java.security.NoSuchProviderException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+class NamedCertHelper
+ extends CertHelper
+{
+ private final String providerName;
+
+ NamedCertHelper(String providerName)
+ {
+ this.providerName = providerName;
+ }
+
+ protected CertificateFactory createCertificateFactory(String type)
+ throws CertificateException, NoSuchProviderException
+ {
+ return CertificateFactory.getInstance(type, providerName);
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/ProviderCertHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/ProviderCertHelper.java
new file mode 100644
index 000000000..ffe37e9bd
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/jcajce/ProviderCertHelper.java
@@ -0,0 +1,22 @@
+package org.spongycastle.cert.jcajce;
+
+import java.security.Provider;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+class ProviderCertHelper
+ extends CertHelper
+{
+ private final Provider provider;
+
+ ProviderCertHelper(Provider provider)
+ {
+ this.provider = provider;
+ }
+
+ protected CertificateFactory createCertificateFactory(String type)
+ throws CertificateException
+ {
+ return CertificateFactory.getInstance(type, provider);
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/BasicOCSPResp.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/BasicOCSPResp.java
new file mode 100644
index 000000000..f3c65670f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/BasicOCSPResp.java
@@ -0,0 +1,212 @@
+package org.spongycastle.cert.ocsp;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ocsp.BasicOCSPResponse;
+import org.spongycastle.asn1.ocsp.ResponseData;
+import org.spongycastle.asn1.ocsp.SingleResponse;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.operator.ContentVerifier;
+import org.spongycastle.operator.ContentVerifierProvider;
+
+/**
+ * <pre>
+ * BasicOCSPResponse ::= SEQUENCE {
+ * tbsResponseData ResponseData,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ * </pre>
+ */
+public class BasicOCSPResp
+{
+ private BasicOCSPResponse resp;
+ private ResponseData data;
+ private Extensions extensions;
+
+ public BasicOCSPResp(
+ BasicOCSPResponse resp)
+ {
+ this.resp = resp;
+ this.data = resp.getTbsResponseData();
+ this.extensions = Extensions.getInstance(resp.getTbsResponseData().getResponseExtensions());
+ }
+
+ /**
+ * Return the DER encoding of the tbsResponseData field.
+ * @return DER encoding of tbsResponseData
+ */
+ public byte[] getTBSResponseData()
+ {
+ try
+ {
+ return resp.getTbsResponseData().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public int getVersion()
+ {
+ return data.getVersion().getValue().intValue() + 1;
+ }
+
+ public RespID getResponderId()
+ {
+ return new RespID(data.getResponderID());
+ }
+
+ public Date getProducedAt()
+ {
+ return OCSPUtils.extractDate(data.getProducedAt());
+ }
+
+ 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 boolean hasExtensions()
+ {
+ return extensions != null;
+ }
+
+ public Extension getExtension(ASN1ObjectIdentifier oid)
+ {
+ if (extensions != null)
+ {
+ return extensions.getExtension(oid);
+ }
+
+ return null;
+ }
+
+ public List getExtensionOIDs()
+ {
+ return OCSPUtils.getExtensionOIDs(extensions);
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return OCSPUtils.getCriticalExtensionOIDs(extensions);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return OCSPUtils.getNonCriticalExtensionOIDs(extensions);
+ }
+
+
+ public ASN1ObjectIdentifier getSignatureAlgOID()
+ {
+ return resp.getSignatureAlgorithm().getAlgorithm();
+ }
+
+ public byte[] getSignature()
+ {
+ return resp.getSignature().getBytes();
+ }
+
+ public X509CertificateHolder[] getCerts()
+ {
+ //
+ // load the certificates if we have any
+ //
+ if (resp.getCerts() != null)
+ {
+ ASN1Sequence s = resp.getCerts();
+
+ if (s != null)
+ {
+ X509CertificateHolder[] certs = new X509CertificateHolder[s.size()];
+
+ for (int i = 0; i != certs.length; i++)
+ {
+ certs[i] = new X509CertificateHolder(Certificate.getInstance(s.getObjectAt(i)));
+ }
+
+ return certs;
+ }
+
+ return OCSPUtils.EMPTY_CERTS;
+ }
+ else
+ {
+ return OCSPUtils.EMPTY_CERTS;
+ }
+ }
+
+ /**
+ * verify the signature against the tbsResponseData object we contain.
+ */
+ public boolean isSignatureValid(
+ ContentVerifierProvider verifierProvider)
+ throws OCSPException
+ {
+ try
+ {
+ ContentVerifier verifier = verifierProvider.get(resp.getSignatureAlgorithm());
+ OutputStream vOut = verifier.getOutputStream();
+
+ vOut.write(resp.getTbsResponseData().getEncoded(ASN1Encoding.DER));
+ vOut.close();
+
+ return verifier.verify(this.getSignature());
+ }
+ 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/pkix/src/main/java/org/spongycastle/cert/ocsp/BasicOCSPRespBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/BasicOCSPRespBuilder.java
new file mode 100644
index 000000000..32b50d1cf
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/BasicOCSPRespBuilder.java
@@ -0,0 +1,264 @@
+package org.spongycastle.cert.ocsp;
+
+import java.io.OutputStream;
+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.DERBitString;
+import org.spongycastle.asn1.DERGeneralizedTime;
+import org.spongycastle.asn1.DERNull;
+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.Extensions;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.DigestCalculator;
+
+/**
+ * Generator for basic OCSP response objects.
+ */
+public class BasicOCSPRespBuilder
+{
+ private List list = new ArrayList();
+ private Extensions responseExtensions = null;
+ private RespID responderID;
+
+ private class ResponseObject
+ {
+ CertificateID certId;
+ CertStatus certStatus;
+ DERGeneralizedTime thisUpdate;
+ DERGeneralizedTime nextUpdate;
+ Extensions extensions;
+
+ public ResponseObject(
+ CertificateID certId,
+ CertificateStatus certStatus,
+ Date thisUpdate,
+ Date nextUpdate,
+ Extensions 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 BasicOCSPRespBuilder(
+ RespID responderID)
+ {
+ this.responderID = responderID;
+ }
+
+ /**
+ * construct with the responderID to be the SHA-1 keyHash of the passed in public key.
+ *
+ * @param key the key info of the responder public key.
+ * @param digCalc a SHA-1 digest calculator
+ */
+ public BasicOCSPRespBuilder(
+ SubjectPublicKeyInfo key,
+ DigestCalculator digCalc)
+ throws OCSPException
+ {
+ this.responderID = new RespID(key, digCalc);
+ }
+
+ /**
+ * Add a response for a particular Certificate ID.
+ *
+ * @param certID certificate ID details
+ * @param certStatus status of the certificate - null if okay
+ */
+ public BasicOCSPRespBuilder addResponse(
+ CertificateID certID,
+ CertificateStatus certStatus)
+ {
+ list.add(new ResponseObject(certID, certStatus, new Date(), null, null));
+
+ return this;
+ }
+
+ /**
+ * 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 BasicOCSPRespBuilder addResponse(
+ CertificateID certID,
+ CertificateStatus certStatus,
+ Extensions singleExtensions)
+ {
+ list.add(new ResponseObject(certID, certStatus, new Date(), null, singleExtensions));
+
+ return this;
+ }
+
+ /**
+ * 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 BasicOCSPRespBuilder addResponse(
+ CertificateID certID,
+ CertificateStatus certStatus,
+ Date nextUpdate,
+ Extensions singleExtensions)
+ {
+ list.add(new ResponseObject(certID, certStatus, new Date(), nextUpdate, singleExtensions));
+
+ return this;
+ }
+
+ /**
+ * 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 BasicOCSPRespBuilder addResponse(
+ CertificateID certID,
+ CertificateStatus certStatus,
+ Date thisUpdate,
+ Date nextUpdate,
+ Extensions singleExtensions)
+ {
+ list.add(new ResponseObject(certID, certStatus, thisUpdate, nextUpdate, singleExtensions));
+
+ return this;
+ }
+
+ /**
+ * Set the extensions for the response.
+ *
+ * @param responseExtensions the extension object to carry.
+ */
+ public BasicOCSPRespBuilder setResponseExtensions(
+ Extensions responseExtensions)
+ {
+ this.responseExtensions = responseExtensions;
+
+ return this;
+ }
+
+ public BasicOCSPResp build(
+ ContentSigner signer,
+ X509CertificateHolder[] chain,
+ Date producedAt)
+ throws OCSPException
+ {
+ Iterator it = list.iterator();
+
+ 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 ASN1GeneralizedTime(producedAt), new DERSequence(responses), responseExtensions);
+ DERBitString bitSig;
+
+ try
+ {
+ OutputStream sigOut = signer.getOutputStream();
+
+ sigOut.write(tbsResp.getEncoded(ASN1Encoding.DER));
+ sigOut.close();
+
+ bitSig = new DERBitString(signer.getSignature());
+ }
+ catch (Exception e)
+ {
+ throw new OCSPException("exception processing TBSRequest: " + e.getMessage(), e);
+ }
+
+ AlgorithmIdentifier sigAlgId = signer.getAlgorithmIdentifier();
+
+ DERSequence chainSeq = null;
+ if (chain != null && chain.length > 0)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ for (int i = 0; i != chain.length; i++)
+ {
+ v.add(chain[i].toASN1Structure());
+ }
+
+ chainSeq = new DERSequence(v);
+ }
+
+ return new BasicOCSPResp(new BasicOCSPResponse(tbsResp, sigAlgId, bitSig, chainSeq));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/CertificateID.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/CertificateID.java
new file mode 100644
index 000000000..aac029ca5
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/CertificateID.java
@@ -0,0 +1,156 @@
+package org.spongycastle.cert.ocsp;
+
+import java.io.OutputStream;
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.ocsp.CertID;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+
+public class CertificateID
+{
+ public static final AlgorithmIdentifier HASH_SHA1 = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
+
+ 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 issuerCert issuing certificate
+ * @param number serial number
+ *
+ * @exception OCSPException if any problems occur creating the id fields.
+ */
+ public CertificateID(
+ DigestCalculator digestCalculator, X509CertificateHolder issuerCert,
+ BigInteger number)
+ throws OCSPException
+ {
+ this.id = createCertID(digestCalculator, issuerCert, new ASN1Integer(number));
+ }
+
+ public ASN1ObjectIdentifier getHashAlgOID()
+ {
+ return id.getHashAlgorithm().getAlgorithm();
+ }
+
+ 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(X509CertificateHolder issuerCert, DigestCalculatorProvider digCalcProvider)
+ throws OCSPException
+ {
+ try
+ {
+ return createCertID(digCalcProvider.get(id.getHashAlgorithm()), issuerCert, id.getSerialNumber()).equals(id);
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new OCSPException("unable to create digest calculator: " + e.getMessage(), e);
+ }
+ }
+
+ 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(DigestCalculator digCalc, X509CertificateHolder issuerCert, ASN1Integer serialNumber)
+ throws OCSPException
+ {
+ try
+ {
+ OutputStream dgOut = digCalc.getOutputStream();
+
+ dgOut.write(issuerCert.toASN1Structure().getSubject().getEncoded(ASN1Encoding.DER));
+ dgOut.close();
+
+ ASN1OctetString issuerNameHash = new DEROctetString(digCalc.getDigest());
+
+ SubjectPublicKeyInfo info = issuerCert.getSubjectPublicKeyInfo();
+
+ dgOut = digCalc.getOutputStream();
+
+ dgOut.write(info.getPublicKeyData().getBytes());
+ dgOut.close();
+
+ ASN1OctetString issuerKeyHash = new DEROctetString(digCalc.getDigest());
+
+ return new CertID(digCalc.getAlgorithmIdentifier(), issuerNameHash, issuerKeyHash, serialNumber);
+ }
+ catch (Exception e)
+ {
+ throw new OCSPException("problem creating ID: " + e, e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/CertificateStatus.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/CertificateStatus.java
new file mode 100644
index 000000000..ba84b8f88
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/CertificateStatus.java
@@ -0,0 +1,6 @@
+package org.spongycastle.cert.ocsp;
+
+public interface CertificateStatus
+{
+ public static final CertificateStatus GOOD = null;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPException.java
new file mode 100644
index 000000000..be91e3d8e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPException.java
@@ -0,0 +1,27 @@
+package org.spongycastle.cert.ocsp;
+
+public class OCSPException
+ extends Exception
+{
+ private Throwable cause;
+
+ public OCSPException(
+ String name)
+ {
+ super(name);
+ }
+
+ public OCSPException(
+ String name,
+ Throwable cause)
+ {
+ super(name);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPReq.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPReq.java
new file mode 100644
index 000000000..170896733
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPReq.java
@@ -0,0 +1,259 @@
+package org.spongycastle.cert.ocsp;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Exception;
+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.Certificate;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.cert.CertIOException;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.operator.ContentVerifier;
+import org.spongycastle.operator.ContentVerifierProvider;
+
+/**
+ * <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
+{
+ private static final X509CertificateHolder[] EMPTY_CERTS = new X509CertificateHolder[0];
+
+ private OCSPRequest req;
+ private Extensions extensions;
+
+ public OCSPReq(
+ OCSPRequest req)
+ {
+ this.req = req;
+ this.extensions = req.getTbsRequest().getRequestExtensions();
+ }
+
+ public OCSPReq(
+ byte[] req)
+ throws IOException
+ {
+ this(new ASN1InputStream(req));
+ }
+
+ private OCSPReq(
+ ASN1InputStream aIn)
+ throws IOException
+ {
+ try
+ {
+ this.req = OCSPRequest.getInstance(aIn.readObject());
+ if (req == null)
+ {
+ throw new CertIOException("malformed request: no request data found");
+ }
+ this.extensions = req.getTbsRequest().getRequestExtensions();
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CertIOException("malformed request: " + e.getMessage(), e);
+ }
+ catch (ClassCastException e)
+ {
+ throw new CertIOException("malformed request: " + e.getMessage(), e);
+ }
+ catch (ASN1Exception e)
+ {
+ throw new CertIOException("malformed request: " + e.getMessage(), e);
+ }
+ }
+
+ public int getVersionNumber()
+ {
+ 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 boolean hasExtensions()
+ {
+ return extensions != null;
+ }
+
+ public Extension getExtension(ASN1ObjectIdentifier oid)
+ {
+ if (extensions != null)
+ {
+ return extensions.getExtension(oid);
+ }
+
+ return null;
+ }
+
+ public List getExtensionOIDs()
+ {
+ return OCSPUtils.getExtensionOIDs(extensions);
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return OCSPUtils.getCriticalExtensionOIDs(extensions);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return OCSPUtils.getNonCriticalExtensionOIDs(extensions);
+ }
+
+ /**
+ * return the object identifier representing the signature algorithm
+ */
+ public ASN1ObjectIdentifier getSignatureAlgOID()
+ {
+ if (!this.isSigned())
+ {
+ return null;
+ }
+
+ return req.getOptionalSignature().getSignatureAlgorithm().getAlgorithm();
+ }
+
+ public byte[] getSignature()
+ {
+ if (!this.isSigned())
+ {
+ return null;
+ }
+
+ return req.getOptionalSignature().getSignature().getBytes();
+ }
+
+ public X509CertificateHolder[] getCerts()
+ {
+ //
+ // load the certificates if we have any
+ //
+ if (req.getOptionalSignature() != null)
+ {
+ ASN1Sequence s = req.getOptionalSignature().getCerts();
+
+ if (s != null)
+ {
+ X509CertificateHolder[] certs = new X509CertificateHolder[s.size()];
+
+ for (int i = 0; i != certs.length; i++)
+ {
+ certs[i] = new X509CertificateHolder(Certificate.getInstance(s.getObjectAt(i)));
+ }
+
+ return certs;
+ }
+
+ return EMPTY_CERTS;
+ }
+ else
+ {
+ return EMPTY_CERTS;
+ }
+ }
+
+ /**
+ * 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 isSignatureValid(
+ ContentVerifierProvider verifierProvider)
+ throws OCSPException
+ {
+ if (!this.isSigned())
+ {
+ throw new OCSPException("attempt to verify signature on unsigned object");
+ }
+
+ try
+ {
+ ContentVerifier verifier = verifierProvider.get(req.getOptionalSignature().getSignatureAlgorithm());
+ OutputStream sOut = verifier.getOutputStream();
+
+ sOut.write(req.getTbsRequest().getEncoded(ASN1Encoding.DER));
+
+ return verifier.verify(this.getSignature());
+ }
+ catch (Exception e)
+ {
+ throw new OCSPException("exception processing signature: " + 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();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPReqBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPReqBuilder.java
new file mode 100644
index 000000000..2bc0a6d1d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPReqBuilder.java
@@ -0,0 +1,199 @@
+package org.spongycastle.cert.ocsp;
+
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.DERBitString;
+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.x500.X500Name;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.operator.ContentSigner;
+
+public class OCSPReqBuilder
+{
+ private List list = new ArrayList();
+ private GeneralName requestorName = null;
+ private Extensions requestExtensions = null;
+
+ private class RequestObject
+ {
+ CertificateID certId;
+ Extensions extensions;
+
+ public RequestObject(
+ CertificateID certId,
+ Extensions extensions)
+ {
+ this.certId = certId;
+ this.extensions = extensions;
+ }
+
+ public Request toRequest()
+ throws Exception
+ {
+ return new Request(certId.toASN1Object(), extensions);
+ }
+ }
+
+ /**
+ * Add a request for the given CertificateID.
+ *
+ * @param certId certificate ID of interest
+ */
+ public OCSPReqBuilder addRequest(
+ CertificateID certId)
+ {
+ list.add(new RequestObject(certId, null));
+
+ return this;
+ }
+
+ /**
+ * Add a request with extensions
+ *
+ * @param certId certificate ID of interest
+ * @param singleRequestExtensions the extensions to attach to the request
+ */
+ public OCSPReqBuilder addRequest(
+ CertificateID certId,
+ Extensions singleRequestExtensions)
+ {
+ list.add(new RequestObject(certId, singleRequestExtensions));
+
+ return this;
+ }
+
+ /**
+ * Set the requestor name to the passed in X500Principal
+ *
+ * @param requestorName a X500Principal representing the requestor name.
+ */
+ public OCSPReqBuilder setRequestorName(
+ X500Name requestorName)
+ {
+ this.requestorName = new GeneralName(GeneralName.directoryName, requestorName);
+
+ return this;
+ }
+
+ public OCSPReqBuilder setRequestorName(
+ GeneralName requestorName)
+ {
+ this.requestorName = requestorName;
+
+ return this;
+ }
+
+ public OCSPReqBuilder setRequestExtensions(
+ Extensions requestExtensions)
+ {
+ this.requestExtensions = requestExtensions;
+
+ return this;
+ }
+
+ private OCSPReq generateRequest(
+ ContentSigner contentSigner,
+ X509CertificateHolder[] chain)
+ throws OCSPException
+ {
+ 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);
+
+ Signature signature = null;
+
+ if (contentSigner != null)
+ {
+ if (requestorName == null)
+ {
+ throw new OCSPException("requestorName must be specified if request is signed.");
+ }
+
+ try
+ {
+ OutputStream sOut = contentSigner.getOutputStream();
+
+ sOut.write(tbsReq.getEncoded(ASN1Encoding.DER));
+
+ sOut.close();
+ }
+ catch (Exception e)
+ {
+ throw new OCSPException("exception processing TBSRequest: " + e, e);
+ }
+
+ DERBitString bitSig = new DERBitString(contentSigner.getSignature());
+
+ AlgorithmIdentifier sigAlgId = contentSigner.getAlgorithmIdentifier();
+
+ if (chain != null && chain.length > 0)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ for (int i = 0; i != chain.length; i++)
+ {
+ v.add(chain[i].toASN1Structure());
+ }
+
+ 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 org.spongycastle.ocsp.OCSPException
+ */
+ public OCSPReq build()
+ throws OCSPException
+ {
+ return generateRequest(null, null);
+ }
+
+ public OCSPReq build(
+ ContentSigner signer,
+ X509CertificateHolder[] chain)
+ throws OCSPException, IllegalArgumentException
+ {
+ if (signer == null)
+ {
+ throw new IllegalArgumentException("no signer specified");
+ }
+
+ return generateRequest(signer, chain);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPResp.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPResp.java
new file mode 100644
index 000000000..0b587f70f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPResp.java
@@ -0,0 +1,141 @@
+package org.spongycastle.cert.ocsp;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.ASN1Exception;
+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;
+import org.spongycastle.cert.CertIOException;
+
+public class OCSPResp
+{
+ 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
+
+ private OCSPResponse resp;
+
+ public OCSPResp(
+ OCSPResponse resp)
+ {
+ this.resp = resp;
+ }
+
+ public OCSPResp(
+ byte[] resp)
+ throws IOException
+ {
+ this(new ByteArrayInputStream(resp));
+ }
+
+ public OCSPResp(
+ InputStream resp)
+ throws IOException
+ {
+ this(new ASN1InputStream(resp));
+ }
+
+ private OCSPResp(
+ ASN1InputStream aIn)
+ throws IOException
+ {
+ try
+ {
+ this.resp = OCSPResponse.getInstance(aIn.readObject());
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CertIOException("malformed response: " + e.getMessage(), e);
+ }
+ catch (ClassCastException e)
+ {
+ throw new CertIOException("malformed response: " + e.getMessage(), e);
+ }
+ catch (ASN1Exception e)
+ {
+ throw new CertIOException("malformed response: " + e.getMessage(), e);
+ }
+
+ if (resp == null)
+ {
+ throw new CertIOException("malformed response: no response data found");
+ }
+ }
+
+ 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();
+ }
+
+ public OCSPResponse toASN1Structure()
+ {
+ return resp;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPRespBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPRespBuilder.java
new file mode 100644
index 000000000..fe2da11d2
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPRespBuilder.java
@@ -0,0 +1,59 @@
+package org.spongycastle.cert.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.
+ */
+public class OCSPRespBuilder
+{
+ 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 build(
+ 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/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPUtils.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPUtils.java
new file mode 100644
index 000000000..a58ca0715
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/OCSPUtils.java
@@ -0,0 +1,64 @@
+package org.spongycastle.cert.ocsp;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.cert.X509CertificateHolder;
+
+class OCSPUtils
+{
+ static final X509CertificateHolder[] EMPTY_CERTS = new X509CertificateHolder[0];
+
+ static Set EMPTY_SET = Collections.unmodifiableSet(new HashSet());
+ static List EMPTY_LIST = Collections.unmodifiableList(new ArrayList());
+
+ static Date extractDate(ASN1GeneralizedTime time)
+ {
+ try
+ {
+ return time.getDate();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("exception processing GeneralizedTime: " + e.getMessage());
+ }
+ }
+
+ static Set getCriticalExtensionOIDs(Extensions extensions)
+ {
+ if (extensions == null)
+ {
+ return EMPTY_SET;
+ }
+
+ return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getCriticalExtensionOIDs())));
+ }
+
+ static Set getNonCriticalExtensionOIDs(Extensions extensions)
+ {
+ if (extensions == null)
+ {
+ return EMPTY_SET;
+ }
+
+ // TODO: should probably produce a set that imposes correct ordering
+ return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getNonCriticalExtensionOIDs())));
+ }
+
+ static List getExtensionOIDs(Extensions extensions)
+ {
+ if (extensions == null)
+ {
+ return EMPTY_LIST;
+ }
+
+ return Collections.unmodifiableList(Arrays.asList(extensions.getExtensionOIDs()));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/Req.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/Req.java
new file mode 100644
index 000000000..52c174dd5
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/Req.java
@@ -0,0 +1,25 @@
+package org.spongycastle.cert.ocsp;
+
+import org.spongycastle.asn1.ocsp.Request;
+import org.spongycastle.asn1.x509.Extensions;
+
+public class Req
+{
+ private Request req;
+
+ public Req(
+ Request req)
+ {
+ this.req = req;
+ }
+
+ public CertificateID getCertID()
+ {
+ return new CertificateID(req.getReqCert());
+ }
+
+ public Extensions getSingleRequestExtensions()
+ {
+ return req.getSingleRequestExtensions();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/RespData.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/RespData.java
new file mode 100644
index 000000000..3db55a3e0
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/RespData.java
@@ -0,0 +1,52 @@
+package org.spongycastle.cert.ocsp;
+
+import java.util.Date;
+
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ocsp.ResponseData;
+import org.spongycastle.asn1.ocsp.SingleResponse;
+import org.spongycastle.asn1.x509.Extensions;
+
+public class RespData
+{
+ private 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()
+ {
+ return OCSPUtils.extractDate(data.getProducedAt());
+ }
+
+ 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 Extensions getResponseExtensions()
+ {
+ return data.getResponseExtensions();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/RespID.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/RespID.java
new file mode 100644
index 000000000..7510200d5
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/RespID.java
@@ -0,0 +1,89 @@
+package org.spongycastle.cert.ocsp;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.ocsp.ResponderID;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.operator.DigestCalculator;
+
+/**
+ * Carrier for a ResponderID.
+ */
+public class RespID
+{
+ public static final AlgorithmIdentifier HASH_SHA1 = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
+
+ ResponderID id;
+
+ public RespID(
+ ResponderID id)
+ {
+ this.id = id;
+ }
+
+ public RespID(
+ X500Name name)
+ {
+ this.id = new ResponderID(name);
+ }
+
+ /**
+ * Calculate a RespID based on the public key of the responder.
+ *
+ * @param subjectPublicKeyInfo the info structure for the responder public key.
+ * @param digCalc a SHA-1 digest calculator.
+ * @throws OCSPException on exception creating ID.
+ */
+ public RespID(
+ SubjectPublicKeyInfo subjectPublicKeyInfo,
+ DigestCalculator digCalc)
+ throws OCSPException
+ {
+ try
+ {
+ if (!digCalc.getAlgorithmIdentifier().equals(HASH_SHA1))
+ {
+ throw new IllegalArgumentException("only SHA-1 can be used with RespID");
+ }
+
+ OutputStream digOut = digCalc.getOutputStream();
+
+ digOut.write(subjectPublicKeyInfo.getPublicKeyData().getBytes());
+ digOut.close();
+
+ this.id = new ResponderID(new DEROctetString(digCalc.getDigest()));
+ }
+ 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/pkix/src/main/java/org/spongycastle/cert/ocsp/RevokedStatus.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/RevokedStatus.java
new file mode 100644
index 000000000..0842ea582
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/RevokedStatus.java
@@ -0,0 +1,55 @@
+package org.spongycastle.cert.ocsp;
+
+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()
+ {
+ return OCSPUtils.extractDate(info.getRevocationTime());
+ }
+
+ 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/pkix/src/main/java/org/spongycastle/cert/ocsp/SingleResp.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/SingleResp.java
new file mode 100644
index 000000000..98beb8b3b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/SingleResp.java
@@ -0,0 +1,102 @@
+package org.spongycastle.cert.ocsp;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ocsp.CertStatus;
+import org.spongycastle.asn1.ocsp.RevokedInfo;
+import org.spongycastle.asn1.ocsp.SingleResponse;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+
+public class SingleResp
+{
+ private SingleResponse resp;
+ private Extensions extensions;
+
+ public SingleResp(
+ SingleResponse resp)
+ {
+ this.resp = resp;
+ this.extensions = resp.getSingleExtensions();
+ }
+
+ 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 CertificateStatus 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()
+ {
+ return OCSPUtils.extractDate(resp.getThisUpdate());
+ }
+
+ /**
+ * 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;
+ }
+
+ return OCSPUtils.extractDate(resp.getNextUpdate());
+ }
+
+ public boolean hasExtensions()
+ {
+ return extensions != null;
+ }
+
+ public Extension getExtension(ASN1ObjectIdentifier oid)
+ {
+ if (extensions != null)
+ {
+ return extensions.getExtension(oid);
+ }
+
+ return null;
+ }
+
+ public List getExtensionOIDs()
+ {
+ return OCSPUtils.getExtensionOIDs(extensions);
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return OCSPUtils.getCriticalExtensionOIDs(extensions);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return OCSPUtils.getNonCriticalExtensionOIDs(extensions);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/UnknownStatus.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/UnknownStatus.java
new file mode 100644
index 000000000..42eda7217
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/UnknownStatus.java
@@ -0,0 +1,12 @@
+package org.spongycastle.cert.ocsp;
+
+/**
+ * wrapper for the UnknownInfo object
+ */
+public class UnknownStatus
+ implements CertificateStatus
+{
+ public UnknownStatus()
+ {
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaBasicOCSPRespBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaBasicOCSPRespBuilder.java
new file mode 100644
index 000000000..cbd591dbb
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaBasicOCSPRespBuilder.java
@@ -0,0 +1,18 @@
+package org.spongycastle.cert.ocsp.jcajce;
+
+import java.security.PublicKey;
+
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.ocsp.BasicOCSPRespBuilder;
+import org.spongycastle.cert.ocsp.OCSPException;
+import org.spongycastle.operator.DigestCalculator;
+
+public class JcaBasicOCSPRespBuilder
+ extends BasicOCSPRespBuilder
+{
+ public JcaBasicOCSPRespBuilder(PublicKey key, DigestCalculator digCalc)
+ throws OCSPException
+ {
+ super(SubjectPublicKeyInfo.getInstance(key.getEncoded()), digCalc);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaCertificateID.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaCertificateID.java
new file mode 100644
index 000000000..d59e7e04c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaCertificateID.java
@@ -0,0 +1,20 @@
+package org.spongycastle.cert.ocsp.jcajce;
+
+import java.math.BigInteger;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.cert.ocsp.CertificateID;
+import org.spongycastle.cert.ocsp.OCSPException;
+import org.spongycastle.operator.DigestCalculator;
+
+public class JcaCertificateID
+ extends CertificateID
+{
+ public JcaCertificateID(DigestCalculator digestCalculator, X509Certificate issuerCert, BigInteger number)
+ throws OCSPException, CertificateEncodingException
+ {
+ super(digestCalculator, new JcaX509CertificateHolder(issuerCert), number);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaRespID.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaRespID.java
new file mode 100644
index 000000000..55a390be9
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/ocsp/jcajce/JcaRespID.java
@@ -0,0 +1,26 @@
+package org.spongycastle.cert.ocsp.jcajce;
+
+import java.security.PublicKey;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.ocsp.OCSPException;
+import org.spongycastle.cert.ocsp.RespID;
+import org.spongycastle.operator.DigestCalculator;
+
+public class JcaRespID
+ extends RespID
+{
+ public JcaRespID(X500Principal name)
+ {
+ super(X500Name.getInstance(name.getEncoded()));
+ }
+
+ public JcaRespID(PublicKey pubKey, DigestCalculator digCalc)
+ throws OCSPException
+ {
+ super(SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()), digCalc);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPath.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPath.java
new file mode 100644
index 000000000..bbb20a4db
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPath.java
@@ -0,0 +1,80 @@
+package org.spongycastle.cert.path;
+
+import org.spongycastle.cert.X509CertificateHolder;
+
+public class CertPath
+{
+ private final X509CertificateHolder[] certificates;
+
+ public CertPath(X509CertificateHolder[] certificates)
+ {
+ this.certificates = copyArray(certificates);
+ }
+
+ public X509CertificateHolder[] getCertificates()
+ {
+ return copyArray(certificates);
+ }
+
+ public CertPathValidationResult validate(CertPathValidation[] ruleSet)
+ {
+ CertPathValidationContext context = new CertPathValidationContext(CertPathUtils.getCriticalExtensionsOIDs(certificates));
+
+ for (int i = 0; i != ruleSet.length; i++)
+ {
+ for (int j = certificates.length - 1; j >= 0; j--)
+ {
+ try
+ {
+ context.setIsEndEntity(j == 0);
+ ruleSet[i].validate(context, certificates[j]);
+ }
+ catch (CertPathValidationException e)
+ { // TODO: introduce object to hold (i and e)
+ return new CertPathValidationResult(context, j, i, e);
+ }
+ }
+ }
+
+ return new CertPathValidationResult(context);
+ }
+
+ public CertPathValidationResult evaluate(CertPathValidation[] ruleSet)
+ {
+ CertPathValidationContext context = new CertPathValidationContext(CertPathUtils.getCriticalExtensionsOIDs(certificates));
+
+ CertPathValidationResultBuilder builder = new CertPathValidationResultBuilder();
+
+ for (int i = 0; i != ruleSet.length; i++)
+ {
+ for (int j = certificates.length - 1; j >= 0; j--)
+ {
+ try
+ {
+ context.setIsEndEntity(j == 0);
+ ruleSet[i].validate(context, certificates[j]);
+ }
+ catch (CertPathValidationException e)
+ {
+ builder.addException(e);
+ }
+ }
+ }
+
+ return builder.build();
+ }
+
+ private X509CertificateHolder[] copyArray(X509CertificateHolder[] array)
+ {
+ X509CertificateHolder[] rv = new X509CertificateHolder[array.length];
+
+ System.arraycopy(array, 0, rv, 0, rv.length);
+
+ return rv;
+ }
+
+ public int length()
+ {
+ return certificates.length;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathUtils.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathUtils.java
new file mode 100644
index 000000000..257e0bb88
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathUtils.java
@@ -0,0 +1,21 @@
+package org.spongycastle.cert.path;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.spongycastle.cert.X509CertificateHolder;
+
+class CertPathUtils
+{
+ static Set getCriticalExtensionsOIDs(X509CertificateHolder[] certificates)
+ {
+ Set criticalExtensions = new HashSet();
+
+ for (int i = 0; i != certificates.length; i++)
+ {
+ criticalExtensions.addAll(certificates[i].getCriticalExtensionOIDs());
+ }
+
+ return criticalExtensions;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidation.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidation.java
new file mode 100644
index 000000000..11f483670
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidation.java
@@ -0,0 +1,11 @@
+package org.spongycastle.cert.path;
+
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.util.Memoable;
+
+public interface CertPathValidation
+ extends Memoable
+{
+ public void validate(CertPathValidationContext context, X509CertificateHolder certificate)
+ throws CertPathValidationException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationContext.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationContext.java
new file mode 100644
index 000000000..010b4ef69
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationContext.java
@@ -0,0 +1,61 @@
+package org.spongycastle.cert.path;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.util.Memoable;
+
+public class CertPathValidationContext
+ implements Memoable
+{
+ private Set criticalExtensions;
+
+ private Set handledExtensions = new HashSet();
+ private boolean endEntity;
+ private int index;
+
+ public CertPathValidationContext(Set criticalExtensionsOIDs)
+ {
+ this.criticalExtensions = criticalExtensionsOIDs;
+ }
+
+ public void addHandledExtension(ASN1ObjectIdentifier extensionIdentifier)
+ {
+ this.handledExtensions.add(extensionIdentifier);
+ }
+
+ public void setIsEndEntity(boolean isEndEntity)
+ {
+ this.endEntity = isEndEntity;
+ }
+
+ public Set getUnhandledCriticalExtensionOIDs()
+ {
+ Set rv = new HashSet(criticalExtensions);
+
+ rv.removeAll(handledExtensions);
+
+ return rv;
+ }
+
+ /**
+ * Returns true if the current certificate is the end-entity certificate.
+ *
+ * @return if current cert end-entity, false otherwise.
+ */
+ public boolean isEndEntity()
+ {
+ return endEntity;
+ }
+
+ public Memoable copy()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void reset(Memoable other)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationException.java
new file mode 100644
index 000000000..0a1188d12
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationException.java
@@ -0,0 +1,24 @@
+package org.spongycastle.cert.path;
+
+public class CertPathValidationException
+ extends Exception
+{
+ private final Exception cause;
+
+ public CertPathValidationException(String msg)
+ {
+ this(msg, null);
+ }
+
+ public CertPathValidationException(String msg, Exception cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationResult.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationResult.java
new file mode 100644
index 000000000..276ef8d48
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationResult.java
@@ -0,0 +1,66 @@
+package org.spongycastle.cert.path;
+
+import java.util.Collections;
+import java.util.Set;
+
+public class CertPathValidationResult
+{
+ private final boolean isValid;
+ private final CertPathValidationException cause;
+ private final Set unhandledCriticalExtensionOIDs;
+
+ private int[] certIndexes;
+
+ public CertPathValidationResult(CertPathValidationContext context)
+ {
+ this.unhandledCriticalExtensionOIDs = Collections.unmodifiableSet(context.getUnhandledCriticalExtensionOIDs());
+ this.isValid = this.unhandledCriticalExtensionOIDs.isEmpty();
+ cause = null;
+ }
+
+ public CertPathValidationResult(CertPathValidationContext context, int certIndex, int ruleIndex, CertPathValidationException cause)
+ {
+ this.unhandledCriticalExtensionOIDs = Collections.unmodifiableSet(context.getUnhandledCriticalExtensionOIDs());
+ this.isValid = false;
+ this.cause = cause;
+ }
+
+ public CertPathValidationResult(CertPathValidationContext context, int[] certIndexes, int[] ruleIndexes, CertPathValidationException[] cause)
+ {
+ // TODO
+ this.unhandledCriticalExtensionOIDs = Collections.unmodifiableSet(context.getUnhandledCriticalExtensionOIDs());
+ this.isValid = false;
+ this.cause = cause[0];
+ this.certIndexes = certIndexes;
+ }
+
+ public boolean isValid()
+ {
+ return isValid;
+ }
+
+ public Exception getCause()
+ {
+ if (cause != null)
+ {
+ return cause;
+ }
+
+ if (!unhandledCriticalExtensionOIDs.isEmpty())
+ {
+ return new CertPathValidationException("Unhandled Critical Extensions");
+ }
+
+ return null;
+ }
+
+ public Set getUnhandledCriticalExtensionOIDs()
+ {
+ return unhandledCriticalExtensionOIDs;
+ }
+
+ public boolean isDetailed()
+ {
+ return this.certIndexes != null;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationResultBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationResultBuilder.java
new file mode 100644
index 000000000..80bf7ff25
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/CertPathValidationResultBuilder.java
@@ -0,0 +1,14 @@
+package org.spongycastle.cert.path;
+
+class CertPathValidationResultBuilder
+{
+ public CertPathValidationResult build()
+ {
+ return new CertPathValidationResult(null, 0, 0, null);
+ }
+
+ public void addException(CertPathValidationException exception)
+ {
+ //To change body of created methods use File | Settings | File Templates.
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/BasicConstraintsValidation.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/BasicConstraintsValidation.java
new file mode 100644
index 000000000..bfe0f1a4d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/BasicConstraintsValidation.java
@@ -0,0 +1,103 @@
+package org.spongycastle.cert.path.validations;
+
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.path.CertPathValidation;
+import org.spongycastle.cert.path.CertPathValidationContext;
+import org.spongycastle.cert.path.CertPathValidationException;
+import org.spongycastle.util.Memoable;
+
+public class BasicConstraintsValidation
+ implements CertPathValidation
+{
+ private boolean isMandatory;
+ private BasicConstraints bc;
+ private int maxPathLength;
+
+ public BasicConstraintsValidation()
+ {
+ this(true);
+ }
+
+ public BasicConstraintsValidation(boolean isMandatory)
+ {
+ this.isMandatory = isMandatory;
+ }
+
+ public void validate(CertPathValidationContext context, X509CertificateHolder certificate)
+ throws CertPathValidationException
+ {
+ if (maxPathLength < 0)
+ {
+ throw new CertPathValidationException("BasicConstraints path length exceeded");
+ }
+
+ context.addHandledExtension(Extension.basicConstraints);
+
+ BasicConstraints certBC = BasicConstraints.fromExtensions(certificate.getExtensions());
+
+ if (certBC != null)
+ {
+ if (bc != null)
+ {
+ if (certBC.isCA())
+ {
+ BigInteger pathLengthConstraint = certBC.getPathLenConstraint();
+
+ if (pathLengthConstraint != null)
+ {
+ int plc = pathLengthConstraint.intValue();
+
+ if (plc < maxPathLength)
+ {
+ maxPathLength = plc;
+ bc = certBC;
+ }
+ }
+ }
+ }
+ else
+ {
+ bc = certBC;
+ if (certBC.isCA())
+ {
+ maxPathLength = certBC.getPathLenConstraint().intValue();
+ }
+ }
+ }
+ else
+ {
+ if (bc != null)
+ {
+ maxPathLength--;
+ }
+ }
+
+ if (isMandatory && bc == null)
+ {
+ throw new CertPathValidationException("BasicConstraints not present in path");
+ }
+ }
+
+ public Memoable copy()
+ {
+ BasicConstraintsValidation v = new BasicConstraintsValidation(isMandatory);
+
+ v.bc = this.bc;
+ v.maxPathLength = this.maxPathLength;
+
+ return v;
+ }
+
+ public void reset(Memoable other)
+ {
+ BasicConstraintsValidation v = (BasicConstraintsValidation)other;
+
+ this.isMandatory = v.isMandatory;
+ this.bc = v.bc;
+ this.maxPathLength = v.maxPathLength;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/CRLValidation.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/CRLValidation.java
new file mode 100644
index 000000000..325126e1a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/CRLValidation.java
@@ -0,0 +1,78 @@
+package org.spongycastle.cert.path.validations;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cert.X509CRLHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.path.CertPathValidation;
+import org.spongycastle.cert.path.CertPathValidationContext;
+import org.spongycastle.cert.path.CertPathValidationException;
+import org.spongycastle.util.Memoable;
+import org.spongycastle.util.Selector;
+import org.spongycastle.util.Store;
+
+public class CRLValidation
+ implements CertPathValidation
+{
+ private Store crls;
+ private X500Name workingIssuerName;
+
+ public CRLValidation(X500Name trustAnchorName, Store crls)
+ {
+ this.workingIssuerName = trustAnchorName;
+ this.crls = crls;
+ }
+
+ public void validate(CertPathValidationContext context, X509CertificateHolder certificate)
+ throws CertPathValidationException
+ {
+ // TODO: add handling of delta CRLs
+ Collection matches = crls.getMatches(new Selector()
+ {
+ public boolean match(Object obj)
+ {
+ X509CRLHolder crl = (X509CRLHolder)obj;
+
+ return (crl.getIssuer().equals(workingIssuerName));
+ }
+
+ public Object clone()
+ {
+ return this;
+ }
+ });
+
+ if (matches.isEmpty())
+ {
+ throw new CertPathValidationException("CRL for " + workingIssuerName + " not found");
+ }
+
+ for (Iterator it = matches.iterator(); it.hasNext();)
+ {
+ X509CRLHolder crl = (X509CRLHolder)it.next();
+
+ // TODO: not quite right!
+ if (crl.getRevokedCertificate(certificate.getSerialNumber()) != null)
+ {
+ throw new CertPathValidationException("Certificate revoked");
+ }
+ }
+
+ this.workingIssuerName = certificate.getSubject();
+ }
+
+ public Memoable copy()
+ {
+ return new CRLValidation(workingIssuerName, crls);
+ }
+
+ public void reset(Memoable other)
+ {
+ CRLValidation v = (CRLValidation)other;
+
+ this.workingIssuerName = v.workingIssuerName;
+ this.crls = v.crls;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/CertificatePoliciesValidation.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/CertificatePoliciesValidation.java
new file mode 100644
index 000000000..7015adb05
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/CertificatePoliciesValidation.java
@@ -0,0 +1,146 @@
+package org.spongycastle.cert.path.validations;
+
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.PolicyConstraints;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.path.CertPathValidation;
+import org.spongycastle.cert.path.CertPathValidationContext;
+import org.spongycastle.cert.path.CertPathValidationException;
+import org.spongycastle.util.Memoable;
+
+public class CertificatePoliciesValidation
+ implements CertPathValidation
+{
+ private int explicitPolicy;
+ private int policyMapping;
+ private int inhibitAnyPolicy;
+
+ CertificatePoliciesValidation(int pathLength)
+ {
+ this(pathLength, false, false, false);
+ }
+
+ CertificatePoliciesValidation(int pathLength, boolean isExplicitPolicyRequired, boolean isAnyPolicyInhibited, boolean isPolicyMappingInhibited)
+ {
+ //
+ // (d)
+ //
+
+ if (isExplicitPolicyRequired)
+ {
+ explicitPolicy = 0;
+ }
+ else
+ {
+ explicitPolicy = pathLength + 1;
+ }
+
+ //
+ // (e)
+ //
+ if (isAnyPolicyInhibited)
+ {
+ inhibitAnyPolicy = 0;
+ }
+ else
+ {
+ inhibitAnyPolicy = pathLength + 1;
+ }
+
+ //
+ // (f)
+ //
+ if (isPolicyMappingInhibited)
+ {
+ policyMapping = 0;
+ }
+ else
+ {
+ policyMapping = pathLength + 1;
+ }
+ }
+
+ public void validate(CertPathValidationContext context, X509CertificateHolder certificate)
+ throws CertPathValidationException
+ {
+ context.addHandledExtension(Extension.policyConstraints);
+ context.addHandledExtension(Extension.inhibitAnyPolicy);
+
+ if (!context.isEndEntity())
+ {
+ if (!ValidationUtils.isSelfIssued(certificate))
+ {
+ //
+ // H (1), (2), (3)
+ //
+ explicitPolicy = countDown(explicitPolicy);
+ policyMapping = countDown(policyMapping);
+ inhibitAnyPolicy = countDown(inhibitAnyPolicy);
+
+ //
+ // I (1), (2)
+ //
+ PolicyConstraints policyConstraints = PolicyConstraints.fromExtensions(certificate.getExtensions());
+
+ if (policyConstraints != null)
+ {
+ BigInteger requireExplicitPolicyMapping = policyConstraints.getRequireExplicitPolicyMapping();
+ if (requireExplicitPolicyMapping != null)
+ {
+ if (requireExplicitPolicyMapping.intValue() < explicitPolicy)
+ {
+ explicitPolicy = requireExplicitPolicyMapping.intValue();
+ }
+ }
+
+ BigInteger inhibitPolicyMapping = policyConstraints.getInhibitPolicyMapping();
+ if (inhibitPolicyMapping != null)
+ {
+ if (inhibitPolicyMapping.intValue() < policyMapping)
+ {
+ policyMapping = inhibitPolicyMapping.intValue();
+ }
+ }
+ }
+
+ //
+ // J
+ //
+ Extension ext = certificate.getExtension(Extension.inhibitAnyPolicy);
+
+ if (ext != null)
+ {
+ int extValue = ASN1Integer.getInstance(ext.getParsedValue()).getValue().intValue();
+
+ if (extValue < inhibitAnyPolicy)
+ {
+ inhibitAnyPolicy = extValue;
+ }
+ }
+ }
+ }
+ }
+
+ private int countDown(int policyCounter)
+ {
+ if (policyCounter != 0)
+ {
+ return policyCounter - 1;
+ }
+
+ return 0;
+ }
+
+ public Memoable copy()
+ {
+ return new CertificatePoliciesValidation(0); // TODO:
+ }
+
+ public void reset(Memoable other)
+ {
+ CertificatePoliciesValidation v = (CertificatePoliciesValidation)other; // TODO:
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/CertificatePoliciesValidationBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/CertificatePoliciesValidationBuilder.java
new file mode 100644
index 000000000..44817b61e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/CertificatePoliciesValidationBuilder.java
@@ -0,0 +1,35 @@
+package org.spongycastle.cert.path.validations;
+
+import org.spongycastle.cert.path.CertPath;
+
+public class CertificatePoliciesValidationBuilder
+{
+ private boolean isExplicitPolicyRequired;
+ private boolean isAnyPolicyInhibited;
+ private boolean isPolicyMappingInhibited;
+
+ public void setAnyPolicyInhibited(boolean anyPolicyInhibited)
+ {
+ isAnyPolicyInhibited = anyPolicyInhibited;
+ }
+
+ public void setExplicitPolicyRequired(boolean explicitPolicyRequired)
+ {
+ isExplicitPolicyRequired = explicitPolicyRequired;
+ }
+
+ public void setPolicyMappingInhibited(boolean policyMappingInhibited)
+ {
+ isPolicyMappingInhibited = policyMappingInhibited;
+ }
+
+ public CertificatePoliciesValidation build(int pathLen)
+ {
+ return new CertificatePoliciesValidation(pathLen, isExplicitPolicyRequired, isAnyPolicyInhibited, isPolicyMappingInhibited);
+ }
+
+ public CertificatePoliciesValidation build(CertPath path)
+ {
+ return build(path.length());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/KeyUsageValidation.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/KeyUsageValidation.java
new file mode 100644
index 000000000..7211b7cd9
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/KeyUsageValidation.java
@@ -0,0 +1,63 @@
+package org.spongycastle.cert.path.validations;
+
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.KeyUsage;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.path.CertPathValidation;
+import org.spongycastle.cert.path.CertPathValidationContext;
+import org.spongycastle.cert.path.CertPathValidationException;
+import org.spongycastle.util.Memoable;
+
+public class KeyUsageValidation
+ implements CertPathValidation
+{
+ private boolean isMandatory;
+
+ public KeyUsageValidation()
+ {
+ this(true);
+ }
+
+ public KeyUsageValidation(boolean isMandatory)
+ {
+ this.isMandatory = isMandatory;
+ }
+
+ public void validate(CertPathValidationContext context, X509CertificateHolder certificate)
+ throws CertPathValidationException
+ {
+ context.addHandledExtension(Extension.keyUsage);
+
+ if (!context.isEndEntity())
+ {
+ KeyUsage usage = KeyUsage.fromExtensions(certificate.getExtensions());
+
+ if (usage != null)
+ {
+ if (!usage.hasUsages(KeyUsage.keyCertSign))
+ {
+ throw new CertPathValidationException("Issuer certificate KeyUsage extension does not permit key signing");
+ }
+ }
+ else
+ {
+ if (isMandatory)
+ {
+ throw new CertPathValidationException("KeyUsage extension not present in CA certificate");
+ }
+ }
+ }
+ }
+
+ public Memoable copy()
+ {
+ return new KeyUsageValidation(isMandatory);
+ }
+
+ public void reset(Memoable other)
+ {
+ KeyUsageValidation v = (KeyUsageValidation)other;
+
+ this.isMandatory = v.isMandatory;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/ParentCertIssuedValidation.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/ParentCertIssuedValidation.java
new file mode 100644
index 000000000..dff47fb77
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/ParentCertIssuedValidation.java
@@ -0,0 +1,127 @@
+package org.spongycastle.cert.path.validations;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Null;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.CertException;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509ContentVerifierProviderBuilder;
+import org.spongycastle.cert.path.CertPathValidation;
+import org.spongycastle.cert.path.CertPathValidationContext;
+import org.spongycastle.cert.path.CertPathValidationException;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.util.Memoable;
+
+public class ParentCertIssuedValidation
+ implements CertPathValidation
+{
+ private X509ContentVerifierProviderBuilder contentVerifierProvider;
+
+ private X500Name workingIssuerName;
+ private SubjectPublicKeyInfo workingPublicKey;
+ private AlgorithmIdentifier workingAlgId;
+
+ public ParentCertIssuedValidation(X509ContentVerifierProviderBuilder contentVerifierProvider)
+ {
+ this.contentVerifierProvider = contentVerifierProvider;
+ }
+
+ public void validate(CertPathValidationContext context, X509CertificateHolder certificate)
+ throws CertPathValidationException
+ {
+ if (workingIssuerName != null)
+ {
+ if (!workingIssuerName.equals(certificate.getIssuer()))
+ {
+ throw new CertPathValidationException("Certificate issue does not match parent");
+ }
+ }
+
+ if (workingPublicKey != null)
+ {
+ try
+ {
+ SubjectPublicKeyInfo validatingKeyInfo;
+
+ if (workingPublicKey.getAlgorithm().equals(workingAlgId))
+ {
+ validatingKeyInfo = workingPublicKey;
+ }
+ else
+ {
+ validatingKeyInfo = new SubjectPublicKeyInfo(workingAlgId, workingPublicKey.parsePublicKey());
+ }
+
+ if (!certificate.isSignatureValid(contentVerifierProvider.build(validatingKeyInfo)))
+ {
+ throw new CertPathValidationException("Certificate signature not for public key in parent");
+ }
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new CertPathValidationException("Unable to create verifier: " + e.getMessage(), e);
+ }
+ catch (CertException e)
+ {
+ throw new CertPathValidationException("Unable to validate signature: " + e.getMessage(), e);
+ }
+ catch (IOException e)
+ {
+ throw new CertPathValidationException("Unable to build public key: " + e.getMessage(), e);
+ }
+ }
+
+ workingIssuerName = certificate.getSubject();
+ workingPublicKey = certificate.getSubjectPublicKeyInfo();
+
+ if (workingAlgId != null)
+ {
+ // check for inherited parameters
+ if (workingPublicKey.getAlgorithm().getAlgorithm().equals(workingAlgId.getAlgorithm()))
+ {
+ if (!isNull(workingPublicKey.getAlgorithm().getParameters()))
+ {
+ workingAlgId = workingPublicKey.getAlgorithm();
+ }
+ }
+ else
+ {
+ workingAlgId = workingPublicKey.getAlgorithm();
+ }
+ }
+ else
+ {
+ workingAlgId = workingPublicKey.getAlgorithm();
+ }
+ }
+
+ private boolean isNull(ASN1Encodable obj)
+ {
+ return obj == null || obj instanceof ASN1Null;
+ }
+
+ public Memoable copy()
+ {
+ ParentCertIssuedValidation v = new ParentCertIssuedValidation(contentVerifierProvider);
+
+ v.workingAlgId = this.workingAlgId;
+ v.workingIssuerName = this.workingIssuerName;
+ v.workingPublicKey = this.workingPublicKey;
+
+ return v;
+ }
+
+ public void reset(Memoable other)
+ {
+ ParentCertIssuedValidation v = (ParentCertIssuedValidation)other;
+
+ this.contentVerifierProvider = v.contentVerifierProvider;
+ this.workingAlgId = v.workingAlgId;
+ this.workingIssuerName = v.workingIssuerName;
+ this.workingPublicKey = v.workingPublicKey;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/ValidationUtils.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/ValidationUtils.java
new file mode 100644
index 000000000..5dbf495ad
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/path/validations/ValidationUtils.java
@@ -0,0 +1,11 @@
+package org.spongycastle.cert.path.validations;
+
+import org.spongycastle.cert.X509CertificateHolder;
+
+class ValidationUtils
+{
+ static boolean isSelfIssued(X509CertificateHolder cert)
+ {
+ return cert.getSubject().equals(cert.getIssuer());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/MSOutlookKeyIdCalculator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/MSOutlookKeyIdCalculator.java
new file mode 100644
index 000000000..e52e6222e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/MSOutlookKeyIdCalculator.java
@@ -0,0 +1,33 @@
+package org.spongycastle.cert.selector;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+
+class MSOutlookKeyIdCalculator
+{
+ static byte[] calculateKeyId(SubjectPublicKeyInfo info)
+ {
+ Digest dig = new SHA1Digest(); // TODO: include definition of SHA-1 here
+ byte[] hash = new byte[dig.getDigestSize()];
+ byte[] spkiEnc = new byte[0];
+ try
+ {
+ spkiEnc = info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return new byte[0];
+ }
+
+ // try the outlook 2010 calculation
+ dig.update(spkiEnc, 0, spkiEnc.length);
+
+ dig.doFinal(hash, 0);
+
+ return hash;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelector.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelector.java
new file mode 100644
index 000000000..3ae30b336
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelector.java
@@ -0,0 +1,268 @@
+package org.spongycastle.cert.selector;
+
+import java.math.BigInteger;
+import java.util.Collection;
+import java.util.Date;
+
+import org.spongycastle.asn1.x509.Extension;
+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.cert.AttributeCertificateHolder;
+import org.spongycastle.cert.AttributeCertificateIssuer;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.util.Selector;
+
+/**
+ * This class is an <code>Selector</code> like implementation to select
+ * attribute certificates from a given set of criteria.
+ */
+public class X509AttributeCertificateHolderSelector
+ implements Selector
+{
+
+ // TODO: name constraints???
+
+ private final AttributeCertificateHolder holder;
+
+ private final AttributeCertificateIssuer issuer;
+
+ private final BigInteger serialNumber;
+
+ private final Date attributeCertificateValid;
+
+ private final X509AttributeCertificateHolder attributeCert;
+
+ private final Collection targetNames;
+
+ private final Collection targetGroups;
+
+ X509AttributeCertificateHolderSelector(
+ AttributeCertificateHolder holder,
+ AttributeCertificateIssuer issuer,
+ BigInteger serialNumber,
+ Date attributeCertificateValid,
+ X509AttributeCertificateHolder attributeCert,
+ Collection targetNames,
+ Collection targetGroups)
+ {
+ this.holder = holder;
+ this.issuer = issuer;
+ this.serialNumber = serialNumber;
+ this.attributeCertificateValid = attributeCertificateValid;
+ this.attributeCert = attributeCert;
+ this.targetNames = targetNames;
+ this.targetGroups = targetGroups;
+ }
+
+ /**
+ * Decides if the given attribute certificate should be selected.
+ *
+ * @param obj The X509AttributeCertificateHolder which should be checked.
+ * @return <code>true</code> if the attribute certificate is a match
+ * <code>false</code> otherwise.
+ */
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509AttributeCertificateHolder))
+ {
+ return false;
+ }
+
+ X509AttributeCertificateHolder attrCert = (X509AttributeCertificateHolder)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)
+ {
+ if (!attrCert.isValidOn(attributeCertificateValid))
+ {
+ return false;
+ }
+ }
+ if (!targetNames.isEmpty() || !targetGroups.isEmpty())
+ {
+ Extension targetInfoExt = attrCert.getExtension(Extension.targetInformation);
+ if (targetInfoExt != null)
+ {
+ TargetInformation targetinfo;
+ try
+ {
+ targetinfo = TargetInformation.getInstance(targetInfoExt.getParsedValue());
+ }
+ 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()
+ {
+ X509AttributeCertificateHolderSelector sel = new X509AttributeCertificateHolderSelector(
+ holder, issuer, serialNumber, attributeCertificateValid, attributeCert, targetNames, targetGroups);
+
+ return sel;
+ }
+
+ /**
+ * Returns the attribute certificate holder which must be matched.
+ *
+ * @return Returns an X509AttributeCertificateHolder
+ */
+ public X509AttributeCertificateHolder getAttributeCert()
+ {
+ return attributeCert;
+ }
+
+ /**
+ * Get the criteria for the validity.
+ *
+ * @return Returns the attributeCertificateValid.
+ */
+ public Date getAttributeCertificateValid()
+ {
+ if (attributeCertificateValid != null)
+ {
+ return new Date(attributeCertificateValid.getTime());
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets the holder.
+ *
+ * @return Returns the holder.
+ */
+ public AttributeCertificateHolder getHolder()
+ {
+ return holder;
+ }
+
+ /**
+ * Returns the issuer criterion.
+ *
+ * @return Returns the issuer.
+ */
+ public AttributeCertificateIssuer getIssuer()
+ {
+ return issuer;
+ }
+
+ /**
+ * Gets the serial number the attribute certificate must have.
+ *
+ * @return Returns the serialNumber.
+ */
+ public BigInteger getSerialNumber()
+ {
+ return serialNumber;
+ }
+
+ /**
+ * Gets the target names. The collection consists of GeneralName objects.
+ * <p>
+ * The returned collection is immutable.
+ *
+ * @return The collection of target names
+ */
+ public Collection getTargetNames()
+ {
+ return targetNames;
+ }
+
+ /**
+ * Gets the target groups. The collection consists of GeneralName objects.
+ * <p>
+ * The returned collection is immutable.
+ *
+ * @return The collection of target groups.
+ */
+ public Collection getTargetGroups()
+ {
+ return targetGroups;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelectorBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelectorBuilder.java
new file mode 100644
index 000000000..35df571d2
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelectorBuilder.java
@@ -0,0 +1,194 @@
+package org.spongycastle.cert.selector;
+
+import java.io.IOException;
+import java.math.BigInteger;
+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.x509.GeneralName;
+import org.spongycastle.cert.AttributeCertificateHolder;
+import org.spongycastle.cert.AttributeCertificateIssuer;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+
+/**
+ * This class builds selectors according to the set criteria.
+ */
+public class X509AttributeCertificateHolderSelectorBuilder
+{
+
+ // TODO: name constraints???
+
+ private AttributeCertificateHolder holder;
+
+ private AttributeCertificateIssuer issuer;
+
+ private BigInteger serialNumber;
+
+ private Date attributeCertificateValid;
+
+ private X509AttributeCertificateHolder attributeCert;
+
+ private Collection targetNames = new HashSet();
+
+ private Collection targetGroups = new HashSet();
+
+ public X509AttributeCertificateHolderSelectorBuilder()
+ {
+ }
+
+ /**
+ * Set the attribute certificate to be matched. If <code>null</code> is
+ * given any will do.
+ *
+ * @param attributeCert The attribute certificate holder to set.
+ */
+ public void setAttributeCert(X509AttributeCertificateHolder attributeCert)
+ {
+ this.attributeCert = attributeCert;
+ }
+
+ /**
+ * 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;
+ }
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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>X509AttributeCertificateHolder</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 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 java.io.IOException if a parsing error occurs.
+ * @see #addTargetName(org.spongycastle.asn1.x509.GeneralName)
+ */
+ public void setTargetNames(Collection names) throws IOException
+ {
+ targetNames = extractGeneralNames(names);
+ }
+
+ /**
+ * Adds a target group criterion for the attribute certificate to the target
+ * information extension criteria. The <code>X509AttributeCertificateHolder</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 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 java.io.IOException if a parsing error occurs.
+ * @see #addTargetGroup(org.spongycastle.asn1.x509.GeneralName)
+ */
+ public void setTargetGroups(Collection names) throws IOException
+ {
+ targetGroups = extractGeneralNames(names);
+ }
+
+ 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();)
+ {
+ temp.add(GeneralName.getInstance(it.next()));
+ }
+ return temp;
+ }
+
+ public X509AttributeCertificateHolderSelector build()
+ {
+ X509AttributeCertificateHolderSelector sel = new X509AttributeCertificateHolderSelector(
+ holder, issuer, serialNumber, attributeCertificateValid, attributeCert, Collections.unmodifiableCollection(new HashSet(targetNames)), Collections.unmodifiableCollection(new HashSet(targetGroups)));
+
+ return sel;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/X509CertificateHolderSelector.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/X509CertificateHolderSelector.java
new file mode 100644
index 000000000..8b6b88e3d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/X509CertificateHolderSelector.java
@@ -0,0 +1,152 @@
+package org.spongycastle.cert.selector;
+
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.cms.IssuerAndSerialNumber;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Selector;
+
+/**
+ * a basic index for a X509CertificateHolder class
+ */
+public class X509CertificateHolderSelector
+ implements Selector
+{
+ private byte[] subjectKeyId;
+
+ private X500Name issuer;
+ private BigInteger serialNumber;
+
+ /**
+ * Construct a selector with the value of a public key's subjectKeyId.
+ *
+ * @param subjectKeyId a subjectKeyId
+ */
+ public X509CertificateHolderSelector(byte[] subjectKeyId)
+ {
+ this(null, null, subjectKeyId);
+ }
+
+ /**
+ * Construct a signer ID based on the issuer and serial number of the signer's associated
+ * certificate.
+ *
+ * @param issuer the issuer of the signer's associated certificate.
+ * @param serialNumber the serial number of the signer's associated certificate.
+ */
+ public X509CertificateHolderSelector(X500Name issuer, BigInteger serialNumber)
+ {
+ this(issuer, serialNumber, null);
+ }
+
+ /**
+ * Construct a signer ID based on the issuer and serial number of the signer's associated
+ * certificate.
+ *
+ * @param issuer the issuer of the signer's associated certificate.
+ * @param serialNumber the serial number of the signer's associated certificate.
+ * @param subjectKeyId the subject key identifier to use to match the signers associated certificate.
+ */
+ public X509CertificateHolderSelector(X500Name issuer, BigInteger serialNumber, byte[] subjectKeyId)
+ {
+ this.issuer = issuer;
+ this.serialNumber = serialNumber;
+ this.subjectKeyId = subjectKeyId;
+ }
+
+ public X500Name getIssuer()
+ {
+ return issuer;
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return serialNumber;
+ }
+
+ public byte[] getSubjectKeyIdentifier()
+ {
+ return Arrays.clone(subjectKeyId);
+ }
+
+ public int hashCode()
+ {
+ int code = Arrays.hashCode(subjectKeyId);
+
+ if (this.serialNumber != null)
+ {
+ code ^= this.serialNumber.hashCode();
+ }
+
+ if (this.issuer != null)
+ {
+ code ^= this.issuer.hashCode();
+ }
+
+ return code;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof X509CertificateHolderSelector))
+ {
+ return false;
+ }
+
+ X509CertificateHolderSelector id = (X509CertificateHolderSelector)o;
+
+ return Arrays.areEqual(subjectKeyId, id.subjectKeyId)
+ && equalsObj(this.serialNumber, id.serialNumber)
+ && equalsObj(this.issuer, id.issuer);
+ }
+
+ private boolean equalsObj(Object a, Object b)
+ {
+ return (a != null) ? a.equals(b) : b == null;
+ }
+
+ public boolean match(Object obj)
+ {
+ if (obj instanceof X509CertificateHolder)
+ {
+ X509CertificateHolder certHldr = (X509CertificateHolder)obj;
+
+ if (this.getSerialNumber() != null)
+ {
+ IssuerAndSerialNumber iAndS = new IssuerAndSerialNumber(certHldr.toASN1Structure());
+
+ return iAndS.getName().equals(this.issuer)
+ && iAndS.getSerialNumber().getValue().equals(this.serialNumber);
+ }
+ else if (subjectKeyId != null)
+ {
+ Extension ext = certHldr.getExtension(Extension.subjectKeyIdentifier);
+
+ if (ext == null)
+ {
+ return Arrays.areEqual(subjectKeyId, MSOutlookKeyIdCalculator.calculateKeyId(certHldr.getSubjectPublicKeyInfo()));
+ }
+
+ byte[] subKeyID = ASN1OctetString.getInstance(ext.getParsedValue()).getOctets();
+
+ return Arrays.areEqual(subjectKeyId, subKeyID);
+ }
+ }
+ else if (obj instanceof byte[])
+ {
+ return Arrays.areEqual(subjectKeyId, (byte[])obj);
+ }
+
+ return false;
+ }
+
+ public Object clone()
+ {
+ return new X509CertificateHolderSelector(this.issuer, this.serialNumber, this.subjectKeyId);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaSelectorConverter.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaSelectorConverter.java
new file mode 100644
index 000000000..551000b07
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaSelectorConverter.java
@@ -0,0 +1,35 @@
+package org.spongycastle.cert.selector.jcajce;
+
+import java.io.IOException;
+import java.security.cert.X509CertSelector;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cert.selector.X509CertificateHolderSelector;
+
+public class JcaSelectorConverter
+{
+ public JcaSelectorConverter()
+ {
+
+ }
+
+ public X509CertificateHolderSelector getCertificateHolderSelector(X509CertSelector certSelector)
+ {
+ try
+ {
+ if (certSelector.getSubjectKeyIdentifier() != null)
+ {
+ return new X509CertificateHolderSelector(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber(), ASN1OctetString.getInstance(certSelector.getSubjectKeyIdentifier()).getOctets());
+ }
+ else
+ {
+ return new X509CertificateHolderSelector(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber());
+ }
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage());
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java
new file mode 100644
index 000000000..6dbcef43f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java
@@ -0,0 +1,57 @@
+package org.spongycastle.cert.selector.jcajce;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.X509CertSelector;
+
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cert.selector.X509CertificateHolderSelector;
+
+public class JcaX509CertSelectorConverter
+{
+ public JcaX509CertSelectorConverter()
+ {
+ }
+
+ protected X509CertSelector doConversion(X500Name issuer, BigInteger serialNumber, byte[] subjectKeyIdentifier)
+ {
+ X509CertSelector selector = new X509CertSelector();
+
+ if (issuer != null)
+ {
+ try
+ {
+ selector.setIssuer(issuer.getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage());
+ }
+ }
+
+ if (serialNumber != null)
+ {
+ selector.setSerialNumber(serialNumber);
+ }
+
+ if (subjectKeyIdentifier != null)
+ {
+ try
+ {
+ selector.setSubjectKeyIdentifier(new DEROctetString(subjectKeyIdentifier).getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage());
+ }
+ }
+
+ return selector;
+ }
+
+ public X509CertSelector getCertSelector(X509CertificateHolderSelector holderSelector)
+ {
+ return doConversion(holderSelector.getIssuer(), holderSelector.getSerialNumber(), holderSelector.getSubjectKeyIdentifier());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertificateHolderSelector.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertificateHolderSelector.java
new file mode 100644
index 000000000..fd73a9fa0
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertificateHolderSelector.java
@@ -0,0 +1,72 @@
+package org.spongycastle.cert.selector.jcajce;
+
+import java.math.BigInteger;
+import java.security.cert.X509Certificate;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.cert.selector.X509CertificateHolderSelector;
+
+public class JcaX509CertificateHolderSelector
+ extends X509CertificateHolderSelector
+{
+ /**
+ * Construct a signer identifier based on the issuer, serial number and subject key identifier (if present) of the passed in
+ * certificate.
+ *
+ * @param certificate certificate providing the issue and serial number and subject key identifier.
+ */
+ public JcaX509CertificateHolderSelector(X509Certificate certificate)
+ {
+ super(convertPrincipal(certificate.getIssuerX500Principal()), certificate.getSerialNumber(), getSubjectKeyId(certificate));
+ }
+
+ /**
+ * Construct a signer identifier based on the provided issuer and serial number..
+ *
+ * @param issuer the issuer to use.
+ * @param serialNumber the serial number to use.
+ */
+ public JcaX509CertificateHolderSelector(X500Principal issuer, BigInteger serialNumber)
+ {
+ super(convertPrincipal(issuer), serialNumber);
+ }
+
+ /**
+ * Construct a signer identifier based on the provided issuer, serial number, and subjectKeyId..
+ *
+ * @param issuer the issuer to use.
+ * @param serialNumber the serial number to use.
+ * @param subjectKeyId the subject key ID to use.
+ */
+ public JcaX509CertificateHolderSelector(X500Principal issuer, BigInteger serialNumber, byte[] subjectKeyId)
+ {
+ super(convertPrincipal(issuer), serialNumber, subjectKeyId);
+ }
+
+ private static X500Name convertPrincipal(X500Principal issuer)
+ {
+ if (issuer == null)
+ {
+ return null;
+ }
+ return X500Name.getInstance(issuer.getEncoded());
+ }
+
+ private static byte[] getSubjectKeyId(X509Certificate cert)
+ {
+ byte[] ext = cert.getExtensionValue(Extension.subjectKeyIdentifier.getId());
+
+ if (ext != null)
+ {
+ return ASN1OctetString.getInstance(ASN1OctetString.getInstance(ext).getOctets()).getOctets();
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/AuthAttributesProvider.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/AuthAttributesProvider.java
new file mode 100644
index 000000000..d2f14c5b4
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/AuthAttributesProvider.java
@@ -0,0 +1,8 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.asn1.ASN1Set;
+
+interface AuthAttributesProvider
+{
+ ASN1Set getAuthAttributes();
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAbsentContent.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAbsentContent.java
new file mode 100644
index 000000000..59409ea12
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAbsentContent.java
@@ -0,0 +1,49 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+
+/**
+ * a class representing null or absent content.
+ */
+public class CMSAbsentContent
+ implements CMSTypedData, CMSReadable
+{
+ private final ASN1ObjectIdentifier type;
+
+ public CMSAbsentContent()
+ {
+ this(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()));
+ }
+
+ public CMSAbsentContent(
+ ASN1ObjectIdentifier type)
+ {
+ this.type = type;
+ }
+
+ public InputStream getInputStream()
+ {
+ return null;
+ }
+
+ public void write(OutputStream zOut)
+ throws IOException, CMSException
+ {
+ // do nothing
+ }
+
+ public Object getContent()
+ {
+ return null;
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return type;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAlgorithm.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAlgorithm.java
new file mode 100644
index 000000000..aa04a47da
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAlgorithm.java
@@ -0,0 +1,51 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.kisa.KISAObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.ntt.NTTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+
+public class CMSAlgorithm
+{
+ public static final ASN1ObjectIdentifier DES_CBC = OIWObjectIdentifiers.desCBC;
+ public static final ASN1ObjectIdentifier DES_EDE3_CBC = PKCSObjectIdentifiers.des_EDE3_CBC;
+ public static final ASN1ObjectIdentifier RC2_CBC = PKCSObjectIdentifiers.RC2_CBC;
+ public static final ASN1ObjectIdentifier IDEA_CBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.188.7.1.1.2");
+ public static final ASN1ObjectIdentifier CAST5_CBC = new ASN1ObjectIdentifier("1.2.840.113533.7.66.10");
+ public static final ASN1ObjectIdentifier AES128_CBC = NISTObjectIdentifiers.id_aes128_CBC;
+ public static final ASN1ObjectIdentifier AES192_CBC = NISTObjectIdentifiers.id_aes192_CBC;
+ public static final ASN1ObjectIdentifier AES256_CBC = NISTObjectIdentifiers.id_aes256_CBC;
+ public static final ASN1ObjectIdentifier CAMELLIA128_CBC = NTTObjectIdentifiers.id_camellia128_cbc;
+ public static final ASN1ObjectIdentifier CAMELLIA192_CBC = NTTObjectIdentifiers.id_camellia192_cbc;
+ public static final ASN1ObjectIdentifier CAMELLIA256_CBC = NTTObjectIdentifiers.id_camellia256_cbc;
+ public static final ASN1ObjectIdentifier SEED_CBC = KISAObjectIdentifiers.id_seedCBC;
+
+ public static final ASN1ObjectIdentifier DES_EDE3_WRAP = PKCSObjectIdentifiers.id_alg_CMS3DESwrap;
+ public static final ASN1ObjectIdentifier AES128_WRAP = NISTObjectIdentifiers.id_aes128_wrap;
+ public static final ASN1ObjectIdentifier AES192_WRAP = NISTObjectIdentifiers.id_aes192_wrap;
+ public static final ASN1ObjectIdentifier AES256_WRAP = NISTObjectIdentifiers.id_aes256_wrap;
+ public static final ASN1ObjectIdentifier CAMELLIA128_WRAP = NTTObjectIdentifiers.id_camellia128_wrap;
+ public static final ASN1ObjectIdentifier CAMELLIA192_WRAP = NTTObjectIdentifiers.id_camellia192_wrap;
+ public static final ASN1ObjectIdentifier CAMELLIA256_WRAP = NTTObjectIdentifiers.id_camellia256_wrap;
+ public static final ASN1ObjectIdentifier SEED_WRAP = KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap;
+
+ public static final ASN1ObjectIdentifier ECDH_SHA1KDF = X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme;
+ public static final ASN1ObjectIdentifier ECMQV_SHA1KDF = X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme;
+
+ public static final ASN1ObjectIdentifier SHA1 = OIWObjectIdentifiers.idSHA1;
+ public static final ASN1ObjectIdentifier SHA224 = NISTObjectIdentifiers.id_sha224;
+ public static final ASN1ObjectIdentifier SHA256 = NISTObjectIdentifiers.id_sha256;
+ public static final ASN1ObjectIdentifier SHA384 = NISTObjectIdentifiers.id_sha384;
+ public static final ASN1ObjectIdentifier SHA512 = NISTObjectIdentifiers.id_sha512;
+ public static final ASN1ObjectIdentifier MD5 = PKCSObjectIdentifiers.md5;
+ public static final ASN1ObjectIdentifier GOST3411 = CryptoProObjectIdentifiers.gostR3411;
+ public static final ASN1ObjectIdentifier RIPEMD128 = TeleTrusTObjectIdentifiers.ripemd128;
+ public static final ASN1ObjectIdentifier RIPEMD160 = TeleTrusTObjectIdentifiers.ripemd160;
+ public static final ASN1ObjectIdentifier RIPEMD256 = TeleTrusTObjectIdentifiers.ripemd256;
+
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAttributeTableGenerationException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAttributeTableGenerationException.java
new file mode 100644
index 000000000..e328f8e59
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAttributeTableGenerationException.java
@@ -0,0 +1,32 @@
+package org.spongycastle.cms;
+
+public class CMSAttributeTableGenerationException
+ extends CMSRuntimeException
+{
+ Exception e;
+
+ public CMSAttributeTableGenerationException(
+ String name)
+ {
+ super(name);
+ }
+
+ public CMSAttributeTableGenerationException(
+ String name,
+ Exception e)
+ {
+ super(name);
+
+ this.e = e;
+ }
+
+ public Exception getUnderlyingException()
+ {
+ return e;
+ }
+
+ public Throwable getCause()
+ {
+ return e;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAttributeTableGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAttributeTableGenerator.java
new file mode 100644
index 000000000..9c44be361
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAttributeTableGenerator.java
@@ -0,0 +1,19 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.asn1.cms.AttributeTable;
+
+import java.util.Map;
+
+/**
+ * Note: The SIGNATURE parameter is only available when generating unsigned attributes.
+ */
+public interface CMSAttributeTableGenerator
+{
+ static final String CONTENT_TYPE = "contentType";
+ static final String DIGEST = "digest";
+ static final String SIGNATURE = "encryptedDigest";
+ static final String DIGEST_ALGORITHM_IDENTIFIER = "digestAlgID";
+
+ AttributeTable getAttributes(Map parameters)
+ throws CMSAttributeTableGenerationException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthEnvelopedData.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthEnvelopedData.java
new file mode 100644
index 000000000..df3ab5cf5
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthEnvelopedData.java
@@ -0,0 +1,78 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.cms.AuthEnvelopedData;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.EncryptedContentInfo;
+import org.spongycastle.asn1.cms.OriginatorInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * containing class for an CMS AuthEnveloped Data object
+ */
+class CMSAuthEnvelopedData
+{
+ RecipientInformationStore recipientInfoStore;
+ ContentInfo contentInfo;
+
+ private OriginatorInfo originator;
+ private AlgorithmIdentifier authEncAlg;
+ private ASN1Set authAttrs;
+ private byte[] mac;
+ private ASN1Set unauthAttrs;
+
+ public CMSAuthEnvelopedData(byte[] authEnvData) throws CMSException
+ {
+ this(CMSUtils.readContentInfo(authEnvData));
+ }
+
+ public CMSAuthEnvelopedData(InputStream authEnvData) throws CMSException
+ {
+ this(CMSUtils.readContentInfo(authEnvData));
+ }
+
+ public CMSAuthEnvelopedData(ContentInfo contentInfo) throws CMSException
+ {
+ this.contentInfo = contentInfo;
+
+ AuthEnvelopedData authEnvData = AuthEnvelopedData.getInstance(contentInfo.getContent());
+
+ this.originator = authEnvData.getOriginatorInfo();
+
+ //
+ // read the recipients
+ //
+ ASN1Set recipientInfos = authEnvData.getRecipientInfos();
+
+ //
+ // read the auth-encrypted content info
+ //
+ EncryptedContentInfo authEncInfo = authEnvData.getAuthEncryptedContentInfo();
+ this.authEncAlg = authEncInfo.getContentEncryptionAlgorithm();
+// final CMSProcessable processable = new CMSProcessableByteArray(
+// authEncInfo.getEncryptedContent().getOctets());
+ CMSSecureReadable secureReadable = new CMSSecureReadable()
+ {
+
+ public InputStream getInputStream()
+ throws IOException, CMSException
+ {
+ return null;
+ }
+ };
+
+ //
+ // build the RecipientInformationStore
+ //
+ this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore(
+ recipientInfos, this.authEncAlg, secureReadable);
+
+ // FIXME These need to be passed to the AEAD cipher as AAD (Additional Authenticated Data)
+ this.authAttrs = authEnvData.getAuthAttrs();
+ this.mac = authEnvData.getMac().getOctets();
+ this.unauthAttrs = authEnvData.getUnauthAttrs();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthEnvelopedGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthEnvelopedGenerator.java
new file mode 100644
index 000000000..f3a802cdf
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthEnvelopedGenerator.java
@@ -0,0 +1,13 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+
+class CMSAuthEnvelopedGenerator
+{
+ public static final String AES128_CCM = NISTObjectIdentifiers.id_aes128_CCM.getId();
+ public static final String AES192_CCM = NISTObjectIdentifiers.id_aes192_CCM.getId();
+ public static final String AES256_CCM = NISTObjectIdentifiers.id_aes256_CCM.getId();
+ public static final String AES128_GCM = NISTObjectIdentifiers.id_aes128_GCM.getId();
+ public static final String AES192_GCM = NISTObjectIdentifiers.id_aes192_GCM.getId();
+ public static final String AES256_GCM = NISTObjectIdentifiers.id_aes256_GCM.getId();
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedData.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedData.java
new file mode 100644
index 000000000..898d5c0c3
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedData.java
@@ -0,0 +1,260 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.AuthenticatedData;
+import org.spongycastle.asn1.cms.CMSAttributes;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.util.Arrays;
+
+/**
+ * containing class for an CMS Authenticated Data object
+ */
+public class CMSAuthenticatedData
+{
+ RecipientInformationStore recipientInfoStore;
+ ContentInfo contentInfo;
+
+ private AlgorithmIdentifier macAlg;
+ private ASN1Set authAttrs;
+ private ASN1Set unauthAttrs;
+ private byte[] mac;
+ private OriginatorInformation originatorInfo;
+
+ public CMSAuthenticatedData(
+ byte[] authData)
+ throws CMSException
+ {
+ this(CMSUtils.readContentInfo(authData));
+ }
+
+ public CMSAuthenticatedData(
+ byte[] authData,
+ DigestCalculatorProvider digestCalculatorProvider)
+ throws CMSException
+ {
+ this(CMSUtils.readContentInfo(authData), digestCalculatorProvider);
+ }
+
+ public CMSAuthenticatedData(
+ InputStream authData)
+ throws CMSException
+ {
+ this(CMSUtils.readContentInfo(authData));
+ }
+
+ public CMSAuthenticatedData(
+ InputStream authData,
+ DigestCalculatorProvider digestCalculatorProvider)
+ throws CMSException
+ {
+ this(CMSUtils.readContentInfo(authData), digestCalculatorProvider);
+ }
+
+ public CMSAuthenticatedData(
+ ContentInfo contentInfo)
+ throws CMSException
+ {
+ this(contentInfo, null);
+ }
+
+ public CMSAuthenticatedData(
+ ContentInfo contentInfo,
+ DigestCalculatorProvider digestCalculatorProvider)
+ throws CMSException
+ {
+ this.contentInfo = contentInfo;
+
+ AuthenticatedData authData = AuthenticatedData.getInstance(contentInfo.getContent());
+
+ if (authData.getOriginatorInfo() != null)
+ {
+ this.originatorInfo = new OriginatorInformation(authData.getOriginatorInfo());
+ }
+
+ //
+ // read the recipients
+ //
+ ASN1Set recipientInfos = authData.getRecipientInfos();
+
+ this.macAlg = authData.getMacAlgorithm();
+
+
+ this.authAttrs = authData.getAuthAttrs();
+ this.mac = authData.getMac().getOctets();
+ this.unauthAttrs = authData.getUnauthAttrs();
+
+ //
+ // read the authenticated content info
+ //
+ ContentInfo encInfo = authData.getEncapsulatedContentInfo();
+ CMSReadable readable = new CMSProcessableByteArray(
+ ASN1OctetString.getInstance(encInfo.getContent()).getOctets());
+
+ //
+ // build the RecipientInformationStore
+ //
+ if (authAttrs != null)
+ {
+ if (digestCalculatorProvider == null)
+ {
+ throw new CMSException("a digest calculator provider is required if authenticated attributes are present");
+ }
+
+ try
+ {
+ CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSDigestAuthenticatedSecureReadable(digestCalculatorProvider.get(authData.getDigestAlgorithm()), readable);
+
+ this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore(recipientInfos, this.macAlg, secureReadable, new AuthAttributesProvider()
+ {
+ public ASN1Set getAuthAttributes()
+ {
+ return authAttrs;
+ }
+ });
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new CMSException("unable to create digest calculator: " + e.getMessage(), e);
+ }
+ }
+ else
+ {
+ CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSAuthenticatedSecureReadable(this.macAlg, readable);
+
+ this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore(recipientInfos, this.macAlg, secureReadable);
+ }
+ }
+
+ /**
+ * Return the originator information associated with this message if present.
+ *
+ * @return OriginatorInformation, null if not present.
+ */
+ public OriginatorInformation getOriginatorInfo()
+ {
+ return originatorInfo;
+ }
+
+ public byte[] getMac()
+ {
+ return Arrays.clone(mac);
+ }
+
+ private byte[] encodeObj(
+ ASN1Encodable obj)
+ throws IOException
+ {
+ if (obj != null)
+ {
+ return obj.toASN1Primitive().getEncoded();
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the MAC algorithm details for the MAC associated with the data in this object.
+ *
+ * @return AlgorithmIdentifier representing the MAC algorithm.
+ */
+ public AlgorithmIdentifier getMacAlgorithm()
+ {
+ return macAlg;
+ }
+
+ /**
+ * return the object identifier for the content MAC algorithm.
+ */
+ public String getMacAlgOID()
+ {
+ return macAlg.getAlgorithm().getId();
+ }
+
+ /**
+ * return the ASN.1 encoded MAC algorithm parameters, or null if
+ * there aren't any.
+ */
+ public byte[] getMacAlgParams()
+ {
+ try
+ {
+ return encodeObj(macAlg.getParameters());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("exception getting encryption parameters " + e);
+ }
+ }
+
+ /**
+ * return a store of the intended recipients for this message
+ */
+ public RecipientInformationStore getRecipientInfos()
+ {
+ return recipientInfoStore;
+ }
+
+ /**
+ * return the ContentInfo
+ */
+ public ContentInfo getContentInfo()
+ {
+ return contentInfo;
+ }
+
+ /**
+ * return a table of the digested attributes indexed by
+ * the OID of the attribute.
+ */
+ public AttributeTable getAuthAttrs()
+ {
+ if (authAttrs == null)
+ {
+ return null;
+ }
+
+ return new AttributeTable(authAttrs);
+ }
+
+ /**
+ * return a table of the undigested attributes indexed by
+ * the OID of the attribute.
+ */
+ public AttributeTable getUnauthAttrs()
+ {
+ if (unauthAttrs == null)
+ {
+ return null;
+ }
+
+ return new AttributeTable(unauthAttrs);
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return contentInfo.getEncoded();
+ }
+
+ public byte[] getContentDigest()
+ {
+ if (authAttrs != null)
+ {
+ return ASN1OctetString.getInstance(getAuthAttrs().get(CMSAttributes.messageDigest).getAttrValues().getObjectAt(0)).getOctets();
+ }
+
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataGenerator.java
new file mode 100644
index 000000000..ca1f95a56
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataGenerator.java
@@ -0,0 +1,181 @@
+package org.spongycastle.cms;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.BEROctetString;
+import org.spongycastle.asn1.BERSet;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.cms.AuthenticatedData;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.MacCalculator;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.util.io.TeeOutputStream;
+
+/**
+ * General class for generating a CMS authenticated-data message.
+ *
+ * A simple example of usage.
+ *
+ * <pre>
+ * CMSAuthenticatedDataGenerator fact = new CMSAuthenticatedDataGenerator();
+ *
+ * adGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(recipientCert).setProvider("SC"));
+ *
+ * CMSAuthenticatedData data = fact.generate(new CMSProcessableByteArray(data),
+ * new JceCMSMacCalculatorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build()));
+ * </pre>
+ */
+public class CMSAuthenticatedDataGenerator
+ extends CMSAuthenticatedGenerator
+{
+ /**
+ * base constructor
+ */
+ public CMSAuthenticatedDataGenerator()
+ {
+ }
+
+ /**
+ * Generate an authenticated data object from the passed in typedData and MacCalculator.
+ *
+ * @param typedData the data to have a MAC attached.
+ * @param macCalculator the calculator of the MAC to be attached.
+ * @return the resulting CMSAuthenticatedData object.
+ * @throws CMSException on failure in encoding data or processing recipients.
+ */
+ public CMSAuthenticatedData generate(CMSTypedData typedData, MacCalculator macCalculator)
+ throws CMSException
+ {
+ return generate(typedData, macCalculator, null);
+ }
+
+ /**
+ * Generate an authenticated data object from the passed in typedData and MacCalculator.
+ *
+ * @param typedData the data to have a MAC attached.
+ * @param macCalculator the calculator of the MAC to be attached.
+ * @param digestCalculator calculator for computing digest of the encapsulated data.
+ * @return the resulting CMSAuthenticatedData object.
+ * @throws CMSException on failure in encoding data or processing recipients.
+ */
+ public CMSAuthenticatedData generate(CMSTypedData typedData, MacCalculator macCalculator, final DigestCalculator digestCalculator)
+ throws CMSException
+ {
+ ASN1EncodableVector recipientInfos = new ASN1EncodableVector();
+ ASN1OctetString encContent;
+ ASN1OctetString macResult;
+
+ for (Iterator it = recipientInfoGenerators.iterator(); it.hasNext();)
+ {
+ RecipientInfoGenerator recipient = (RecipientInfoGenerator)it.next();
+
+ recipientInfos.add(recipient.generate(macCalculator.getKey()));
+ }
+
+ AuthenticatedData authData;
+
+ if (digestCalculator != null)
+ {
+ try
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ OutputStream out = new TeeOutputStream(digestCalculator.getOutputStream(), bOut);
+
+ typedData.write(out);
+
+ out.close();
+
+ encContent = new BEROctetString(bOut.toByteArray());
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("unable to perform digest calculation: " + e.getMessage(), e);
+ }
+
+ Map parameters = getBaseParameters(typedData.getContentType(), digestCalculator.getAlgorithmIdentifier(), digestCalculator.getDigest());
+
+ if (authGen == null)
+ {
+ authGen = new DefaultAuthenticatedAttributeTableGenerator();
+ }
+ ASN1Set authed = new DERSet(authGen.getAttributes(Collections.unmodifiableMap(parameters)).toASN1EncodableVector());
+
+ try
+ {
+ OutputStream mOut = macCalculator.getOutputStream();
+
+ mOut.write(authed.getEncoded(ASN1Encoding.DER));
+
+ mOut.close();
+
+ macResult = new DEROctetString(macCalculator.getMac());
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("exception decoding algorithm parameters.", e);
+ }
+ ASN1Set unauthed = (unauthGen != null) ? new BERSet(unauthGen.getAttributes(Collections.unmodifiableMap(parameters)).toASN1EncodableVector()) : null;
+
+ ContentInfo eci = new ContentInfo(
+ CMSObjectIdentifiers.data,
+ encContent);
+
+ authData = new AuthenticatedData(originatorInfo, new DERSet(recipientInfos), macCalculator.getAlgorithmIdentifier(), digestCalculator.getAlgorithmIdentifier(), eci, authed, macResult, unauthed);
+ }
+ else
+ {
+ try
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ OutputStream mOut = new TeeOutputStream(bOut, macCalculator.getOutputStream());
+
+ typedData.write(mOut);
+
+ mOut.close();
+
+ encContent = new BEROctetString(bOut.toByteArray());
+
+ macResult = new DEROctetString(macCalculator.getMac());
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("exception decoding algorithm parameters.", e);
+ }
+
+ ASN1Set unauthed = (unauthGen != null) ? new BERSet(unauthGen.getAttributes(new HashMap()).toASN1EncodableVector()) : null;
+
+ ContentInfo eci = new ContentInfo(
+ CMSObjectIdentifiers.data,
+ encContent);
+
+ authData = new AuthenticatedData(originatorInfo, new DERSet(recipientInfos), macCalculator.getAlgorithmIdentifier(), null, eci, null, macResult, unauthed);
+ }
+
+ ContentInfo contentInfo = new ContentInfo(
+ CMSObjectIdentifiers.authenticatedData, authData);
+
+ return new CMSAuthenticatedData(contentInfo, new DigestCalculatorProvider()
+ {
+ public DigestCalculator get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ throws OperatorCreationException
+ {
+ return digestCalculator;
+ }
+ });
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataParser.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataParser.java
new file mode 100644
index 000000000..b524b4ac9
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataParser.java
@@ -0,0 +1,348 @@
+package org.spongycastle.cms;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1OctetStringParser;
+import org.spongycastle.asn1.ASN1SequenceParser;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.ASN1SetParser;
+import org.spongycastle.asn1.BERTags;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.AuthenticatedDataParser;
+import org.spongycastle.asn1.cms.CMSAttributes;
+import org.spongycastle.asn1.cms.ContentInfoParser;
+import org.spongycastle.asn1.cms.OriginatorInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.util.Arrays;
+
+/**
+ * Parsing class for an CMS Authenticated Data object from an input stream.
+ * <p>
+ * Note: that because we are in a streaming mode only one recipient can be tried and it is important
+ * that the methods on the parser are called in the appropriate order.
+ * </p>
+ * <p>
+ * Example of use - assuming the first recipient matches the private key we have.
+ * <pre>
+ * CMSAuthenticatedDataParser ad = new CMSAuthenticatedDataParser(inputStream);
+ *
+ * RecipientInformationStore recipients = ad.getRecipientInfos();
+ *
+ * Collection c = recipients.getRecipients();
+ * Iterator it = c.iterator();
+ *
+ * if (it.hasNext())
+ * {
+ * RecipientInformation recipient = (RecipientInformation)it.next();
+ *
+ * CMSTypedStream recData = recipient.getContentStream(new JceKeyTransAuthenticatedRecipient(privateKey).setProvider("SC"));
+ *
+ * processDataStream(recData.getContentStream());
+ *
+ * if (!Arrays.equals(ad.getMac(), recipient.getMac())
+ * {
+ * System.err.println("Data corrupted!!!!");
+ * }
+ * }
+ * </pre>
+ * Note: this class does not introduce buffering - if you are processing large files you should create
+ * the parser with:
+ * <pre>
+ * CMSAuthenticatedDataParser ep = new CMSAuthenticatedDataParser(new BufferedInputStream(inputStream, bufSize));
+ * </pre>
+ * where bufSize is a suitably large buffer size.
+ */
+public class CMSAuthenticatedDataParser
+ extends CMSContentInfoParser
+{
+ RecipientInformationStore recipientInfoStore;
+ AuthenticatedDataParser authData;
+
+ private AlgorithmIdentifier macAlg;
+ private byte[] mac;
+ private AttributeTable authAttrs;
+ private ASN1Set authAttrSet;
+ private AttributeTable unauthAttrs;
+
+ private boolean authAttrNotRead;
+ private boolean unauthAttrNotRead;
+ private OriginatorInformation originatorInfo;
+
+ public CMSAuthenticatedDataParser(
+ byte[] envelopedData)
+ throws CMSException, IOException
+ {
+ this(new ByteArrayInputStream(envelopedData));
+ }
+
+ public CMSAuthenticatedDataParser(
+ byte[] envelopedData,
+ DigestCalculatorProvider digestCalculatorProvider)
+ throws CMSException, IOException
+ {
+ this(new ByteArrayInputStream(envelopedData), digestCalculatorProvider);
+ }
+
+ public CMSAuthenticatedDataParser(
+ InputStream envelopedData)
+ throws CMSException, IOException
+ {
+ this(envelopedData, null);
+ }
+
+ public CMSAuthenticatedDataParser(
+ InputStream envelopedData,
+ DigestCalculatorProvider digestCalculatorProvider)
+ throws CMSException, IOException
+ {
+ super(envelopedData);
+
+ this.authAttrNotRead = true;
+ this.authData = new AuthenticatedDataParser((ASN1SequenceParser)_contentInfo.getContent(BERTags.SEQUENCE));
+
+ // TODO Validate version?
+ //DERInteger version = this.authData.getVersion();
+
+ OriginatorInfo info = authData.getOriginatorInfo();
+
+ if (info != null)
+ {
+ this.originatorInfo = new OriginatorInformation(info);
+ }
+ //
+ // read the recipients
+ //
+ ASN1Set recipientInfos = ASN1Set.getInstance(authData.getRecipientInfos().toASN1Primitive());
+
+ this.macAlg = authData.getMacAlgorithm();
+
+ //
+ // build the RecipientInformationStore
+ //
+ AlgorithmIdentifier digestAlgorithm = authData.getDigestAlgorithm();
+
+ if (digestAlgorithm != null)
+ {
+ if (digestCalculatorProvider == null)
+ {
+ throw new CMSException("a digest calculator provider is required if authenticated attributes are present");
+ }
+
+ //
+ // read the authenticated content info
+ //
+ ContentInfoParser data = authData.getEncapsulatedContentInfo();
+ CMSReadable readable = new CMSProcessableInputStream(
+ ((ASN1OctetStringParser)data.getContent(BERTags.OCTET_STRING)).getOctetStream());
+
+ try
+ {
+ CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSDigestAuthenticatedSecureReadable(digestCalculatorProvider.get(digestAlgorithm), readable);
+
+ this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore(recipientInfos, this.macAlg, secureReadable, new AuthAttributesProvider()
+ {
+ public ASN1Set getAuthAttributes()
+ {
+ try
+ {
+ return getAuthAttrSet();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("can't parse authenticated attributes!");
+ }
+ }
+ });
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new CMSException("unable to create digest calculator: " + e.getMessage(), e);
+ }
+ }
+ else
+ {
+ //
+ // read the authenticated content info
+ //
+ ContentInfoParser data = authData.getEncapsulatedContentInfo();
+ CMSReadable readable = new CMSProcessableInputStream(
+ ((ASN1OctetStringParser)data.getContent(BERTags.OCTET_STRING)).getOctetStream());
+
+ CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSAuthenticatedSecureReadable(this.macAlg, readable);
+
+ this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore(recipientInfos, this.macAlg, secureReadable);
+ }
+
+
+ }
+
+ /**
+ * Return the originator information associated with this message if present.
+ *
+ * @return OriginatorInformation, null if not present.
+ */
+ public OriginatorInformation getOriginatorInfo()
+ {
+ return originatorInfo;
+ }
+
+ /**
+ * Return the MAC algorithm details for the MAC associated with the data in this object.
+ *
+ * @return AlgorithmIdentifier representing the MAC algorithm.
+ */
+ public AlgorithmIdentifier getMacAlgorithm()
+ {
+ return macAlg;
+ }
+
+ /**
+ * return the object identifier for the mac algorithm.
+ */
+ public String getMacAlgOID()
+ {
+ return macAlg.getAlgorithm().toString();
+ }
+
+ /**
+ * return the ASN.1 encoded encryption algorithm parameters, or null if
+ * there aren't any.
+ */
+ public byte[] getMacAlgParams()
+ {
+ try
+ {
+ return encodeObj(macAlg.getParameters());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("exception getting encryption parameters " + e);
+ }
+ }
+
+ /**
+ * return a store of the intended recipients for this message
+ */
+ public RecipientInformationStore getRecipientInfos()
+ {
+ return recipientInfoStore;
+ }
+
+ public byte[] getMac()
+ throws IOException
+ {
+ if (mac == null)
+ {
+ getAuthAttrs();
+ mac = authData.getMac().getOctets();
+ }
+ return Arrays.clone(mac);
+ }
+
+ private ASN1Set getAuthAttrSet()
+ throws IOException
+ {
+ if (authAttrs == null && authAttrNotRead)
+ {
+ ASN1SetParser set = authData.getAuthAttrs();
+
+ if (set != null)
+ {
+ authAttrSet = (ASN1Set)set.toASN1Primitive();
+ }
+
+ authAttrNotRead = false;
+ }
+
+ return authAttrSet;
+ }
+
+ /**
+ * return a table of the unauthenticated attributes indexed by
+ * the OID of the attribute.
+ * @exception java.io.IOException
+ */
+ public AttributeTable getAuthAttrs()
+ throws IOException
+ {
+ if (authAttrs == null && authAttrNotRead)
+ {
+ ASN1Set set = getAuthAttrSet();
+
+ if (set != null)
+ {
+ authAttrs = new AttributeTable(set);
+ }
+ }
+
+ return authAttrs;
+ }
+
+ /**
+ * return a table of the unauthenticated attributes indexed by
+ * the OID of the attribute.
+ * @exception java.io.IOException
+ */
+ public AttributeTable getUnauthAttrs()
+ throws IOException
+ {
+ if (unauthAttrs == null && unauthAttrNotRead)
+ {
+ ASN1SetParser set = authData.getUnauthAttrs();
+
+ unauthAttrNotRead = false;
+
+ if (set != null)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ ASN1Encodable o;
+
+ while ((o = set.readObject()) != null)
+ {
+ ASN1SequenceParser seq = (ASN1SequenceParser)o;
+
+ v.add(seq.toASN1Primitive());
+ }
+
+ unauthAttrs = new AttributeTable(new DERSet(v));
+ }
+ }
+
+ return unauthAttrs;
+ }
+
+ private byte[] encodeObj(
+ ASN1Encodable obj)
+ throws IOException
+ {
+ if (obj != null)
+ {
+ return obj.toASN1Primitive().getEncoded();
+ }
+
+ return null;
+ }
+
+ /**
+ * This will only be valid after the content has been read.
+ *
+ * @return the contents of the messageDigest attribute, if available. Null if not present.
+ */
+ public byte[] getContentDigest()
+ {
+ if (authAttrs != null)
+ {
+ return ASN1OctetString.getInstance(authAttrs.get(CMSAttributes.messageDigest).getAttrValues().getObjectAt(0)).getOctets();
+ }
+
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataStreamGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataStreamGenerator.java
new file mode 100644
index 000000000..739b0b1d5
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedDataStreamGenerator.java
@@ -0,0 +1,310 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.BERSequenceGenerator;
+import org.spongycastle.asn1.BERSet;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.DERTaggedObject;
+import org.spongycastle.asn1.cms.AuthenticatedData;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.MacCalculator;
+import org.spongycastle.util.io.TeeOutputStream;
+
+/**
+ * General class for generating a CMS authenticated-data message stream.
+ * <p>
+ * A simple example of usage.
+ * <pre>
+ * CMSAuthenticatedDataStreamGenerator edGen = new CMSAuthenticatedDataStreamGenerator();
+ *
+ * edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(cert).setProvider("SC"));
+ *
+ * ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ *
+ * OutputStream out = edGen.open(
+ * bOut, new JceCMSMacCalculatorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider("SC").build());*
+ * out.write(data);
+ *
+ * out.close();
+ * </pre>
+ */
+public class CMSAuthenticatedDataStreamGenerator
+ extends CMSAuthenticatedGenerator
+{
+ // Currently not handled
+// private Object _originatorInfo = null;
+// private Object _unprotectedAttributes = null;
+ private int bufferSize;
+ private boolean berEncodeRecipientSet;
+ private MacCalculator macCalculator;
+
+ /**
+ * base constructor
+ */
+ public CMSAuthenticatedDataStreamGenerator()
+ {
+ }
+
+ /**
+ * Set the underlying string size for encapsulated data
+ *
+ * @param bufferSize length of octet strings to buffer the data.
+ */
+ public void setBufferSize(
+ int bufferSize)
+ {
+ this.bufferSize = bufferSize;
+ }
+
+ /**
+ * Use a BER Set to store the recipient information. By default recipients are
+ * stored in a DER encoding.
+ *
+ * @param useBerEncodingForRecipients true if a BER set should be used, false if DER.
+ */
+ public void setBEREncodeRecipients(
+ boolean useBerEncodingForRecipients)
+ {
+ berEncodeRecipientSet = useBerEncodingForRecipients;
+ }
+
+ /**
+ * generate an authenticated data structure with the encapsulated bytes marked as DATA.
+ *
+ * @param out the stream to store the authenticated structure in.
+ * @param macCalculator calculator for the MAC to be attached to the data.
+ */
+ public OutputStream open(
+ OutputStream out,
+ MacCalculator macCalculator)
+ throws CMSException
+ {
+ return open(CMSObjectIdentifiers.data, out, macCalculator);
+ }
+
+ public OutputStream open(
+ OutputStream out,
+ MacCalculator macCalculator,
+ DigestCalculator digestCalculator)
+ throws CMSException
+ {
+ return open(CMSObjectIdentifiers.data, out, macCalculator, digestCalculator);
+ }
+
+ /**
+ * generate an authenticated data structure with the encapsulated bytes marked as type dataType.
+ *
+ * @param dataType the type of the data been written to the object.
+ * @param out the stream to store the authenticated structure in.
+ * @param macCalculator calculator for the MAC to be attached to the data.
+ */
+ public OutputStream open(
+ ASN1ObjectIdentifier dataType,
+ OutputStream out,
+ MacCalculator macCalculator)
+ throws CMSException
+ {
+ return open(dataType, out, macCalculator, null);
+ }
+
+ /**
+ * generate an authenticated data structure with the encapsulated bytes marked as type dataType.
+ *
+ * @param dataType the type of the data been written to the object.
+ * @param out the stream to store the authenticated structure in.
+ * @param macCalculator calculator for the MAC to be attached to the data.
+ * @param digestCalculator calculator for computing digest of the encapsulated data.
+ */
+ public OutputStream open(
+ ASN1ObjectIdentifier dataType,
+ OutputStream out,
+ MacCalculator macCalculator,
+ DigestCalculator digestCalculator)
+ throws CMSException
+ {
+ this.macCalculator = macCalculator;
+
+ try
+ {
+ ASN1EncodableVector recipientInfos = new ASN1EncodableVector();
+
+ for (Iterator it = recipientInfoGenerators.iterator(); it.hasNext();)
+ {
+ RecipientInfoGenerator recipient = (RecipientInfoGenerator)it.next();
+
+ recipientInfos.add(recipient.generate(macCalculator.getKey()));
+ }
+
+ //
+ // ContentInfo
+ //
+ BERSequenceGenerator cGen = new BERSequenceGenerator(out);
+
+ cGen.addObject(CMSObjectIdentifiers.authenticatedData);
+
+ //
+ // Authenticated Data
+ //
+ BERSequenceGenerator authGen = new BERSequenceGenerator(cGen.getRawOutputStream(), 0, true);
+
+ authGen.addObject(new DERInteger(AuthenticatedData.calculateVersion(originatorInfo)));
+
+ if (originatorInfo != null)
+ {
+ authGen.addObject(new DERTaggedObject(false, 0, originatorInfo));
+ }
+
+ if (berEncodeRecipientSet)
+ {
+ authGen.getRawOutputStream().write(new BERSet(recipientInfos).getEncoded());
+ }
+ else
+ {
+ authGen.getRawOutputStream().write(new DERSet(recipientInfos).getEncoded());
+ }
+
+ AlgorithmIdentifier macAlgId = macCalculator.getAlgorithmIdentifier();
+
+ authGen.getRawOutputStream().write(macAlgId.getEncoded());
+
+ if (digestCalculator != null)
+ {
+ authGen.addObject(new DERTaggedObject(false, 1, digestCalculator.getAlgorithmIdentifier()));
+ }
+
+ BERSequenceGenerator eiGen = new BERSequenceGenerator(authGen.getRawOutputStream());
+
+ eiGen.addObject(dataType);
+
+ OutputStream octetStream = CMSUtils.createBEROctetOutputStream(
+ eiGen.getRawOutputStream(), 0, false, bufferSize);
+
+ OutputStream mOut;
+
+ if (digestCalculator != null)
+ {
+ mOut = new TeeOutputStream(octetStream, digestCalculator.getOutputStream());
+ }
+ else
+ {
+ mOut = new TeeOutputStream(octetStream, macCalculator.getOutputStream());
+ }
+
+ return new CmsAuthenticatedDataOutputStream(macCalculator, digestCalculator, dataType, mOut, cGen, authGen, eiGen);
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("exception decoding algorithm parameters.", e);
+ }
+ }
+
+ private class CmsAuthenticatedDataOutputStream
+ extends OutputStream
+ {
+ private OutputStream dataStream;
+ private BERSequenceGenerator cGen;
+ private BERSequenceGenerator envGen;
+ private BERSequenceGenerator eiGen;
+ private MacCalculator macCalculator;
+ private DigestCalculator digestCalculator;
+ private ASN1ObjectIdentifier contentType;
+
+ public CmsAuthenticatedDataOutputStream(
+ MacCalculator macCalculator,
+ DigestCalculator digestCalculator,
+ ASN1ObjectIdentifier contentType,
+ OutputStream dataStream,
+ BERSequenceGenerator cGen,
+ BERSequenceGenerator envGen,
+ BERSequenceGenerator eiGen)
+ {
+ this.macCalculator = macCalculator;
+ this.digestCalculator = digestCalculator;
+ this.contentType = contentType;
+ this.dataStream = dataStream;
+ this.cGen = cGen;
+ this.envGen = envGen;
+ this.eiGen = eiGen;
+ }
+
+ public void write(
+ int b)
+ throws IOException
+ {
+ dataStream.write(b);
+ }
+
+ public void write(
+ byte[] bytes,
+ int off,
+ int len)
+ throws IOException
+ {
+ dataStream.write(bytes, off, len);
+ }
+
+ public void write(
+ byte[] bytes)
+ throws IOException
+ {
+ dataStream.write(bytes);
+ }
+
+ public void close()
+ throws IOException
+ {
+ dataStream.close();
+ eiGen.close();
+
+ Map parameters;
+
+ if (digestCalculator != null)
+ {
+ parameters = Collections.unmodifiableMap(getBaseParameters(contentType, digestCalculator.getAlgorithmIdentifier(), digestCalculator.getDigest()));
+
+ if (authGen == null)
+ {
+ authGen = new DefaultAuthenticatedAttributeTableGenerator();
+ }
+
+ ASN1Set authed = new DERSet(authGen.getAttributes(parameters).toASN1EncodableVector());
+
+ OutputStream mOut = macCalculator.getOutputStream();
+
+ mOut.write(authed.getEncoded(ASN1Encoding.DER));
+
+ mOut.close();
+
+ envGen.addObject(new DERTaggedObject(false, 2, authed));
+ }
+ else
+ {
+ parameters = Collections.unmodifiableMap(new HashMap());
+ }
+
+ envGen.addObject(new DEROctetString(macCalculator.getMac()));
+
+ if (unauthGen != null)
+ {
+ envGen.addObject(new DERTaggedObject(false, 3, new BERSet(unauthGen.getAttributes(parameters).toASN1EncodableVector())));
+ }
+
+ envGen.close();
+ cGen.close();
+ }
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedGenerator.java
new file mode 100644
index 000000000..d5ea1b8cf
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSAuthenticatedGenerator.java
@@ -0,0 +1,40 @@
+package org.spongycastle.cms;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public class CMSAuthenticatedGenerator
+ extends CMSEnvelopedGenerator
+{
+ protected CMSAttributeTableGenerator authGen;
+ protected CMSAttributeTableGenerator unauthGen;
+
+ /**
+ * base constructor
+ */
+ public CMSAuthenticatedGenerator()
+ {
+ }
+
+ public void setAuthenticatedAttributeGenerator(CMSAttributeTableGenerator authGen)
+ {
+ this.authGen = authGen;
+ }
+
+ public void setUnauthenticatedAttributeGenerator(CMSAttributeTableGenerator unauthGen)
+ {
+ this.unauthGen = unauthGen;
+ }
+
+ protected Map getBaseParameters(ASN1ObjectIdentifier contentType, AlgorithmIdentifier digAlgId, byte[] hash)
+ {
+ Map param = new HashMap();
+ param.put(CMSAttributeTableGenerator.CONTENT_TYPE, contentType);
+ param.put(CMSAttributeTableGenerator.DIGEST_ALGORITHM_IDENTIFIER, digAlgId);
+ param.put(CMSAttributeTableGenerator.DIGEST, hash.clone());
+ return param;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSCompressedData.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSCompressedData.java
new file mode 100644
index 000000000..f6aa02d10
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSCompressedData.java
@@ -0,0 +1,107 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.cms.CompressedData;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.operator.InputExpander;
+import org.spongycastle.operator.InputExpanderProvider;
+
+/**
+ * containing class for an CMS Compressed Data object
+ * <pre>
+ * CMSCompressedData cd = new CMSCompressedData(inputStream);
+ *
+ * process(cd.getContent(new ZlibExpanderProvider()));
+ * </pre>
+ */
+public class CMSCompressedData
+{
+ ContentInfo contentInfo;
+ CompressedData comData;
+
+ public CMSCompressedData(
+ byte[] compressedData)
+ throws CMSException
+ {
+ this(CMSUtils.readContentInfo(compressedData));
+ }
+
+ public CMSCompressedData(
+ InputStream compressedData)
+ throws CMSException
+ {
+ this(CMSUtils.readContentInfo(compressedData));
+ }
+
+ public CMSCompressedData(
+ ContentInfo contentInfo)
+ throws CMSException
+ {
+ this.contentInfo = contentInfo;
+
+ try
+ {
+ this.comData = CompressedData.getInstance(contentInfo.getContent());
+ }
+ catch (ClassCastException e)
+ {
+ throw new CMSException("Malformed content.", e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CMSException("Malformed content.", e);
+ }
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return contentInfo.getContentType();
+ }
+
+ /**
+ * Return the uncompressed content.
+ *
+ * @param expanderProvider a provider of expander algorithm implementations.
+ * @return the uncompressed content
+ * @throws CMSException if there is an exception un-compressing the data.
+ */
+ public byte[] getContent(InputExpanderProvider expanderProvider)
+ throws CMSException
+ {
+ ContentInfo content = comData.getEncapContentInfo();
+
+ ASN1OctetString bytes = (ASN1OctetString)content.getContent();
+ InputExpander expander = expanderProvider.get(comData.getCompressionAlgorithmIdentifier());
+ InputStream zIn = expander.getInputStream(bytes.getOctetStream());
+
+ try
+ {
+ return CMSUtils.streamToByteArray(zIn);
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("exception reading compressed stream.", e);
+ }
+ }
+
+ /**
+ * return the ContentInfo
+ */
+ public ContentInfo toASN1Structure()
+ {
+ return contentInfo;
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return contentInfo.getEncoded();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataGenerator.java
new file mode 100644
index 000000000..b26e84a32
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataGenerator.java
@@ -0,0 +1,74 @@
+package org.spongycastle.cms;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.BEROctetString;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.CompressedData;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.OutputCompressor;
+
+/**
+ * General class for generating a compressed CMS message.
+ * <p>
+ * A simple example of usage.
+ * <p>
+ * <pre>
+ * CMSCompressedDataGenerator fact = new CMSCompressedDataGenerator();
+ *
+ * CMSCompressedData data = fact.generate(content, new ZlibCompressor());
+ * </pre>
+ */
+public class CMSCompressedDataGenerator
+{
+ public static final String ZLIB = "1.2.840.113549.1.9.16.3.8";
+
+ /**
+ * base constructor
+ */
+ public CMSCompressedDataGenerator()
+ {
+ }
+
+ /**
+ * generate an object that contains an CMS Compressed Data
+ */
+ public CMSCompressedData generate(
+ CMSTypedData content,
+ OutputCompressor compressor)
+ throws CMSException
+ {
+ AlgorithmIdentifier comAlgId;
+ ASN1OctetString comOcts;
+
+ try
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ OutputStream zOut = compressor.getOutputStream(bOut);
+
+ content.write(zOut);
+
+ zOut.close();
+
+ comAlgId = compressor.getAlgorithmIdentifier();
+ comOcts = new BEROctetString(bOut.toByteArray());
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("exception encoding data.", e);
+ }
+
+ ContentInfo comContent = new ContentInfo(
+ content.getContentType(), comOcts);
+
+ ContentInfo contentInfo = new ContentInfo(
+ CMSObjectIdentifiers.compressedData,
+ new CompressedData(comAlgId, comContent));
+
+ return new CMSCompressedData(contentInfo);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataParser.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataParser.java
new file mode 100644
index 000000000..bc853f2ac
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataParser.java
@@ -0,0 +1,72 @@
+package org.spongycastle.cms;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.ASN1OctetStringParser;
+import org.spongycastle.asn1.ASN1SequenceParser;
+import org.spongycastle.asn1.BERTags;
+import org.spongycastle.asn1.cms.CompressedDataParser;
+import org.spongycastle.asn1.cms.ContentInfoParser;
+import org.spongycastle.operator.InputExpander;
+import org.spongycastle.operator.InputExpanderProvider;
+
+/**
+ * Class for reading a CMS Compressed Data stream.
+ * <pre>
+ * CMSCompressedDataParser cp = new CMSCompressedDataParser(inputStream);
+ *
+ * process(cp.getContent(new ZlibExpanderProvider()).getContentStream());
+ * </pre>
+ * Note: this class does not introduce buffering - if you are processing large files you should create
+ * the parser with:
+ * <pre>
+ * CMSCompressedDataParser ep = new CMSCompressedDataParser(new BufferedInputStream(inputStream, bufSize));
+ * </pre>
+ * where bufSize is a suitably large buffer size.
+ */
+public class CMSCompressedDataParser
+ extends CMSContentInfoParser
+{
+ public CMSCompressedDataParser(
+ byte[] compressedData)
+ throws CMSException
+ {
+ this(new ByteArrayInputStream(compressedData));
+ }
+
+ public CMSCompressedDataParser(
+ InputStream compressedData)
+ throws CMSException
+ {
+ super(compressedData);
+ }
+
+ /**
+ * Return a typed stream which will allow the reading of the compressed content in
+ * expanded form.
+ *
+ * @param expanderProvider a provider of expander algorithm implementations.
+ * @return a type stream which will yield the un-compressed content.
+ * @throws CMSException if there is an exception parsing the CompressedData object.
+ */
+ public CMSTypedStream getContent(InputExpanderProvider expanderProvider)
+ throws CMSException
+ {
+ try
+ {
+ CompressedDataParser comData = new CompressedDataParser((ASN1SequenceParser)_contentInfo.getContent(BERTags.SEQUENCE));
+ ContentInfoParser content = comData.getEncapContentInfo();
+ InputExpander expander = expanderProvider.get(comData.getCompressionAlgorithmIdentifier());
+
+ ASN1OctetStringParser bytes = (ASN1OctetStringParser)content.getContent(BERTags.OCTET_STRING);
+
+ return new CMSTypedStream(content.getContentType().getId(), expander.getInputStream(bytes.getOctetStream()));
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("IOException reading compressed content.", e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataStreamGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataStreamGenerator.java
new file mode 100644
index 000000000..47af9b4f7
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSCompressedDataStreamGenerator.java
@@ -0,0 +1,165 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.BERSequenceGenerator;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.operator.OutputCompressor;
+
+/**
+ * General class for generating a compressed CMS message stream.
+ * <p>
+ * A simple example of usage.
+ * </p>
+ * <pre>
+ * CMSCompressedDataStreamGenerator gen = new CMSCompressedDataStreamGenerator();
+ *
+ * OutputStream cOut = gen.open(outputStream, new ZlibCompressor());
+ *
+ * cOut.write(data);
+ *
+ * cOut.close();
+ * </pre>
+ */
+public class CMSCompressedDataStreamGenerator
+{
+ public static final String ZLIB = "1.2.840.113549.1.9.16.3.8";
+
+ private int _bufferSize;
+
+ /**
+ * base constructor
+ */
+ public CMSCompressedDataStreamGenerator()
+ {
+ }
+
+ /**
+ * Set the underlying string size for encapsulated data
+ *
+ * @param bufferSize length of octet strings to buffer the data.
+ */
+ public void setBufferSize(
+ int bufferSize)
+ {
+ _bufferSize = bufferSize;
+ }
+
+ /**
+ * Open a compressing output stream with the PKCS#7 content type OID of "data".
+ *
+ * @param out the stream to encode to.
+ * @param compressor the type of compressor to use.
+ * @return an output stream to write the data be compressed to.
+ * @throws IOException
+ */
+ public OutputStream open(
+ OutputStream out,
+ OutputCompressor compressor)
+ throws IOException
+ {
+ return open(CMSObjectIdentifiers.data, out, compressor);
+ }
+
+ /**
+ * Open a compressing output stream.
+ *
+ * @param contentOID the content type OID.
+ * @param out the stream to encode to.
+ * @param compressor the type of compressor to use.
+ * @return an output stream to write the data be compressed to.
+ * @throws IOException
+ */
+ public OutputStream open(
+ ASN1ObjectIdentifier contentOID,
+ OutputStream out,
+ OutputCompressor compressor)
+ throws IOException
+ {
+ BERSequenceGenerator sGen = new BERSequenceGenerator(out);
+
+ sGen.addObject(CMSObjectIdentifiers.compressedData);
+
+ //
+ // Compressed Data
+ //
+ BERSequenceGenerator cGen = new BERSequenceGenerator(sGen.getRawOutputStream(), 0, true);
+
+ cGen.addObject(new ASN1Integer(0));
+
+ //
+ // AlgorithmIdentifier
+ //
+ cGen.addObject(compressor.getAlgorithmIdentifier());
+
+ //
+ // Encapsulated ContentInfo
+ //
+ BERSequenceGenerator eiGen = new BERSequenceGenerator(cGen.getRawOutputStream());
+
+ eiGen.addObject(contentOID);
+
+ OutputStream octetStream = CMSUtils.createBEROctetOutputStream(
+ eiGen.getRawOutputStream(), 0, true, _bufferSize);
+
+ return new CmsCompressedOutputStream(
+ compressor.getOutputStream(octetStream), sGen, cGen, eiGen);
+ }
+
+ private class CmsCompressedOutputStream
+ extends OutputStream
+ {
+ private OutputStream _out;
+ private BERSequenceGenerator _sGen;
+ private BERSequenceGenerator _cGen;
+ private BERSequenceGenerator _eiGen;
+
+ CmsCompressedOutputStream(
+ OutputStream out,
+ BERSequenceGenerator sGen,
+ BERSequenceGenerator cGen,
+ BERSequenceGenerator eiGen)
+ {
+ _out = out;
+ _sGen = sGen;
+ _cGen = cGen;
+ _eiGen = eiGen;
+ }
+
+ public void write(
+ int b)
+ throws IOException
+ {
+ _out.write(b);
+ }
+
+
+ public void write(
+ byte[] bytes,
+ int off,
+ int len)
+ throws IOException
+ {
+ _out.write(bytes, off, len);
+ }
+
+ public void write(
+ byte[] bytes)
+ throws IOException
+ {
+ _out.write(bytes);
+ }
+
+ public void close()
+ throws IOException
+ {
+ _out.close();
+ _eiGen.close();
+ _cGen.close();
+ _sGen.close();
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSConfig.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSConfig.java
new file mode 100644
index 000000000..d53a984ff
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSConfig.java
@@ -0,0 +1,34 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+
+public class CMSConfig
+{
+ /**
+ * Set the mapping for the encryption algorithm used in association with a SignedData generation
+ * or interpretation.
+ *
+ * @param oid object identifier to map.
+ * @param algorithmName algorithm name to use.
+ */
+ public static void setSigningEncryptionAlgorithmMapping(String oid, String algorithmName)
+ {
+ ASN1ObjectIdentifier id = new ASN1ObjectIdentifier(oid);
+
+ CMSSignedHelper.INSTANCE.setSigningEncryptionAlgorithmMapping(id, algorithmName);
+ }
+
+ /**
+ * Set the mapping for the digest algorithm to use in conjunction with a SignedData generation
+ * or interpretation.
+ *
+ * @param oid object identifier to map.
+ * @param algorithmName algorithm name to use.
+ */
+ public static void setSigningDigestAlgorithmMapping(String oid, String algorithmName)
+ {
+ ASN1ObjectIdentifier id = new ASN1ObjectIdentifier(oid);
+
+ CMSSignedHelper.INSTANCE.setSigningDigestAlgorithmMapping(id, algorithmName);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSContentInfoParser.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSContentInfoParser.java
new file mode 100644
index 000000000..10ef9ffdf
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSContentInfoParser.java
@@ -0,0 +1,45 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.ASN1SequenceParser;
+import org.spongycastle.asn1.ASN1StreamParser;
+import org.spongycastle.asn1.cms.ContentInfoParser;
+
+public class CMSContentInfoParser
+{
+ protected ContentInfoParser _contentInfo;
+ protected InputStream _data;
+
+ protected CMSContentInfoParser(
+ InputStream data)
+ throws CMSException
+ {
+ _data = data;
+
+ try
+ {
+ ASN1StreamParser in = new ASN1StreamParser(data);
+
+ _contentInfo = new ContentInfoParser((ASN1SequenceParser)in.readObject());
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("IOException reading content.", e);
+ }
+ catch (ClassCastException e)
+ {
+ throw new CMSException("Unexpected object reading content.", e);
+ }
+ }
+
+ /**
+ * Close the underlying data stream.
+ * @throws IOException if the close fails.
+ */
+ public void close() throws IOException
+ {
+ _data.close();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSDigestedData.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSDigestedData.java
new file mode 100644
index 000000000..fb07fb53b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSDigestedData.java
@@ -0,0 +1,136 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.DigestedData;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.util.Arrays;
+
+/**
+ * containing class for an CMS Digested Data object
+ * <pre>
+ * CMSDigestedData cd = new CMSDigestedData(inputStream);
+ *
+ *
+ * process(cd.getContent());
+ * </pre>
+ */
+public class CMSDigestedData
+{
+ private ContentInfo contentInfo;
+ private DigestedData digestedData;
+
+ public CMSDigestedData(
+ byte[] compressedData)
+ throws CMSException
+ {
+ this(CMSUtils.readContentInfo(compressedData));
+ }
+
+ public CMSDigestedData(
+ InputStream compressedData)
+ throws CMSException
+ {
+ this(CMSUtils.readContentInfo(compressedData));
+ }
+
+ public CMSDigestedData(
+ ContentInfo contentInfo)
+ throws CMSException
+ {
+ this.contentInfo = contentInfo;
+
+ try
+ {
+ this.digestedData = DigestedData.getInstance(contentInfo.getContent());
+ }
+ catch (ClassCastException e)
+ {
+ throw new CMSException("Malformed content.", e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CMSException("Malformed content.", e);
+ }
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return contentInfo.getContentType();
+ }
+
+ public AlgorithmIdentifier getDigestAlgorithm()
+ {
+ return digestedData.getDigestAlgorithm();
+ }
+
+ /**
+ * Return the digested content
+ *
+ * @return the digested content
+ * @throws CMSException if there is an exception un-compressing the data.
+ */
+ public CMSProcessable getDigestedContent()
+ throws CMSException
+ {
+ ContentInfo content = digestedData.getEncapContentInfo();
+
+ try
+ {
+ return new CMSProcessableByteArray(content.getContentType(), ((ASN1OctetString)content.getContent()).getOctets());
+ }
+ catch (Exception e)
+ {
+ throw new CMSException("exception reading digested stream.", e);
+ }
+ }
+
+ /**
+ * return the ContentInfo
+ */
+ public ContentInfo toASN1Structure()
+ {
+ return contentInfo;
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return contentInfo.getEncoded();
+ }
+
+ public boolean verify(DigestCalculatorProvider calculatorProvider)
+ throws CMSException
+ {
+ try
+ {
+ ContentInfo content = digestedData.getEncapContentInfo();
+ DigestCalculator calc = calculatorProvider.get(digestedData.getDigestAlgorithm());
+
+ OutputStream dOut = calc.getOutputStream();
+
+ dOut.write(((ASN1OctetString)content.getContent()).getOctets());
+
+ return Arrays.areEqual(digestedData.getDigest(), calc.getDigest());
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new CMSException("unable to create digest calculator: " + e.getMessage(), e);
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("unable process content: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedData.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedData.java
new file mode 100644
index 000000000..c833610ac
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedData.java
@@ -0,0 +1,62 @@
+package org.spongycastle.cms;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.EncryptedContentInfo;
+import org.spongycastle.asn1.cms.EncryptedData;
+import org.spongycastle.operator.InputDecryptor;
+import org.spongycastle.operator.InputDecryptorProvider;
+
+public class CMSEncryptedData
+{
+ private ContentInfo contentInfo;
+ private EncryptedData encryptedData;
+
+ public CMSEncryptedData(ContentInfo contentInfo)
+ {
+ this.contentInfo = contentInfo;
+
+ this.encryptedData = EncryptedData.getInstance(contentInfo.getContent());
+ }
+
+ public byte[] getContent(InputDecryptorProvider inputDecryptorProvider)
+ throws CMSException
+ {
+ try
+ {
+ return CMSUtils.streamToByteArray(getContentStream(inputDecryptorProvider).getContentStream());
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("unable to parse internal stream: " + e.getMessage(), e);
+ }
+ }
+
+ public CMSTypedStream getContentStream(InputDecryptorProvider inputDecryptorProvider)
+ throws CMSException
+ {
+ try
+ {
+ EncryptedContentInfo encContentInfo = encryptedData.getEncryptedContentInfo();
+ InputDecryptor decrytor = inputDecryptorProvider.get(encContentInfo.getContentEncryptionAlgorithm());
+
+ ByteArrayInputStream encIn = new ByteArrayInputStream(encContentInfo.getEncryptedContent().getOctets());
+
+ return new CMSTypedStream(encContentInfo.getContentType(), decrytor.getInputStream(encIn));
+ }
+ catch (Exception e)
+ {
+ throw new CMSException("unable to create stream: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * return the ContentInfo
+ */
+ public ContentInfo toASN1Structure()
+ {
+ return contentInfo;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedDataGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedDataGenerator.java
new file mode 100644
index 000000000..b2a750870
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedDataGenerator.java
@@ -0,0 +1,109 @@
+package org.spongycastle.cms;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.HashMap;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.BEROctetString;
+import org.spongycastle.asn1.BERSet;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.EncryptedContentInfo;
+import org.spongycastle.asn1.cms.EncryptedData;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.OutputEncryptor;
+
+/**
+ * General class for generating a CMS enveloped-data message.
+ *
+ * A simple example of usage.
+ *
+ * <pre>
+ * CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+ *
+ * CMSEncryptedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+ *
+ * CMSEncryptedData ed = edGen.generate(
+ * msg,
+ * new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC)
+ * .setProvider("SC").build());
+ *
+ * </pre>
+ */
+public class CMSEncryptedDataGenerator
+ extends CMSEncryptedGenerator
+{
+ /**
+ * base constructor
+ */
+ public CMSEncryptedDataGenerator()
+ {
+ }
+
+ private CMSEncryptedData doGenerate(
+ CMSTypedData content,
+ OutputEncryptor contentEncryptor)
+ throws CMSException
+ {
+ AlgorithmIdentifier encAlgId;
+ ASN1OctetString encContent;
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ try
+ {
+ OutputStream cOut = contentEncryptor.getOutputStream(bOut);
+
+ content.write(cOut);
+
+ cOut.close();
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("");
+ }
+
+ byte[] encryptedContent = bOut.toByteArray();
+
+ encAlgId = contentEncryptor.getAlgorithmIdentifier();
+
+ encContent = new BEROctetString(encryptedContent);
+
+ EncryptedContentInfo eci = new EncryptedContentInfo(
+ content.getContentType(),
+ encAlgId,
+ encContent);
+
+ ASN1Set unprotectedAttrSet = null;
+ if (unprotectedAttributeGenerator != null)
+ {
+ AttributeTable attrTable = unprotectedAttributeGenerator.getAttributes(new HashMap());
+
+ unprotectedAttrSet = new BERSet(attrTable.toASN1EncodableVector());
+ }
+
+ ContentInfo contentInfo = new ContentInfo(
+ CMSObjectIdentifiers.encryptedData,
+ new EncryptedData(eci, unprotectedAttrSet));
+
+ return new CMSEncryptedData(contentInfo);
+ }
+
+ /**
+ * generate an encrypted object that contains an CMS Encrypted Data structure.
+ *
+ * @param content the content to be encrypted
+ * @param contentEncryptor the symmetric key based encryptor to encrypt the content with.
+ */
+ public CMSEncryptedData generate(
+ CMSTypedData content,
+ OutputEncryptor contentEncryptor)
+ throws CMSException
+ {
+ return doGenerate(content, contentEncryptor);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedGenerator.java
new file mode 100644
index 000000000..cce7a6d43
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEncryptedGenerator.java
@@ -0,0 +1,21 @@
+package org.spongycastle.cms;
+
+/**
+ * General class for generating a CMS encrypted-data message.
+ */
+public class CMSEncryptedGenerator
+{
+ protected CMSAttributeTableGenerator unprotectedAttributeGenerator = null;
+
+ /**
+ * base constructor
+ */
+ protected CMSEncryptedGenerator()
+ {
+ }
+
+ public void setUnprotectedAttributeGenerator(CMSAttributeTableGenerator unprotectedAttributeGenerator)
+ {
+ this.unprotectedAttributeGenerator = unprotectedAttributeGenerator;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedData.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedData.java
new file mode 100644
index 000000000..cc4cd30c9
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedData.java
@@ -0,0 +1,206 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.EncryptedContentInfo;
+import org.spongycastle.asn1.cms.EnvelopedData;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * containing class for an CMS Enveloped Data object
+ * <p>
+ * Example of use - assuming the first recipient matches the private key we have.
+ * <pre>
+ * CMSEnvelopedData ed = new CMSEnvelopedData(inputStream);
+ *
+ * RecipientInformationStore recipients = ed.getRecipientInfos();
+ *
+ * Collection c = recipients.getRecipients();
+ * Iterator it = c.iterator();
+ *
+ * if (it.hasNext())
+ * {
+ * RecipientInformation recipient = (RecipientInformation)it.next();
+ *
+ * byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(privateKey).setProvider("SC"));
+ *
+ * processData(recData);
+ * }
+ * </pre>
+ */
+public class CMSEnvelopedData
+{
+ RecipientInformationStore recipientInfoStore;
+ ContentInfo contentInfo;
+
+ private AlgorithmIdentifier encAlg;
+ private ASN1Set unprotectedAttributes;
+ private OriginatorInformation originatorInfo;
+
+ public CMSEnvelopedData(
+ byte[] envelopedData)
+ throws CMSException
+ {
+ this(CMSUtils.readContentInfo(envelopedData));
+ }
+
+ public CMSEnvelopedData(
+ InputStream envelopedData)
+ throws CMSException
+ {
+ this(CMSUtils.readContentInfo(envelopedData));
+ }
+
+ /**
+ * Construct a CMSEnvelopedData object from a content info object.
+ *
+ * @param contentInfo the contentInfo containing the CMS EnvelopedData object.
+ * @throws CMSException in the case where malformed content is encountered.
+ */
+ public CMSEnvelopedData(
+ ContentInfo contentInfo)
+ throws CMSException
+ {
+ this.contentInfo = contentInfo;
+
+ try
+ {
+ EnvelopedData envData = EnvelopedData.getInstance(contentInfo.getContent());
+
+ if (envData.getOriginatorInfo() != null)
+ {
+ originatorInfo = new OriginatorInformation(envData.getOriginatorInfo());
+ }
+
+ //
+ // read the recipients
+ //
+ ASN1Set recipientInfos = envData.getRecipientInfos();
+
+ //
+ // read the encrypted content info
+ //
+ EncryptedContentInfo encInfo = envData.getEncryptedContentInfo();
+ this.encAlg = encInfo.getContentEncryptionAlgorithm();
+ CMSReadable readable = new CMSProcessableByteArray(encInfo.getEncryptedContent().getOctets());
+ CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSEnvelopedSecureReadable(
+ this.encAlg, readable);
+
+ //
+ // build the RecipientInformationStore
+ //
+ this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore(
+ recipientInfos, this.encAlg, secureReadable);
+
+ this.unprotectedAttributes = envData.getUnprotectedAttrs();
+ }
+ catch (ClassCastException e)
+ {
+ throw new CMSException("Malformed content.", e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CMSException("Malformed content.", e);
+ }
+ }
+
+ private byte[] encodeObj(
+ ASN1Encodable obj)
+ throws IOException
+ {
+ if (obj != null)
+ {
+ return obj.toASN1Primitive().getEncoded();
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the originator information associated with this message if present.
+ *
+ * @return OriginatorInformation, null if not present.
+ */
+ public OriginatorInformation getOriginatorInfo()
+ {
+ return originatorInfo;
+ }
+
+ /**
+ * Return the content encryption algorithm details for the data in this object.
+ *
+ * @return AlgorithmIdentifier representing the content encryption algorithm.
+ */
+ public AlgorithmIdentifier getContentEncryptionAlgorithm()
+ {
+ return encAlg;
+ }
+
+ /**
+ * return the object identifier for the content encryption algorithm.
+ */
+ public String getEncryptionAlgOID()
+ {
+ return encAlg.getAlgorithm().getId();
+ }
+
+ /**
+ * return the ASN.1 encoded encryption algorithm parameters, or null if
+ * there aren't any.
+ */
+ public byte[] getEncryptionAlgParams()
+ {
+ try
+ {
+ return encodeObj(encAlg.getParameters());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("exception getting encryption parameters " + e);
+ }
+ }
+
+ /**
+ * return a store of the intended recipients for this message
+ */
+ public RecipientInformationStore getRecipientInfos()
+ {
+ return recipientInfoStore;
+ }
+
+ /**
+ * return the ContentInfo
+ */
+ public ContentInfo toASN1Structure()
+ {
+ return contentInfo;
+ }
+
+ /**
+ * return a table of the unprotected attributes indexed by
+ * the OID of the attribute.
+ */
+ public AttributeTable getUnprotectedAttributes()
+ {
+ if (unprotectedAttributes == null)
+ {
+ return null;
+ }
+
+ return new AttributeTable(unprotectedAttributes);
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return contentInfo.getEncoded();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataGenerator.java
new file mode 100644
index 000000000..b23a82544
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataGenerator.java
@@ -0,0 +1,131 @@
+package org.spongycastle.cms;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.BEROctetString;
+import org.spongycastle.asn1.BERSet;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.EncryptedContentInfo;
+import org.spongycastle.asn1.cms.EnvelopedData;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OutputEncryptor;
+
+/**
+ * General class for generating a CMS enveloped-data message.
+ *
+ * A simple example of usage.
+ *
+ * <pre>
+ * CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+ *
+ * CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+ *
+ * edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(recipientCert).setProvider("SC"));
+ *
+ * CMSEnvelopedData ed = edGen.generate(
+ * msg,
+ * new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC)
+ * .setProvider("SC").build());
+ *
+ * </pre>
+ */
+public class CMSEnvelopedDataGenerator
+ extends CMSEnvelopedGenerator
+{
+ /**
+ * base constructor
+ */
+ public CMSEnvelopedDataGenerator()
+ {
+ }
+
+ private CMSEnvelopedData doGenerate(
+ CMSTypedData content,
+ OutputEncryptor contentEncryptor)
+ throws CMSException
+ {
+ if (!oldRecipientInfoGenerators.isEmpty())
+ {
+ throw new IllegalStateException("can only use addRecipientGenerator() with this method");
+ }
+
+ ASN1EncodableVector recipientInfos = new ASN1EncodableVector();
+ AlgorithmIdentifier encAlgId;
+ ASN1OctetString encContent;
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ try
+ {
+ OutputStream cOut = contentEncryptor.getOutputStream(bOut);
+
+ content.write(cOut);
+
+ cOut.close();
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("");
+ }
+
+ byte[] encryptedContent = bOut.toByteArray();
+
+ encAlgId = contentEncryptor.getAlgorithmIdentifier();
+
+ encContent = new BEROctetString(encryptedContent);
+
+ GenericKey encKey = contentEncryptor.getKey();
+
+ for (Iterator it = recipientInfoGenerators.iterator(); it.hasNext();)
+ {
+ RecipientInfoGenerator recipient = (RecipientInfoGenerator)it.next();
+
+ recipientInfos.add(recipient.generate(encKey));
+ }
+
+ EncryptedContentInfo eci = new EncryptedContentInfo(
+ content.getContentType(),
+ encAlgId,
+ encContent);
+
+ ASN1Set unprotectedAttrSet = null;
+ if (unprotectedAttributeGenerator != null)
+ {
+ AttributeTable attrTable = unprotectedAttributeGenerator.getAttributes(new HashMap());
+
+ unprotectedAttrSet = new BERSet(attrTable.toASN1EncodableVector());
+ }
+
+ ContentInfo contentInfo = new ContentInfo(
+ CMSObjectIdentifiers.envelopedData,
+ new EnvelopedData(originatorInfo, new DERSet(recipientInfos), eci, unprotectedAttrSet));
+
+ return new CMSEnvelopedData(contentInfo);
+ }
+
+ /**
+ * generate an enveloped object that contains an CMS Enveloped Data
+ * object using the given provider.
+ *
+ * @param content the content to be encrypted
+ * @param contentEncryptor the symmetric key based encryptor to encrypt the content with.
+ */
+ public CMSEnvelopedData generate(
+ CMSTypedData content,
+ OutputEncryptor contentEncryptor)
+ throws CMSException
+ {
+ return doGenerate(content, contentEncryptor);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataParser.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataParser.java
new file mode 100644
index 000000000..45d602e2a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataParser.java
@@ -0,0 +1,208 @@
+package org.spongycastle.cms;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1OctetStringParser;
+import org.spongycastle.asn1.ASN1SequenceParser;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.ASN1SetParser;
+import org.spongycastle.asn1.BERTags;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.EncryptedContentInfoParser;
+import org.spongycastle.asn1.cms.EnvelopedDataParser;
+import org.spongycastle.asn1.cms.OriginatorInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * Parsing class for an CMS Enveloped Data object from an input stream.
+ * <p>
+ * Note: that because we are in a streaming mode only one recipient can be tried and it is important
+ * that the methods on the parser are called in the appropriate order.
+ * </p>
+ * <p>
+ * Example of use - assuming the first recipient matches the private key we have.
+ * <pre>
+ * CMSEnvelopedDataParser ep = new CMSEnvelopedDataParser(inputStream);
+ *
+ * RecipientInformationStore recipients = ep.getRecipientInfos();
+ *
+ * Collection c = recipients.getRecipients();
+ * Iterator it = c.iterator();
+ *
+ * if (it.hasNext())
+ * {
+ * RecipientInformation recipient = (RecipientInformation)it.next();
+ *
+ * CMSTypedStream recData = recipient.getContentStream(new JceKeyTransEnvelopedRecipient(privateKey).setProvider("SC"));
+ *
+ * processDataStream(recData.getContentStream());
+ * }
+ * </pre>
+ * Note: this class does not introduce buffering - if you are processing large files you should create
+ * the parser with:
+ * <pre>
+ * CMSEnvelopedDataParser ep = new CMSEnvelopedDataParser(new BufferedInputStream(inputStream, bufSize));
+ * </pre>
+ * where bufSize is a suitably large buffer size.
+ */
+public class CMSEnvelopedDataParser
+ extends CMSContentInfoParser
+{
+ RecipientInformationStore recipientInfoStore;
+ EnvelopedDataParser envelopedData;
+
+ private AlgorithmIdentifier encAlg;
+ private AttributeTable unprotectedAttributes;
+ private boolean attrNotRead;
+ private OriginatorInformation originatorInfo;
+
+ public CMSEnvelopedDataParser(
+ byte[] envelopedData)
+ throws CMSException, IOException
+ {
+ this(new ByteArrayInputStream(envelopedData));
+ }
+
+ public CMSEnvelopedDataParser(
+ InputStream envelopedData)
+ throws CMSException, IOException
+ {
+ super(envelopedData);
+
+ this.attrNotRead = true;
+ this.envelopedData = new EnvelopedDataParser((ASN1SequenceParser)_contentInfo.getContent(BERTags.SEQUENCE));
+
+ // TODO Validate version?
+ //DERInteger version = this._envelopedData.getVersion();
+
+ OriginatorInfo info = this.envelopedData.getOriginatorInfo();
+
+ if (info != null)
+ {
+ this.originatorInfo = new OriginatorInformation(info);
+ }
+
+ //
+ // read the recipients
+ //
+ ASN1Set recipientInfos = ASN1Set.getInstance(this.envelopedData.getRecipientInfos().toASN1Primitive());
+
+ //
+ // read the encrypted content info
+ //
+ EncryptedContentInfoParser encInfo = this.envelopedData.getEncryptedContentInfo();
+ this.encAlg = encInfo.getContentEncryptionAlgorithm();
+ CMSReadable readable = new CMSProcessableInputStream(
+ ((ASN1OctetStringParser)encInfo.getEncryptedContent(BERTags.OCTET_STRING)).getOctetStream());
+ CMSSecureReadable secureReadable = new CMSEnvelopedHelper.CMSEnvelopedSecureReadable(
+ this.encAlg, readable);
+
+ //
+ // build the RecipientInformationStore
+ //
+ this.recipientInfoStore = CMSEnvelopedHelper.buildRecipientInformationStore(
+ recipientInfos, this.encAlg, secureReadable);
+ }
+
+ /**
+ * return the object identifier for the content encryption algorithm.
+ */
+ public String getEncryptionAlgOID()
+ {
+ return encAlg.getAlgorithm().toString();
+ }
+
+ /**
+ * return the ASN.1 encoded encryption algorithm parameters, or null if
+ * there aren't any.
+ */
+ public byte[] getEncryptionAlgParams()
+ {
+ try
+ {
+ return encodeObj(encAlg.getParameters());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("exception getting encryption parameters " + e);
+ }
+ }
+
+ /**
+ * Return the content encryption algorithm details for the data in this object.
+ *
+ * @return AlgorithmIdentifier representing the content encryption algorithm.
+ */
+ public AlgorithmIdentifier getContentEncryptionAlgorithm()
+ {
+ return encAlg;
+ }
+
+ /**
+ * Return the originator information associated with this message if present.
+ *
+ * @return OriginatorInformation, null if not present.
+ */
+ public OriginatorInformation getOriginatorInfo()
+ {
+ return originatorInfo;
+ }
+
+ /**
+ * return a store of the intended recipients for this message
+ */
+ public RecipientInformationStore getRecipientInfos()
+ {
+ return recipientInfoStore;
+ }
+
+ /**
+ * return a table of the unprotected attributes indexed by
+ * the OID of the attribute.
+ * @exception IOException
+ */
+ public AttributeTable getUnprotectedAttributes()
+ throws IOException
+ {
+ if (unprotectedAttributes == null && attrNotRead)
+ {
+ ASN1SetParser set = envelopedData.getUnprotectedAttrs();
+
+ attrNotRead = false;
+
+ if (set != null)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ ASN1Encodable o;
+
+ while ((o = set.readObject()) != null)
+ {
+ ASN1SequenceParser seq = (ASN1SequenceParser)o;
+
+ v.add(seq.toASN1Primitive());
+ }
+
+ unprotectedAttributes = new AttributeTable(new DERSet(v));
+ }
+ }
+
+ return unprotectedAttributes;
+ }
+
+ private byte[] encodeObj(
+ ASN1Encodable obj)
+ throws IOException
+ {
+ if (obj != null)
+ {
+ return obj.toASN1Primitive().getEncoded();
+ }
+
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataStreamGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataStreamGenerator.java
new file mode 100644
index 000000000..86f0a7c5f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedDataStreamGenerator.java
@@ -0,0 +1,305 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.BERSequenceGenerator;
+import org.spongycastle.asn1.BERSet;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.DERTaggedObject;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.EnvelopedData;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OutputEncryptor;
+
+/**
+ * General class for generating a CMS enveloped-data message stream.
+ * <p>
+ * A simple example of usage.
+ * <pre>
+ * CMSEnvelopedDataStreamGenerator edGen = new CMSEnvelopedDataStreamGenerator();
+ *
+ * edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(recipientCert).setProvider("SC"));
+ *
+ * ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ *
+ * OutputStream out = edGen.open(
+ * bOut, new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC)
+ * .setProvider("SC").build());
+ * out.write(data);
+ *
+ * out.close();
+ * </pre>
+ */
+public class CMSEnvelopedDataStreamGenerator
+ extends CMSEnvelopedGenerator
+{
+ private ASN1Set _unprotectedAttributes = null;
+ private int _bufferSize;
+ private boolean _berEncodeRecipientSet;
+
+ /**
+ * base constructor
+ */
+ public CMSEnvelopedDataStreamGenerator()
+ {
+ }
+
+ /**
+ * Set the underlying string size for encapsulated data
+ *
+ * @param bufferSize length of octet strings to buffer the data.
+ */
+ public void setBufferSize(
+ int bufferSize)
+ {
+ _bufferSize = bufferSize;
+ }
+
+ /**
+ * Use a BER Set to store the recipient information
+ */
+ public void setBEREncodeRecipients(
+ boolean berEncodeRecipientSet)
+ {
+ _berEncodeRecipientSet = berEncodeRecipientSet;
+ }
+
+ private ASN1Integer getVersion()
+ {
+ if (originatorInfo != null || _unprotectedAttributes != null)
+ {
+ return new ASN1Integer(2);
+ }
+ else
+ {
+ return new ASN1Integer(0);
+ }
+ }
+
+ private OutputStream doOpen(
+ ASN1ObjectIdentifier dataType,
+ OutputStream out,
+ OutputEncryptor encryptor)
+ throws IOException, CMSException
+ {
+ ASN1EncodableVector recipientInfos = new ASN1EncodableVector();
+ GenericKey encKey = encryptor.getKey();
+ Iterator it = recipientInfoGenerators.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInfoGenerator recipient = (RecipientInfoGenerator)it.next();
+
+ recipientInfos.add(recipient.generate(encKey));
+ }
+
+ return open(dataType, out, recipientInfos, encryptor);
+ }
+
+ protected OutputStream open(
+ ASN1ObjectIdentifier dataType,
+ OutputStream out,
+ ASN1EncodableVector recipientInfos,
+ OutputEncryptor encryptor)
+ throws IOException
+ {
+ //
+ // ContentInfo
+ //
+ BERSequenceGenerator cGen = new BERSequenceGenerator(out);
+
+ cGen.addObject(CMSObjectIdentifiers.envelopedData);
+
+ //
+ // Encrypted Data
+ //
+ BERSequenceGenerator envGen = new BERSequenceGenerator(cGen.getRawOutputStream(), 0, true);
+
+ envGen.addObject(getVersion());
+
+ if (originatorInfo != null)
+ {
+ envGen.addObject(new DERTaggedObject(false, 0, originatorInfo));
+ }
+
+ if (_berEncodeRecipientSet)
+ {
+ envGen.getRawOutputStream().write(new BERSet(recipientInfos).getEncoded());
+ }
+ else
+ {
+ envGen.getRawOutputStream().write(new DERSet(recipientInfos).getEncoded());
+ }
+
+ BERSequenceGenerator eiGen = new BERSequenceGenerator(envGen.getRawOutputStream());
+
+ eiGen.addObject(dataType);
+
+ AlgorithmIdentifier encAlgId = encryptor.getAlgorithmIdentifier();
+
+ eiGen.getRawOutputStream().write(encAlgId.getEncoded());
+
+ OutputStream octetStream = CMSUtils.createBEROctetOutputStream(
+ eiGen.getRawOutputStream(), 0, false, _bufferSize);
+
+ OutputStream cOut = encryptor.getOutputStream(octetStream);
+
+ return new CmsEnvelopedDataOutputStream(cOut, cGen, envGen, eiGen);
+ }
+
+ protected OutputStream open(
+ OutputStream out,
+ ASN1EncodableVector recipientInfos,
+ OutputEncryptor encryptor)
+ throws CMSException
+ {
+ try
+ {
+ //
+ // ContentInfo
+ //
+ BERSequenceGenerator cGen = new BERSequenceGenerator(out);
+
+ cGen.addObject(CMSObjectIdentifiers.envelopedData);
+
+ //
+ // Encrypted Data
+ //
+ BERSequenceGenerator envGen = new BERSequenceGenerator(cGen.getRawOutputStream(), 0, true);
+
+ ASN1Set recipients;
+ if (_berEncodeRecipientSet)
+ {
+ recipients = new BERSet(recipientInfos);
+ }
+ else
+ {
+ recipients = new DERSet(recipientInfos);
+ }
+
+ envGen.addObject(new ASN1Integer(EnvelopedData.calculateVersion(originatorInfo, recipients, _unprotectedAttributes)));
+
+ if (originatorInfo != null)
+ {
+ envGen.addObject(new DERTaggedObject(false, 0, originatorInfo));
+ }
+
+ envGen.getRawOutputStream().write(recipients.getEncoded());
+
+ BERSequenceGenerator eiGen = new BERSequenceGenerator(envGen.getRawOutputStream());
+
+ eiGen.addObject(CMSObjectIdentifiers.data);
+
+ AlgorithmIdentifier encAlgId = encryptor.getAlgorithmIdentifier();
+
+ eiGen.getRawOutputStream().write(encAlgId.getEncoded());
+
+ OutputStream octetStream = CMSUtils.createBEROctetOutputStream(
+ eiGen.getRawOutputStream(), 0, false, _bufferSize);
+
+ return new CmsEnvelopedDataOutputStream(encryptor.getOutputStream(octetStream), cGen, envGen, eiGen);
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("exception decoding algorithm parameters.", e);
+ }
+ }
+
+ /**
+ * generate an enveloped object that contains an CMS Enveloped Data
+ * object using the given encryptor.
+ */
+ public OutputStream open(
+ OutputStream out,
+ OutputEncryptor encryptor)
+ throws CMSException, IOException
+ {
+ return doOpen(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()), out, encryptor);
+ }
+
+ /**
+ * generate an enveloped object that contains an CMS Enveloped Data
+ * object using the given encryptor and marking the data as being of the passed
+ * in type.
+ */
+ public OutputStream open(
+ ASN1ObjectIdentifier dataType,
+ OutputStream out,
+ OutputEncryptor encryptor)
+ throws CMSException, IOException
+ {
+ return doOpen(dataType, out, encryptor);
+ }
+
+ private class CmsEnvelopedDataOutputStream
+ extends OutputStream
+ {
+ private OutputStream _out;
+ private BERSequenceGenerator _cGen;
+ private BERSequenceGenerator _envGen;
+ private BERSequenceGenerator _eiGen;
+
+ public CmsEnvelopedDataOutputStream(
+ OutputStream out,
+ BERSequenceGenerator cGen,
+ BERSequenceGenerator envGen,
+ BERSequenceGenerator eiGen)
+ {
+ _out = out;
+ _cGen = cGen;
+ _envGen = envGen;
+ _eiGen = eiGen;
+ }
+
+ public void write(
+ int b)
+ throws IOException
+ {
+ _out.write(b);
+ }
+
+ public void write(
+ byte[] bytes,
+ int off,
+ int len)
+ throws IOException
+ {
+ _out.write(bytes, off, len);
+ }
+
+ public void write(
+ byte[] bytes)
+ throws IOException
+ {
+ _out.write(bytes);
+ }
+
+ public void close()
+ throws IOException
+ {
+ _out.close();
+ _eiGen.close();
+
+ if (unprotectedAttributeGenerator != null)
+ {
+ AttributeTable attrTable = unprotectedAttributeGenerator.getAttributes(new HashMap());
+
+ ASN1Set unprotectedAttrs = new BERSet(attrTable.toASN1EncodableVector());
+
+ _envGen.addObject(new DERTaggedObject(false, 1, unprotectedAttrs));
+ }
+
+ _envGen.close();
+ _cGen.close();
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedGenerator.java
new file mode 100644
index 000000000..c8702240a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedGenerator.java
@@ -0,0 +1,75 @@
+package org.spongycastle.cms;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.spongycastle.asn1.cms.OriginatorInfo;
+import org.spongycastle.asn1.kisa.KISAObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.ntt.NTTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+
+/**
+ * General class for generating a CMS enveloped-data message.
+ */
+public class CMSEnvelopedGenerator
+{
+ public static final String DES_EDE3_CBC = PKCSObjectIdentifiers.des_EDE3_CBC.getId();
+ public static final String RC2_CBC = PKCSObjectIdentifiers.RC2_CBC.getId();
+ public static final String IDEA_CBC = "1.3.6.1.4.1.188.7.1.1.2";
+ public static final String CAST5_CBC = "1.2.840.113533.7.66.10";
+ public static final String AES128_CBC = NISTObjectIdentifiers.id_aes128_CBC.getId();
+ public static final String AES192_CBC = NISTObjectIdentifiers.id_aes192_CBC.getId();
+ public static final String AES256_CBC = NISTObjectIdentifiers.id_aes256_CBC.getId();
+ public static final String CAMELLIA128_CBC = NTTObjectIdentifiers.id_camellia128_cbc.getId();
+ public static final String CAMELLIA192_CBC = NTTObjectIdentifiers.id_camellia192_cbc.getId();
+ public static final String CAMELLIA256_CBC = NTTObjectIdentifiers.id_camellia256_cbc.getId();
+ public static final String SEED_CBC = KISAObjectIdentifiers.id_seedCBC.getId();
+
+ public static final String DES_EDE3_WRAP = PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId();
+ public static final String AES128_WRAP = NISTObjectIdentifiers.id_aes128_wrap.getId();
+ public static final String AES192_WRAP = NISTObjectIdentifiers.id_aes192_wrap.getId();
+ public static final String AES256_WRAP = NISTObjectIdentifiers.id_aes256_wrap.getId();
+ public static final String CAMELLIA128_WRAP = NTTObjectIdentifiers.id_camellia128_wrap.getId();
+ public static final String CAMELLIA192_WRAP = NTTObjectIdentifiers.id_camellia192_wrap.getId();
+ public static final String CAMELLIA256_WRAP = NTTObjectIdentifiers.id_camellia256_wrap.getId();
+ public static final String SEED_WRAP = KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap.getId();
+
+ public static final String ECDH_SHA1KDF = X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme.getId();
+ public static final String ECMQV_SHA1KDF = X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme.getId();
+
+ final List oldRecipientInfoGenerators = new ArrayList();
+ final List recipientInfoGenerators = new ArrayList();
+
+ protected CMSAttributeTableGenerator unprotectedAttributeGenerator = null;
+
+ protected OriginatorInfo originatorInfo;
+
+ /**
+ * base constructor
+ */
+ public CMSEnvelopedGenerator()
+ {
+ }
+
+ public void setUnprotectedAttributeGenerator(CMSAttributeTableGenerator unprotectedAttributeGenerator)
+ {
+ this.unprotectedAttributeGenerator = unprotectedAttributeGenerator;
+ }
+
+ public void setOriginatorInfo(OriginatorInformation originatorInfo)
+ {
+ this.originatorInfo = originatorInfo.toASN1Structure();
+ }
+
+ /**
+ * Add a generator to produce the recipient info required.
+ *
+ * @param recipientGenerator a generator of a recipient info object.
+ */
+ public void addRecipientInfoGenerator(RecipientInfoGenerator recipientGenerator)
+ {
+ recipientInfoGenerators.add(recipientGenerator);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedHelper.java
new file mode 100644
index 000000000..e0a71f933
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSEnvelopedHelper.java
@@ -0,0 +1,203 @@
+package org.spongycastle.cms;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.cms.KEKRecipientInfo;
+import org.spongycastle.asn1.cms.KeyAgreeRecipientInfo;
+import org.spongycastle.asn1.cms.KeyTransRecipientInfo;
+import org.spongycastle.asn1.cms.PasswordRecipientInfo;
+import org.spongycastle.asn1.cms.RecipientInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.util.Integers;
+
+class CMSEnvelopedHelper
+{
+ static final CMSEnvelopedHelper INSTANCE = new CMSEnvelopedHelper();
+
+ private static final Map KEYSIZES = new HashMap();
+ private static final Map BASE_CIPHER_NAMES = new HashMap();
+ private static final Map CIPHER_ALG_NAMES = new HashMap();
+ private static final Map MAC_ALG_NAMES = new HashMap();
+
+ static
+ {
+ KEYSIZES.put(CMSEnvelopedGenerator.DES_EDE3_CBC, Integers.valueOf(192));
+ KEYSIZES.put(CMSEnvelopedGenerator.AES128_CBC, Integers.valueOf(128));
+ KEYSIZES.put(CMSEnvelopedGenerator.AES192_CBC, Integers.valueOf(192));
+ KEYSIZES.put(CMSEnvelopedGenerator.AES256_CBC, Integers.valueOf(256));
+
+ BASE_CIPHER_NAMES.put(CMSEnvelopedGenerator.DES_EDE3_CBC, "DESEDE");
+ BASE_CIPHER_NAMES.put(CMSEnvelopedGenerator.AES128_CBC, "AES");
+ BASE_CIPHER_NAMES.put(CMSEnvelopedGenerator.AES192_CBC, "AES");
+ BASE_CIPHER_NAMES.put(CMSEnvelopedGenerator.AES256_CBC, "AES");
+
+ CIPHER_ALG_NAMES.put(CMSEnvelopedGenerator.DES_EDE3_CBC, "DESEDE/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSEnvelopedGenerator.AES128_CBC, "AES/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSEnvelopedGenerator.AES192_CBC, "AES/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSEnvelopedGenerator.AES256_CBC, "AES/CBC/PKCS5Padding");
+
+ MAC_ALG_NAMES.put(CMSEnvelopedGenerator.DES_EDE3_CBC, "DESEDEMac");
+ MAC_ALG_NAMES.put(CMSEnvelopedGenerator.AES128_CBC, "AESMac");
+ MAC_ALG_NAMES.put(CMSEnvelopedGenerator.AES192_CBC, "AESMac");
+ MAC_ALG_NAMES.put(CMSEnvelopedGenerator.AES256_CBC, "AESMac");
+ }
+
+
+
+ int getKeySize(String oid)
+ {
+ Integer keySize = (Integer)KEYSIZES.get(oid);
+
+ if (keySize == null)
+ {
+ throw new IllegalArgumentException("no keysize for " + oid);
+ }
+
+ return keySize.intValue();
+ }
+
+
+
+ static RecipientInformationStore buildRecipientInformationStore(
+ ASN1Set recipientInfos, AlgorithmIdentifier messageAlgorithm, CMSSecureReadable secureReadable)
+ {
+ return buildRecipientInformationStore(recipientInfos, messageAlgorithm, secureReadable, null);
+ }
+
+ static RecipientInformationStore buildRecipientInformationStore(
+ ASN1Set recipientInfos, AlgorithmIdentifier messageAlgorithm, CMSSecureReadable secureReadable, AuthAttributesProvider additionalData)
+ {
+ List infos = new ArrayList();
+ for (int i = 0; i != recipientInfos.size(); i++)
+ {
+ RecipientInfo info = RecipientInfo.getInstance(recipientInfos.getObjectAt(i));
+
+ readRecipientInfo(infos, info, messageAlgorithm, secureReadable, additionalData);
+ }
+ return new RecipientInformationStore(infos);
+ }
+
+ private static void readRecipientInfo(
+ List infos, RecipientInfo info, AlgorithmIdentifier messageAlgorithm, CMSSecureReadable secureReadable, AuthAttributesProvider additionalData)
+ {
+ ASN1Encodable recipInfo = info.getInfo();
+ if (recipInfo instanceof KeyTransRecipientInfo)
+ {
+ infos.add(new KeyTransRecipientInformation(
+ (KeyTransRecipientInfo)recipInfo, messageAlgorithm, secureReadable, additionalData));
+ }
+ else if (recipInfo instanceof KEKRecipientInfo)
+ {
+ infos.add(new KEKRecipientInformation(
+ (KEKRecipientInfo)recipInfo, messageAlgorithm, secureReadable, additionalData));
+ }
+ else if (recipInfo instanceof KeyAgreeRecipientInfo)
+ {
+ KeyAgreeRecipientInformation.readRecipientInfo(infos,
+ (KeyAgreeRecipientInfo)recipInfo, messageAlgorithm, secureReadable, additionalData);
+ }
+ else if (recipInfo instanceof PasswordRecipientInfo)
+ {
+ infos.add(new PasswordRecipientInformation(
+ (PasswordRecipientInfo)recipInfo, messageAlgorithm, secureReadable, additionalData));
+ }
+ }
+
+ static class CMSDigestAuthenticatedSecureReadable
+ implements CMSSecureReadable
+ {
+ private DigestCalculator digestCalculator;
+ private CMSReadable readable;
+
+ public CMSDigestAuthenticatedSecureReadable(DigestCalculator digestCalculator, CMSReadable readable)
+ {
+ this.digestCalculator = digestCalculator;
+ this.readable = readable;
+ }
+
+ public InputStream getInputStream()
+ throws IOException, CMSException
+ {
+ return new FilterInputStream(readable.getInputStream())
+ {
+ public int read()
+ throws IOException
+ {
+ int b = in.read();
+
+ if (b >= 0)
+ {
+ digestCalculator.getOutputStream().write(b);
+ }
+
+ return b;
+ }
+
+ public int read(byte[] inBuf, int inOff, int inLen)
+ throws IOException
+ {
+ int n = in.read(inBuf, inOff, inLen);
+
+ if (n >= 0)
+ {
+ digestCalculator.getOutputStream().write(inBuf, inOff, n);
+ }
+
+ return n;
+ }
+ };
+ }
+
+ public byte[] getDigest()
+ {
+ return digestCalculator.getDigest();
+ }
+ }
+
+ static class CMSAuthenticatedSecureReadable implements CMSSecureReadable
+ {
+ private AlgorithmIdentifier algorithm;
+ private CMSReadable readable;
+
+ CMSAuthenticatedSecureReadable(AlgorithmIdentifier algorithm, CMSReadable readable)
+ {
+ this.algorithm = algorithm;
+ this.readable = readable;
+ }
+
+ public InputStream getInputStream()
+ throws IOException, CMSException
+ {
+ return readable.getInputStream();
+ }
+
+ }
+
+ static class CMSEnvelopedSecureReadable implements CMSSecureReadable
+ {
+ private AlgorithmIdentifier algorithm;
+ private CMSReadable readable;
+
+ CMSEnvelopedSecureReadable(AlgorithmIdentifier algorithm, CMSReadable readable)
+ {
+ this.algorithm = algorithm;
+ this.readable = readable;
+ }
+
+ public InputStream getInputStream()
+ throws IOException, CMSException
+ {
+ return readable.getInputStream();
+ }
+
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSException.java
new file mode 100644
index 000000000..dd8401201
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSException.java
@@ -0,0 +1,32 @@
+package org.spongycastle.cms;
+
+public class CMSException
+ extends Exception
+{
+ Exception e;
+
+ public CMSException(
+ String msg)
+ {
+ super(msg);
+ }
+
+ public CMSException(
+ String msg,
+ Exception e)
+ {
+ super(msg);
+
+ this.e = e;
+ }
+
+ public Exception getUnderlyingException()
+ {
+ return e;
+ }
+
+ public Throwable getCause()
+ {
+ return e;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSProcessable.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSProcessable.java
new file mode 100644
index 000000000..ed27eb159
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSProcessable.java
@@ -0,0 +1,21 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Use CMSTypedData instead of this. See CMSProcessableFile/ByteArray for defaults.
+ */
+public interface CMSProcessable
+{
+ /**
+ * generic routine to copy out the data we want processed - the OutputStream
+ * passed in will do the handling on it's own.
+ * <p>
+ * Note: this routine may be called multiple times.
+ */
+ public void write(OutputStream out)
+ throws IOException, CMSException;
+
+ public Object getContent();
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSProcessableByteArray.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSProcessableByteArray.java
new file mode 100644
index 000000000..2732a26ed
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSProcessableByteArray.java
@@ -0,0 +1,55 @@
+package org.spongycastle.cms;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.util.Arrays;
+
+/**
+ * a holding class for a byte array of data to be processed.
+ */
+public class CMSProcessableByteArray
+ implements CMSTypedData, CMSReadable
+{
+ private final ASN1ObjectIdentifier type;
+ private final byte[] bytes;
+
+ public CMSProcessableByteArray(
+ byte[] bytes)
+ {
+ this(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()), bytes);
+ }
+
+ public CMSProcessableByteArray(
+ ASN1ObjectIdentifier type,
+ byte[] bytes)
+ {
+ this.type = type;
+ this.bytes = bytes;
+ }
+
+ public InputStream getInputStream()
+ {
+ return new ByteArrayInputStream(bytes);
+ }
+
+ public void write(OutputStream zOut)
+ throws IOException, CMSException
+ {
+ zOut.write(bytes);
+ }
+
+ public Object getContent()
+ {
+ return Arrays.clone(bytes);
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return type;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSProcessableFile.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSProcessableFile.java
new file mode 100644
index 000000000..6415dd5d0
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSProcessableFile.java
@@ -0,0 +1,80 @@
+package org.spongycastle.cms;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+
+/**
+ * a holding class for a file of data to be processed.
+ */
+public class CMSProcessableFile
+ implements CMSTypedData, CMSReadable
+{
+ private static final int DEFAULT_BUF_SIZE = 32 * 1024;
+
+ private final ASN1ObjectIdentifier type;
+ private final File file;
+ private final byte[] buf;
+
+ public CMSProcessableFile(
+ File file)
+ {
+ this(file, DEFAULT_BUF_SIZE);
+ }
+
+ public CMSProcessableFile(
+ File file,
+ int bufSize)
+ {
+ this(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()), file, bufSize);
+ }
+
+ public CMSProcessableFile(
+ ASN1ObjectIdentifier type,
+ File file,
+ int bufSize)
+ {
+ this.type = type;
+ this.file = file;
+ buf = new byte[bufSize];
+ }
+
+ public InputStream getInputStream()
+ throws IOException, CMSException
+ {
+ return new BufferedInputStream(new FileInputStream(file), DEFAULT_BUF_SIZE);
+ }
+
+ public void write(OutputStream zOut)
+ throws IOException, CMSException
+ {
+ FileInputStream fIn = new FileInputStream(file);
+ int len;
+
+ while ((len = fIn.read(buf, 0, buf.length)) > 0)
+ {
+ zOut.write(buf, 0, len);
+ }
+
+ fIn.close();
+ }
+
+ /**
+ * Return the file handle.
+ */
+ public Object getContent()
+ {
+ return file;
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return type;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSProcessableInputStream.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSProcessableInputStream.java
new file mode 100644
index 000000000..fc644c957
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSProcessableInputStream.java
@@ -0,0 +1,50 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.spongycastle.util.io.Streams;
+
+class CMSProcessableInputStream implements CMSProcessable, CMSReadable
+{
+ private InputStream input;
+ private boolean used = false;
+
+ public CMSProcessableInputStream(
+ InputStream input)
+ {
+ this.input = input;
+ }
+
+ public InputStream getInputStream()
+ {
+ checkSingleUsage();
+
+ return input;
+ }
+
+ public void write(OutputStream zOut)
+ throws IOException, CMSException
+ {
+ checkSingleUsage();
+
+ Streams.pipeAll(input, zOut);
+ input.close();
+ }
+
+ public Object getContent()
+ {
+ return getInputStream();
+ }
+
+ private synchronized void checkSingleUsage()
+ {
+ if (used)
+ {
+ throw new IllegalStateException("CMSProcessableInputStream can only be used once");
+ }
+
+ used = true;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSReadable.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSReadable.java
new file mode 100644
index 000000000..ecf79a43d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSReadable.java
@@ -0,0 +1,10 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+interface CMSReadable
+{
+ public InputStream getInputStream()
+ throws IOException, CMSException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSRuntimeException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSRuntimeException.java
new file mode 100644
index 000000000..29805bb2d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSRuntimeException.java
@@ -0,0 +1,32 @@
+package org.spongycastle.cms;
+
+public class CMSRuntimeException
+ extends RuntimeException
+{
+ Exception e;
+
+ public CMSRuntimeException(
+ String name)
+ {
+ super(name);
+ }
+
+ public CMSRuntimeException(
+ String name,
+ Exception e)
+ {
+ super(name);
+
+ this.e = e;
+ }
+
+ public Exception getUnderlyingException()
+ {
+ return e;
+ }
+
+ public Throwable getCause()
+ {
+ return e;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSecureReadable.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSecureReadable.java
new file mode 100644
index 000000000..b16aef111
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSecureReadable.java
@@ -0,0 +1,10 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+interface CMSSecureReadable
+{
+ InputStream getInputStream()
+ throws IOException, CMSException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignatureAlgorithmNameGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignatureAlgorithmNameGenerator.java
new file mode 100644
index 000000000..8941a90bb
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignatureAlgorithmNameGenerator.java
@@ -0,0 +1,15 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface CMSSignatureAlgorithmNameGenerator
+{
+ /**
+ * Return the digest algorithm using one of the standard string
+ * representations rather than the algorithm object identifier (if possible).
+ *
+ * @param digestAlg the digest algorithm id.
+ * @param encryptionAlg the encryption, or signing, algorithm id.
+ */
+ String getSignatureName(AlgorithmIdentifier digestAlg, AlgorithmIdentifier encryptionAlg);
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignatureEncryptionAlgorithmFinder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignatureEncryptionAlgorithmFinder.java
new file mode 100644
index 000000000..886b41015
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignatureEncryptionAlgorithmFinder.java
@@ -0,0 +1,17 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * Finder which is used to look up the algorithm identifiers representing the encryption algorithms that
+ * are associated with a particular signature algorithm.
+ */
+public interface CMSSignatureEncryptionAlgorithmFinder
+{
+ /**
+ * Return the encryption algorithm identifier associated with the passed in signatureAlgorithm
+ * @param signatureAlgorithm the algorithm identifier of the signature of interest
+ * @return the algorithm identifier to be associated with the encryption algorithm used in signature creation.
+ */
+ AlgorithmIdentifier findEncryptionAlgorithm(AlgorithmIdentifier signatureAlgorithm);
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedData.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedData.java
new file mode 100644
index 000000000..cea2c955a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedData.java
@@ -0,0 +1,543 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.BERSequence;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.SignedData;
+import org.spongycastle.asn1.cms.SignerInfo;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.SignatureAlgorithmIdentifierFinder;
+import org.spongycastle.util.Store;
+
+/**
+ * general class for handling a pkcs7-signature message.
+ *
+ * A simple example of usage - note, in the example below the validity of
+ * the certificate isn't verified, just the fact that one of the certs
+ * matches the given signer...
+ *
+ * <pre>
+ * Store certStore = s.getCertificates();
+ * SignerInformationStore signers = s.getSignerInfos();
+ * Collection c = signers.getSigners();
+ * Iterator it = c.iterator();
+ *
+ * while (it.hasNext())
+ * {
+ * SignerInformation signer = (SignerInformation)it.next();
+ * Collection certCollection = certStore.getMatches(signer.getSID());
+ *
+ * Iterator certIt = certCollection.iterator();
+ * X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+ *
+ * if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("SC").build(cert)))
+ * {
+ * verified++;
+ * }
+ * }
+ * </pre>
+ */
+public class CMSSignedData
+{
+ private static final CMSSignedHelper HELPER = CMSSignedHelper.INSTANCE;
+
+ SignedData signedData;
+ ContentInfo contentInfo;
+ CMSTypedData signedContent;
+ SignerInformationStore signerInfoStore;
+
+ private Map hashes;
+
+ private CMSSignedData(
+ CMSSignedData c)
+ {
+ this.signedData = c.signedData;
+ this.contentInfo = c.contentInfo;
+ this.signedContent = c.signedContent;
+ this.signerInfoStore = c.signerInfoStore;
+ }
+
+ public CMSSignedData(
+ byte[] sigBlock)
+ throws CMSException
+ {
+ this(CMSUtils.readContentInfo(sigBlock));
+ }
+
+ public CMSSignedData(
+ CMSProcessable signedContent,
+ byte[] sigBlock)
+ throws CMSException
+ {
+ this(signedContent, CMSUtils.readContentInfo(sigBlock));
+ }
+
+ /**
+ * Content with detached signature, digests precomputed
+ *
+ * @param hashes a map of precomputed digests for content indexed by name of hash.
+ * @param sigBlock the signature object.
+ */
+ public CMSSignedData(
+ Map hashes,
+ byte[] sigBlock)
+ throws CMSException
+ {
+ this(hashes, CMSUtils.readContentInfo(sigBlock));
+ }
+
+ /**
+ * base constructor - content with detached signature.
+ *
+ * @param signedContent the content that was signed.
+ * @param sigData the signature object.
+ */
+ public CMSSignedData(
+ CMSProcessable signedContent,
+ InputStream sigData)
+ throws CMSException
+ {
+ this(signedContent, CMSUtils.readContentInfo(new ASN1InputStream(sigData)));
+ }
+
+ /**
+ * base constructor - with encapsulated content
+ */
+ public CMSSignedData(
+ InputStream sigData)
+ throws CMSException
+ {
+ this(CMSUtils.readContentInfo(sigData));
+ }
+
+ public CMSSignedData(
+ final CMSProcessable signedContent,
+ ContentInfo sigData)
+ throws CMSException
+ {
+ if (signedContent instanceof CMSTypedData)
+ {
+ this.signedContent = (CMSTypedData)signedContent;
+ }
+ else
+ {
+ this.signedContent = new CMSTypedData()
+ {
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return signedData.getEncapContentInfo().getContentType();
+ }
+
+ public void write(OutputStream out)
+ throws IOException, CMSException
+ {
+ signedContent.write(out);
+ }
+
+ public Object getContent()
+ {
+ return signedContent.getContent();
+ }
+ };
+ }
+
+ this.contentInfo = sigData;
+ this.signedData = getSignedData();
+ }
+
+ public CMSSignedData(
+ Map hashes,
+ ContentInfo sigData)
+ throws CMSException
+ {
+ this.hashes = hashes;
+ this.contentInfo = sigData;
+ this.signedData = getSignedData();
+ }
+
+ public CMSSignedData(
+ ContentInfo sigData)
+ throws CMSException
+ {
+ this.contentInfo = sigData;
+ this.signedData = getSignedData();
+
+ //
+ // this can happen if the signed message is sent simply to send a
+ // certificate chain.
+ //
+ if (signedData.getEncapContentInfo().getContent() != null)
+ {
+ this.signedContent = new CMSProcessableByteArray(signedData.getEncapContentInfo().getContentType(),
+ ((ASN1OctetString)(signedData.getEncapContentInfo()
+ .getContent())).getOctets());
+ }
+ else
+ {
+ this.signedContent = null;
+ }
+ }
+
+ private SignedData getSignedData()
+ throws CMSException
+ {
+ try
+ {
+ return SignedData.getInstance(contentInfo.getContent());
+ }
+ catch (ClassCastException e)
+ {
+ throw new CMSException("Malformed content.", e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CMSException("Malformed content.", e);
+ }
+ }
+
+ /**
+ * Return the version number for this object
+ */
+ public int getVersion()
+ {
+ return signedData.getVersion().getValue().intValue();
+ }
+
+ /**
+ * return the collection of signers that are associated with the
+ * signatures for the message.
+ */
+ public SignerInformationStore getSignerInfos()
+ {
+ if (signerInfoStore == null)
+ {
+ ASN1Set s = signedData.getSignerInfos();
+ List signerInfos = new ArrayList();
+ SignatureAlgorithmIdentifierFinder sigAlgFinder = new DefaultSignatureAlgorithmIdentifierFinder();
+
+ for (int i = 0; i != s.size(); i++)
+ {
+ SignerInfo info = SignerInfo.getInstance(s.getObjectAt(i));
+ ASN1ObjectIdentifier contentType = signedData.getEncapContentInfo().getContentType();
+
+ if (hashes == null)
+ {
+ signerInfos.add(new SignerInformation(info, contentType, signedContent, null));
+ }
+ else
+ {
+ Object obj = hashes.keySet().iterator().next();
+ byte[] hash = (obj instanceof String) ? (byte[])hashes.get(info.getDigestAlgorithm().getAlgorithm().getId()) : (byte[])hashes.get(info.getDigestAlgorithm().getAlgorithm());
+
+ signerInfos.add(new SignerInformation(info, contentType, null, hash));
+ }
+ }
+
+ signerInfoStore = new SignerInformationStore(signerInfos);
+ }
+
+ return signerInfoStore;
+ }
+
+ /**
+ * Return any X.509 certificate objects in this SignedData structure as a Store of X509CertificateHolder objects.
+ *
+ * @return a Store of X509CertificateHolder objects.
+ */
+ public Store getCertificates()
+ {
+ return HELPER.getCertificates(signedData.getCertificates());
+ }
+
+ /**
+ * Return any X.509 CRL objects in this SignedData structure as a Store of X509CRLHolder objects.
+ *
+ * @return a Store of X509CRLHolder objects.
+ */
+ public Store getCRLs()
+ {
+ return HELPER.getCRLs(signedData.getCRLs());
+ }
+
+ /**
+ * Return any X.509 attribute certificate objects in this SignedData structure as a Store of X509AttributeCertificateHolder objects.
+ *
+ * @return a Store of X509AttributeCertificateHolder objects.
+ */
+ public Store getAttributeCertificates()
+ {
+ return HELPER.getAttributeCertificates(signedData.getCertificates());
+ }
+
+ /**
+ * Return any OtherRevocationInfo OtherRevInfo objects of the type indicated by otherRevocationInfoFormat in
+ * this SignedData structure.
+ *
+ * @param otherRevocationInfoFormat OID of the format type been looked for.
+ *
+ * @return a Store of ASN1Encodable objects representing any objects of otherRevocationInfoFormat found.
+ */
+ public Store getOtherRevocationInfo(ASN1ObjectIdentifier otherRevocationInfoFormat)
+ {
+ return HELPER.getOtherRevocationInfo(otherRevocationInfoFormat, signedData.getCRLs());
+ }
+
+ /**
+ * Return the a string representation of the OID associated with the
+ * encapsulated content info structure carried in the signed data.
+ *
+ * @return the OID for the content type.
+ */
+ public String getSignedContentTypeOID()
+ {
+ return signedData.getEncapContentInfo().getContentType().getId();
+ }
+
+ public CMSTypedData getSignedContent()
+ {
+ return signedContent;
+ }
+
+ /**
+ * return the ContentInfo
+ */
+ public ContentInfo toASN1Structure()
+ {
+ return contentInfo;
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return contentInfo.getEncoded();
+ }
+
+ /**
+ * Verify all the SignerInformation objects and their associated counter signatures attached
+ * to this CMS SignedData object.
+ *
+ * @param verifierProvider a provider of SignerInformationVerifier objects.
+ * @return true if all verify, false otherwise.
+ * @throws CMSException if an exception occurs during the verification process.
+ */
+ public boolean verifySignatures(SignerInformationVerifierProvider verifierProvider)
+ throws CMSException
+ {
+ return verifySignatures(verifierProvider, false);
+ }
+
+ /**
+ * Verify all the SignerInformation objects and optionally their associated counter signatures attached
+ * to this CMS SignedData object.
+ *
+ * @param verifierProvider a provider of SignerInformationVerifier objects.
+ * @param ignoreCounterSignatures if true don't check counter signatures. If false check counter signatures as well.
+ * @return true if all verify, false otherwise.
+ * @throws CMSException if an exception occurs during the verification process.
+ */
+ public boolean verifySignatures(SignerInformationVerifierProvider verifierProvider, boolean ignoreCounterSignatures)
+ throws CMSException
+ {
+ Collection signers = this.getSignerInfos().getSigners();
+
+ for (Iterator it = signers.iterator(); it.hasNext();)
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+
+ try
+ {
+ SignerInformationVerifier verifier = verifierProvider.get(signer.getSID());
+
+ if (!signer.verify(verifier))
+ {
+ return false;
+ }
+
+ if (!ignoreCounterSignatures)
+ {
+ Collection counterSigners = signer.getCounterSignatures().getSigners();
+
+ for (Iterator cIt = counterSigners.iterator(); cIt.hasNext();)
+ {
+ SignerInformation counterSigner = (SignerInformation)cIt.next();
+ SignerInformationVerifier counterVerifier = verifierProvider.get(signer.getSID());
+
+ if (!counterSigner.verify(counterVerifier))
+ {
+ return false;
+ }
+ }
+ }
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new CMSException("failure in verifier provider: " + e.getMessage(), e);
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Replace the SignerInformation store associated with this
+ * CMSSignedData object with the new one passed in. You would
+ * probably only want to do this if you wanted to change the unsigned
+ * attributes associated with a signer, or perhaps delete one.
+ *
+ * @param signedData the signed data object to be used as a base.
+ * @param signerInformationStore the new signer information store to use.
+ * @return a new signed data object.
+ */
+ public static CMSSignedData replaceSigners(
+ CMSSignedData signedData,
+ SignerInformationStore signerInformationStore)
+ {
+ //
+ // copy
+ //
+ CMSSignedData cms = new CMSSignedData(signedData);
+
+ //
+ // replace the store
+ //
+ cms.signerInfoStore = signerInformationStore;
+
+ //
+ // replace the signers in the SignedData object
+ //
+ ASN1EncodableVector digestAlgs = new ASN1EncodableVector();
+ ASN1EncodableVector vec = new ASN1EncodableVector();
+
+ Iterator it = signerInformationStore.getSigners().iterator();
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ digestAlgs.add(CMSSignedHelper.INSTANCE.fixAlgID(signer.getDigestAlgorithmID()));
+ vec.add(signer.toASN1Structure());
+ }
+
+ ASN1Set digests = new DERSet(digestAlgs);
+ ASN1Set signers = new DERSet(vec);
+ ASN1Sequence sD = (ASN1Sequence)signedData.signedData.toASN1Primitive();
+
+ vec = new ASN1EncodableVector();
+
+ //
+ // signers are the last item in the sequence.
+ //
+ vec.add(sD.getObjectAt(0)); // version
+ vec.add(digests);
+
+ for (int i = 2; i != sD.size() - 1; i++)
+ {
+ vec.add(sD.getObjectAt(i));
+ }
+
+ vec.add(signers);
+
+ cms.signedData = SignedData.getInstance(new BERSequence(vec));
+
+ //
+ // replace the contentInfo with the new one
+ //
+ cms.contentInfo = new ContentInfo(cms.contentInfo.getContentType(), cms.signedData);
+
+ return cms;
+ }
+
+ /**
+ * Replace the certificate and CRL information associated with this
+ * CMSSignedData object with the new one passed in.
+ *
+ * @param signedData the signed data object to be used as a base.
+ * @param certificates the new certificates to be used.
+ * @param attrCerts the new attribute certificates to be used.
+ * @param crls the new CRLs to be used.
+ * @return a new signed data object.
+ * @exception CMSException if there is an error processing the CertStore
+ */
+ public static CMSSignedData replaceCertificatesAndCRLs(
+ CMSSignedData signedData,
+ Store certificates,
+ Store attrCerts,
+ Store crls)
+ throws CMSException
+ {
+ //
+ // copy
+ //
+ CMSSignedData cms = new CMSSignedData(signedData);
+
+ //
+ // replace the certs and crls in the SignedData object
+ //
+ ASN1Set certSet = null;
+ ASN1Set crlSet = null;
+
+ if (certificates != null || attrCerts != null)
+ {
+ List certs = new ArrayList();
+
+ if (certificates != null)
+ {
+ certs.addAll(CMSUtils.getCertificatesFromStore(certificates));
+ }
+ if (attrCerts != null)
+ {
+ certs.addAll(CMSUtils.getAttributeCertificatesFromStore(attrCerts));
+ }
+
+ ASN1Set set = CMSUtils.createBerSetFromList(certs);
+
+ if (set.size() != 0)
+ {
+ certSet = set;
+ }
+ }
+
+ if (crls != null)
+ {
+ ASN1Set set = CMSUtils.createBerSetFromList(CMSUtils.getCRLsFromStore(crls));
+
+ if (set.size() != 0)
+ {
+ crlSet = set;
+ }
+ }
+
+ //
+ // replace the CMS structure.
+ //
+ cms.signedData = new SignedData(signedData.signedData.getDigestAlgorithms(),
+ signedData.signedData.getEncapContentInfo(),
+ certSet,
+ crlSet,
+ signedData.signedData.getSignerInfos());
+
+ //
+ // replace the contentInfo with the new one
+ //
+ cms.contentInfo = new ContentInfo(cms.contentInfo.getContentType(), cms.signedData);
+
+ return cms;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataGenerator.java
new file mode 100644
index 000000000..529ca14a9
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataGenerator.java
@@ -0,0 +1,232 @@
+package org.spongycastle.cms;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.BEROctetString;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.SignedData;
+import org.spongycastle.asn1.cms.SignerInfo;
+
+/**
+ * general class for generating a pkcs7-signature message.
+ * <p>
+ * A simple example of usage, generating a detached signature.
+ *
+ * <pre>
+ * List certList = new ArrayList();
+ * CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
+ *
+ * certList.add(signCert);
+ *
+ * Store certs = new JcaCertStore(certList);
+ *
+ * CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+ * ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("SC").build(signKP.getPrivate());
+ *
+ * gen.addSignerInfoGenerator(
+ * new JcaSignerInfoGeneratorBuilder(
+ * new JcaDigestCalculatorProviderBuilder().setProvider("SC").build())
+ * .build(sha1Signer, signCert));
+ *
+ * gen.addCertificates(certs);
+ *
+ * CMSSignedData sigData = gen.generate(msg, false);
+ * </pre>
+ */
+public class CMSSignedDataGenerator
+ extends CMSSignedGenerator
+{
+ private List signerInfs = new ArrayList();
+
+ /**
+ * base constructor
+ */
+ public CMSSignedDataGenerator()
+ {
+ }
+
+ /**
+ * Generate a CMS Signed Data object carrying a detached CMS signature.
+ *
+ * @param content the content to be signed.
+ */
+ public CMSSignedData generate(
+ CMSTypedData content)
+ throws CMSException
+ {
+ return generate(content, false);
+ }
+
+ /**
+ * Generate a CMS Signed Data object which can be carrying a detached CMS signature, or have encapsulated data, depending on the value
+ * of the encapsulated parameter.
+ *
+ * @param content the content to be signed.
+ * @param encapsulate true if the content should be encapsulated in the signature, false otherwise.
+ */
+ public CMSSignedData generate(
+ // FIXME Avoid accessing more than once to support CMSProcessableInputStream
+ CMSTypedData content,
+ boolean encapsulate)
+ throws CMSException
+ {
+ if (!signerInfs.isEmpty())
+ {
+ throw new IllegalStateException("this method can only be used with SignerInfoGenerator");
+ }
+
+ // TODO
+// if (signerInfs.isEmpty())
+// {
+// /* RFC 3852 5.2
+// * "In the degenerate case where there are no signers, the
+// * EncapsulatedContentInfo value being "signed" is irrelevant. In this
+// * case, the content type within the EncapsulatedContentInfo value being
+// * "signed" MUST be id-data (as defined in section 4), and the content
+// * field of the EncapsulatedContentInfo value MUST be omitted."
+// */
+// if (encapsulate)
+// {
+// throw new IllegalArgumentException("no signers, encapsulate must be false");
+// }
+// if (!DATA.equals(eContentType))
+// {
+// throw new IllegalArgumentException("no signers, eContentType must be id-data");
+// }
+// }
+//
+// if (!DATA.equals(eContentType))
+// {
+// /* RFC 3852 5.3
+// * [The 'signedAttrs']...
+// * field is optional, but it MUST be present if the content type of
+// * the EncapsulatedContentInfo value being signed is not id-data.
+// */
+// // TODO signedAttrs must be present for all signers
+// }
+
+ ASN1EncodableVector digestAlgs = new ASN1EncodableVector();
+ ASN1EncodableVector signerInfos = new ASN1EncodableVector();
+
+ digests.clear(); // clear the current preserved digest state
+
+ //
+ // add the precalculated SignerInfo objects.
+ //
+ for (Iterator it = _signers.iterator(); it.hasNext();)
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ digestAlgs.add(CMSSignedHelper.INSTANCE.fixAlgID(signer.getDigestAlgorithmID()));
+
+ // TODO Verify the content type and calculated digest match the precalculated SignerInfo
+ signerInfos.add(signer.toASN1Structure());
+ }
+
+ //
+ // add the SignerInfo objects
+ //
+ ASN1ObjectIdentifier contentTypeOID = content.getContentType();
+
+ ASN1OctetString octs = null;
+
+ if (content != null)
+ {
+ ByteArrayOutputStream bOut = null;
+
+ if (encapsulate)
+ {
+ bOut = new ByteArrayOutputStream();
+ }
+
+ OutputStream cOut = CMSUtils.attachSignersToOutputStream(signerGens, bOut);
+
+ // Just in case it's unencapsulated and there are no signers!
+ cOut = CMSUtils.getSafeOutputStream(cOut);
+
+ try
+ {
+ content.write(cOut);
+
+ cOut.close();
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("data processing exception: " + e.getMessage(), e);
+ }
+
+ if (encapsulate)
+ {
+ octs = new BEROctetString(bOut.toByteArray());
+ }
+ }
+
+ for (Iterator it = signerGens.iterator(); it.hasNext();)
+ {
+ SignerInfoGenerator sGen = (SignerInfoGenerator)it.next();
+ SignerInfo inf = sGen.generate(contentTypeOID);
+
+ digestAlgs.add(inf.getDigestAlgorithm());
+ signerInfos.add(inf);
+
+ byte[] calcDigest = sGen.getCalculatedDigest();
+
+ if (calcDigest != null)
+ {
+ digests.put(inf.getDigestAlgorithm().getAlgorithm().getId(), calcDigest);
+ }
+ }
+
+ ASN1Set certificates = null;
+
+ if (certs.size() != 0)
+ {
+ certificates = CMSUtils.createBerSetFromList(certs);
+ }
+
+ ASN1Set certrevlist = null;
+
+ if (crls.size() != 0)
+ {
+ certrevlist = CMSUtils.createBerSetFromList(crls);
+ }
+
+ ContentInfo encInfo = new ContentInfo(contentTypeOID, octs);
+
+ SignedData sd = new SignedData(
+ new DERSet(digestAlgs),
+ encInfo,
+ certificates,
+ certrevlist,
+ new DERSet(signerInfos));
+
+ ContentInfo contentInfo = new ContentInfo(
+ CMSObjectIdentifiers.signedData, sd);
+
+ return new CMSSignedData(content, contentInfo);
+ }
+
+ /**
+ * generate a set of one or more SignerInformation objects representing counter signatures on
+ * the passed in SignerInformation object.
+ *
+ * @param signer the signer to be countersigned
+ * @return a store containing the signers.
+ */
+ public SignerInformationStore generateCounterSigners(SignerInformation signer)
+ throws CMSException
+ {
+ return this.generate(new CMSProcessableByteArray(null, signer.getSignature()), false).getSignerInfos();
+ }
+}
+
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataParser.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataParser.java
new file mode 100644
index 000000000..89edf8734
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataParser.java
@@ -0,0 +1,624 @@
+package org.spongycastle.cms;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Generator;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetStringParser;
+import org.spongycastle.asn1.ASN1SequenceParser;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.ASN1SetParser;
+import org.spongycastle.asn1.ASN1StreamParser;
+import org.spongycastle.asn1.BERSequenceGenerator;
+import org.spongycastle.asn1.BERSetParser;
+import org.spongycastle.asn1.BERTaggedObject;
+import org.spongycastle.asn1.BERTags;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.DERTaggedObject;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.ContentInfoParser;
+import org.spongycastle.asn1.cms.SignedDataParser;
+import org.spongycastle.asn1.cms.SignerInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.util.Store;
+import org.spongycastle.util.io.Streams;
+
+/**
+ * Parsing class for an CMS Signed Data object from an input stream.
+ * <p>
+ * Note: that because we are in a streaming mode only one signer can be tried and it is important
+ * that the methods on the parser are called in the appropriate order.
+ * </p>
+ * <p>
+ * A simple example of usage for an encapsulated signature.
+ * </p>
+ * <p>
+ * Two notes: first, in the example below the validity of
+ * the certificate isn't verified, just the fact that one of the certs
+ * matches the given signer, and, second, because we are in a streaming
+ * mode the order of the operations is important.
+ * </p>
+ * <pre>
+ * CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider("SC").build(), encapSigData);
+ *
+ * sp.getSignedContent().drain();
+ *
+ * Store certStore = sp.getCertificates();
+ * SignerInformationStore signers = sp.getSignerInfos();
+ *
+ * Collection c = signers.getSigners();
+ * Iterator it = c.iterator();
+ *
+ * while (it.hasNext())
+ * {
+ * SignerInformation signer = (SignerInformation)it.next();
+ * Collection certCollection = certStore.getMatches(signer.getSID());
+ *
+ * Iterator certIt = certCollection.iterator();
+ * X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+ *
+ * System.out.println("verify returns: " + signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("SC").build(cert)));
+ * }
+ * </pre>
+ * Note also: this class does not introduce buffering - if you are processing large files you should create
+ * the parser with:
+ * <pre>
+ * CMSSignedDataParser ep = new CMSSignedDataParser(new BufferedInputStream(encapSigData, bufSize));
+ * </pre>
+ * where bufSize is a suitably large buffer size.
+ */
+public class CMSSignedDataParser
+ extends CMSContentInfoParser
+{
+ private static final CMSSignedHelper HELPER = CMSSignedHelper.INSTANCE;
+
+ private SignedDataParser _signedData;
+ private ASN1ObjectIdentifier _signedContentType;
+ private CMSTypedStream _signedContent;
+ private Map digests;
+
+ private SignerInformationStore _signerInfoStore;
+ private ASN1Set _certSet, _crlSet;
+ private boolean _isCertCrlParsed;
+
+ public CMSSignedDataParser(
+ DigestCalculatorProvider digestCalculatorProvider,
+ byte[] sigBlock)
+ throws CMSException
+ {
+ this(digestCalculatorProvider, new ByteArrayInputStream(sigBlock));
+ }
+
+ public CMSSignedDataParser(
+ DigestCalculatorProvider digestCalculatorProvider,
+ CMSTypedStream signedContent,
+ byte[] sigBlock)
+ throws CMSException
+ {
+ this(digestCalculatorProvider, signedContent, new ByteArrayInputStream(sigBlock));
+ }
+
+ /**
+ * base constructor - with encapsulated content
+ */
+ public CMSSignedDataParser(
+ DigestCalculatorProvider digestCalculatorProvider,
+ InputStream sigData)
+ throws CMSException
+ {
+ this(digestCalculatorProvider, null, sigData);
+ }
+
+ /**
+ * base constructor
+ *
+ * @param digestCalculatorProvider for generating accumulating digests
+ * @param signedContent the content that was signed.
+ * @param sigData the signature object stream.
+ */
+ public CMSSignedDataParser(
+ DigestCalculatorProvider digestCalculatorProvider,
+ CMSTypedStream signedContent,
+ InputStream sigData)
+ throws CMSException
+ {
+ super(sigData);
+
+ try
+ {
+ _signedContent = signedContent;
+ _signedData = SignedDataParser.getInstance(_contentInfo.getContent(BERTags.SEQUENCE));
+ digests = new HashMap();
+
+ ASN1SetParser digAlgs = _signedData.getDigestAlgorithms();
+ ASN1Encodable o;
+
+ while ((o = digAlgs.readObject()) != null)
+ {
+ AlgorithmIdentifier algId = AlgorithmIdentifier.getInstance(o);
+ try
+ {
+ DigestCalculator calculator = digestCalculatorProvider.get(algId);
+
+ if (calculator != null)
+ {
+ this.digests.put(algId.getAlgorithm(), calculator);
+ }
+ }
+ catch (OperatorCreationException e)
+ {
+ // ignore
+ }
+ }
+
+ //
+ // If the message is simply a certificate chain message getContent() may return null.
+ //
+ ContentInfoParser cont = _signedData.getEncapContentInfo();
+ ASN1OctetStringParser octs = (ASN1OctetStringParser)
+ cont.getContent(BERTags.OCTET_STRING);
+
+ if (octs != null)
+ {
+ CMSTypedStream ctStr = new CMSTypedStream(
+ cont.getContentType().getId(), octs.getOctetStream());
+
+ if (_signedContent == null)
+ {
+ _signedContent = ctStr;
+ }
+ else
+ {
+ //
+ // content passed in, need to read past empty encapsulated content info object if present
+ //
+ ctStr.drain();
+ }
+ }
+
+ if (signedContent == null)
+ {
+ _signedContentType = cont.getContentType();
+ }
+ else
+ {
+ _signedContentType = _signedContent.getContentType();
+ }
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("io exception: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Return the version number for the SignedData object
+ *
+ * @return the version number
+ */
+ public int getVersion()
+ {
+ return _signedData.getVersion().getValue().intValue();
+ }
+
+ /**
+ * return the collection of signers that are associated with the
+ * signatures for the message.
+ * @throws CMSException
+ */
+ public SignerInformationStore getSignerInfos()
+ throws CMSException
+ {
+ if (_signerInfoStore == null)
+ {
+ populateCertCrlSets();
+
+ List signerInfos = new ArrayList();
+ Map hashes = new HashMap();
+
+ Iterator it = digests.keySet().iterator();
+ while (it.hasNext())
+ {
+ Object digestKey = it.next();
+
+ hashes.put(digestKey, ((DigestCalculator)digests.get(digestKey)).getDigest());
+ }
+
+ try
+ {
+ ASN1SetParser s = _signedData.getSignerInfos();
+ ASN1Encodable o;
+
+ while ((o = s.readObject()) != null)
+ {
+ SignerInfo info = SignerInfo.getInstance(o.toASN1Primitive());
+
+ byte[] hash = (byte[])hashes.get(info.getDigestAlgorithm().getAlgorithm());
+
+ signerInfos.add(new SignerInformation(info, _signedContentType, null, hash));
+ }
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("io exception: " + e.getMessage(), e);
+ }
+
+ _signerInfoStore = new SignerInformationStore(signerInfos);
+ }
+
+ return _signerInfoStore;
+ }
+
+ /**
+ * Return any X.509 certificate objects in this SignedData structure as a Store of X509CertificateHolder objects.
+ *
+ * @return a Store of X509CertificateHolder objects.
+ */
+ public Store getCertificates()
+ throws CMSException
+ {
+ populateCertCrlSets();
+
+ return HELPER.getCertificates(_certSet);
+ }
+
+ /**
+ * Return any X.509 CRL objects in this SignedData structure as a Store of X509CRLHolder objects.
+ *
+ * @return a Store of X509CRLHolder objects.
+ */
+ public Store getCRLs()
+ throws CMSException
+ {
+ populateCertCrlSets();
+
+ return HELPER.getCRLs(_crlSet);
+ }
+
+ /**
+ * Return any X.509 attribute certificate objects in this SignedData structure as a Store of X509AttributeCertificateHolder objects.
+ *
+ * @return a Store of X509AttributeCertificateHolder objects.
+ */
+ public Store getAttributeCertificates()
+ throws CMSException
+ {
+ populateCertCrlSets();
+
+ return HELPER.getAttributeCertificates(_certSet);
+ }
+
+ /**
+ * Return any OtherRevocationInfo OtherRevInfo objects of the type indicated by otherRevocationInfoFormat in
+ * this SignedData structure.
+ *
+ * @param otherRevocationInfoFormat OID of the format type been looked for.
+ *
+ * @return a Store of ASN1Encodable objects representing any objects of otherRevocationInfoFormat found.
+ */
+ public Store getOtherRevocationInfo(ASN1ObjectIdentifier otherRevocationInfoFormat)
+ throws CMSException
+ {
+ populateCertCrlSets();
+
+ return HELPER.getOtherRevocationInfo(otherRevocationInfoFormat, _crlSet);
+ }
+
+ private void populateCertCrlSets()
+ throws CMSException
+ {
+ if (_isCertCrlParsed)
+ {
+ return;
+ }
+
+ _isCertCrlParsed = true;
+
+ try
+ {
+ // care! Streaming - these must be done in exactly this order.
+ _certSet = getASN1Set(_signedData.getCertificates());
+ _crlSet = getASN1Set(_signedData.getCrls());
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("problem parsing cert/crl sets", e);
+ }
+ }
+
+ /**
+ * Return the a string representation of the OID associated with the
+ * encapsulated content info structure carried in the signed data.
+ *
+ * @return the OID for the content type.
+ */
+ public String getSignedContentTypeOID()
+ {
+ return _signedContentType.getId();
+ }
+
+ public CMSTypedStream getSignedContent()
+ {
+ if (_signedContent == null)
+ {
+ return null;
+ }
+
+ InputStream digStream = CMSUtils.attachDigestsToInputStream(
+ digests.values(), _signedContent.getContentStream());
+
+ return new CMSTypedStream(_signedContent.getContentType(), digStream);
+ }
+
+ /**
+ * Replace the signerinformation store associated with the passed
+ * in message contained in the stream original with the new one passed in.
+ * You would probably only want to do this if you wanted to change the unsigned
+ * attributes associated with a signer, or perhaps delete one.
+ * <p>
+ * The output stream is returned unclosed.
+ * </p>
+ * @param original the signed data stream to be used as a base.
+ * @param signerInformationStore the new signer information store to use.
+ * @param out the stream to write the new signed data object to.
+ * @return out.
+ */
+ public static OutputStream replaceSigners(
+ InputStream original,
+ SignerInformationStore signerInformationStore,
+ OutputStream out)
+ throws CMSException, IOException
+ {
+ ASN1StreamParser in = new ASN1StreamParser(original);
+ ContentInfoParser contentInfo = new ContentInfoParser((ASN1SequenceParser)in.readObject());
+ SignedDataParser signedData = SignedDataParser.getInstance(contentInfo.getContent(BERTags.SEQUENCE));
+
+ BERSequenceGenerator sGen = new BERSequenceGenerator(out);
+
+ sGen.addObject(CMSObjectIdentifiers.signedData);
+
+ BERSequenceGenerator sigGen = new BERSequenceGenerator(sGen.getRawOutputStream(), 0, true);
+
+ // version number
+ sigGen.addObject(signedData.getVersion());
+
+ // digests
+ signedData.getDigestAlgorithms().toASN1Primitive(); // skip old ones
+
+ ASN1EncodableVector digestAlgs = new ASN1EncodableVector();
+
+ for (Iterator it = signerInformationStore.getSigners().iterator(); it.hasNext();)
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ digestAlgs.add(CMSSignedHelper.INSTANCE.fixAlgID(signer.getDigestAlgorithmID()));
+ }
+
+ sigGen.getRawOutputStream().write(new DERSet(digestAlgs).getEncoded());
+
+ // encap content info
+ ContentInfoParser encapContentInfo = signedData.getEncapContentInfo();
+
+ BERSequenceGenerator eiGen = new BERSequenceGenerator(sigGen.getRawOutputStream());
+
+ eiGen.addObject(encapContentInfo.getContentType());
+
+ pipeEncapsulatedOctetString(encapContentInfo, eiGen.getRawOutputStream());
+
+ eiGen.close();
+
+
+ writeSetToGeneratorTagged(sigGen, signedData.getCertificates(), 0);
+ writeSetToGeneratorTagged(sigGen, signedData.getCrls(), 1);
+
+
+ ASN1EncodableVector signerInfos = new ASN1EncodableVector();
+ for (Iterator it = signerInformationStore.getSigners().iterator(); it.hasNext();)
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+
+ signerInfos.add(signer.toASN1Structure());
+ }
+
+ sigGen.getRawOutputStream().write(new DERSet(signerInfos).getEncoded());
+
+ sigGen.close();
+
+ sGen.close();
+
+ return out;
+ }
+
+ /**
+ * Replace the certificate and CRL information associated with this
+ * CMSSignedData object with the new one passed in.
+ * <p>
+ * The output stream is returned unclosed.
+ * </p>
+ * @param original the signed data stream to be used as a base.
+ * @param certs new certificates to be used, if any.
+ * @param crls new CRLs to be used, if any.
+ * @param attrCerts new attribute certificates to be used, if any.
+ * @param out the stream to write the new signed data object to.
+ * @return out.
+ * @exception CMSException if there is an error processing the CertStore
+ */
+ public static OutputStream replaceCertificatesAndCRLs(
+ InputStream original,
+ Store certs,
+ Store crls,
+ Store attrCerts,
+ OutputStream out)
+ throws CMSException, IOException
+ {
+ ASN1StreamParser in = new ASN1StreamParser(original);
+ ContentInfoParser contentInfo = new ContentInfoParser((ASN1SequenceParser)in.readObject());
+ SignedDataParser signedData = SignedDataParser.getInstance(contentInfo.getContent(BERTags.SEQUENCE));
+
+ BERSequenceGenerator sGen = new BERSequenceGenerator(out);
+
+ sGen.addObject(CMSObjectIdentifiers.signedData);
+
+ BERSequenceGenerator sigGen = new BERSequenceGenerator(sGen.getRawOutputStream(), 0, true);
+
+ // version number
+ sigGen.addObject(signedData.getVersion());
+
+ // digests
+ sigGen.getRawOutputStream().write(signedData.getDigestAlgorithms().toASN1Primitive().getEncoded());
+
+ // encap content info
+ ContentInfoParser encapContentInfo = signedData.getEncapContentInfo();
+
+ BERSequenceGenerator eiGen = new BERSequenceGenerator(sigGen.getRawOutputStream());
+
+ eiGen.addObject(encapContentInfo.getContentType());
+
+ pipeEncapsulatedOctetString(encapContentInfo, eiGen.getRawOutputStream());
+
+ eiGen.close();
+
+ //
+ // skip existing certs and CRLs
+ //
+ getASN1Set(signedData.getCertificates());
+ getASN1Set(signedData.getCrls());
+
+ //
+ // replace the certs and crls in the SignedData object
+ //
+ if (certs != null || attrCerts != null)
+ {
+ List certificates = new ArrayList();
+
+ if (certs != null)
+ {
+ certificates.addAll(CMSUtils.getCertificatesFromStore(certs));
+ }
+ if (attrCerts != null)
+ {
+ certificates.addAll(CMSUtils.getAttributeCertificatesFromStore(attrCerts));
+ }
+
+ ASN1Set asn1Certs = CMSUtils.createBerSetFromList(certificates);
+
+ if (asn1Certs.size() > 0)
+ {
+ sigGen.getRawOutputStream().write(new DERTaggedObject(false, 0, asn1Certs).getEncoded());
+ }
+ }
+
+ if (crls != null)
+ {
+ ASN1Set asn1Crls = CMSUtils.createBerSetFromList(CMSUtils.getCRLsFromStore(crls));
+
+ if (asn1Crls.size() > 0)
+ {
+ sigGen.getRawOutputStream().write(new DERTaggedObject(false, 1, asn1Crls).getEncoded());
+ }
+ }
+
+ sigGen.getRawOutputStream().write(signedData.getSignerInfos().toASN1Primitive().getEncoded());
+
+ sigGen.close();
+
+ sGen.close();
+
+ return out;
+ }
+
+ private static void writeSetToGeneratorTagged(
+ ASN1Generator asn1Gen,
+ ASN1SetParser asn1SetParser,
+ int tagNo)
+ throws IOException
+ {
+ ASN1Set asn1Set = getASN1Set(asn1SetParser);
+
+ if (asn1Set != null)
+ {
+ if (asn1SetParser instanceof BERSetParser)
+ {
+ asn1Gen.getRawOutputStream().write(new BERTaggedObject(false, tagNo, asn1Set).getEncoded());
+ }
+ else
+ {
+ asn1Gen.getRawOutputStream().write(new DERTaggedObject(false, tagNo, asn1Set).getEncoded());
+ }
+ }
+ }
+
+ private static ASN1Set getASN1Set(
+ ASN1SetParser asn1SetParser)
+ {
+ return asn1SetParser == null
+ ? null
+ : ASN1Set.getInstance(asn1SetParser.toASN1Primitive());
+ }
+
+ private static void pipeEncapsulatedOctetString(ContentInfoParser encapContentInfo,
+ OutputStream rawOutputStream) throws IOException
+ {
+ ASN1OctetStringParser octs = (ASN1OctetStringParser)
+ encapContentInfo.getContent(BERTags.OCTET_STRING);
+
+ if (octs != null)
+ {
+ pipeOctetString(octs, rawOutputStream);
+ }
+
+// BERTaggedObjectParser contentObject = (BERTaggedObjectParser)encapContentInfo.getContentObject();
+// if (contentObject != null)
+// {
+// // Handle IndefiniteLengthInputStream safely
+// InputStream input = ASN1StreamParser.getSafeRawInputStream(contentObject.getContentStream(true));
+//
+// // TODO BerTaggedObjectGenerator?
+// BEROutputStream berOut = new BEROutputStream(rawOutputStream);
+// berOut.write(DERTags.CONSTRUCTED | DERTags.TAGGED | 0);
+// berOut.write(0x80);
+//
+// pipeRawOctetString(input, rawOutputStream);
+//
+// berOut.write(0x00);
+// berOut.write(0x00);
+//
+// input.close();
+// }
+ }
+
+ private static void pipeOctetString(
+ ASN1OctetStringParser octs,
+ OutputStream output)
+ throws IOException
+ {
+ // TODO Allow specification of a specific fragment size?
+ OutputStream outOctets = CMSUtils.createBEROctetOutputStream(
+ output, 0, true, 0);
+ Streams.pipeAll(octs.getOctetStream(), outOctets);
+ outOctets.close();
+ }
+
+// private static void pipeRawOctetString(
+// InputStream rawInput,
+// OutputStream rawOutput)
+// throws IOException
+// {
+// InputStream tee = new TeeInputStream(rawInput, rawOutput);
+// ASN1StreamParser sp = new ASN1StreamParser(tee);
+// ASN1OctetStringParser octs = (ASN1OctetStringParser)sp.readObject();
+// Streams.drain(octs.getOctetStream());
+// }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataStreamGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataStreamGenerator.java
new file mode 100644
index 000000000..15a94bf58
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedDataStreamGenerator.java
@@ -0,0 +1,486 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.BERSequenceGenerator;
+import org.spongycastle.asn1.BERTaggedObject;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.SignerInfo;
+
+/**
+ * General class for generating a pkcs7-signature message stream.
+ * <p>
+ * A simple example of usage.
+ * </p>
+ * <pre>
+ * X509Certificate signCert = ...
+ * certList.add(signCert);
+ *
+ * Store certs = new JcaCertStore(certList);
+ * ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("SC").build(signKP.getPrivate());
+ *
+ * CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+ *
+ * gen.addSignerInfoGenerator(
+ * new JcaSignerInfoGeneratorBuilder(
+ * new JcaDigestCalculatorProviderBuilder().setProvider("SC").build())
+ * .build(sha1Signer, signCert));
+ *
+ * gen.addCertificates(certs);
+ *
+ * OutputStream sigOut = gen.open(bOut);
+ *
+ * sigOut.write("Hello World!".getBytes());
+ *
+ * sigOut.close();
+ * </pre>
+ */
+public class CMSSignedDataStreamGenerator
+ extends CMSSignedGenerator
+{
+ private int _bufferSize;
+
+ /**
+ * base constructor
+ */
+ public CMSSignedDataStreamGenerator()
+ {
+ }
+
+ /**
+ * Set the underlying string size for encapsulated data
+ *
+ * @param bufferSize length of octet strings to buffer the data.
+ */
+ public void setBufferSize(
+ int bufferSize)
+ {
+ _bufferSize = bufferSize;
+ }
+
+ /**
+ * generate a signed object that for a CMS Signed Data
+ * object using the given provider.
+ */
+ public OutputStream open(
+ OutputStream out)
+ throws IOException
+ {
+ return open(out, false);
+ }
+
+ /**
+ * generate a signed object that for a CMS Signed Data
+ * object using the given provider - if encapsulate is true a copy
+ * of the message will be included in the signature with the
+ * default content type "data".
+ */
+ public OutputStream open(
+ OutputStream out,
+ boolean encapsulate)
+ throws IOException
+ {
+ return open(CMSObjectIdentifiers.data, out, encapsulate);
+ }
+
+ /**
+ * generate a signed object that for a CMS Signed Data
+ * object using the given provider - if encapsulate is true a copy
+ * of the message will be included in the signature with the
+ * default content type "data". If dataOutputStream is non null the data
+ * being signed will be written to the stream as it is processed.
+ * @param out stream the CMS object is to be written to.
+ * @param encapsulate true if data should be encapsulated.
+ * @param dataOutputStream output stream to copy the data being signed to.
+ */
+ public OutputStream open(
+ OutputStream out,
+ boolean encapsulate,
+ OutputStream dataOutputStream)
+ throws IOException
+ {
+ return open(CMSObjectIdentifiers.data, out, encapsulate, dataOutputStream);
+ }
+
+ /**
+ * generate a signed object that for a CMS Signed Data
+ * object using the given provider - if encapsulate is true a copy
+ * of the message will be included in the signature. The content type
+ * is set according to the OID represented by the string signedContentType.
+ */
+ public OutputStream open(
+ ASN1ObjectIdentifier eContentType,
+ OutputStream out,
+ boolean encapsulate)
+ throws IOException
+ {
+ return open(eContentType, out, encapsulate, null);
+ }
+
+ /**
+ * generate a signed object that for a CMS Signed Data
+ * object using the given provider - if encapsulate is true a copy
+ * of the message will be included in the signature. The content type
+ * is set according to the OID represented by the string signedContentType.
+ * @param eContentType OID for data to be signed.
+ * @param out stream the CMS object is to be written to.
+ * @param encapsulate true if data should be encapsulated.
+ * @param dataOutputStream output stream to copy the data being signed to.
+ */
+ public OutputStream open(
+ ASN1ObjectIdentifier eContentType,
+ OutputStream out,
+ boolean encapsulate,
+ OutputStream dataOutputStream)
+ throws IOException
+ {
+ // TODO
+// if (_signerInfs.isEmpty())
+// {
+// /* RFC 3852 5.2
+// * "In the degenerate case where there are no signers, the
+// * EncapsulatedContentInfo value being "signed" is irrelevant. In this
+// * case, the content type within the EncapsulatedContentInfo value being
+// * "signed" MUST be id-data (as defined in section 4), and the content
+// * field of the EncapsulatedContentInfo value MUST be omitted."
+// */
+// if (encapsulate)
+// {
+// throw new IllegalArgumentException("no signers, encapsulate must be false");
+// }
+// if (!DATA.equals(eContentType))
+// {
+// throw new IllegalArgumentException("no signers, eContentType must be id-data");
+// }
+// }
+//
+// if (!DATA.equals(eContentType))
+// {
+// /* RFC 3852 5.3
+// * [The 'signedAttrs']...
+// * field is optional, but it MUST be present if the content type of
+// * the EncapsulatedContentInfo value being signed is not id-data.
+// */
+// // TODO signedAttrs must be present for all signers
+// }
+
+ //
+ // ContentInfo
+ //
+ BERSequenceGenerator sGen = new BERSequenceGenerator(out);
+
+ sGen.addObject(CMSObjectIdentifiers.signedData);
+
+ //
+ // Signed Data
+ //
+ BERSequenceGenerator sigGen = new BERSequenceGenerator(sGen.getRawOutputStream(), 0, true);
+
+ sigGen.addObject(calculateVersion(eContentType));
+
+ ASN1EncodableVector digestAlgs = new ASN1EncodableVector();
+
+ //
+ // add the precalculated SignerInfo digest algorithms.
+ //
+ for (Iterator it = _signers.iterator(); it.hasNext();)
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ digestAlgs.add(CMSSignedHelper.INSTANCE.fixAlgID(signer.getDigestAlgorithmID()));
+ }
+
+ //
+ // add the new digests
+ //
+
+ for (Iterator it = signerGens.iterator(); it.hasNext();)
+ {
+ SignerInfoGenerator signerGen = (SignerInfoGenerator)it.next();
+
+ digestAlgs.add(signerGen.getDigestAlgorithm());
+ }
+
+ sigGen.getRawOutputStream().write(new DERSet(digestAlgs).getEncoded());
+
+ BERSequenceGenerator eiGen = new BERSequenceGenerator(sigGen.getRawOutputStream());
+ eiGen.addObject(eContentType);
+
+ // If encapsulating, add the data as an octet string in the sequence
+ OutputStream encapStream = encapsulate
+ ? CMSUtils.createBEROctetOutputStream(eiGen.getRawOutputStream(), 0, true, _bufferSize)
+ : null;
+
+ // Also send the data to 'dataOutputStream' if necessary
+ OutputStream contentStream = CMSUtils.getSafeTeeOutputStream(dataOutputStream, encapStream);
+
+ // Let all the signers see the data as it is written
+ OutputStream sigStream = CMSUtils.attachSignersToOutputStream(signerGens, contentStream);
+
+ return new CmsSignedDataOutputStream(sigStream, eContentType, sGen, sigGen, eiGen);
+ }
+
+ // RFC3852, section 5.1:
+ // IF ((certificates is present) AND
+ // (any certificates with a type of other are present)) OR
+ // ((crls is present) AND
+ // (any crls with a type of other are present))
+ // THEN version MUST be 5
+ // ELSE
+ // IF (certificates is present) AND
+ // (any version 2 attribute certificates are present)
+ // THEN version MUST be 4
+ // ELSE
+ // IF ((certificates is present) AND
+ // (any version 1 attribute certificates are present)) OR
+ // (any SignerInfo structures are version 3) OR
+ // (encapContentInfo eContentType is other than id-data)
+ // THEN version MUST be 3
+ // ELSE version MUST be 1
+ //
+ private ASN1Integer calculateVersion(
+ ASN1ObjectIdentifier contentOid)
+ {
+ boolean otherCert = false;
+ boolean otherCrl = false;
+ boolean attrCertV1Found = false;
+ boolean attrCertV2Found = false;
+
+ if (certs != null)
+ {
+ for (Iterator it = certs.iterator(); it.hasNext();)
+ {
+ Object obj = it.next();
+ if (obj instanceof ASN1TaggedObject)
+ {
+ ASN1TaggedObject tagged = (ASN1TaggedObject)obj;
+
+ if (tagged.getTagNo() == 1)
+ {
+ attrCertV1Found = true;
+ }
+ else if (tagged.getTagNo() == 2)
+ {
+ attrCertV2Found = true;
+ }
+ else if (tagged.getTagNo() == 3)
+ {
+ otherCert = true;
+ }
+ }
+ }
+ }
+
+ if (otherCert)
+ {
+ return new ASN1Integer(5);
+ }
+
+ if (crls != null) // no need to check if otherCert is true
+ {
+ for (Iterator it = crls.iterator(); it.hasNext();)
+ {
+ Object obj = it.next();
+ if (obj instanceof ASN1TaggedObject)
+ {
+ otherCrl = true;
+ }
+ }
+ }
+
+ if (otherCrl)
+ {
+ return new ASN1Integer(5);
+ }
+
+ if (attrCertV2Found)
+ {
+ return new ASN1Integer(4);
+ }
+
+ if (attrCertV1Found)
+ {
+ return new ASN1Integer(3);
+ }
+
+ if (checkForVersion3(_signers, signerGens))
+ {
+ return new ASN1Integer(3);
+ }
+
+ if (!CMSObjectIdentifiers.data.equals(contentOid))
+ {
+ return new ASN1Integer(3);
+ }
+
+ return new ASN1Integer(1);
+ }
+
+ private boolean checkForVersion3(List signerInfos, List signerInfoGens)
+ {
+ for (Iterator it = signerInfos.iterator(); it.hasNext();)
+ {
+ SignerInfo s = SignerInfo.getInstance(((SignerInformation)it.next()).toASN1Structure());
+
+ if (s.getVersion().getValue().intValue() == 3)
+ {
+ return true;
+ }
+ }
+
+ for (Iterator it = signerInfoGens.iterator(); it.hasNext();)
+ {
+ SignerInfoGenerator s = (SignerInfoGenerator)it.next();
+
+ if (s.getGeneratedVersion() == 3)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private class CmsSignedDataOutputStream
+ extends OutputStream
+ {
+ private OutputStream _out;
+ private ASN1ObjectIdentifier _contentOID;
+ private BERSequenceGenerator _sGen;
+ private BERSequenceGenerator _sigGen;
+ private BERSequenceGenerator _eiGen;
+
+ public CmsSignedDataOutputStream(
+ OutputStream out,
+ ASN1ObjectIdentifier contentOID,
+ BERSequenceGenerator sGen,
+ BERSequenceGenerator sigGen,
+ BERSequenceGenerator eiGen)
+ {
+ _out = out;
+ _contentOID = contentOID;
+ _sGen = sGen;
+ _sigGen = sigGen;
+ _eiGen = eiGen;
+ }
+
+ public void write(
+ int b)
+ throws IOException
+ {
+ _out.write(b);
+ }
+
+ public void write(
+ byte[] bytes,
+ int off,
+ int len)
+ throws IOException
+ {
+ _out.write(bytes, off, len);
+ }
+
+ public void write(
+ byte[] bytes)
+ throws IOException
+ {
+ _out.write(bytes);
+ }
+
+ public void close()
+ throws IOException
+ {
+ _out.close();
+ _eiGen.close();
+
+ digests.clear(); // clear the current preserved digest state
+
+ if (certs.size() != 0)
+ {
+ ASN1Set certSet = CMSUtils.createBerSetFromList(certs);
+
+ _sigGen.getRawOutputStream().write(new BERTaggedObject(false, 0, certSet).getEncoded());
+ }
+
+ if (crls.size() != 0)
+ {
+ ASN1Set crlSet = CMSUtils.createBerSetFromList(crls);
+
+ _sigGen.getRawOutputStream().write(new BERTaggedObject(false, 1, crlSet).getEncoded());
+ }
+
+ //
+ // collect all the SignerInfo objects
+ //
+ ASN1EncodableVector signerInfos = new ASN1EncodableVector();
+
+ //
+ // add the generated SignerInfo objects
+ //
+
+ for (Iterator it = signerGens.iterator(); it.hasNext();)
+ {
+ SignerInfoGenerator sigGen = (SignerInfoGenerator)it.next();
+
+
+ try
+ {
+ signerInfos.add(sigGen.generate(_contentOID));
+
+ byte[] calculatedDigest = sigGen.getCalculatedDigest();
+
+ digests.put(sigGen.getDigestAlgorithm().getAlgorithm().getId(), calculatedDigest);
+ }
+ catch (CMSException e)
+ {
+ throw new CMSStreamException("exception generating signers: " + e.getMessage(), e);
+ }
+ }
+
+ //
+ // add the precalculated SignerInfo objects
+ //
+ {
+ Iterator it = _signers.iterator();
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+
+ // TODO Verify the content type and calculated digest match the precalculated SignerInfo
+// if (!signer.getContentType().equals(_contentOID))
+// {
+// // TODO The precalculated content type did not match - error?
+// }
+//
+// byte[] calculatedDigest = (byte[])_digests.get(signer.getDigestAlgOID());
+// if (calculatedDigest == null)
+// {
+// // TODO We can't confirm this digest because we didn't calculate it - error?
+// }
+// else
+// {
+// if (!Arrays.areEqual(signer.getContentDigest(), calculatedDigest))
+// {
+// // TODO The precalculated digest did not match - error?
+// }
+// }
+
+ signerInfos.add(signer.toASN1Structure());
+ }
+ }
+
+ _sigGen.getRawOutputStream().write(new DERSet(signerInfos).getEncoded());
+
+ _sigGen.close();
+ _sGen.close();
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedGenerator.java
new file mode 100644
index 000000000..b2747d9ff
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedGenerator.java
@@ -0,0 +1,239 @@
+package org.spongycastle.cms;
+
+import java.util.ArrayList;
+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 org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERTaggedObject;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.OtherRevocationInfoFormat;
+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.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.cert.X509CRLHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Store;
+
+public class CMSSignedGenerator
+{
+ /**
+ * Default type for the signed data.
+ */
+ public static final String DATA = CMSObjectIdentifiers.data.getId();
+
+ public static final String DIGEST_SHA1 = OIWObjectIdentifiers.idSHA1.getId();
+ public static final String DIGEST_SHA224 = NISTObjectIdentifiers.id_sha224.getId();
+ public static final String DIGEST_SHA256 = NISTObjectIdentifiers.id_sha256.getId();
+ public static final String DIGEST_SHA384 = NISTObjectIdentifiers.id_sha384.getId();
+ public static final String DIGEST_SHA512 = NISTObjectIdentifiers.id_sha512.getId();
+ public static final String DIGEST_MD5 = PKCSObjectIdentifiers.md5.getId();
+ public static final String DIGEST_GOST3411 = CryptoProObjectIdentifiers.gostR3411.getId();
+ public static final String DIGEST_RIPEMD128 = TeleTrusTObjectIdentifiers.ripemd128.getId();
+ public static final String DIGEST_RIPEMD160 = TeleTrusTObjectIdentifiers.ripemd160.getId();
+ public static final String DIGEST_RIPEMD256 = TeleTrusTObjectIdentifiers.ripemd256.getId();
+
+ public static final String ENCRYPTION_RSA = PKCSObjectIdentifiers.rsaEncryption.getId();
+ public static final String ENCRYPTION_DSA = X9ObjectIdentifiers.id_dsa_with_sha1.getId();
+ public static final String ENCRYPTION_ECDSA = X9ObjectIdentifiers.ecdsa_with_SHA1.getId();
+ public static final String ENCRYPTION_RSA_PSS = PKCSObjectIdentifiers.id_RSASSA_PSS.getId();
+ public static final String ENCRYPTION_GOST3410 = CryptoProObjectIdentifiers.gostR3410_94.getId();
+ public static final String ENCRYPTION_ECGOST3410 = CryptoProObjectIdentifiers.gostR3410_2001.getId();
+
+ private static final String ENCRYPTION_ECDSA_WITH_SHA1 = X9ObjectIdentifiers.ecdsa_with_SHA1.getId();
+ private static final String ENCRYPTION_ECDSA_WITH_SHA224 = X9ObjectIdentifiers.ecdsa_with_SHA224.getId();
+ private static final String ENCRYPTION_ECDSA_WITH_SHA256 = X9ObjectIdentifiers.ecdsa_with_SHA256.getId();
+ private static final String ENCRYPTION_ECDSA_WITH_SHA384 = X9ObjectIdentifiers.ecdsa_with_SHA384.getId();
+ private static final String ENCRYPTION_ECDSA_WITH_SHA512 = X9ObjectIdentifiers.ecdsa_with_SHA512.getId();
+
+ private static final Set NO_PARAMS = new HashSet();
+ private static final Map EC_ALGORITHMS = new HashMap();
+
+ static
+ {
+ NO_PARAMS.add(ENCRYPTION_DSA);
+ NO_PARAMS.add(ENCRYPTION_ECDSA);
+ NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA1);
+ NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA224);
+ NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA256);
+ NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA384);
+ NO_PARAMS.add(ENCRYPTION_ECDSA_WITH_SHA512);
+
+ EC_ALGORITHMS.put(DIGEST_SHA1, ENCRYPTION_ECDSA_WITH_SHA1);
+ EC_ALGORITHMS.put(DIGEST_SHA224, ENCRYPTION_ECDSA_WITH_SHA224);
+ EC_ALGORITHMS.put(DIGEST_SHA256, ENCRYPTION_ECDSA_WITH_SHA256);
+ EC_ALGORITHMS.put(DIGEST_SHA384, ENCRYPTION_ECDSA_WITH_SHA384);
+ EC_ALGORITHMS.put(DIGEST_SHA512, ENCRYPTION_ECDSA_WITH_SHA512);
+ }
+
+ protected List certs = new ArrayList();
+ protected List crls = new ArrayList();
+ protected List _signers = new ArrayList();
+ protected List signerGens = new ArrayList();
+ protected Map digests = new HashMap();
+
+ /**
+ * base constructor
+ */
+ protected CMSSignedGenerator()
+ {
+ }
+
+ protected Map getBaseParameters(ASN1ObjectIdentifier contentType, AlgorithmIdentifier digAlgId, byte[] hash)
+ {
+ Map param = new HashMap();
+ param.put(CMSAttributeTableGenerator.CONTENT_TYPE, contentType);
+ param.put(CMSAttributeTableGenerator.DIGEST_ALGORITHM_IDENTIFIER, digAlgId);
+ param.put(CMSAttributeTableGenerator.DIGEST, Arrays.clone(hash));
+ return param;
+ }
+
+ /**
+ * Add a certificate to the certificate set to be included with the generated SignedData message.
+ *
+ * @param certificate the certificate to be included.
+ * @throws CMSException if the certificate cannot be encoded for adding.
+ */
+ public void addCertificate(
+ X509CertificateHolder certificate)
+ throws CMSException
+ {
+ certs.add(certificate.toASN1Structure());
+ }
+
+ /**
+ * Add the certificates in certStore to the certificate set to be included with the generated SignedData message.
+ *
+ * @param certStore the store containing the certificates to be included.
+ * @throws CMSException if the certificates cannot be encoded for adding.
+ */
+ public void addCertificates(
+ Store certStore)
+ throws CMSException
+ {
+ certs.addAll(CMSUtils.getCertificatesFromStore(certStore));
+ }
+
+ /**
+ * Add a CRL to the CRL set to be included with the generated SignedData message.
+ *
+ * @param crl the CRL to be included.
+ */
+ public void addCRL(X509CRLHolder crl)
+ {
+ crls.add(crl.toASN1Structure());
+ }
+
+ /**
+ * Add the CRLs in crlStore to the CRL set to be included with the generated SignedData message.
+ *
+ * @param crlStore the store containing the CRLs to be included.
+ * @throws CMSException if the CRLs cannot be encoded for adding.
+ */
+ public void addCRLs(
+ Store crlStore)
+ throws CMSException
+ {
+ crls.addAll(CMSUtils.getCRLsFromStore(crlStore));
+ }
+
+ /**
+ * Add the attribute certificates in attrStore to the certificate set to be included with the generated SignedData message.
+ *
+ * @param attrCert the store containing the certificates to be included.
+ * @throws CMSException if the attribute certificate cannot be encoded for adding.
+ */
+ public void addAttributeCertificate(
+ X509AttributeCertificateHolder attrCert)
+ throws CMSException
+ {
+ certs.add(new DERTaggedObject(false, 2, attrCert.toASN1Structure()));
+ }
+
+ /**
+ * Add the attribute certificates in attrStore to the certificate set to be included with the generated SignedData message.
+ *
+ * @param attrStore the store containing the certificates to be included.
+ * @throws CMSException if the attribute certificate cannot be encoded for adding.
+ */
+ public void addAttributeCertificates(
+ Store attrStore)
+ throws CMSException
+ {
+ certs.addAll(CMSUtils.getAttributeCertificatesFromStore(attrStore));
+ }
+
+ /**
+ * Add a single instance of otherRevocationData to the CRL set to be included with the generated SignedData message.
+ *
+ * @param otherRevocationInfoFormat the OID specifying the format of the otherRevocationInfo data.
+ * @param otherRevocationInfo the otherRevocationInfo ASN.1 structure.
+ */
+ public void addOtherRevocationInfo(
+ ASN1ObjectIdentifier otherRevocationInfoFormat,
+ ASN1Encodable otherRevocationInfo)
+ {
+ crls.add(new DERTaggedObject(false, 1, new OtherRevocationInfoFormat(otherRevocationInfoFormat, otherRevocationInfo)));
+ }
+
+ /**
+ * Add a Store of otherRevocationData to the CRL set to be included with the generated SignedData message.
+ *
+ * @param otherRevocationInfoFormat the OID specifying the format of the otherRevocationInfo data.
+ * @param otherRevocationInfos a Store of otherRevocationInfo data to add.
+ */
+ public void addOtherRevocationInfo(
+ ASN1ObjectIdentifier otherRevocationInfoFormat,
+ Store otherRevocationInfos)
+ {
+ crls.addAll(CMSUtils.getOthersFromStore(otherRevocationInfoFormat, otherRevocationInfos));
+ }
+
+ /**
+ * Add a store of pre-calculated signers to the generator.
+ *
+ * @param signerStore store of signers
+ */
+ public void addSigners(
+ SignerInformationStore signerStore)
+ {
+ Iterator it = signerStore.getSigners().iterator();
+
+ while (it.hasNext())
+ {
+ _signers.add(it.next());
+ }
+ }
+
+ /**
+ * Add a generator for a particular signer to this CMS SignedData generator.
+ *
+ * @param infoGen the generator representing the particular signer.
+ */
+ public void addSignerInfoGenerator(SignerInfoGenerator infoGen)
+ {
+ signerGens.add(infoGen);
+ }
+
+ /**
+ * Return a map of oids and byte arrays representing the digests calculated on the content during
+ * the last generate.
+ *
+ * @return a map of oids (as String objects) and byte[] representing digests.
+ */
+ public Map getGeneratedDigests()
+ {
+ return new HashMap(digests);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedHelper.java
new file mode 100644
index 000000000..1f4187bc5
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignedHelper.java
@@ -0,0 +1,253 @@
+package org.spongycastle.cms;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.cms.OtherRevocationInfoFormat;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.eac.EACObjectIdentifiers;
+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.AttributeCertificate;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.cert.X509CRLHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.util.CollectionStore;
+import org.spongycastle.util.Store;
+
+class CMSSignedHelper
+{
+ static final CMSSignedHelper INSTANCE = new CMSSignedHelper();
+
+ private static final Map encryptionAlgs = new HashMap();
+ private static final Map digestAlgs = new HashMap();
+ private static final Map digestAliases = new HashMap();
+
+ private static void addEntries(ASN1ObjectIdentifier alias, String digest, String encryption)
+ {
+ digestAlgs.put(alias.getId(), digest);
+ encryptionAlgs.put(alias.getId(), encryption);
+ }
+
+ static
+ {
+ addEntries(NISTObjectIdentifiers.dsa_with_sha224, "SHA224", "DSA");
+ addEntries(NISTObjectIdentifiers.dsa_with_sha256, "SHA256", "DSA");
+ addEntries(NISTObjectIdentifiers.dsa_with_sha384, "SHA384", "DSA");
+ addEntries(NISTObjectIdentifiers.dsa_with_sha512, "SHA512", "DSA");
+ addEntries(OIWObjectIdentifiers.dsaWithSHA1, "SHA1", "DSA");
+ addEntries(OIWObjectIdentifiers.md4WithRSA, "MD4", "RSA");
+ addEntries(OIWObjectIdentifiers.md4WithRSAEncryption, "MD4", "RSA");
+ addEntries(OIWObjectIdentifiers.md5WithRSA, "MD5", "RSA");
+ addEntries(OIWObjectIdentifiers.sha1WithRSA, "SHA1", "RSA");
+ addEntries(PKCSObjectIdentifiers.md2WithRSAEncryption, "MD2", "RSA");
+ addEntries(PKCSObjectIdentifiers.md4WithRSAEncryption, "MD4", "RSA");
+ addEntries(PKCSObjectIdentifiers.md5WithRSAEncryption, "MD5", "RSA");
+ addEntries(PKCSObjectIdentifiers.sha1WithRSAEncryption, "SHA1", "RSA");
+ addEntries(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224", "RSA");
+ addEntries(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256", "RSA");
+ addEntries(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384", "RSA");
+ addEntries(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512", "RSA");
+ addEntries(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1", "ECDSA");
+ addEntries(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224", "ECDSA");
+ addEntries(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256", "ECDSA");
+ addEntries(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384", "ECDSA");
+ addEntries(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512", "ECDSA");
+ addEntries(X9ObjectIdentifiers.id_dsa_with_sha1, "SHA1", "DSA");
+ addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_1, "SHA1", "ECDSA");
+ addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224", "ECDSA");
+ addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_256, "SHA256", "ECDSA");
+ addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_384, "SHA384", "ECDSA");
+ addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_512, "SHA512", "ECDSA");
+ addEntries(EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_1, "SHA1", "RSA");
+ addEntries(EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_256, "SHA256", "RSA");
+ addEntries(EACObjectIdentifiers.id_TA_RSA_PSS_SHA_1, "SHA1", "RSAandMGF1");
+ addEntries(EACObjectIdentifiers.id_TA_RSA_PSS_SHA_256, "SHA256", "RSAandMGF1");
+
+ encryptionAlgs.put(X9ObjectIdentifiers.id_dsa.getId(), "DSA");
+ encryptionAlgs.put(PKCSObjectIdentifiers.rsaEncryption.getId(), "RSA");
+ encryptionAlgs.put(TeleTrusTObjectIdentifiers.teleTrusTRSAsignatureAlgorithm, "RSA");
+ encryptionAlgs.put(X509ObjectIdentifiers.id_ea_rsa.getId(), "RSA");
+ encryptionAlgs.put(CMSSignedDataGenerator.ENCRYPTION_RSA_PSS, "RSAandMGF1");
+ encryptionAlgs.put(CryptoProObjectIdentifiers.gostR3410_94.getId(), "GOST3410");
+ encryptionAlgs.put(CryptoProObjectIdentifiers.gostR3410_2001.getId(), "ECGOST3410");
+ encryptionAlgs.put("1.3.6.1.4.1.5849.1.6.2", "ECGOST3410");
+ encryptionAlgs.put("1.3.6.1.4.1.5849.1.1.5", "GOST3410");
+ encryptionAlgs.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001.getId(), "ECGOST3410");
+ encryptionAlgs.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94.getId(), "GOST3410");
+
+ digestAlgs.put(PKCSObjectIdentifiers.md2.getId(), "MD2");
+ digestAlgs.put(PKCSObjectIdentifiers.md4.getId(), "MD4");
+ digestAlgs.put(PKCSObjectIdentifiers.md5.getId(), "MD5");
+ digestAlgs.put(OIWObjectIdentifiers.idSHA1.getId(), "SHA1");
+ digestAlgs.put(NISTObjectIdentifiers.id_sha224.getId(), "SHA224");
+ digestAlgs.put(NISTObjectIdentifiers.id_sha256.getId(), "SHA256");
+ digestAlgs.put(NISTObjectIdentifiers.id_sha384.getId(), "SHA384");
+ digestAlgs.put(NISTObjectIdentifiers.id_sha512.getId(), "SHA512");
+ digestAlgs.put(TeleTrusTObjectIdentifiers.ripemd128.getId(), "RIPEMD128");
+ digestAlgs.put(TeleTrusTObjectIdentifiers.ripemd160.getId(), "RIPEMD160");
+ digestAlgs.put(TeleTrusTObjectIdentifiers.ripemd256.getId(), "RIPEMD256");
+ digestAlgs.put(CryptoProObjectIdentifiers.gostR3411.getId(), "GOST3411");
+ digestAlgs.put("1.3.6.1.4.1.5849.1.2.1", "GOST3411");
+
+ digestAliases.put("SHA1", new String[] { "SHA-1" });
+ digestAliases.put("SHA224", new String[] { "SHA-224" });
+ digestAliases.put("SHA256", new String[] { "SHA-256" });
+ digestAliases.put("SHA384", new String[] { "SHA-384" });
+ digestAliases.put("SHA512", new String[] { "SHA-512" });
+ }
+
+
+ /**
+ * Return the digest encryption algorithm using one of the standard
+ * JCA string representations rather the the algorithm identifier (if
+ * possible).
+ */
+ String getEncryptionAlgName(
+ String encryptionAlgOID)
+ {
+ String algName = (String)encryptionAlgs.get(encryptionAlgOID);
+
+ if (algName != null)
+ {
+ return algName;
+ }
+
+ return encryptionAlgOID;
+ }
+
+ AlgorithmIdentifier fixAlgID(AlgorithmIdentifier algId)
+ {
+ if (algId.getParameters() == null)
+ {
+ return new AlgorithmIdentifier(algId.getAlgorithm(), DERNull.INSTANCE);
+ }
+
+ return algId;
+ }
+
+ void setSigningEncryptionAlgorithmMapping(ASN1ObjectIdentifier oid, String algorithmName)
+ {
+ encryptionAlgs.put(oid.getId(), algorithmName);
+ }
+
+ void setSigningDigestAlgorithmMapping(ASN1ObjectIdentifier oid, String algorithmName)
+ {
+ digestAlgs.put(oid.getId(), algorithmName);
+ }
+
+ Store getCertificates(ASN1Set certSet)
+ {
+ if (certSet != null)
+ {
+ List certList = new ArrayList(certSet.size());
+
+ for (Enumeration en = certSet.getObjects(); en.hasMoreElements();)
+ {
+ ASN1Primitive obj = ((ASN1Encodable)en.nextElement()).toASN1Primitive();
+
+ if (obj instanceof ASN1Sequence)
+ {
+ certList.add(new X509CertificateHolder(Certificate.getInstance(obj)));
+ }
+ }
+
+ return new CollectionStore(certList);
+ }
+
+ return new CollectionStore(new ArrayList());
+ }
+
+ Store getAttributeCertificates(ASN1Set certSet)
+ {
+ if (certSet != null)
+ {
+ List certList = new ArrayList(certSet.size());
+
+ for (Enumeration en = certSet.getObjects(); en.hasMoreElements();)
+ {
+ ASN1Primitive obj = ((ASN1Encodable)en.nextElement()).toASN1Primitive();
+
+ if (obj instanceof ASN1TaggedObject)
+ {
+ certList.add(new X509AttributeCertificateHolder(AttributeCertificate.getInstance(((ASN1TaggedObject)obj).getObject())));
+ }
+ }
+
+ return new CollectionStore(certList);
+ }
+
+ return new CollectionStore(new ArrayList());
+ }
+
+ Store getCRLs(ASN1Set crlSet)
+ {
+ if (crlSet != null)
+ {
+ List crlList = new ArrayList(crlSet.size());
+
+ for (Enumeration en = crlSet.getObjects(); en.hasMoreElements();)
+ {
+ ASN1Primitive obj = ((ASN1Encodable)en.nextElement()).toASN1Primitive();
+
+ if (obj instanceof ASN1Sequence)
+ {
+ crlList.add(new X509CRLHolder(CertificateList.getInstance(obj)));
+ }
+ }
+
+ return new CollectionStore(crlList);
+ }
+
+ return new CollectionStore(new ArrayList());
+ }
+
+ Store getOtherRevocationInfo(ASN1ObjectIdentifier otherRevocationInfoFormat, ASN1Set crlSet)
+ {
+ if (crlSet != null)
+ {
+ List crlList = new ArrayList(crlSet.size());
+
+ for (Enumeration en = crlSet.getObjects(); en.hasMoreElements();)
+ {
+ ASN1Primitive obj = ((ASN1Encodable)en.nextElement()).toASN1Primitive();
+
+ if (obj instanceof ASN1TaggedObject)
+ {
+ ASN1TaggedObject tObj = ASN1TaggedObject.getInstance(obj);
+
+ if (tObj.getTagNo() == 1)
+ {
+ OtherRevocationInfoFormat other = OtherRevocationInfoFormat.getInstance(tObj, false);
+
+ if (otherRevocationInfoFormat.equals(other.getInfoFormat()))
+ {
+ crlList.add(other.getInfo());
+ }
+ }
+ }
+ }
+
+ return new CollectionStore(crlList);
+ }
+
+ return new CollectionStore(new ArrayList());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignerDigestMismatchException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignerDigestMismatchException.java
new file mode 100644
index 000000000..c2bf8a264
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSSignerDigestMismatchException.java
@@ -0,0 +1,11 @@
+package org.spongycastle.cms;
+
+public class CMSSignerDigestMismatchException
+ extends CMSException
+{
+ public CMSSignerDigestMismatchException(
+ String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSStreamException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSStreamException.java
new file mode 100644
index 000000000..655503539
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSStreamException.java
@@ -0,0 +1,26 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+
+public class CMSStreamException
+ extends IOException
+{
+ private final Throwable underlying;
+
+ CMSStreamException(String msg)
+ {
+ super(msg);
+ this.underlying = null;
+ }
+
+ CMSStreamException(String msg, Throwable underlying)
+ {
+ super(msg);
+ this.underlying = underlying;
+ }
+
+ public Throwable getCause()
+ {
+ return underlying;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSTypedData.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSTypedData.java
new file mode 100644
index 000000000..eb044d959
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSTypedData.java
@@ -0,0 +1,9 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+
+public interface CMSTypedData
+ extends CMSProcessable
+{
+ ASN1ObjectIdentifier getContentType();
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSTypedStream.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSTypedStream.java
new file mode 100644
index 000000000..749844273
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSTypedStream.java
@@ -0,0 +1,86 @@
+package org.spongycastle.cms;
+
+import java.io.BufferedInputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.util.io.Streams;
+
+public class CMSTypedStream
+{
+ private static final int BUF_SIZ = 32 * 1024;
+
+ private final ASN1ObjectIdentifier _oid;
+ private final InputStream _in;
+
+ public CMSTypedStream(
+ InputStream in)
+ {
+ this(PKCSObjectIdentifiers.data.getId(), in, BUF_SIZ);
+ }
+
+ public CMSTypedStream(
+ String oid,
+ InputStream in)
+ {
+ this(new ASN1ObjectIdentifier(oid), in, BUF_SIZ);
+ }
+
+ public CMSTypedStream(
+ String oid,
+ InputStream in,
+ int bufSize)
+ {
+ this(new ASN1ObjectIdentifier(oid), in, bufSize);
+ }
+
+ public CMSTypedStream(
+ ASN1ObjectIdentifier oid,
+ InputStream in)
+ {
+ this(oid, in, BUF_SIZ);
+ }
+
+ public CMSTypedStream(
+ ASN1ObjectIdentifier oid,
+ InputStream in,
+ int bufSize)
+ {
+ _oid = oid;
+ _in = new FullReaderStream(new BufferedInputStream(in, bufSize));
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return _oid;
+ }
+
+ public InputStream getContentStream()
+ {
+ return _in;
+ }
+
+ public void drain()
+ throws IOException
+ {
+ Streams.drain(_in);
+ _in.close();
+ }
+
+ private static class FullReaderStream extends FilterInputStream
+ {
+ FullReaderStream(InputStream in)
+ {
+ super(in);
+ }
+
+ public int read(byte[] buf, int off, int len) throws IOException
+ {
+ int totalRead = Streams.readFully(super.in, buf, off, len);
+ return totalRead > 0 ? totalRead : -1;
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSUtils.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSUtils.java
new file mode 100644
index 000000000..1294251c8
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSUtils.java
@@ -0,0 +1,253 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.BEROctetStringGenerator;
+import org.spongycastle.asn1.BERSet;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.DERTaggedObject;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.OtherRevocationInfoFormat;
+import org.spongycastle.asn1.ocsp.OCSPResponse;
+import org.spongycastle.asn1.ocsp.OCSPResponseStatus;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.cert.X509CRLHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.util.Store;
+import org.spongycastle.util.io.Streams;
+import org.spongycastle.util.io.TeeInputStream;
+import org.spongycastle.util.io.TeeOutputStream;
+
+class CMSUtils
+{
+ static ContentInfo readContentInfo(
+ byte[] input)
+ throws CMSException
+ {
+ // enforce limit checking as from a byte array
+ return readContentInfo(new ASN1InputStream(input));
+ }
+
+ static ContentInfo readContentInfo(
+ InputStream input)
+ throws CMSException
+ {
+ // enforce some limit checking
+ return readContentInfo(new ASN1InputStream(input));
+ }
+
+ static List getCertificatesFromStore(Store certStore)
+ throws CMSException
+ {
+ List certs = new ArrayList();
+
+ try
+ {
+ for (Iterator it = certStore.getMatches(null).iterator(); it.hasNext();)
+ {
+ X509CertificateHolder c = (X509CertificateHolder)it.next();
+
+ certs.add(c.toASN1Structure());
+ }
+
+ return certs;
+ }
+ catch (ClassCastException e)
+ {
+ throw new CMSException("error processing certs", e);
+ }
+ }
+
+ static List getAttributeCertificatesFromStore(Store attrStore)
+ throws CMSException
+ {
+ List certs = new ArrayList();
+
+ try
+ {
+ for (Iterator it = attrStore.getMatches(null).iterator(); it.hasNext();)
+ {
+ X509AttributeCertificateHolder attrCert = (X509AttributeCertificateHolder)it.next();
+
+ certs.add(new DERTaggedObject(false, 2, attrCert.toASN1Structure()));
+ }
+
+ return certs;
+ }
+ catch (ClassCastException e)
+ {
+ throw new CMSException("error processing certs", e);
+ }
+ }
+
+
+ static List getCRLsFromStore(Store crlStore)
+ throws CMSException
+ {
+ List certs = new ArrayList();
+
+ try
+ {
+ for (Iterator it = crlStore.getMatches(null).iterator(); it.hasNext();)
+ {
+ X509CRLHolder c = (X509CRLHolder)it.next();
+
+ certs.add(c.toASN1Structure());
+ }
+
+ return certs;
+ }
+ catch (ClassCastException e)
+ {
+ throw new CMSException("error processing certs", e);
+ }
+ }
+
+ static Collection getOthersFromStore(ASN1ObjectIdentifier otherRevocationInfoFormat, Store otherRevocationInfos)
+ {
+ List others = new ArrayList();
+
+ for (Iterator it = otherRevocationInfos.getMatches(null).iterator(); it.hasNext();)
+ {
+ ASN1Encodable info = (ASN1Encodable)it.next();
+
+ if (CMSObjectIdentifiers.id_ri_ocsp_response.equals(otherRevocationInfoFormat))
+ {
+ OCSPResponse resp = OCSPResponse.getInstance(info);
+
+ if (resp.getResponseStatus().getValue().intValue() != OCSPResponseStatus.SUCCESSFUL)
+ {
+ throw new IllegalArgumentException("cannot add unsuccessful OCSP response to CMS SignedData");
+ }
+ }
+
+ others.add(new DERTaggedObject(false, 1, new OtherRevocationInfoFormat(otherRevocationInfoFormat, info)));
+ }
+
+ return others;
+ }
+
+ static ASN1Set createBerSetFromList(List derObjects)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ for (Iterator it = derObjects.iterator(); it.hasNext();)
+ {
+ v.add((ASN1Encodable)it.next());
+ }
+
+ return new BERSet(v);
+ }
+
+ static ASN1Set createDerSetFromList(List derObjects)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ for (Iterator it = derObjects.iterator(); it.hasNext();)
+ {
+ v.add((ASN1Encodable)it.next());
+ }
+
+ return new DERSet(v);
+ }
+
+ static OutputStream createBEROctetOutputStream(OutputStream s,
+ int tagNo, boolean isExplicit, int bufferSize) throws IOException
+ {
+ BEROctetStringGenerator octGen = new BEROctetStringGenerator(s, tagNo, isExplicit);
+
+ if (bufferSize != 0)
+ {
+ return octGen.getOctetOutputStream(new byte[bufferSize]);
+ }
+
+ return octGen.getOctetOutputStream();
+ }
+
+ private static ContentInfo readContentInfo(
+ ASN1InputStream in)
+ throws CMSException
+ {
+ try
+ {
+ return ContentInfo.getInstance(in.readObject());
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("IOException reading content.", e);
+ }
+ catch (ClassCastException e)
+ {
+ throw new CMSException("Malformed content.", e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CMSException("Malformed content.", e);
+ }
+ }
+
+ public static byte[] streamToByteArray(
+ InputStream in)
+ throws IOException
+ {
+ return Streams.readAll(in);
+ }
+
+ public static byte[] streamToByteArray(
+ InputStream in,
+ int limit)
+ throws IOException
+ {
+ return Streams.readAllLimited(in, limit);
+ }
+
+ static InputStream attachDigestsToInputStream(Collection digests, InputStream s)
+ {
+ InputStream result = s;
+ Iterator it = digests.iterator();
+ while (it.hasNext())
+ {
+ DigestCalculator digest = (DigestCalculator)it.next();
+ result = new TeeInputStream(result, digest.getOutputStream());
+ }
+ return result;
+ }
+
+ static OutputStream attachSignersToOutputStream(Collection signers, OutputStream s)
+ {
+ OutputStream result = s;
+ Iterator it = signers.iterator();
+ while (it.hasNext())
+ {
+ SignerInfoGenerator signerGen = (SignerInfoGenerator)it.next();
+ result = getSafeTeeOutputStream(result, signerGen.getCalculatingOutputStream());
+ }
+ return result;
+ }
+
+ static OutputStream getSafeOutputStream(OutputStream s)
+ {
+ return s == null ? new NullOutputStream() : s;
+ }
+
+ static OutputStream getSafeTeeOutputStream(OutputStream s1,
+ OutputStream s2)
+ {
+ return s1 == null ? getSafeOutputStream(s2)
+ : s2 == null ? getSafeOutputStream(s1) : new TeeOutputStream(
+ s1, s2);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSVerifierCertificateNotValidException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSVerifierCertificateNotValidException.java
new file mode 100644
index 000000000..bdcf131b4
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/CMSVerifierCertificateNotValidException.java
@@ -0,0 +1,11 @@
+package org.spongycastle.cms;
+
+public class CMSVerifierCertificateNotValidException
+ extends CMSException
+{
+ public CMSVerifierCertificateNotValidException(
+ String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/DefaultAuthenticatedAttributeTableGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/DefaultAuthenticatedAttributeTableGenerator.java
new file mode 100644
index 000000000..3fa4cf702
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/DefaultAuthenticatedAttributeTableGenerator.java
@@ -0,0 +1,91 @@
+package org.spongycastle.cms;
+
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.cms.Attribute;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSAttributes;
+
+/**
+ * Default authenticated attributes generator.
+ */
+public class DefaultAuthenticatedAttributeTableGenerator
+ implements CMSAttributeTableGenerator
+{
+ private final Hashtable table;
+
+ /**
+ * Initialise to use all defaults
+ */
+ public DefaultAuthenticatedAttributeTableGenerator()
+ {
+ table = new Hashtable();
+ }
+
+ /**
+ * Initialise with some extra attributes or overrides.
+ *
+ * @param attributeTable initial attribute table to use.
+ */
+ public DefaultAuthenticatedAttributeTableGenerator(
+ AttributeTable attributeTable)
+ {
+ if (attributeTable != null)
+ {
+ table = attributeTable.toHashtable();
+ }
+ else
+ {
+ table = new Hashtable();
+ }
+ }
+
+ /**
+ * Create a standard attribute table from the passed in parameters - this will
+ * normally include contentType and messageDigest. If the constructor
+ * using an AttributeTable was used, entries in it for contentType and
+ * messageDigest will override the generated ones.
+ *
+ * @param parameters source parameters for table generation.
+ *
+ * @return a filled in Hashtable of attributes.
+ */
+ protected Hashtable createStandardAttributeTable(
+ Map parameters)
+ {
+ Hashtable std = (Hashtable)table.clone();
+
+ if (!std.containsKey(CMSAttributes.contentType))
+ {
+ ASN1ObjectIdentifier contentType = ASN1ObjectIdentifier.getInstance(
+ parameters.get(CMSAttributeTableGenerator.CONTENT_TYPE));
+ Attribute attr = new Attribute(CMSAttributes.contentType,
+ new DERSet(contentType));
+ std.put(attr.getAttrType(), attr);
+ }
+
+ if (!std.containsKey(CMSAttributes.messageDigest))
+ {
+ byte[] messageDigest = (byte[])parameters.get(
+ CMSAttributeTableGenerator.DIGEST);
+ Attribute attr = new Attribute(CMSAttributes.messageDigest,
+ new DERSet(new DEROctetString(messageDigest)));
+ std.put(attr.getAttrType(), attr);
+ }
+
+ return std;
+ }
+
+ /**
+ * @param parameters source parameters
+ * @return the populated attribute table
+ */
+ public AttributeTable getAttributes(Map parameters)
+ {
+ return new AttributeTable(createStandardAttributeTable(parameters));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java
new file mode 100644
index 000000000..9a4f09226
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java
@@ -0,0 +1,154 @@
+package org.spongycastle.cms;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.eac.EACObjectIdentifiers;
+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.X509ObjectIdentifiers;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+
+public class DefaultCMSSignatureAlgorithmNameGenerator
+ implements CMSSignatureAlgorithmNameGenerator
+{
+ private final Map encryptionAlgs = new HashMap();
+ private final Map digestAlgs = new HashMap();
+
+ private void addEntries(ASN1ObjectIdentifier alias, String digest, String encryption)
+ {
+ digestAlgs.put(alias, digest);
+ encryptionAlgs.put(alias, encryption);
+ }
+
+ public DefaultCMSSignatureAlgorithmNameGenerator()
+ {
+ addEntries(NISTObjectIdentifiers.dsa_with_sha224, "SHA224", "DSA");
+ addEntries(NISTObjectIdentifiers.dsa_with_sha256, "SHA256", "DSA");
+ addEntries(NISTObjectIdentifiers.dsa_with_sha384, "SHA384", "DSA");
+ addEntries(NISTObjectIdentifiers.dsa_with_sha512, "SHA512", "DSA");
+ addEntries(OIWObjectIdentifiers.dsaWithSHA1, "SHA1", "DSA");
+ addEntries(OIWObjectIdentifiers.md4WithRSA, "MD4", "RSA");
+ addEntries(OIWObjectIdentifiers.md4WithRSAEncryption, "MD4", "RSA");
+ addEntries(OIWObjectIdentifiers.md5WithRSA, "MD5", "RSA");
+ addEntries(OIWObjectIdentifiers.sha1WithRSA, "SHA1", "RSA");
+ addEntries(PKCSObjectIdentifiers.md2WithRSAEncryption, "MD2", "RSA");
+ addEntries(PKCSObjectIdentifiers.md4WithRSAEncryption, "MD4", "RSA");
+ addEntries(PKCSObjectIdentifiers.md5WithRSAEncryption, "MD5", "RSA");
+ addEntries(PKCSObjectIdentifiers.sha1WithRSAEncryption, "SHA1", "RSA");
+ addEntries(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224", "RSA");
+ addEntries(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256", "RSA");
+ addEntries(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384", "RSA");
+ addEntries(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512", "RSA");
+ addEntries(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1", "ECDSA");
+ addEntries(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224", "ECDSA");
+ addEntries(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256", "ECDSA");
+ addEntries(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384", "ECDSA");
+ addEntries(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512", "ECDSA");
+ addEntries(X9ObjectIdentifiers.id_dsa_with_sha1, "SHA1", "DSA");
+ addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_1, "SHA1", "ECDSA");
+ addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224", "ECDSA");
+ addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_256, "SHA256", "ECDSA");
+ addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_384, "SHA384", "ECDSA");
+ addEntries(EACObjectIdentifiers.id_TA_ECDSA_SHA_512, "SHA512", "ECDSA");
+ addEntries(EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_1, "SHA1", "RSA");
+ addEntries(EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_256, "SHA256", "RSA");
+ addEntries(EACObjectIdentifiers.id_TA_RSA_PSS_SHA_1, "SHA1", "RSAandMGF1");
+ addEntries(EACObjectIdentifiers.id_TA_RSA_PSS_SHA_256, "SHA256", "RSAandMGF1");
+
+ encryptionAlgs.put(X9ObjectIdentifiers.id_dsa, "DSA");
+ encryptionAlgs.put(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ encryptionAlgs.put(TeleTrusTObjectIdentifiers.teleTrusTRSAsignatureAlgorithm, "RSA");
+ encryptionAlgs.put(X509ObjectIdentifiers.id_ea_rsa, "RSA");
+ encryptionAlgs.put(PKCSObjectIdentifiers.id_RSASSA_PSS, "RSAandMGF1");
+ encryptionAlgs.put(CryptoProObjectIdentifiers.gostR3410_94, "GOST3410");
+ encryptionAlgs.put(CryptoProObjectIdentifiers.gostR3410_2001, "ECGOST3410");
+ encryptionAlgs.put(new ASN1ObjectIdentifier("1.3.6.1.4.1.5849.1.6.2"), "ECGOST3410");
+ encryptionAlgs.put(new ASN1ObjectIdentifier("1.3.6.1.4.1.5849.1.1.5"), "GOST3410");
+ encryptionAlgs.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "ECGOST3410");
+ encryptionAlgs.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3410");
+
+ digestAlgs.put(PKCSObjectIdentifiers.md2, "MD2");
+ digestAlgs.put(PKCSObjectIdentifiers.md4, "MD4");
+ digestAlgs.put(PKCSObjectIdentifiers.md5, "MD5");
+ digestAlgs.put(OIWObjectIdentifiers.idSHA1, "SHA1");
+ digestAlgs.put(NISTObjectIdentifiers.id_sha224, "SHA224");
+ digestAlgs.put(NISTObjectIdentifiers.id_sha256, "SHA256");
+ digestAlgs.put(NISTObjectIdentifiers.id_sha384, "SHA384");
+ digestAlgs.put(NISTObjectIdentifiers.id_sha512, "SHA512");
+ digestAlgs.put(TeleTrusTObjectIdentifiers.ripemd128, "RIPEMD128");
+ digestAlgs.put(TeleTrusTObjectIdentifiers.ripemd160, "RIPEMD160");
+ digestAlgs.put(TeleTrusTObjectIdentifiers.ripemd256, "RIPEMD256");
+ digestAlgs.put(CryptoProObjectIdentifiers.gostR3411, "GOST3411");
+ digestAlgs.put(new ASN1ObjectIdentifier("1.3.6.1.4.1.5849.1.2.1"), "GOST3411");
+ }
+
+ /**
+ * Return the digest algorithm using one of the standard JCA string
+ * representations rather than the algorithm identifier (if possible).
+ */
+ private String getDigestAlgName(
+ ASN1ObjectIdentifier digestAlgOID)
+ {
+ String algName = (String)digestAlgs.get(digestAlgOID);
+
+ if (algName != null)
+ {
+ return algName;
+ }
+
+ return digestAlgOID.getId();
+ }
+
+ /**
+ * Return the digest encryption algorithm using one of the standard
+ * JCA string representations rather the the algorithm identifier (if
+ * possible).
+ */
+ private String getEncryptionAlgName(
+ ASN1ObjectIdentifier encryptionAlgOID)
+ {
+ String algName = (String)encryptionAlgs.get(encryptionAlgOID);
+
+ if (algName != null)
+ {
+ return algName;
+ }
+
+ return encryptionAlgOID.getId();
+ }
+
+ /**
+ * Set the mapping for the encryption algorithm used in association with a SignedData generation
+ * or interpretation.
+ *
+ * @param oid object identifier to map.
+ * @param algorithmName algorithm name to use.
+ */
+ protected void setSigningEncryptionAlgorithmMapping(ASN1ObjectIdentifier oid, String algorithmName)
+ {
+ encryptionAlgs.put(oid, algorithmName);
+ }
+
+ /**
+ * Set the mapping for the digest algorithm to use in conjunction with a SignedData generation
+ * or interpretation.
+ *
+ * @param oid object identifier to map.
+ * @param algorithmName algorithm name to use.
+ */
+ protected void setSigningDigestAlgorithmMapping(ASN1ObjectIdentifier oid, String algorithmName)
+ {
+ digestAlgs.put(oid, algorithmName);
+ }
+
+ public String getSignatureName(AlgorithmIdentifier digestAlg, AlgorithmIdentifier encryptionAlg)
+ {
+ return getDigestAlgName(digestAlg.getAlgorithm()) + "with" + getEncryptionAlgName(encryptionAlg.getAlgorithm());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java
new file mode 100644
index 000000000..4608bb108
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/DefaultCMSSignatureEncryptionAlgorithmFinder.java
@@ -0,0 +1,46 @@
+package org.spongycastle.cms;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public class DefaultCMSSignatureEncryptionAlgorithmFinder
+ implements CMSSignatureEncryptionAlgorithmFinder
+{
+ private static final Set RSA_PKCS1d5 = new HashSet();
+
+ static
+ {
+ RSA_PKCS1d5.add(PKCSObjectIdentifiers.md2WithRSAEncryption);
+ RSA_PKCS1d5.add(PKCSObjectIdentifiers.md4WithRSAEncryption);
+ RSA_PKCS1d5.add(PKCSObjectIdentifiers.md5WithRSAEncryption);
+ RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ RSA_PKCS1d5.add(PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ RSA_PKCS1d5.add(OIWObjectIdentifiers.md4WithRSAEncryption);
+ RSA_PKCS1d5.add(OIWObjectIdentifiers.md4WithRSA);
+ RSA_PKCS1d5.add(OIWObjectIdentifiers.md5WithRSA);
+ RSA_PKCS1d5.add(OIWObjectIdentifiers.sha1WithRSA);
+ RSA_PKCS1d5.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ RSA_PKCS1d5.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ RSA_PKCS1d5.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ }
+
+ public AlgorithmIdentifier findEncryptionAlgorithm(AlgorithmIdentifier signatureAlgorithm)
+ {
+ // RFC3370 section 3.2
+ if (RSA_PKCS1d5.contains(signatureAlgorithm.getAlgorithm()))
+ {
+ return new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE);
+ }
+
+ return signatureAlgorithm;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/DefaultSignedAttributeTableGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/DefaultSignedAttributeTableGenerator.java
new file mode 100644
index 000000000..ba570c288
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/DefaultSignedAttributeTableGenerator.java
@@ -0,0 +1,121 @@
+package org.spongycastle.cms;
+
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.cms.Attribute;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSAttributes;
+import org.spongycastle.asn1.cms.Time;
+
+/**
+ * Default signed attributes generator.
+ */
+public class DefaultSignedAttributeTableGenerator
+ implements CMSAttributeTableGenerator
+{
+ private final Hashtable table;
+
+ /**
+ * Initialise to use all defaults
+ */
+ public DefaultSignedAttributeTableGenerator()
+ {
+ table = new Hashtable();
+ }
+
+ /**
+ * Initialise with some extra attributes or overrides.
+ *
+ * @param attributeTable initial attribute table to use.
+ */
+ public DefaultSignedAttributeTableGenerator(
+ AttributeTable attributeTable)
+ {
+ if (attributeTable != null)
+ {
+ table = attributeTable.toHashtable();
+ }
+ else
+ {
+ table = new Hashtable();
+ }
+ }
+
+ /**
+ * Create a standard attribute table from the passed in parameters - this will
+ * normally include contentType, signingTime, and messageDigest. If the constructor
+ * using an AttributeTable was used, entries in it for contentType, signingTime, and
+ * messageDigest will override the generated ones.
+ *
+ * @param parameters source parameters for table generation.
+ *
+ * @return a filled in Hashtable of attributes.
+ */
+ protected Hashtable createStandardAttributeTable(
+ Map parameters)
+ {
+ Hashtable std = copyHashTable(table);
+
+ if (!std.containsKey(CMSAttributes.contentType))
+ {
+ ASN1ObjectIdentifier contentType = ASN1ObjectIdentifier.getInstance(
+ parameters.get(CMSAttributeTableGenerator.CONTENT_TYPE));
+
+ // contentType will be null if we're trying to generate a counter signature.
+ if (contentType != null)
+ {
+ Attribute attr = new Attribute(CMSAttributes.contentType,
+ new DERSet(contentType));
+ std.put(attr.getAttrType(), attr);
+ }
+ }
+
+ if (!std.containsKey(CMSAttributes.signingTime))
+ {
+ Date signingTime = new Date();
+ Attribute attr = new Attribute(CMSAttributes.signingTime,
+ new DERSet(new Time(signingTime)));
+ std.put(attr.getAttrType(), attr);
+ }
+
+ if (!std.containsKey(CMSAttributes.messageDigest))
+ {
+ byte[] messageDigest = (byte[])parameters.get(
+ CMSAttributeTableGenerator.DIGEST);
+ Attribute attr = new Attribute(CMSAttributes.messageDigest,
+ new DERSet(new DEROctetString(messageDigest)));
+ std.put(attr.getAttrType(), attr);
+ }
+
+ return std;
+ }
+
+ /**
+ * @param parameters source parameters
+ * @return the populated attribute table
+ */
+ public AttributeTable getAttributes(Map parameters)
+ {
+ return new AttributeTable(createStandardAttributeTable(parameters));
+ }
+
+ private static Hashtable copyHashTable(Hashtable paramsMap)
+ {
+ Hashtable newTable = new Hashtable();
+
+ Enumeration keys = paramsMap.keys();
+ while (keys.hasMoreElements())
+ {
+ Object key = keys.nextElement();
+ newTable.put(key, paramsMap.get(key));
+ }
+
+ return newTable;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KEKRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KEKRecipient.java
new file mode 100644
index 000000000..3b14a89dc
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KEKRecipient.java
@@ -0,0 +1,10 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface KEKRecipient
+ extends Recipient
+{
+ RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncAlg, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentKey)
+ throws CMSException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KEKRecipientId.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KEKRecipientId.java
new file mode 100644
index 000000000..2025c7c16
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KEKRecipientId.java
@@ -0,0 +1,63 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.util.Arrays;
+
+public class KEKRecipientId
+ extends RecipientId
+{
+ private byte[] keyIdentifier;
+
+ /**
+ * Construct a recipient ID with the key identifier of a KEK recipient.
+ *
+ * @param keyIdentifier a subjectKeyId
+ */
+ public KEKRecipientId(byte[] keyIdentifier)
+ {
+ super(kek);
+
+ this.keyIdentifier = keyIdentifier;
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(keyIdentifier);
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof KEKRecipientId))
+ {
+ return false;
+ }
+
+ KEKRecipientId id = (KEKRecipientId)o;
+
+ return Arrays.areEqual(keyIdentifier, id.keyIdentifier);
+ }
+
+ public byte[] getKeyIdentifier()
+ {
+ return Arrays.clone(keyIdentifier);
+ }
+
+ public Object clone()
+ {
+ return new KEKRecipientId(keyIdentifier);
+ }
+
+ public boolean match(Object obj)
+ {
+ if (obj instanceof byte[])
+ {
+ return Arrays.areEqual(keyIdentifier, (byte[])obj);
+ }
+ else if (obj instanceof KEKRecipientInformation)
+ {
+ return ((KEKRecipientInformation)obj).getRID().equals(this);
+ }
+
+ return false;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KEKRecipientInfoGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KEKRecipientInfoGenerator.java
new file mode 100644
index 000000000..480fb5fe9
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KEKRecipientInfoGenerator.java
@@ -0,0 +1,39 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.cms.KEKIdentifier;
+import org.spongycastle.asn1.cms.KEKRecipientInfo;
+import org.spongycastle.asn1.cms.RecipientInfo;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+import org.spongycastle.operator.SymmetricKeyWrapper;
+
+public abstract class KEKRecipientInfoGenerator
+ implements RecipientInfoGenerator
+{
+ private final KEKIdentifier kekIdentifier;
+
+ protected final SymmetricKeyWrapper wrapper;
+
+ protected KEKRecipientInfoGenerator(KEKIdentifier kekIdentifier, SymmetricKeyWrapper wrapper)
+ {
+ this.kekIdentifier = kekIdentifier;
+ this.wrapper = wrapper;
+ }
+
+ public final RecipientInfo generate(GenericKey contentEncryptionKey)
+ throws CMSException
+ {
+ try
+ {
+ ASN1OctetString encryptedKey = new DEROctetString(wrapper.generateWrappedKey(contentEncryptionKey));
+
+ return new RecipientInfo(new KEKRecipientInfo(kekIdentifier, wrapper.getAlgorithmIdentifier(), encryptedKey));
+ }
+ catch (OperatorException e)
+ {
+ throw new CMSException("exception wrapping content key: " + e.getMessage(), e);
+ }
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KEKRecipientInformation.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KEKRecipientInformation.java
new file mode 100644
index 000000000..3388d6fa6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KEKRecipientInformation.java
@@ -0,0 +1,38 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.cms.KEKIdentifier;
+import org.spongycastle.asn1.cms.KEKRecipientInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * the RecipientInfo class for a recipient who has been sent a message
+ * encrypted using a secret key known to the other side.
+ */
+public class KEKRecipientInformation
+ extends RecipientInformation
+{
+ private KEKRecipientInfo info;
+
+ KEKRecipientInformation(
+ KEKRecipientInfo info,
+ AlgorithmIdentifier messageAlgorithm,
+ CMSSecureReadable secureReadable,
+ AuthAttributesProvider additionalData)
+ {
+ super(info.getKeyEncryptionAlgorithm(), messageAlgorithm, secureReadable, additionalData);
+
+ this.info = info;
+
+ KEKIdentifier kekId = info.getKekid();
+
+ this.rid = new KEKRecipientId(kekId.getKeyIdentifier().getOctets());
+ }
+
+ protected RecipientOperator getRecipientOperator(Recipient recipient)
+ throws CMSException, IOException
+ {
+ return ((KEKRecipient)recipient).getRecipientOperator(keyEncAlg, messageAlgorithm, info.getEncryptedKey().getOctets());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipient.java
new file mode 100644
index 000000000..ab3a7451d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipient.java
@@ -0,0 +1,14 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+
+public interface KeyAgreeRecipient
+ extends Recipient
+{
+ RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncAlg, AlgorithmIdentifier contentEncryptionAlgorithm, SubjectPublicKeyInfo senderPublicKey, ASN1OctetString userKeyingMaterial, byte[] encryptedContentKey)
+ throws CMSException;
+
+ AlgorithmIdentifier getPrivateKeyAlgorithmIdentifier();
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientId.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientId.java
new file mode 100644
index 000000000..c5f2aa14e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientId.java
@@ -0,0 +1,89 @@
+package org.spongycastle.cms;
+
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cert.selector.X509CertificateHolderSelector;
+
+public class KeyAgreeRecipientId
+ extends RecipientId
+{
+ private X509CertificateHolderSelector baseSelector;
+
+ private KeyAgreeRecipientId(X509CertificateHolderSelector baseSelector)
+ {
+ super(keyAgree);
+
+ this.baseSelector = baseSelector;
+ }
+
+ /**
+ * Construct a key agree recipient ID with the value of a public key's subjectKeyId.
+ *
+ * @param subjectKeyId a subjectKeyId
+ */
+ public KeyAgreeRecipientId(byte[] subjectKeyId)
+ {
+ this(null, null, subjectKeyId);
+ }
+
+ /**
+ * Construct a key agree recipient ID based on the issuer and serial number of the recipient's associated
+ * certificate.
+ *
+ * @param issuer the issuer of the recipient's associated certificate.
+ * @param serialNumber the serial number of the recipient's associated certificate.
+ */
+ public KeyAgreeRecipientId(X500Name issuer, BigInteger serialNumber)
+ {
+ this(issuer, serialNumber, null);
+ }
+
+ public KeyAgreeRecipientId(X500Name issuer, BigInteger serialNumber, byte[] subjectKeyId)
+ {
+ this(new X509CertificateHolderSelector(issuer, serialNumber, subjectKeyId));
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return baseSelector.getSerialNumber();
+ }
+
+ public byte[] getSubjectKeyIdentifier()
+ {
+ return baseSelector.getSubjectKeyIdentifier();
+ }
+
+ public int hashCode()
+ {
+ return baseSelector.hashCode();
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof KeyAgreeRecipientId))
+ {
+ return false;
+ }
+
+ KeyAgreeRecipientId id = (KeyAgreeRecipientId)o;
+
+ return this.baseSelector.equals(id.baseSelector);
+ }
+
+ public Object clone()
+ {
+ return new KeyAgreeRecipientId(baseSelector);
+ }
+
+ public boolean match(Object obj)
+ {
+ if (obj instanceof KeyAgreeRecipientInformation)
+ {
+ return ((KeyAgreeRecipientInformation)obj).getRID().equals(this);
+ }
+
+ return baseSelector.match(obj);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientInfoGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientInfoGenerator.java
new file mode 100644
index 000000000..b80ec3751
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientInfoGenerator.java
@@ -0,0 +1,80 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.cms.KeyAgreeRecipientInfo;
+import org.spongycastle.asn1.cms.OriginatorIdentifierOrKey;
+import org.spongycastle.asn1.cms.OriginatorPublicKey;
+import org.spongycastle.asn1.cms.RecipientInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.operator.GenericKey;
+
+public abstract class KeyAgreeRecipientInfoGenerator
+ implements RecipientInfoGenerator
+{
+ private ASN1ObjectIdentifier keyAgreementOID;
+ private ASN1ObjectIdentifier keyEncryptionOID;
+ private SubjectPublicKeyInfo originatorKeyInfo;
+
+ protected KeyAgreeRecipientInfoGenerator(ASN1ObjectIdentifier keyAgreementOID, SubjectPublicKeyInfo originatorKeyInfo, ASN1ObjectIdentifier keyEncryptionOID)
+ {
+ this.originatorKeyInfo = originatorKeyInfo;
+ this.keyAgreementOID = keyAgreementOID;
+ this.keyEncryptionOID = keyEncryptionOID;
+ }
+
+ public RecipientInfo generate(GenericKey contentEncryptionKey)
+ throws CMSException
+ {
+ OriginatorIdentifierOrKey originator = new OriginatorIdentifierOrKey(
+ createOriginatorPublicKey(originatorKeyInfo));
+
+ ASN1EncodableVector params = new ASN1EncodableVector();
+ params.add(keyEncryptionOID);
+ params.add(DERNull.INSTANCE);
+ AlgorithmIdentifier keyEncAlg = new AlgorithmIdentifier(keyEncryptionOID, DERNull.INSTANCE);
+ AlgorithmIdentifier keyAgreeAlg = new AlgorithmIdentifier(keyAgreementOID, keyEncAlg);
+
+ ASN1Sequence recipients = generateRecipientEncryptedKeys(keyAgreeAlg, keyEncAlg, contentEncryptionKey);
+ ASN1Encodable userKeyingMaterial = getUserKeyingMaterial(keyAgreeAlg);
+
+ if (userKeyingMaterial != null)
+ {
+ try
+ {
+ return new RecipientInfo(new KeyAgreeRecipientInfo(originator, new DEROctetString(userKeyingMaterial),
+ keyAgreeAlg, recipients));
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("unable to encode userKeyingMaterial: " + e.getMessage(), e);
+ }
+ }
+ else
+ {
+ return new RecipientInfo(new KeyAgreeRecipientInfo(originator, null,
+ keyAgreeAlg, recipients));
+ }
+ }
+
+ protected OriginatorPublicKey createOriginatorPublicKey(SubjectPublicKeyInfo originatorKeyInfo)
+ {
+ return new OriginatorPublicKey(
+ new AlgorithmIdentifier(originatorKeyInfo.getAlgorithm().getAlgorithm(), DERNull.INSTANCE),
+ originatorKeyInfo.getPublicKeyData().getBytes());
+ }
+
+ protected abstract ASN1Sequence generateRecipientEncryptedKeys(AlgorithmIdentifier keyAgreeAlgorithm, AlgorithmIdentifier keyEncAlgorithm, GenericKey contentEncryptionKey)
+ throws CMSException;
+
+ protected abstract ASN1Encodable getUserKeyingMaterial(AlgorithmIdentifier keyAgreeAlgorithm)
+ throws CMSException;
+
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientInformation.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientInformation.java
new file mode 100644
index 000000000..c00dcdf32
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyAgreeRecipientInformation.java
@@ -0,0 +1,131 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.cms.IssuerAndSerialNumber;
+import org.spongycastle.asn1.cms.KeyAgreeRecipientIdentifier;
+import org.spongycastle.asn1.cms.KeyAgreeRecipientInfo;
+import org.spongycastle.asn1.cms.OriginatorIdentifierOrKey;
+import org.spongycastle.asn1.cms.OriginatorPublicKey;
+import org.spongycastle.asn1.cms.RecipientEncryptedKey;
+import org.spongycastle.asn1.cms.RecipientKeyIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+
+/**
+ * the RecipientInfo class for a recipient who has been sent a message
+ * encrypted using key agreement.
+ */
+public class KeyAgreeRecipientInformation
+ extends RecipientInformation
+{
+ private KeyAgreeRecipientInfo info;
+ private ASN1OctetString encryptedKey;
+
+ static void readRecipientInfo(List infos, KeyAgreeRecipientInfo info,
+ AlgorithmIdentifier messageAlgorithm, CMSSecureReadable secureReadable, AuthAttributesProvider additionalData)
+ {
+ ASN1Sequence s = info.getRecipientEncryptedKeys();
+
+ for (int i = 0; i < s.size(); ++i)
+ {
+ RecipientEncryptedKey id = RecipientEncryptedKey.getInstance(
+ s.getObjectAt(i));
+
+ RecipientId rid;
+
+ KeyAgreeRecipientIdentifier karid = id.getIdentifier();
+ IssuerAndSerialNumber iAndSN = karid.getIssuerAndSerialNumber();
+
+ if (iAndSN != null)
+ {
+ rid = new KeyAgreeRecipientId(iAndSN.getName(), iAndSN.getSerialNumber().getValue());
+ }
+ else
+ {
+ RecipientKeyIdentifier rKeyID = karid.getRKeyID();
+
+ // Note: 'date' and 'other' fields of RecipientKeyIdentifier appear to be only informational
+
+ rid = new KeyAgreeRecipientId(rKeyID.getSubjectKeyIdentifier().getOctets());
+ }
+
+ infos.add(new KeyAgreeRecipientInformation(info, rid, id.getEncryptedKey(), messageAlgorithm,
+ secureReadable, additionalData));
+ }
+ }
+
+ KeyAgreeRecipientInformation(
+ KeyAgreeRecipientInfo info,
+ RecipientId rid,
+ ASN1OctetString encryptedKey,
+ AlgorithmIdentifier messageAlgorithm,
+ CMSSecureReadable secureReadable,
+ AuthAttributesProvider additionalData)
+ {
+ super(info.getKeyEncryptionAlgorithm(), messageAlgorithm, secureReadable, additionalData);
+
+ this.info = info;
+ this.rid = rid;
+ this.encryptedKey = encryptedKey;
+ }
+
+ private SubjectPublicKeyInfo getSenderPublicKeyInfo(AlgorithmIdentifier recKeyAlgId,
+ OriginatorIdentifierOrKey originator)
+ throws CMSException, IOException
+ {
+ OriginatorPublicKey opk = originator.getOriginatorKey();
+ if (opk != null)
+ {
+ return getPublicKeyInfoFromOriginatorPublicKey(recKeyAlgId, opk);
+ }
+
+ OriginatorId origID;
+
+ IssuerAndSerialNumber iAndSN = originator.getIssuerAndSerialNumber();
+ if (iAndSN != null)
+ {
+ origID = new OriginatorId(iAndSN.getName(), iAndSN.getSerialNumber().getValue());
+ }
+ else
+ {
+ SubjectKeyIdentifier ski = originator.getSubjectKeyIdentifier();
+
+ origID = new OriginatorId(ski.getKeyIdentifier());
+ }
+
+ return getPublicKeyInfoFromOriginatorId(origID);
+ }
+
+ private SubjectPublicKeyInfo getPublicKeyInfoFromOriginatorPublicKey(AlgorithmIdentifier recKeyAlgId,
+ OriginatorPublicKey originatorPublicKey)
+ {
+ SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(
+ recKeyAlgId,
+ originatorPublicKey.getPublicKey().getBytes());
+
+ return pubInfo;
+ }
+
+ private SubjectPublicKeyInfo getPublicKeyInfoFromOriginatorId(OriginatorId origID)
+ throws CMSException
+ {
+ // TODO Support all alternatives for OriginatorIdentifierOrKey
+ // see RFC 3852 6.2.2
+ throw new CMSException("No support for 'originator' as IssuerAndSerialNumber or SubjectKeyIdentifier");
+ }
+
+ protected RecipientOperator getRecipientOperator(Recipient recipient)
+ throws CMSException, IOException
+ {
+ KeyAgreeRecipient agreeRecipient = (KeyAgreeRecipient)recipient;
+ AlgorithmIdentifier recKeyAlgId = agreeRecipient.getPrivateKeyAlgorithmIdentifier();
+
+ return ((KeyAgreeRecipient)recipient).getRecipientOperator(keyEncAlg, messageAlgorithm, getSenderPublicKeyInfo(recKeyAlgId,
+ info.getOriginator()), info.getUserKeyingMaterial(), encryptedKey.getOctets());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipient.java
new file mode 100644
index 000000000..04201d0d1
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipient.java
@@ -0,0 +1,10 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface KeyTransRecipient
+ extends Recipient
+{
+ RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncAlg, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentKey)
+ throws CMSException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientId.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientId.java
new file mode 100644
index 000000000..b76e19f42
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientId.java
@@ -0,0 +1,102 @@
+package org.spongycastle.cms;
+
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cert.selector.X509CertificateHolderSelector;
+
+public class KeyTransRecipientId
+ extends RecipientId
+{
+ private X509CertificateHolderSelector baseSelector;
+
+ private KeyTransRecipientId(X509CertificateHolderSelector baseSelector)
+ {
+ super(keyTrans);
+
+ this.baseSelector = baseSelector;
+ }
+
+ /**
+ * Construct a key trans recipient ID with the value of a public key's subjectKeyId.
+ *
+ * @param subjectKeyId a subjectKeyId
+ */
+ public KeyTransRecipientId(byte[] subjectKeyId)
+ {
+ this(null, null, subjectKeyId);
+ }
+
+ /**
+ * Construct a key trans recipient ID based on the issuer and serial number of the recipient's associated
+ * certificate.
+ *
+ * @param issuer the issuer of the recipient's associated certificate.
+ * @param serialNumber the serial number of the recipient's associated certificate.
+ */
+ public KeyTransRecipientId(X500Name issuer, BigInteger serialNumber)
+ {
+ this(issuer, serialNumber, null);
+ }
+
+ /**
+ * Construct a key trans recipient ID based on the issuer and serial number of the recipient's associated
+ * certificate.
+ *
+ * @param issuer the issuer of the recipient's associated certificate.
+ * @param serialNumber the serial number of the recipient's associated certificate.
+ * @param subjectKeyId the subject key identifier to use to match the recipients associated certificate.
+ */
+ public KeyTransRecipientId(X500Name issuer, BigInteger serialNumber, byte[] subjectKeyId)
+ {
+ this(new X509CertificateHolderSelector(issuer, serialNumber, subjectKeyId));
+ }
+
+ public X500Name getIssuer()
+ {
+ return baseSelector.getIssuer();
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return baseSelector.getSerialNumber();
+ }
+
+ public byte[] getSubjectKeyIdentifier()
+ {
+ return baseSelector.getSubjectKeyIdentifier();
+ }
+
+ public int hashCode()
+ {
+ return baseSelector.hashCode();
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof KeyTransRecipientId))
+ {
+ return false;
+ }
+
+ KeyTransRecipientId id = (KeyTransRecipientId)o;
+
+ return this.baseSelector.equals(id.baseSelector);
+ }
+
+ public Object clone()
+ {
+ return new KeyTransRecipientId(this.baseSelector);
+ }
+
+ public boolean match(Object obj)
+ {
+ if (obj instanceof KeyTransRecipientInformation)
+ {
+ return ((KeyTransRecipientInformation)obj).getRID().equals(this);
+ }
+
+ return baseSelector.match(obj);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientInfoGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientInfoGenerator.java
new file mode 100644
index 000000000..c78a4ff88
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientInfoGenerator.java
@@ -0,0 +1,58 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.cms.IssuerAndSerialNumber;
+import org.spongycastle.asn1.cms.KeyTransRecipientInfo;
+import org.spongycastle.asn1.cms.RecipientIdentifier;
+import org.spongycastle.asn1.cms.RecipientInfo;
+import org.spongycastle.operator.AsymmetricKeyWrapper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+
+public abstract class KeyTransRecipientInfoGenerator
+ implements RecipientInfoGenerator
+{
+ protected final AsymmetricKeyWrapper wrapper;
+
+ private IssuerAndSerialNumber issuerAndSerial;
+ private byte[] subjectKeyIdentifier;
+
+ protected KeyTransRecipientInfoGenerator(IssuerAndSerialNumber issuerAndSerial, AsymmetricKeyWrapper wrapper)
+ {
+ this.issuerAndSerial = issuerAndSerial;
+ this.wrapper = wrapper;
+ }
+
+ protected KeyTransRecipientInfoGenerator(byte[] subjectKeyIdentifier, AsymmetricKeyWrapper wrapper)
+ {
+ this.subjectKeyIdentifier = subjectKeyIdentifier;
+ this.wrapper = wrapper;
+ }
+
+ public final RecipientInfo generate(GenericKey contentEncryptionKey)
+ throws CMSException
+ {
+ byte[] encryptedKeyBytes;
+ try
+ {
+ encryptedKeyBytes = wrapper.generateWrappedKey(contentEncryptionKey);
+ }
+ catch (OperatorException e)
+ {
+ throw new CMSException("exception wrapping content key: " + e.getMessage(), e);
+ }
+
+ RecipientIdentifier recipId;
+ if (issuerAndSerial != null)
+ {
+ recipId = new RecipientIdentifier(issuerAndSerial);
+ }
+ else
+ {
+ recipId = new RecipientIdentifier(new DEROctetString(subjectKeyIdentifier));
+ }
+
+ return new RecipientInfo(new KeyTransRecipientInfo(recipId, wrapper.getAlgorithmIdentifier(),
+ new DEROctetString(encryptedKeyBytes)));
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientInformation.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientInformation.java
new file mode 100644
index 000000000..f671b8cd2
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/KeyTransRecipientInformation.java
@@ -0,0 +1,50 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.cms.IssuerAndSerialNumber;
+import org.spongycastle.asn1.cms.KeyTransRecipientInfo;
+import org.spongycastle.asn1.cms.RecipientIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * the KeyTransRecipientInformation class for a recipient who has been sent a secret
+ * key encrypted using their public key that needs to be used to
+ * extract the message.
+ */
+public class KeyTransRecipientInformation
+ extends RecipientInformation
+{
+ private KeyTransRecipientInfo info;
+
+ KeyTransRecipientInformation(
+ KeyTransRecipientInfo info,
+ AlgorithmIdentifier messageAlgorithm,
+ CMSSecureReadable secureReadable,
+ AuthAttributesProvider additionalData)
+ {
+ super(info.getKeyEncryptionAlgorithm(), messageAlgorithm, secureReadable, additionalData);
+
+ this.info = info;
+
+ RecipientIdentifier r = info.getRecipientIdentifier();
+
+ if (r.isTagged())
+ {
+ ASN1OctetString octs = ASN1OctetString.getInstance(r.getId());
+
+ rid = new KeyTransRecipientId(octs.getOctets());
+ }
+ else
+ {
+ IssuerAndSerialNumber iAnds = IssuerAndSerialNumber.getInstance(r.getId());
+
+ rid = new KeyTransRecipientId(iAnds.getName(), iAnds.getSerialNumber().getValue());
+ }
+ }
+
+ protected RecipientOperator getRecipientOperator(Recipient recipient)
+ throws CMSException
+ {
+ return ((KeyTransRecipient)recipient).getRecipientOperator(keyEncAlg, messageAlgorithm, info.getEncryptedKey().getOctets());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/NullOutputStream.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/NullOutputStream.java
new file mode 100644
index 000000000..c5ccd4ec5
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/NullOutputStream.java
@@ -0,0 +1,28 @@
+/**
+ *
+ */
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+class NullOutputStream
+ extends OutputStream
+{
+ public void write(byte[] buf)
+ throws IOException
+ {
+ // do nothing
+ }
+
+ public void write(byte[] buf, int off, int len)
+ throws IOException
+ {
+ // do nothing
+ }
+
+ public void write(int b) throws IOException
+ {
+ // do nothing
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/OriginatorId.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/OriginatorId.java
new file mode 100644
index 000000000..eee06cea7
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/OriginatorId.java
@@ -0,0 +1,118 @@
+package org.spongycastle.cms;
+
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Selector;
+
+/**
+ * a basic index for an originator.
+ */
+class OriginatorId
+ implements Selector
+{
+ private byte[] subjectKeyId;
+
+ private X500Name issuer;
+ private BigInteger serialNumber;
+
+ /**
+ * Construct a signer ID with the value of a public key's subjectKeyId.
+ *
+ * @param subjectKeyId a subjectKeyId
+ */
+ public OriginatorId(byte[] subjectKeyId)
+ {
+ setSubjectKeyID(subjectKeyId);
+ }
+
+ private void setSubjectKeyID(byte[] subjectKeyId)
+ {
+ this.subjectKeyId = subjectKeyId;
+ }
+
+ /**
+ * Construct a signer ID based on the issuer and serial number of the signer's associated
+ * certificate.
+ *
+ * @param issuer the issuer of the signer's associated certificate.
+ * @param serialNumber the serial number of the signer's associated certificate.
+ */
+ public OriginatorId(X500Name issuer, BigInteger serialNumber)
+ {
+ setIssuerAndSerial(issuer, serialNumber);
+ }
+
+ private void setIssuerAndSerial(X500Name issuer, BigInteger serialNumber)
+ {
+ this.issuer = issuer;
+ this.serialNumber = serialNumber;
+ }
+
+ /**
+ * Construct a signer ID based on the issuer and serial number of the signer's associated
+ * certificate.
+ *
+ * @param issuer the issuer of the signer's associated certificate.
+ * @param serialNumber the serial number of the signer's associated certificate.
+ * @param subjectKeyId the subject key identifier to use to match the signers associated certificate.
+ */
+ public OriginatorId(X500Name issuer, BigInteger serialNumber, byte[] subjectKeyId)
+ {
+ setIssuerAndSerial(issuer, serialNumber);
+ setSubjectKeyID(subjectKeyId);
+ }
+
+ public X500Name getIssuer()
+ {
+ return issuer;
+ }
+
+ public Object clone()
+ {
+ return new OriginatorId(this.issuer, this.serialNumber, this.subjectKeyId);
+ }
+
+ public int hashCode()
+ {
+ int code = Arrays.hashCode(subjectKeyId);
+
+ if (this.serialNumber != null)
+ {
+ code ^= this.serialNumber.hashCode();
+ }
+
+ if (this.issuer != null)
+ {
+ code ^= this.issuer.hashCode();
+ }
+
+ return code;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof OriginatorId))
+ {
+ return false;
+ }
+
+ OriginatorId id = (OriginatorId)o;
+
+ return Arrays.areEqual(subjectKeyId, id.subjectKeyId)
+ && equalsObj(this.serialNumber, id.serialNumber)
+ && equalsObj(this.issuer, id.issuer);
+ }
+
+ private boolean equalsObj(Object a, Object b)
+ {
+ return (a != null) ? a.equals(b) : b == null;
+ }
+
+ public boolean match(Object obj)
+ {
+ return false;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/OriginatorInfoGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/OriginatorInfoGenerator.java
new file mode 100644
index 000000000..fd70ab525
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/OriginatorInfoGenerator.java
@@ -0,0 +1,54 @@
+package org.spongycastle.cms;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.spongycastle.asn1.cms.OriginatorInfo;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.util.Store;
+
+public class OriginatorInfoGenerator
+{
+ private final List origCerts;
+ private final List origCRLs;
+
+ public OriginatorInfoGenerator(X509CertificateHolder origCert)
+ {
+ this.origCerts = new ArrayList(1);
+ this.origCRLs = null;
+ origCerts.add(origCert.toASN1Structure());
+ }
+
+ public OriginatorInfoGenerator(Store origCerts)
+ throws CMSException
+ {
+ this(origCerts, null);
+ }
+
+ public OriginatorInfoGenerator(Store origCerts, Store origCRLs)
+ throws CMSException
+ {
+ this.origCerts = CMSUtils.getCertificatesFromStore(origCerts);
+
+ if (origCRLs != null)
+ {
+ this.origCRLs = CMSUtils.getCRLsFromStore(origCRLs);
+ }
+ else
+ {
+ this.origCRLs = null;
+ }
+ }
+
+ public OriginatorInformation generate()
+ {
+ if (origCRLs != null)
+ {
+ return new OriginatorInformation(new OriginatorInfo(CMSUtils.createDerSetFromList(origCerts), CMSUtils.createDerSetFromList(origCRLs)));
+ }
+ else
+ {
+ return new OriginatorInformation(new OriginatorInfo(CMSUtils.createDerSetFromList(origCerts), null));
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/OriginatorInformation.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/OriginatorInformation.java
new file mode 100644
index 000000000..4db9a10a9
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/OriginatorInformation.java
@@ -0,0 +1,95 @@
+package org.spongycastle.cms;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.cms.OriginatorInfo;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.cert.X509CRLHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.util.CollectionStore;
+import org.spongycastle.util.Store;
+
+public class OriginatorInformation
+{
+ private OriginatorInfo originatorInfo;
+
+ OriginatorInformation(OriginatorInfo originatorInfo)
+ {
+ this.originatorInfo = originatorInfo;
+ }
+
+ /**
+ * Return the certificates stored in the underlying OriginatorInfo object.
+ *
+ * @return a Store of X509CertificateHolder objects.
+ */
+ public Store getCertificates()
+ {
+ ASN1Set certSet = originatorInfo.getCertificates();
+
+ if (certSet != null)
+ {
+ List certList = new ArrayList(certSet.size());
+
+ for (Enumeration en = certSet.getObjects(); en.hasMoreElements();)
+ {
+ ASN1Primitive obj = ((ASN1Encodable)en.nextElement()).toASN1Primitive();
+
+ if (obj instanceof ASN1Sequence)
+ {
+ certList.add(new X509CertificateHolder(Certificate.getInstance(obj)));
+ }
+ }
+
+ return new CollectionStore(certList);
+ }
+
+ return new CollectionStore(new ArrayList());
+ }
+
+ /**
+ * Return the CRLs stored in the underlying OriginatorInfo object.
+ *
+ * @return a Store of X509CRLHolder objects.
+ */
+ public Store getCRLs()
+ {
+ ASN1Set crlSet = originatorInfo.getCRLs();
+
+ if (crlSet != null)
+ {
+ List crlList = new ArrayList(crlSet.size());
+
+ for (Enumeration en = crlSet.getObjects(); en.hasMoreElements();)
+ {
+ ASN1Primitive obj = ((ASN1Encodable)en.nextElement()).toASN1Primitive();
+
+ if (obj instanceof ASN1Sequence)
+ {
+ crlList.add(new X509CRLHolder(CertificateList.getInstance(obj)));
+ }
+ }
+
+ return new CollectionStore(crlList);
+ }
+
+ return new CollectionStore(new ArrayList());
+ }
+
+ /**
+ * Return the underlying ASN.1 object defining this SignerInformation object.
+ *
+ * @return a OriginatorInfo.
+ */
+ public OriginatorInfo toASN1Structure()
+ {
+ return originatorInfo;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/PasswordRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/PasswordRecipient.java
new file mode 100644
index 000000000..b2762dd01
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/PasswordRecipient.java
@@ -0,0 +1,17 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface PasswordRecipient
+ extends Recipient
+{
+ public static final int PKCS5_SCHEME2 = 0;
+ public static final int PKCS5_SCHEME2_UTF8 = 1;
+
+ RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] derivedKey, byte[] encryptedEncryptedContentKey)
+ throws CMSException;
+
+ int getPasswordConversionScheme();
+
+ char[] getPassword();
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientId.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientId.java
new file mode 100644
index 000000000..d3efe2f51
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientId.java
@@ -0,0 +1,44 @@
+package org.spongycastle.cms;
+
+public class PasswordRecipientId
+ extends RecipientId
+{
+ /**
+ * Construct a recipient ID of the password type.
+ */
+ public PasswordRecipientId()
+ {
+ super(password);
+ }
+
+ public int hashCode()
+ {
+ return password;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof PasswordRecipientId))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public Object clone()
+ {
+ return new PasswordRecipientId();
+ }
+
+ public boolean match(Object obj)
+ {
+ if (obj instanceof PasswordRecipientInformation)
+ {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientInfoGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientInfoGenerator.java
new file mode 100644
index 000000000..aa1b5a0b2
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientInfoGenerator.java
@@ -0,0 +1,138 @@
+package org.spongycastle.cms;
+
+import java.security.SecureRandom;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.cms.PasswordRecipientInfo;
+import org.spongycastle.asn1.cms.RecipientInfo;
+import org.spongycastle.asn1.pkcs.PBKDF2Params;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.PBEParametersGenerator;
+import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.operator.GenericKey;
+
+public abstract class PasswordRecipientInfoGenerator
+ implements RecipientInfoGenerator
+{
+ private char[] password;
+ private AlgorithmIdentifier keyDerivationAlgorithm;
+ private ASN1ObjectIdentifier kekAlgorithm;
+ private SecureRandom random;
+ private int schemeID;
+ private int keySize;
+ private int blockSize;
+
+ protected PasswordRecipientInfoGenerator(ASN1ObjectIdentifier kekAlgorithm, char[] password)
+ {
+ this(kekAlgorithm, password, getKeySize(kekAlgorithm), ((Integer)PasswordRecipientInformation.BLOCKSIZES.get(kekAlgorithm)).intValue());
+ }
+
+ protected PasswordRecipientInfoGenerator(ASN1ObjectIdentifier kekAlgorithm, char[] password, int keySize, int blockSize)
+ {
+ this.password = password;
+ this.schemeID = PasswordRecipient.PKCS5_SCHEME2_UTF8;
+ this.kekAlgorithm = kekAlgorithm;
+ this.keySize = keySize;
+ this.blockSize = blockSize;
+ }
+
+ private static int getKeySize(ASN1ObjectIdentifier kekAlgorithm)
+ {
+ Integer size = (Integer)PasswordRecipientInformation.KEYSIZES.get(kekAlgorithm);
+
+ if (size == null)
+ {
+ throw new IllegalArgumentException("cannot find key size for algorithm: " + kekAlgorithm);
+ }
+
+ return size.intValue();
+ }
+
+ public PasswordRecipientInfoGenerator setPasswordConversionScheme(int schemeID)
+ {
+ this.schemeID = schemeID;
+
+ return this;
+ }
+
+ public PasswordRecipientInfoGenerator setSaltAndIterationCount(byte[] salt, int iterationCount)
+ {
+ this.keyDerivationAlgorithm = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, iterationCount));
+
+ return this;
+ }
+
+ public PasswordRecipientInfoGenerator setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public RecipientInfo generate(GenericKey contentEncryptionKey)
+ throws CMSException
+ {
+ byte[] iv = new byte[blockSize]; /// TODO: set IV size properly!
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(iv);
+
+ if (keyDerivationAlgorithm == null)
+ {
+ byte[] salt = new byte[20];
+
+ random.nextBytes(salt);
+
+ keyDerivationAlgorithm = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, 1024));
+ }
+
+ PBKDF2Params params = PBKDF2Params.getInstance(keyDerivationAlgorithm.getParameters());
+ byte[] derivedKey;
+
+ if (schemeID == PasswordRecipient.PKCS5_SCHEME2)
+ {
+ PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator();
+
+ gen.init(PBEParametersGenerator.PKCS5PasswordToBytes(password), params.getSalt(), params.getIterationCount().intValue());
+
+ derivedKey = ((KeyParameter)gen.generateDerivedParameters(keySize)).getKey();
+ }
+ else
+ {
+ PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator();
+
+ gen.init(PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(password), params.getSalt(), params.getIterationCount().intValue());
+
+ derivedKey = ((KeyParameter)gen.generateDerivedParameters(keySize)).getKey();
+ }
+
+ AlgorithmIdentifier kekAlgorithmId = new AlgorithmIdentifier(kekAlgorithm, new DEROctetString(iv));
+
+ byte[] encryptedKeyBytes = generateEncryptedBytes(kekAlgorithmId, derivedKey, contentEncryptionKey);
+
+ ASN1OctetString encryptedKey = new DEROctetString(encryptedKeyBytes);
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ v.add(kekAlgorithm);
+ v.add(new DEROctetString(iv));
+
+ AlgorithmIdentifier keyEncryptionAlgorithm = new AlgorithmIdentifier(
+ PKCSObjectIdentifiers.id_alg_PWRI_KEK, new DERSequence(v));
+
+ return new RecipientInfo(new PasswordRecipientInfo(keyDerivationAlgorithm,
+ keyEncryptionAlgorithm, encryptedKey));
+ }
+
+ protected abstract byte[] generateEncryptedBytes(AlgorithmIdentifier algorithm, byte[] derivedKey, GenericKey contentEncryptionKey)
+ throws CMSException;
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientInformation.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientInformation.java
new file mode 100644
index 000000000..90b7c4996
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/PasswordRecipientInformation.java
@@ -0,0 +1,135 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.cms.PasswordRecipientInfo;
+import org.spongycastle.asn1.pkcs.PBKDF2Params;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.PBEParametersGenerator;
+import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.util.Integers;
+
+/**
+ * the RecipientInfo class for a recipient who has been sent a message
+ * encrypted using a password.
+ */
+public class PasswordRecipientInformation
+ extends RecipientInformation
+{
+ static Map KEYSIZES = new HashMap();
+ static Map BLOCKSIZES = new HashMap();
+
+ static
+ {
+ BLOCKSIZES.put(CMSAlgorithm.DES_EDE3_CBC, Integers.valueOf(8));
+ BLOCKSIZES.put(CMSAlgorithm.AES128_CBC, Integers.valueOf(16));
+ BLOCKSIZES.put(CMSAlgorithm.AES192_CBC, Integers.valueOf(16));
+ BLOCKSIZES.put(CMSAlgorithm.AES256_CBC, Integers.valueOf(16));
+
+ KEYSIZES.put(CMSAlgorithm.DES_EDE3_CBC, Integers.valueOf(192));
+ KEYSIZES.put(CMSAlgorithm.AES128_CBC, Integers.valueOf(128));
+ KEYSIZES.put(CMSAlgorithm.AES192_CBC, Integers.valueOf(192));
+ KEYSIZES.put(CMSAlgorithm.AES256_CBC, Integers.valueOf(256));
+ }
+
+ private PasswordRecipientInfo info;
+
+ PasswordRecipientInformation(
+ PasswordRecipientInfo info,
+ AlgorithmIdentifier messageAlgorithm,
+ CMSSecureReadable secureReadable,
+ AuthAttributesProvider additionalData)
+ {
+ super(info.getKeyEncryptionAlgorithm(), messageAlgorithm, secureReadable, additionalData);
+
+ this.info = info;
+ this.rid = new PasswordRecipientId();
+ }
+
+ /**
+ * return the object identifier for the key derivation algorithm, or null
+ * if there is none present.
+ *
+ * @return OID for key derivation algorithm, if present.
+ */
+ public String getKeyDerivationAlgOID()
+ {
+ if (info.getKeyDerivationAlgorithm() != null)
+ {
+ return info.getKeyDerivationAlgorithm().getAlgorithm().getId();
+ }
+
+ return null;
+ }
+
+ /**
+ * return the ASN.1 encoded key derivation algorithm parameters, or null if
+ * there aren't any.
+ * @return ASN.1 encoding of key derivation algorithm parameters.
+ */
+ public byte[] getKeyDerivationAlgParams()
+ {
+ try
+ {
+ if (info.getKeyDerivationAlgorithm() != null)
+ {
+ ASN1Encodable params = info.getKeyDerivationAlgorithm().getParameters();
+ if (params != null)
+ {
+ return params.toASN1Primitive().getEncoded();
+ }
+ }
+
+ return null;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("exception getting encryption parameters " + e);
+ }
+ }
+
+ /**
+ * Return the key derivation algorithm details for the key in this recipient.
+ *
+ * @return AlgorithmIdentifier representing the key derivation algorithm.
+ */
+ public AlgorithmIdentifier getKeyDerivationAlgorithm()
+ {
+ return info.getKeyDerivationAlgorithm();
+ }
+
+ protected RecipientOperator getRecipientOperator(Recipient recipient)
+ throws CMSException, IOException
+ {
+ PasswordRecipient pbeRecipient = (PasswordRecipient)recipient;
+ AlgorithmIdentifier kekAlg = AlgorithmIdentifier.getInstance(info.getKeyEncryptionAlgorithm());
+ AlgorithmIdentifier kekAlgParams = AlgorithmIdentifier.getInstance(kekAlg.getParameters());
+
+ byte[] passwordBytes = getPasswordBytes(pbeRecipient.getPasswordConversionScheme(),
+ pbeRecipient.getPassword());
+ PBKDF2Params params = PBKDF2Params.getInstance(info.getKeyDerivationAlgorithm().getParameters());
+
+ PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator();
+ gen.init(passwordBytes, params.getSalt(), params.getIterationCount().intValue());
+
+ int keySize = ((Integer)KEYSIZES.get(kekAlgParams.getAlgorithm())).intValue();
+
+ byte[] derivedKey = ((KeyParameter)gen.generateDerivedParameters(keySize)).getKey();
+
+ return pbeRecipient.getRecipientOperator(kekAlgParams, messageAlgorithm, derivedKey, info.getEncryptedKey().getOctets());
+ }
+
+ protected byte[] getPasswordBytes(int scheme, char[] password)
+ {
+ if (scheme == PasswordRecipient.PKCS5_SCHEME2)
+ {
+ return PBEParametersGenerator.PKCS5PasswordToBytes(password);
+ }
+
+ return PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(password);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/Recipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/Recipient.java
new file mode 100644
index 000000000..17a3e4f8f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/Recipient.java
@@ -0,0 +1,5 @@
+package org.spongycastle.cms;
+
+public interface Recipient
+{
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientId.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientId.java
new file mode 100644
index 000000000..78a4bc22d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientId.java
@@ -0,0 +1,31 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.util.Selector;
+
+public abstract class RecipientId
+ implements Selector
+{
+ public static final int keyTrans = 0;
+ public static final int kek = 1;
+ public static final int keyAgree = 2;
+ public static final int password = 3;
+
+ private final int type;
+
+ protected RecipientId(int type)
+ {
+ this.type = type;
+ }
+
+ /**
+ * Return the type code for this recipient ID.
+ *
+ * @return one of keyTrans, kek, keyAgree, password
+ */
+ public int getType()
+ {
+ return type;
+ }
+
+ public abstract Object clone();
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientInfoGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientInfoGenerator.java
new file mode 100644
index 000000000..f61b3d971
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientInfoGenerator.java
@@ -0,0 +1,10 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.asn1.cms.RecipientInfo;
+import org.spongycastle.operator.GenericKey;
+
+public interface RecipientInfoGenerator
+{
+ RecipientInfo generate(GenericKey contentEncryptionKey)
+ throws CMSException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientInformation.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientInformation.java
new file mode 100644
index 000000000..c083baa92
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientInformation.java
@@ -0,0 +1,181 @@
+package org.spongycastle.cms;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.util.io.Streams;
+
+public abstract class RecipientInformation
+{
+ protected RecipientId rid;
+ protected AlgorithmIdentifier keyEncAlg;
+ protected AlgorithmIdentifier messageAlgorithm;
+ protected CMSSecureReadable secureReadable;
+
+ private AuthAttributesProvider additionalData;
+
+ private byte[] resultMac;
+ private RecipientOperator operator;
+
+ RecipientInformation(
+ AlgorithmIdentifier keyEncAlg,
+ AlgorithmIdentifier messageAlgorithm,
+ CMSSecureReadable secureReadable,
+ AuthAttributesProvider additionalData)
+ {
+ this.keyEncAlg = keyEncAlg;
+ this.messageAlgorithm = messageAlgorithm;
+ this.secureReadable = secureReadable;
+ this.additionalData = additionalData;
+ }
+
+ public RecipientId getRID()
+ {
+ return rid;
+ }
+
+ private byte[] encodeObj(
+ ASN1Encodable obj)
+ throws IOException
+ {
+ if (obj != null)
+ {
+ return obj.toASN1Primitive().getEncoded();
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the key encryption algorithm details for the key in this recipient.
+ *
+ * @return AlgorithmIdentifier representing the key encryption algorithm.
+ */
+ public AlgorithmIdentifier getKeyEncryptionAlgorithm()
+ {
+ return keyEncAlg;
+ }
+
+ /**
+ * return the object identifier for the key encryption algorithm.
+ *
+ * @return OID for key encryption algorithm.
+ */
+ public String getKeyEncryptionAlgOID()
+ {
+ return keyEncAlg.getAlgorithm().getId();
+ }
+
+ /**
+ * return the ASN.1 encoded key encryption algorithm parameters, or null if
+ * there aren't any.
+ *
+ * @return ASN.1 encoding of key encryption algorithm parameters.
+ */
+ public byte[] getKeyEncryptionAlgParams()
+ {
+ try
+ {
+ return encodeObj(keyEncAlg.getParameters());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("exception getting encryption parameters " + e);
+ }
+ }
+
+ /**
+ * Return the content digest calculated during the read of the content if one has been generated. This will
+ * only happen if we are dealing with authenticated data and authenticated attributes are present.
+ *
+ * @return byte array containing the digest.
+ */
+ public byte[] getContentDigest()
+ {
+ if (secureReadable instanceof CMSEnvelopedHelper.CMSDigestAuthenticatedSecureReadable)
+ {
+ return ((CMSEnvelopedHelper.CMSDigestAuthenticatedSecureReadable)secureReadable).getDigest();
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the MAC calculated for the recipient. Note: this call is only meaningful once all
+ * the content has been read.
+ *
+ * @return byte array containing the mac.
+ */
+ public byte[] getMac()
+ {
+ if (resultMac == null)
+ {
+ if (operator.isMacBased())
+ {
+ if (additionalData != null)
+ {
+ try
+ {
+ Streams.drain(operator.getInputStream(new ByteArrayInputStream(additionalData.getAuthAttributes().getEncoded(ASN1Encoding.DER))));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("unable to drain input: " + e.getMessage());
+ }
+ }
+ resultMac = operator.getMac();
+ }
+ }
+
+ return resultMac;
+ }
+
+ /**
+ * Return the decrypted/encapsulated content in the EnvelopedData after recovering the content
+ * encryption/MAC key using the passed in Recipient.
+ *
+ * @param recipient recipient object to use to recover content encryption key
+ * @return the content inside the EnvelopedData this RecipientInformation is associated with.
+ * @throws CMSException if the content-encryption/MAC key cannot be recovered.
+ */
+ public byte[] getContent(
+ Recipient recipient)
+ throws CMSException
+ {
+ try
+ {
+ return CMSUtils.streamToByteArray(getContentStream(recipient).getContentStream());
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("unable to parse internal stream: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Return a CMSTypedStream representing the content in the EnvelopedData after recovering the content
+ * encryption/MAC key using the passed in Recipient.
+ *
+ * @param recipient recipient object to use to recover content encryption key
+ * @return the content inside the EnvelopedData this RecipientInformation is associated with.
+ * @throws CMSException if the content-encryption/MAC key cannot be recovered.
+ */
+ public CMSTypedStream getContentStream(Recipient recipient)
+ throws CMSException, IOException
+ {
+ operator = getRecipientOperator(recipient);
+
+ if (additionalData != null)
+ {
+ return new CMSTypedStream(secureReadable.getInputStream());
+ }
+
+ return new CMSTypedStream(operator.getInputStream(secureReadable.getInputStream()));
+ }
+
+ protected abstract RecipientOperator getRecipientOperator(Recipient recipient)
+ throws CMSException, IOException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientInformationStore.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientInformationStore.java
new file mode 100644
index 000000000..f995874c2
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientInformationStore.java
@@ -0,0 +1,115 @@
+package org.spongycastle.cms;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.spongycastle.asn1.x500.X500Name;
+
+public class RecipientInformationStore
+{
+ private final List all; //ArrayList[RecipientInformation]
+ private final Map table = new HashMap(); // HashMap[RecipientID, ArrayList[RecipientInformation]]
+
+ public RecipientInformationStore(
+ Collection recipientInfos)
+ {
+ Iterator it = recipientInfos.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipientInformation = (RecipientInformation)it.next();
+ RecipientId rid = recipientInformation.getRID();
+
+ List list = (ArrayList)table.get(rid);
+ if (list == null)
+ {
+ list = new ArrayList(1);
+ table.put(rid, list);
+ }
+
+ list.add(recipientInformation);
+ }
+
+ this.all = new ArrayList(recipientInfos);
+ }
+
+ /**
+ * Return the first RecipientInformation object that matches the
+ * passed in selector. Null if there are no matches.
+ *
+ * @param selector to identify a recipient
+ * @return a single RecipientInformation object. Null if none matches.
+ */
+ public RecipientInformation get(
+ RecipientId selector)
+ {
+ Collection list = getRecipients(selector);
+
+ return list.size() == 0 ? null : (RecipientInformation)list.iterator().next();
+ }
+
+ /**
+ * Return the number of recipients in the collection.
+ *
+ * @return number of recipients identified.
+ */
+ public int size()
+ {
+ return all.size();
+ }
+
+ /**
+ * Return all recipients in the collection
+ *
+ * @return a collection of recipients.
+ */
+ public Collection getRecipients()
+ {
+ return new ArrayList(all);
+ }
+
+ /**
+ * Return possible empty collection with recipients matching the passed in RecipientId
+ *
+ * @param selector a recipient id to select against.
+ * @return a collection of RecipientInformation objects.
+ */
+ public Collection getRecipients(
+ RecipientId selector)
+ {
+ if (selector instanceof KeyTransRecipientId)
+ {
+ KeyTransRecipientId keyTrans = (KeyTransRecipientId)selector;
+
+ X500Name issuer = keyTrans.getIssuer();
+ byte[] subjectKeyId = keyTrans.getSubjectKeyIdentifier();
+
+ if (issuer != null && subjectKeyId != null)
+ {
+ List results = new ArrayList();
+
+ Collection match1 = getRecipients(new KeyTransRecipientId(issuer, keyTrans.getSerialNumber()));
+ if (match1 != null)
+ {
+ results.addAll(match1);
+ }
+
+ Collection match2 = getRecipients(new KeyTransRecipientId(subjectKeyId));
+ if (match2 != null)
+ {
+ results.addAll(match2);
+ }
+
+ return results;
+ }
+ }
+
+ List list = (ArrayList)table.get(selector);
+
+ return list == null ? new ArrayList() : new ArrayList(list);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientOperator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientOperator.java
new file mode 100644
index 000000000..c254dbf35
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/RecipientOperator.java
@@ -0,0 +1,48 @@
+package org.spongycastle.cms;
+
+import java.io.InputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.InputDecryptor;
+import org.spongycastle.operator.MacCalculator;
+import org.spongycastle.util.io.TeeInputStream;
+
+public class RecipientOperator
+{
+ private final AlgorithmIdentifier algorithmIdentifier;
+ private final Object operator;
+
+ public RecipientOperator(InputDecryptor decryptor)
+ {
+ this.algorithmIdentifier = decryptor.getAlgorithmIdentifier();
+ this.operator = decryptor;
+ }
+
+ public RecipientOperator(MacCalculator macCalculator)
+ {
+ this.algorithmIdentifier = macCalculator.getAlgorithmIdentifier();
+ this.operator = macCalculator;
+ }
+
+ public InputStream getInputStream(InputStream dataIn)
+ {
+ if (operator instanceof InputDecryptor)
+ {
+ return ((InputDecryptor)operator).getInputStream(dataIn);
+ }
+ else
+ {
+ return new TeeInputStream(dataIn, ((MacCalculator)operator).getOutputStream());
+ }
+ }
+
+ public boolean isMacBased()
+ {
+ return operator instanceof MacCalculator;
+ }
+
+ public byte[] getMac()
+ {
+ return ((MacCalculator)operator).getMac();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerId.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerId.java
new file mode 100644
index 000000000..a7434f8a6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerId.java
@@ -0,0 +1,104 @@
+package org.spongycastle.cms;
+
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cert.selector.X509CertificateHolderSelector;
+import org.spongycastle.util.Selector;
+
+/**
+ * a basic index for a signer.
+ */
+public class SignerId
+ implements Selector
+{
+ private X509CertificateHolderSelector baseSelector;
+
+ private SignerId(X509CertificateHolderSelector baseSelector)
+ {
+ this.baseSelector = baseSelector;
+ }
+
+ /**
+ * Construct a signer ID with the value of a public key's subjectKeyId.
+ *
+ * @param subjectKeyId a subjectKeyId
+ */
+ public SignerId(byte[] subjectKeyId)
+ {
+ this(null, null, subjectKeyId);
+ }
+
+ /**
+ * Construct a signer ID based on the issuer and serial number of the signer's associated
+ * certificate.
+ *
+ * @param issuer the issuer of the signer's associated certificate.
+ * @param serialNumber the serial number of the signer's associated certificate.
+ */
+ public SignerId(X500Name issuer, BigInteger serialNumber)
+ {
+ this(issuer, serialNumber, null);
+ }
+
+ /**
+ * Construct a signer ID based on the issuer and serial number of the signer's associated
+ * certificate.
+ *
+ * @param issuer the issuer of the signer's associated certificate.
+ * @param serialNumber the serial number of the signer's associated certificate.
+ * @param subjectKeyId the subject key identifier to use to match the signers associated certificate.
+ */
+ public SignerId(X500Name issuer, BigInteger serialNumber, byte[] subjectKeyId)
+ {
+ this(new X509CertificateHolderSelector(issuer, serialNumber, subjectKeyId));
+ }
+
+ public X500Name getIssuer()
+ {
+ return baseSelector.getIssuer();
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return baseSelector.getSerialNumber();
+ }
+
+ public byte[] getSubjectKeyIdentifier()
+ {
+ return baseSelector.getSubjectKeyIdentifier();
+ }
+
+ public int hashCode()
+ {
+ return baseSelector.hashCode();
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof SignerId))
+ {
+ return false;
+ }
+
+ SignerId id = (SignerId)o;
+
+ return this.baseSelector.equals(id.baseSelector);
+ }
+
+ public boolean match(Object obj)
+ {
+ if (obj instanceof SignerInformation)
+ {
+ return ((SignerInformation)obj).getSID().equals(this);
+ }
+
+ return baseSelector.match(obj);
+ }
+
+ public Object clone()
+ {
+ return new SignerId(this.baseSelector);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInfoGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInfoGenerator.java
new file mode 100644
index 000000000..6e5a80886
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInfoGenerator.java
@@ -0,0 +1,291 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.SignerIdentifier;
+import org.spongycastle.asn1.cms.SignerInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.io.TeeOutputStream;
+
+public class SignerInfoGenerator
+{
+ private final SignerIdentifier signerIdentifier;
+ private final CMSAttributeTableGenerator sAttrGen;
+ private final CMSAttributeTableGenerator unsAttrGen;
+ private final ContentSigner signer;
+ private final DigestCalculator digester;
+ private final DigestAlgorithmIdentifierFinder digAlgFinder = new DefaultDigestAlgorithmIdentifierFinder();
+ private final CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder;
+
+ private byte[] calculatedDigest = null;
+ private X509CertificateHolder certHolder;
+
+ SignerInfoGenerator(
+ SignerIdentifier signerIdentifier,
+ ContentSigner signer,
+ DigestCalculatorProvider digesterProvider,
+ CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder)
+ throws OperatorCreationException
+ {
+ this(signerIdentifier, signer, digesterProvider, sigEncAlgFinder, false);
+ }
+
+ SignerInfoGenerator(
+ SignerIdentifier signerIdentifier,
+ ContentSigner signer,
+ DigestCalculatorProvider digesterProvider,
+ CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder,
+ boolean isDirectSignature)
+ throws OperatorCreationException
+ {
+ this.signerIdentifier = signerIdentifier;
+ this.signer = signer;
+
+ if (digesterProvider != null)
+ {
+ this.digester = digesterProvider.get(digAlgFinder.find(signer.getAlgorithmIdentifier()));
+ }
+ else
+ {
+ this.digester = null;
+ }
+
+ if (isDirectSignature)
+ {
+ this.sAttrGen = null;
+ this.unsAttrGen = null;
+ }
+ else
+ {
+ this.sAttrGen = new DefaultSignedAttributeTableGenerator();
+ this.unsAttrGen = null;
+ }
+
+ this.sigEncAlgFinder = sigEncAlgFinder;
+ }
+
+ public SignerInfoGenerator(
+ SignerInfoGenerator original,
+ CMSAttributeTableGenerator sAttrGen,
+ CMSAttributeTableGenerator unsAttrGen)
+ {
+ this.signerIdentifier = original.signerIdentifier;
+ this.signer = original.signer;
+ this.digester = original.digester;
+ this.sigEncAlgFinder = original.sigEncAlgFinder;
+ this.sAttrGen = sAttrGen;
+ this.unsAttrGen = unsAttrGen;
+ }
+
+ SignerInfoGenerator(
+ SignerIdentifier signerIdentifier,
+ ContentSigner signer,
+ DigestCalculatorProvider digesterProvider,
+ CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder,
+ CMSAttributeTableGenerator sAttrGen,
+ CMSAttributeTableGenerator unsAttrGen)
+ throws OperatorCreationException
+ {
+ this.signerIdentifier = signerIdentifier;
+ this.signer = signer;
+
+ if (digesterProvider != null)
+ {
+ this.digester = digesterProvider.get(digAlgFinder.find(signer.getAlgorithmIdentifier()));
+ }
+ else
+ {
+ this.digester = null;
+ }
+
+ this.sAttrGen = sAttrGen;
+ this.unsAttrGen = unsAttrGen;
+ this.sigEncAlgFinder = sigEncAlgFinder;
+ }
+
+ public SignerIdentifier getSID()
+ {
+ return signerIdentifier;
+ }
+
+ public int getGeneratedVersion()
+ {
+ return signerIdentifier.isTagged() ? 3 : 1;
+ }
+
+ public boolean hasAssociatedCertificate()
+ {
+ return certHolder != null;
+ }
+
+ public X509CertificateHolder getAssociatedCertificate()
+ {
+ return certHolder;
+ }
+
+ public AlgorithmIdentifier getDigestAlgorithm()
+ {
+ if (digester != null)
+ {
+ return digester.getAlgorithmIdentifier();
+ }
+
+ return digAlgFinder.find(signer.getAlgorithmIdentifier());
+ }
+
+ public OutputStream getCalculatingOutputStream()
+ {
+ if (digester != null)
+ {
+ if (sAttrGen == null)
+ {
+ return new TeeOutputStream(digester.getOutputStream(), signer.getOutputStream());
+ }
+ return digester.getOutputStream();
+ }
+ else
+ {
+ return signer.getOutputStream();
+ }
+ }
+
+ public SignerInfo generate(ASN1ObjectIdentifier contentType)
+ throws CMSException
+ {
+ try
+ {
+ /* RFC 3852 5.4
+ * The result of the message digest calculation process depends on
+ * whether the signedAttrs field is present. When the field is absent,
+ * the result is just the message digest of the content as described
+ *
+ * above. When the field is present, however, the result is the message
+ * digest of the complete DER encoding of the SignedAttrs value
+ * contained in the signedAttrs field.
+ */
+ ASN1Set signedAttr = null;
+
+ AlgorithmIdentifier digestAlg = null;
+
+ if (sAttrGen != null)
+ {
+ digestAlg = digester.getAlgorithmIdentifier();
+ calculatedDigest = digester.getDigest();
+ Map parameters = getBaseParameters(contentType, digester.getAlgorithmIdentifier(), calculatedDigest);
+ AttributeTable signed = sAttrGen.getAttributes(Collections.unmodifiableMap(parameters));
+
+ signedAttr = getAttributeSet(signed);
+
+ // sig must be composed from the DER encoding.
+ OutputStream sOut = signer.getOutputStream();
+
+ sOut.write(signedAttr.getEncoded(ASN1Encoding.DER));
+
+ sOut.close();
+ }
+ else
+ {
+ if (digester != null)
+ {
+ digestAlg = digester.getAlgorithmIdentifier();
+ calculatedDigest = digester.getDigest();
+ }
+ else
+ {
+ digestAlg = digAlgFinder.find(signer.getAlgorithmIdentifier());
+ calculatedDigest = null;
+ }
+ }
+
+ byte[] sigBytes = signer.getSignature();
+
+ ASN1Set unsignedAttr = null;
+ if (unsAttrGen != null)
+ {
+ Map parameters = getBaseParameters(contentType, digestAlg, calculatedDigest);
+ parameters.put(CMSAttributeTableGenerator.SIGNATURE, Arrays.clone(sigBytes));
+
+ AttributeTable unsigned = unsAttrGen.getAttributes(Collections.unmodifiableMap(parameters));
+
+ unsignedAttr = getAttributeSet(unsigned);
+ }
+
+ AlgorithmIdentifier digestEncryptionAlgorithm = sigEncAlgFinder.findEncryptionAlgorithm(signer.getAlgorithmIdentifier());
+
+ return new SignerInfo(signerIdentifier, digestAlg,
+ signedAttr, digestEncryptionAlgorithm, new DEROctetString(sigBytes), unsignedAttr);
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("encoding error.", e);
+ }
+ }
+
+ void setAssociatedCertificate(X509CertificateHolder certHolder)
+ {
+ this.certHolder = certHolder;
+ }
+
+ private ASN1Set getAttributeSet(
+ AttributeTable attr)
+ {
+ if (attr != null)
+ {
+ return new DERSet(attr.toASN1EncodableVector());
+ }
+
+ return null;
+ }
+
+ private Map getBaseParameters(ASN1ObjectIdentifier contentType, AlgorithmIdentifier digAlgId, byte[] hash)
+ {
+ Map param = new HashMap();
+
+ if (contentType != null)
+ {
+ param.put(CMSAttributeTableGenerator.CONTENT_TYPE, contentType);
+ }
+
+ param.put(CMSAttributeTableGenerator.DIGEST_ALGORITHM_IDENTIFIER, digAlgId);
+ param.put(CMSAttributeTableGenerator.DIGEST, Arrays.clone(hash));
+ return param;
+ }
+
+ public byte[] getCalculatedDigest()
+ {
+ if (calculatedDigest != null)
+ {
+ return Arrays.clone(calculatedDigest);
+ }
+
+ return null;
+ }
+
+ public CMSAttributeTableGenerator getSignedAttributeTableGenerator()
+ {
+ return sAttrGen;
+ }
+
+ public CMSAttributeTableGenerator getUnsignedAttributeTableGenerator()
+ {
+ return unsAttrGen;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInfoGeneratorBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInfoGeneratorBuilder.java
new file mode 100644
index 000000000..a33005e0c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInfoGeneratorBuilder.java
@@ -0,0 +1,139 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.cms.IssuerAndSerialNumber;
+import org.spongycastle.asn1.cms.SignerIdentifier;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+
+/**
+ * Builder for SignerInfo generator objects.
+ */
+public class SignerInfoGeneratorBuilder
+{
+ private DigestCalculatorProvider digestProvider;
+ private boolean directSignature;
+ private CMSAttributeTableGenerator signedGen;
+ private CMSAttributeTableGenerator unsignedGen;
+ private CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder;
+
+ /**
+ * Base constructor.
+ *
+ * @param digestProvider a provider of digest calculators for the algorithms required in the signature and attribute calculations.
+ */
+ public SignerInfoGeneratorBuilder(DigestCalculatorProvider digestProvider)
+ {
+ this(digestProvider, new DefaultCMSSignatureEncryptionAlgorithmFinder());
+ }
+
+ /**
+ * Base constructor.
+ *
+ * @param digestProvider a provider of digest calculators for the algorithms required in the signature and attribute calculations.
+ */
+ public SignerInfoGeneratorBuilder(DigestCalculatorProvider digestProvider, CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder)
+ {
+ this.digestProvider = digestProvider;
+ this.sigEncAlgFinder = sigEncAlgFinder;
+ }
+
+ /**
+ * If the passed in flag is true, the signer signature will be based on the data, not
+ * a collection of signed attributes, and no signed attributes will be included.
+ *
+ * @return the builder object
+ */
+ public SignerInfoGeneratorBuilder setDirectSignature(boolean hasNoSignedAttributes)
+ {
+ this.directSignature = hasNoSignedAttributes;
+
+ return this;
+ }
+
+ /**
+ * Provide a custom signed attribute generator.
+ *
+ * @param signedGen a generator of signed attributes.
+ * @return the builder object
+ */
+ public SignerInfoGeneratorBuilder setSignedAttributeGenerator(CMSAttributeTableGenerator signedGen)
+ {
+ this.signedGen = signedGen;
+
+ return this;
+ }
+
+ /**
+ * Provide a generator of unsigned attributes.
+ *
+ * @param unsignedGen a generator for signed attributes.
+ * @return the builder object
+ */
+ public SignerInfoGeneratorBuilder setUnsignedAttributeGenerator(CMSAttributeTableGenerator unsignedGen)
+ {
+ this.unsignedGen = unsignedGen;
+
+ return this;
+ }
+
+ /**
+ * Build a generator with the passed in certHolder issuer and serial number as the signerIdentifier.
+ *
+ * @param contentSigner operator for generating the final signature in the SignerInfo with.
+ * @param certHolder carrier for the X.509 certificate related to the contentSigner.
+ * @return a SignerInfoGenerator
+ * @throws OperatorCreationException if the generator cannot be built.
+ */
+ public SignerInfoGenerator build(ContentSigner contentSigner, X509CertificateHolder certHolder)
+ throws OperatorCreationException
+ {
+ SignerIdentifier sigId = new SignerIdentifier(new IssuerAndSerialNumber(certHolder.toASN1Structure()));
+
+ SignerInfoGenerator sigInfoGen = createGenerator(contentSigner, sigId);
+
+ sigInfoGen.setAssociatedCertificate(certHolder);
+
+ return sigInfoGen;
+ }
+
+ /**
+ * Build a generator with the passed in subjectKeyIdentifier as the signerIdentifier. If used you should
+ * try to follow the calculation described in RFC 5280 section 4.2.1.2.
+ *
+ * @param contentSigner operator for generating the final signature in the SignerInfo with.
+ * @param subjectKeyIdentifier key identifier to identify the public key for verifying the signature.
+ * @return a SignerInfoGenerator
+ * @throws OperatorCreationException if the generator cannot be built.
+ */
+ public SignerInfoGenerator build(ContentSigner contentSigner, byte[] subjectKeyIdentifier)
+ throws OperatorCreationException
+ {
+ SignerIdentifier sigId = new SignerIdentifier(new DEROctetString(subjectKeyIdentifier));
+
+ return createGenerator(contentSigner, sigId);
+ }
+
+ private SignerInfoGenerator createGenerator(ContentSigner contentSigner, SignerIdentifier sigId)
+ throws OperatorCreationException
+ {
+ if (directSignature)
+ {
+ return new SignerInfoGenerator(sigId, contentSigner, digestProvider, sigEncAlgFinder, true);
+ }
+
+ if (signedGen != null || unsignedGen != null)
+ {
+ if (signedGen == null)
+ {
+ signedGen = new DefaultSignedAttributeTableGenerator();
+ }
+
+ return new SignerInfoGenerator(sigId, contentSigner, digestProvider, sigEncAlgFinder, signedGen, unsignedGen);
+ }
+
+ return new SignerInfoGenerator(sigId, contentSigner, digestProvider, sigEncAlgFinder);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInformation.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInformation.java
new file mode 100644
index 000000000..353f27e6d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInformation.java
@@ -0,0 +1,680 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.cms.Attribute;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSAttributes;
+import org.spongycastle.asn1.cms.IssuerAndSerialNumber;
+import org.spongycastle.asn1.cms.SignerIdentifier;
+import org.spongycastle.asn1.cms.SignerInfo;
+import org.spongycastle.asn1.cms.Time;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.DigestInfo;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.operator.ContentVerifier;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.RawContentVerifier;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.io.TeeOutputStream;
+
+/**
+ * an expanded SignerInfo block from a CMS Signed message
+ */
+public class SignerInformation
+{
+ private SignerId sid;
+ private SignerInfo info;
+ private AlgorithmIdentifier digestAlgorithm;
+ private AlgorithmIdentifier encryptionAlgorithm;
+ private final ASN1Set signedAttributeSet;
+ private final ASN1Set unsignedAttributeSet;
+ private CMSProcessable content;
+ private byte[] signature;
+ private ASN1ObjectIdentifier contentType;
+ private byte[] resultDigest;
+
+ // Derived
+ private AttributeTable signedAttributeValues;
+ private AttributeTable unsignedAttributeValues;
+ private boolean isCounterSignature;
+
+ SignerInformation(
+ SignerInfo info,
+ ASN1ObjectIdentifier contentType,
+ CMSProcessable content,
+ byte[] resultDigest)
+ {
+ this.info = info;
+ this.contentType = contentType;
+ this.isCounterSignature = contentType == null;
+
+ SignerIdentifier s = info.getSID();
+
+ if (s.isTagged())
+ {
+ ASN1OctetString octs = ASN1OctetString.getInstance(s.getId());
+
+ sid = new SignerId(octs.getOctets());
+ }
+ else
+ {
+ IssuerAndSerialNumber iAnds = IssuerAndSerialNumber.getInstance(s.getId());
+
+ sid = new SignerId(iAnds.getName(), iAnds.getSerialNumber().getValue());
+ }
+
+ this.digestAlgorithm = info.getDigestAlgorithm();
+ this.signedAttributeSet = info.getAuthenticatedAttributes();
+ this.unsignedAttributeSet = info.getUnauthenticatedAttributes();
+ this.encryptionAlgorithm = info.getDigestEncryptionAlgorithm();
+ this.signature = info.getEncryptedDigest().getOctets();
+
+ this.content = content;
+ this.resultDigest = resultDigest;
+ }
+
+ public boolean isCounterSignature()
+ {
+ return isCounterSignature;
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return this.contentType;
+ }
+
+ private byte[] encodeObj(
+ ASN1Encodable obj)
+ throws IOException
+ {
+ if (obj != null)
+ {
+ return obj.toASN1Primitive().getEncoded();
+ }
+
+ return null;
+ }
+
+ public SignerId getSID()
+ {
+ return sid;
+ }
+
+ /**
+ * return the version number for this objects underlying SignerInfo structure.
+ */
+ public int getVersion()
+ {
+ return info.getVersion().getValue().intValue();
+ }
+
+ public AlgorithmIdentifier getDigestAlgorithmID()
+ {
+ return digestAlgorithm;
+ }
+
+ /**
+ * return the object identifier for the signature.
+ */
+ public String getDigestAlgOID()
+ {
+ return digestAlgorithm.getAlgorithm().getId();
+ }
+
+ /**
+ * return the signature parameters, or null if there aren't any.
+ */
+ public byte[] getDigestAlgParams()
+ {
+ try
+ {
+ return encodeObj(digestAlgorithm.getParameters());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("exception getting digest parameters " + e);
+ }
+ }
+
+ /**
+ * return the content digest that was calculated during verification.
+ */
+ public byte[] getContentDigest()
+ {
+ if (resultDigest == null)
+ {
+ throw new IllegalStateException("method can only be called after verify.");
+ }
+
+ return Arrays.clone(resultDigest);
+ }
+
+ /**
+ * return the object identifier for the signature.
+ */
+ public String getEncryptionAlgOID()
+ {
+ return encryptionAlgorithm.getAlgorithm().getId();
+ }
+
+ /**
+ * return the signature/encryption algorithm parameters, or null if
+ * there aren't any.
+ */
+ public byte[] getEncryptionAlgParams()
+ {
+ try
+ {
+ return encodeObj(encryptionAlgorithm.getParameters());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("exception getting encryption parameters " + e);
+ }
+ }
+
+ /**
+ * return a table of the signed attributes - indexed by
+ * the OID of the attribute.
+ */
+ public AttributeTable getSignedAttributes()
+ {
+ if (signedAttributeSet != null && signedAttributeValues == null)
+ {
+ signedAttributeValues = new AttributeTable(signedAttributeSet);
+ }
+
+ return signedAttributeValues;
+ }
+
+ /**
+ * return a table of the unsigned attributes indexed by
+ * the OID of the attribute.
+ */
+ public AttributeTable getUnsignedAttributes()
+ {
+ if (unsignedAttributeSet != null && unsignedAttributeValues == null)
+ {
+ unsignedAttributeValues = new AttributeTable(unsignedAttributeSet);
+ }
+
+ return unsignedAttributeValues;
+ }
+
+ /**
+ * return the encoded signature
+ */
+ public byte[] getSignature()
+ {
+ return Arrays.clone(signature);
+ }
+
+ /**
+ * Return a SignerInformationStore containing the counter signatures attached to this
+ * signer. If no counter signatures are present an empty store is returned.
+ */
+ public SignerInformationStore getCounterSignatures()
+ {
+ // TODO There are several checks implied by the RFC3852 comments that are missing
+
+ /*
+ The countersignature attribute MUST be an unsigned attribute; it MUST
+ NOT be a signed attribute, an authenticated attribute, an
+ unauthenticated attribute, or an unprotected attribute.
+ */
+ AttributeTable unsignedAttributeTable = getUnsignedAttributes();
+ if (unsignedAttributeTable == null)
+ {
+ return new SignerInformationStore(new ArrayList(0));
+ }
+
+ List counterSignatures = new ArrayList();
+
+ /*
+ The UnsignedAttributes syntax is defined as a SET OF Attributes. The
+ UnsignedAttributes in a signerInfo may include multiple instances of
+ the countersignature attribute.
+ */
+ ASN1EncodableVector allCSAttrs = unsignedAttributeTable.getAll(CMSAttributes.counterSignature);
+
+ for (int i = 0; i < allCSAttrs.size(); ++i)
+ {
+ Attribute counterSignatureAttribute = (Attribute)allCSAttrs.get(i);
+
+ /*
+ A countersignature attribute can have multiple attribute values. The
+ syntax is defined as a SET OF AttributeValue, and there MUST be one
+ or more instances of AttributeValue present.
+ */
+ ASN1Set values = counterSignatureAttribute.getAttrValues();
+ if (values.size() < 1)
+ {
+ // TODO Throw an appropriate exception?
+ }
+
+ for (Enumeration en = values.getObjects(); en.hasMoreElements();)
+ {
+ /*
+ Countersignature values have the same meaning as SignerInfo values
+ for ordinary signatures, except that:
+
+ 1. The signedAttributes field MUST NOT contain a content-type
+ attribute; there is no content type for countersignatures.
+
+ 2. The signedAttributes field MUST contain a message-digest
+ attribute if it contains any other attributes.
+
+ 3. The input to the message-digesting process is the contents
+ octets of the DER encoding of the signatureValue field of the
+ SignerInfo value with which the attribute is associated.
+ */
+ SignerInfo si = SignerInfo.getInstance(en.nextElement());
+
+ counterSignatures.add(new SignerInformation(si, null, new CMSProcessableByteArray(getSignature()), null));
+ }
+ }
+
+ return new SignerInformationStore(counterSignatures);
+ }
+
+ /**
+ * return the DER encoding of the signed attributes.
+ * @throws IOException if an encoding error occurs.
+ */
+ public byte[] getEncodedSignedAttributes()
+ throws IOException
+ {
+ if (signedAttributeSet != null)
+ {
+ return signedAttributeSet.getEncoded();
+ }
+
+ return null;
+ }
+
+ private boolean doVerify(
+ SignerInformationVerifier verifier)
+ throws CMSException
+ {
+ String encName = CMSSignedHelper.INSTANCE.getEncryptionAlgName(this.getEncryptionAlgOID());
+ ContentVerifier contentVerifier;
+
+ try
+ {
+ contentVerifier = verifier.getContentVerifier(encryptionAlgorithm, info.getDigestAlgorithm());
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new CMSException("can't create content verifier: " + e.getMessage(), e);
+ }
+
+ try
+ {
+ OutputStream sigOut = contentVerifier.getOutputStream();
+
+ if (resultDigest == null)
+ {
+ DigestCalculator calc = verifier.getDigestCalculator(this.getDigestAlgorithmID());
+ if (content != null)
+ {
+ OutputStream digOut = calc.getOutputStream();
+
+ if (signedAttributeSet == null)
+ {
+ if (contentVerifier instanceof RawContentVerifier)
+ {
+ content.write(digOut);
+ }
+ else
+ {
+ OutputStream cOut = new TeeOutputStream(digOut, sigOut);
+
+ content.write(cOut);
+
+ cOut.close();
+ }
+ }
+ else
+ {
+ content.write(digOut);
+ sigOut.write(this.getEncodedSignedAttributes());
+ }
+
+ digOut.close();
+ }
+ else if (signedAttributeSet != null)
+ {
+ sigOut.write(this.getEncodedSignedAttributes());
+ }
+ else
+ {
+ // TODO Get rid of this exception and just treat content==null as empty not missing?
+ throw new CMSException("data not encapsulated in signature - use detached constructor.");
+ }
+
+ resultDigest = calc.getDigest();
+ }
+ else
+ {
+ if (signedAttributeSet == null)
+ {
+ if (content != null)
+ {
+ content.write(sigOut);
+ }
+ }
+ else
+ {
+ sigOut.write(this.getEncodedSignedAttributes());
+ }
+ }
+
+ sigOut.close();
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("can't process mime object to create signature.", e);
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new CMSException("can't create digest calculator: " + e.getMessage(), e);
+ }
+
+ // RFC 3852 11.1 Check the content-type attribute is correct
+ {
+ ASN1Primitive validContentType = getSingleValuedSignedAttribute(
+ CMSAttributes.contentType, "content-type");
+ if (validContentType == null)
+ {
+ if (!isCounterSignature && signedAttributeSet != null)
+ {
+ throw new CMSException("The content-type attribute type MUST be present whenever signed attributes are present in signed-data");
+ }
+ }
+ else
+ {
+ if (isCounterSignature)
+ {
+ throw new CMSException("[For counter signatures,] the signedAttributes field MUST NOT contain a content-type attribute");
+ }
+
+ if (!(validContentType instanceof ASN1ObjectIdentifier))
+ {
+ throw new CMSException("content-type attribute value not of ASN.1 type 'OBJECT IDENTIFIER'");
+ }
+
+ ASN1ObjectIdentifier signedContentType = (ASN1ObjectIdentifier)validContentType;
+
+ if (!signedContentType.equals(contentType))
+ {
+ throw new CMSException("content-type attribute value does not match eContentType");
+ }
+ }
+ }
+
+ // RFC 3852 11.2 Check the message-digest attribute is correct
+ {
+ ASN1Primitive validMessageDigest = getSingleValuedSignedAttribute(
+ CMSAttributes.messageDigest, "message-digest");
+ if (validMessageDigest == null)
+ {
+ if (signedAttributeSet != null)
+ {
+ throw new CMSException("the message-digest signed attribute type MUST be present when there are any signed attributes present");
+ }
+ }
+ else
+ {
+ if (!(validMessageDigest instanceof ASN1OctetString))
+ {
+ throw new CMSException("message-digest attribute value not of ASN.1 type 'OCTET STRING'");
+ }
+
+ ASN1OctetString signedMessageDigest = (ASN1OctetString)validMessageDigest;
+
+ if (!Arrays.constantTimeAreEqual(resultDigest, signedMessageDigest.getOctets()))
+ {
+ throw new CMSSignerDigestMismatchException("message-digest attribute value does not match calculated value");
+ }
+ }
+ }
+
+ // RFC 3852 11.4 Validate countersignature attribute(s)
+ {
+ AttributeTable signedAttrTable = this.getSignedAttributes();
+ if (signedAttrTable != null
+ && signedAttrTable.getAll(CMSAttributes.counterSignature).size() > 0)
+ {
+ throw new CMSException("A countersignature attribute MUST NOT be a signed attribute");
+ }
+
+ AttributeTable unsignedAttrTable = this.getUnsignedAttributes();
+ if (unsignedAttrTable != null)
+ {
+ ASN1EncodableVector csAttrs = unsignedAttrTable.getAll(CMSAttributes.counterSignature);
+ for (int i = 0; i < csAttrs.size(); ++i)
+ {
+ Attribute csAttr = (Attribute)csAttrs.get(i);
+ if (csAttr.getAttrValues().size() < 1)
+ {
+ throw new CMSException("A countersignature attribute MUST contain at least one AttributeValue");
+ }
+
+ // Note: We don't recursively validate the countersignature value
+ }
+ }
+ }
+
+ try
+ {
+ if (signedAttributeSet == null && resultDigest != null)
+ {
+ if (contentVerifier instanceof RawContentVerifier)
+ {
+ RawContentVerifier rawVerifier = (RawContentVerifier)contentVerifier;
+
+ if (encName.equals("RSA"))
+ {
+ DigestInfo digInfo = new DigestInfo(new AlgorithmIdentifier(digestAlgorithm.getAlgorithm(), DERNull.INSTANCE), resultDigest);
+
+ return rawVerifier.verify(digInfo.getEncoded(ASN1Encoding.DER), this.getSignature());
+ }
+
+ return rawVerifier.verify(resultDigest, this.getSignature());
+ }
+ }
+
+ return contentVerifier.verify(this.getSignature());
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("can't process mime object to create signature.", e);
+ }
+ }
+
+ /**
+ * Verify that the given verifier can successfully verify the signature on
+ * this SignerInformation object.
+ *
+ * @param verifier a suitably configured SignerInformationVerifier.
+ * @return true if the signer information is verified, false otherwise.
+ * @throws org.spongycastle.cms.CMSVerifierCertificateNotValidException if the provider has an associated certificate and the certificate is not valid at the time given as the SignerInfo's signing time.
+ * @throws org.spongycastle.cms.CMSException if the verifier is unable to create a ContentVerifiers or DigestCalculators.
+ */
+ public boolean verify(SignerInformationVerifier verifier)
+ throws CMSException
+ {
+ Time signingTime = getSigningTime(); // has to be validated if present.
+
+ if (verifier.hasAssociatedCertificate())
+ {
+ if (signingTime != null)
+ {
+ X509CertificateHolder dcv = verifier.getAssociatedCertificate();
+
+ if (!dcv.isValidOn(signingTime.getDate()))
+ {
+ throw new CMSVerifierCertificateNotValidException("verifier not valid at signingTime");
+ }
+ }
+ }
+
+ return doVerify(verifier);
+ }
+
+ /**
+ * Return the underlying ASN.1 object defining this SignerInformation object.
+ *
+ * @return a SignerInfo.
+ */
+ public SignerInfo toASN1Structure()
+ {
+ return info;
+ }
+
+ private ASN1Primitive getSingleValuedSignedAttribute(
+ ASN1ObjectIdentifier attrOID, String printableName)
+ throws CMSException
+ {
+ AttributeTable unsignedAttrTable = this.getUnsignedAttributes();
+ if (unsignedAttrTable != null
+ && unsignedAttrTable.getAll(attrOID).size() > 0)
+ {
+ throw new CMSException("The " + printableName
+ + " attribute MUST NOT be an unsigned attribute");
+ }
+
+ AttributeTable signedAttrTable = this.getSignedAttributes();
+ if (signedAttrTable == null)
+ {
+ return null;
+ }
+
+ ASN1EncodableVector v = signedAttrTable.getAll(attrOID);
+ switch (v.size())
+ {
+ case 0:
+ return null;
+ case 1:
+ {
+ Attribute t = (Attribute)v.get(0);
+ ASN1Set attrValues = t.getAttrValues();
+ if (attrValues.size() != 1)
+ {
+ throw new CMSException("A " + printableName
+ + " attribute MUST have a single attribute value");
+ }
+
+ return attrValues.getObjectAt(0).toASN1Primitive();
+ }
+ default:
+ throw new CMSException("The SignedAttributes in a signerInfo MUST NOT include multiple instances of the "
+ + printableName + " attribute");
+ }
+ }
+
+ private Time getSigningTime() throws CMSException
+ {
+ ASN1Primitive validSigningTime = getSingleValuedSignedAttribute(
+ CMSAttributes.signingTime, "signing-time");
+
+ if (validSigningTime == null)
+ {
+ return null;
+ }
+
+ try
+ {
+ return Time.getInstance(validSigningTime);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CMSException("signing-time attribute value not a valid 'Time' structure");
+ }
+ }
+
+ /**
+ * Return a signer information object with the passed in unsigned
+ * attributes replacing the ones that are current associated with
+ * the object passed in.
+ *
+ * @param signerInformation the signerInfo to be used as the basis.
+ * @param unsignedAttributes the unsigned attributes to add.
+ * @return a copy of the original SignerInformationObject with the changed attributes.
+ */
+ public static SignerInformation replaceUnsignedAttributes(
+ SignerInformation signerInformation,
+ AttributeTable unsignedAttributes)
+ {
+ SignerInfo sInfo = signerInformation.info;
+ ASN1Set unsignedAttr = null;
+
+ if (unsignedAttributes != null)
+ {
+ unsignedAttr = new DERSet(unsignedAttributes.toASN1EncodableVector());
+ }
+
+ return new SignerInformation(
+ new SignerInfo(sInfo.getSID(), sInfo.getDigestAlgorithm(),
+ sInfo.getAuthenticatedAttributes(), sInfo.getDigestEncryptionAlgorithm(), sInfo.getEncryptedDigest(), unsignedAttr),
+ signerInformation.contentType, signerInformation.content, null);
+ }
+
+ /**
+ * Return a signer information object with passed in SignerInformationStore representing counter
+ * signatures attached as an unsigned attribute.
+ *
+ * @param signerInformation the signerInfo to be used as the basis.
+ * @param counterSigners signer info objects carrying counter signature.
+ * @return a copy of the original SignerInformationObject with the changed attributes.
+ */
+ public static SignerInformation addCounterSigners(
+ SignerInformation signerInformation,
+ SignerInformationStore counterSigners)
+ {
+ // TODO Perform checks from RFC 3852 11.4
+
+ SignerInfo sInfo = signerInformation.info;
+ AttributeTable unsignedAttr = signerInformation.getUnsignedAttributes();
+ ASN1EncodableVector v;
+
+ if (unsignedAttr != null)
+ {
+ v = unsignedAttr.toASN1EncodableVector();
+ }
+ else
+ {
+ v = new ASN1EncodableVector();
+ }
+
+ ASN1EncodableVector sigs = new ASN1EncodableVector();
+
+ for (Iterator it = counterSigners.getSigners().iterator(); it.hasNext();)
+ {
+ sigs.add(((SignerInformation)it.next()).toASN1Structure());
+ }
+
+ v.add(new Attribute(CMSAttributes.counterSignature, new DERSet(sigs)));
+
+ return new SignerInformation(
+ new SignerInfo(sInfo.getSID(), sInfo.getDigestAlgorithm(),
+ sInfo.getAuthenticatedAttributes(), sInfo.getDigestEncryptionAlgorithm(), sInfo.getEncryptedDigest(), new DERSet(v)),
+ signerInformation.contentType, signerInformation.content, null);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInformationStore.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInformationStore.java
new file mode 100644
index 000000000..df3bb9685
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInformationStore.java
@@ -0,0 +1,109 @@
+package org.spongycastle.cms;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+public class SignerInformationStore
+{
+ private List all = new ArrayList();
+ private Map table = new HashMap();
+
+ public SignerInformationStore(
+ Collection signerInfos)
+ {
+ Iterator it = signerInfos.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ SignerId sid = signer.getSID();
+
+ List list = (ArrayList)table.get(sid);
+ if (list == null)
+ {
+ list = new ArrayList(1);
+ table.put(sid, list);
+ }
+
+ list.add(signer);
+ }
+
+ this.all = new ArrayList(signerInfos);
+ }
+
+ /**
+ * Return the first SignerInformation object that matches the
+ * passed in selector. Null if there are no matches.
+ *
+ * @param selector to identify a signer
+ * @return a single SignerInformation object. Null if none matches.
+ */
+ public SignerInformation get(
+ SignerId selector)
+ {
+ Collection list = getSigners(selector);
+
+ return list.size() == 0 ? null : (SignerInformation) list.iterator().next();
+ }
+
+ /**
+ * Return the number of signers in the collection.
+ *
+ * @return number of signers identified.
+ */
+ public int size()
+ {
+ return all.size();
+ }
+
+ /**
+ * Return all signers in the collection
+ *
+ * @return a collection of signers.
+ */
+ public Collection getSigners()
+ {
+ return new ArrayList(all);
+ }
+
+ /**
+ * Return possible empty collection with signers matching the passed in SignerId
+ *
+ * @param selector a signer id to select against.
+ * @return a collection of SignerInformation objects.
+ */
+ public Collection getSigners(
+ SignerId selector)
+ {
+ if (selector.getIssuer() != null && selector.getSubjectKeyIdentifier() != null)
+ {
+ List results = new ArrayList();
+
+ Collection match1 = getSigners(new SignerId(selector.getIssuer(), selector.getSerialNumber()));
+
+ if (match1 != null)
+ {
+ results.addAll(match1);
+ }
+
+ Collection match2 = getSigners(new SignerId(selector.getSubjectKeyIdentifier()));
+
+ if (match2 != null)
+ {
+ results.addAll(match2);
+ }
+
+ return results;
+ }
+ else
+ {
+ List list = (ArrayList)table.get(selector);
+
+ return list == null ? new ArrayList() : new ArrayList(list);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInformationVerifier.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInformationVerifier.java
new file mode 100644
index 000000000..ea9de675c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInformationVerifier.java
@@ -0,0 +1,50 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.operator.ContentVerifier;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.SignatureAlgorithmIdentifierFinder;
+
+public class SignerInformationVerifier
+{
+ private ContentVerifierProvider verifierProvider;
+ private DigestCalculatorProvider digestProvider;
+ private SignatureAlgorithmIdentifierFinder sigAlgorithmFinder;
+ private CMSSignatureAlgorithmNameGenerator sigNameGenerator;
+
+ public SignerInformationVerifier(CMSSignatureAlgorithmNameGenerator sigNameGenerator, SignatureAlgorithmIdentifierFinder sigAlgorithmFinder, ContentVerifierProvider verifierProvider, DigestCalculatorProvider digestProvider)
+ {
+ this.sigNameGenerator = sigNameGenerator;
+ this.sigAlgorithmFinder = sigAlgorithmFinder;
+ this.verifierProvider = verifierProvider;
+ this.digestProvider = digestProvider;
+ }
+
+ public boolean hasAssociatedCertificate()
+ {
+ return verifierProvider.hasAssociatedCertificate();
+ }
+
+ public X509CertificateHolder getAssociatedCertificate()
+ {
+ return verifierProvider.getAssociatedCertificate();
+ }
+
+ public ContentVerifier getContentVerifier(AlgorithmIdentifier signingAlgorithm, AlgorithmIdentifier digestAlgorithm)
+ throws OperatorCreationException
+ {
+ String signatureName = sigNameGenerator.getSignatureName(digestAlgorithm, signingAlgorithm);
+
+ return verifierProvider.get(sigAlgorithmFinder.find(signatureName));
+ }
+
+ public DigestCalculator getDigestCalculator(AlgorithmIdentifier algorithmIdentifier)
+ throws OperatorCreationException
+ {
+ return digestProvider.get(algorithmIdentifier);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInformationVerifierProvider.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInformationVerifierProvider.java
new file mode 100644
index 000000000..d6e7d6e5b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SignerInformationVerifierProvider.java
@@ -0,0 +1,16 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.operator.OperatorCreationException;
+
+public interface SignerInformationVerifierProvider
+{
+ /**
+ * Return a SignerInformationVerifierProvider suitable for the passed in SID.
+ *
+ * @param sid the SignerId we are trying to match for.
+ * @return a verifier if one is available, null otherwise.
+ * @throws OperatorCreationException if creation of the verifier fails when it should suceed.
+ */
+ public SignerInformationVerifier get(SignerId sid)
+ throws OperatorCreationException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SimpleAttributeTableGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SimpleAttributeTableGenerator.java
new file mode 100644
index 000000000..25c55b785
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/SimpleAttributeTableGenerator.java
@@ -0,0 +1,25 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.asn1.cms.AttributeTable;
+
+import java.util.Map;
+
+/**
+ * Basic generator that just returns a preconstructed attribute table
+ */
+public class SimpleAttributeTableGenerator
+ implements CMSAttributeTableGenerator
+{
+ private final AttributeTable attributes;
+
+ public SimpleAttributeTableGenerator(
+ AttributeTable attributes)
+ {
+ this.attributes = attributes;
+ }
+
+ public AttributeTable getAttributes(Map parameters)
+ {
+ return attributes;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcCMSContentEncryptorBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcCMSContentEncryptorBuilder.java
new file mode 100644
index 000000000..22f79fb77
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcCMSContentEncryptorBuilder.java
@@ -0,0 +1,124 @@
+package org.spongycastle.cms.bc;
+
+import java.io.OutputStream;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.crypto.BufferedBlockCipher;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.StreamCipher;
+import org.spongycastle.crypto.io.CipherOutputStream;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OutputEncryptor;
+import org.spongycastle.util.Integers;
+
+public class BcCMSContentEncryptorBuilder
+{
+ private static Map keySizes = new HashMap();
+
+ static
+ {
+ keySizes.put(CMSAlgorithm.AES128_CBC, Integers.valueOf(128));
+ keySizes.put(CMSAlgorithm.AES192_CBC, Integers.valueOf(192));
+ keySizes.put(CMSAlgorithm.AES256_CBC, Integers.valueOf(256));
+
+ keySizes.put(CMSAlgorithm.CAMELLIA128_CBC, Integers.valueOf(128));
+ keySizes.put(CMSAlgorithm.CAMELLIA192_CBC, Integers.valueOf(192));
+ keySizes.put(CMSAlgorithm.CAMELLIA256_CBC, Integers.valueOf(256));
+ }
+
+ private static int getKeySize(ASN1ObjectIdentifier oid)
+ {
+ Integer size = (Integer)keySizes.get(oid);
+
+ if (size != null)
+ {
+ return size.intValue();
+ }
+
+ return -1;
+ }
+
+ private final ASN1ObjectIdentifier encryptionOID;
+ private final int keySize;
+
+ private EnvelopedDataHelper helper = new EnvelopedDataHelper();
+ private SecureRandom random;
+
+ public BcCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID)
+ {
+ this(encryptionOID, getKeySize(encryptionOID));
+ }
+
+ public BcCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID, int keySize)
+ {
+ this.encryptionOID = encryptionOID;
+ this.keySize = keySize;
+ }
+
+ public BcCMSContentEncryptorBuilder setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public OutputEncryptor build()
+ throws CMSException
+ {
+ return new CMSOutputEncryptor(encryptionOID, keySize, random);
+ }
+
+ private class CMSOutputEncryptor
+ implements OutputEncryptor
+ {
+ private KeyParameter encKey;
+ private AlgorithmIdentifier algorithmIdentifier;
+ private Object cipher;
+
+ CMSOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, SecureRandom random)
+ throws CMSException
+ {
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ CipherKeyGenerator keyGen = helper.createKeyGenerator(encryptionOID, random);
+
+ encKey = new KeyParameter(keyGen.generateKey());
+
+ algorithmIdentifier = helper.generateAlgorithmIdentifier(encryptionOID, encKey, random);
+
+ cipher = helper.createContentCipher(true, encKey, algorithmIdentifier);
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmIdentifier;
+ }
+
+ public OutputStream getOutputStream(OutputStream dOut)
+ {
+ if (cipher instanceof BufferedBlockCipher)
+ {
+ return new CipherOutputStream(dOut, (BufferedBlockCipher)cipher);
+ }
+ else
+ {
+ return new CipherOutputStream(dOut, (StreamCipher)cipher);
+ }
+ }
+
+ public GenericKey getKey()
+ {
+ return new GenericKey(algorithmIdentifier, encKey.getKey());
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKEnvelopedRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKEnvelopedRecipient.java
new file mode 100644
index 000000000..afde8a02c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKEnvelopedRecipient.java
@@ -0,0 +1,49 @@
+package org.spongycastle.cms.bc;
+
+import java.io.InputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.RecipientOperator;
+import org.spongycastle.crypto.BufferedBlockCipher;
+import org.spongycastle.crypto.StreamCipher;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.operator.InputDecryptor;
+import org.spongycastle.operator.bc.BcSymmetricKeyUnwrapper;
+
+public class BcKEKEnvelopedRecipient
+ extends BcKEKRecipient
+{
+ public BcKEKEnvelopedRecipient(BcSymmetricKeyUnwrapper unwrapper)
+ {
+ super(unwrapper);
+ }
+
+ public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey)
+ throws CMSException
+ {
+ KeyParameter secretKey = (KeyParameter)extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, encryptedContentEncryptionKey);
+
+ final Object dataCipher = EnvelopedDataHelper.createContentCipher(false, secretKey, contentEncryptionAlgorithm);
+
+ return new RecipientOperator(new InputDecryptor()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return contentEncryptionAlgorithm;
+ }
+
+ public InputStream getInputStream(InputStream dataOut)
+ {
+ if (dataCipher instanceof BufferedBlockCipher)
+ {
+ return new org.spongycastle.crypto.io.CipherInputStream(dataOut, (BufferedBlockCipher)dataCipher);
+ }
+ else
+ {
+ return new org.spongycastle.crypto.io.CipherInputStream(dataOut, (StreamCipher)dataCipher);
+ }
+ }
+ });
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKRecipient.java
new file mode 100644
index 000000000..066deaa62
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKRecipient.java
@@ -0,0 +1,33 @@
+package org.spongycastle.cms.bc;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.KEKRecipient;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.operator.OperatorException;
+import org.spongycastle.operator.SymmetricKeyUnwrapper;
+import org.spongycastle.operator.bc.BcSymmetricKeyUnwrapper;
+
+public abstract class BcKEKRecipient
+ implements KEKRecipient
+{
+ private SymmetricKeyUnwrapper unwrapper;
+
+ public BcKEKRecipient(BcSymmetricKeyUnwrapper unwrapper)
+ {
+ this.unwrapper = unwrapper;
+ }
+
+ protected CipherParameters extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey)
+ throws CMSException
+ {
+ try
+ {
+ return CMSUtils.getBcKey(unwrapper.generateUnwrappedKey(contentEncryptionAlgorithm, encryptedContentEncryptionKey));
+ }
+ catch (OperatorException e)
+ {
+ throw new CMSException("exception unwrapping key: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKRecipientInfoGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKRecipientInfoGenerator.java
new file mode 100644
index 000000000..2a2ad9e79
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKEKRecipientInfoGenerator.java
@@ -0,0 +1,19 @@
+package org.spongycastle.cms.bc;
+
+import org.spongycastle.asn1.cms.KEKIdentifier;
+import org.spongycastle.cms.KEKRecipientInfoGenerator;
+import org.spongycastle.operator.bc.BcSymmetricKeyWrapper;
+
+public class BcKEKRecipientInfoGenerator
+ extends KEKRecipientInfoGenerator
+{
+ public BcKEKRecipientInfoGenerator(KEKIdentifier kekIdentifier, BcSymmetricKeyWrapper kekWrapper)
+ {
+ super(kekIdentifier, kekWrapper);
+ }
+
+ public BcKEKRecipientInfoGenerator(byte[] keyIdentifier, BcSymmetricKeyWrapper kekWrapper)
+ {
+ this(new KEKIdentifier(keyIdentifier, null, null), kekWrapper);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKeyTransRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKeyTransRecipient.java
new file mode 100644
index 000000000..ab50269d7
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKeyTransRecipient.java
@@ -0,0 +1,36 @@
+package org.spongycastle.cms.bc;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.KeyTransRecipient;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.operator.AsymmetricKeyUnwrapper;
+import org.spongycastle.operator.OperatorException;
+import org.spongycastle.operator.bc.BcRSAAsymmetricKeyUnwrapper;
+
+public abstract class BcKeyTransRecipient
+ implements KeyTransRecipient
+{
+ private AsymmetricKeyParameter recipientKey;
+
+ public BcKeyTransRecipient(AsymmetricKeyParameter recipientKey)
+ {
+ this.recipientKey = recipientKey;
+ }
+
+ protected CipherParameters extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedEncryptionKey)
+ throws CMSException
+ {
+ AsymmetricKeyUnwrapper unwrapper = new BcRSAAsymmetricKeyUnwrapper(keyEncryptionAlgorithm, recipientKey);
+
+ try
+ {
+ return CMSUtils.getBcKey(unwrapper.generateUnwrappedKey(encryptedKeyAlgorithm, encryptedEncryptionKey));
+ }
+ catch (OperatorException e)
+ {
+ throw new CMSException("exception unwrapping key: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKeyTransRecipientInfoGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKeyTransRecipientInfoGenerator.java
new file mode 100644
index 000000000..c987d5a26
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcKeyTransRecipientInfoGenerator.java
@@ -0,0 +1,20 @@
+package org.spongycastle.cms.bc;
+
+import org.spongycastle.asn1.cms.IssuerAndSerialNumber;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cms.KeyTransRecipientInfoGenerator;
+import org.spongycastle.operator.bc.BcAsymmetricKeyWrapper;
+
+public abstract class BcKeyTransRecipientInfoGenerator
+ extends KeyTransRecipientInfoGenerator
+{
+ public BcKeyTransRecipientInfoGenerator(X509CertificateHolder recipientCert, BcAsymmetricKeyWrapper wrapper)
+ {
+ super(new IssuerAndSerialNumber(recipientCert.toASN1Structure()), wrapper);
+ }
+
+ public BcKeyTransRecipientInfoGenerator(byte[] subjectKeyIdentifier, BcAsymmetricKeyWrapper wrapper)
+ {
+ super(subjectKeyIdentifier, wrapper);
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordEnvelopedRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordEnvelopedRecipient.java
new file mode 100644
index 000000000..0b9a529ff
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordEnvelopedRecipient.java
@@ -0,0 +1,49 @@
+package org.spongycastle.cms.bc;
+
+import java.io.InputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.RecipientOperator;
+import org.spongycastle.crypto.BufferedBlockCipher;
+import org.spongycastle.crypto.StreamCipher;
+import org.spongycastle.crypto.io.CipherInputStream;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.operator.InputDecryptor;
+
+public class BcPasswordEnvelopedRecipient
+ extends BcPasswordRecipient
+{
+ public BcPasswordEnvelopedRecipient(char[] password)
+ {
+ super(password);
+ }
+
+ public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] derivedKey, byte[] encryptedContentEncryptionKey)
+ throws CMSException
+ {
+ KeyParameter secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, derivedKey, encryptedContentEncryptionKey);
+
+ final Object dataCipher = EnvelopedDataHelper.createContentCipher(false, secretKey, contentEncryptionAlgorithm);
+
+ return new RecipientOperator(new InputDecryptor()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return contentEncryptionAlgorithm;
+ }
+
+ public InputStream getInputStream(InputStream dataOut)
+ {
+ if (dataCipher instanceof BufferedBlockCipher)
+ {
+ return new CipherInputStream(dataOut, (BufferedBlockCipher)dataCipher);
+ }
+ else
+ {
+ return new CipherInputStream(dataOut, (StreamCipher)dataCipher);
+ }
+ }
+ });
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordRecipient.java
new file mode 100644
index 000000000..5317bb5ff
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordRecipient.java
@@ -0,0 +1,61 @@
+package org.spongycastle.cms.bc;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.PasswordRecipient;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.Wrapper;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithIV;
+
+/**
+ * the RecipientInfo class for a recipient who has been sent a message
+ * encrypted using a password.
+ */
+public abstract class BcPasswordRecipient
+ implements PasswordRecipient
+{
+ private int schemeID = PasswordRecipient.PKCS5_SCHEME2_UTF8;
+ private char[] password;
+
+ BcPasswordRecipient(
+ char[] password)
+ {
+ this.password = password;
+ }
+
+ public BcPasswordRecipient setPasswordConversionScheme(int schemeID)
+ {
+ this.schemeID = schemeID;
+
+ return this;
+ }
+
+ protected KeyParameter extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] derivedKey, byte[] encryptedContentEncryptionKey)
+ throws CMSException
+ {
+ Wrapper keyEncryptionCipher = EnvelopedDataHelper.createRFC3211Wrapper(keyEncryptionAlgorithm.getAlgorithm());
+
+ keyEncryptionCipher.init(false, new ParametersWithIV(new KeyParameter(derivedKey), ASN1OctetString.getInstance(keyEncryptionAlgorithm.getParameters()).getOctets()));
+
+ try
+ {
+ return new KeyParameter(keyEncryptionCipher.unwrap(encryptedContentEncryptionKey, 0, encryptedContentEncryptionKey.length));
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new CMSException("unable to unwrap key: " + e.getMessage(), e);
+ }
+ }
+
+ public int getPasswordConversionScheme()
+ {
+ return schemeID;
+ }
+
+ public char[] getPassword()
+ {
+ return password;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordRecipientInfoGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordRecipientInfoGenerator.java
new file mode 100644
index 000000000..c1559be79
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcPasswordRecipientInfoGenerator.java
@@ -0,0 +1,31 @@
+package org.spongycastle.cms.bc;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.PasswordRecipientInfoGenerator;
+import org.spongycastle.crypto.Wrapper;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithIV;
+import org.spongycastle.operator.GenericKey;
+
+public class BcPasswordRecipientInfoGenerator
+ extends PasswordRecipientInfoGenerator
+{
+ public BcPasswordRecipientInfoGenerator(ASN1ObjectIdentifier kekAlgorithm, char[] password)
+ {
+ super(kekAlgorithm, password);
+ }
+
+ public byte[] generateEncryptedBytes(AlgorithmIdentifier keyEncryptionAlgorithm, byte[] derivedKey, GenericKey contentEncryptionKey)
+ throws CMSException
+ {
+ byte[] contentEncryptionKeySpec = ((KeyParameter)CMSUtils.getBcKey(contentEncryptionKey)).getKey();
+ Wrapper keyEncryptionCipher = EnvelopedDataHelper.createRFC3211Wrapper(keyEncryptionAlgorithm.getAlgorithm());
+
+ keyEncryptionCipher.init(true, new ParametersWithIV(new KeyParameter(derivedKey), ASN1OctetString.getInstance(keyEncryptionAlgorithm.getParameters()).getOctets()));
+
+ return keyEncryptionCipher.wrap(contentEncryptionKeySpec, 0, contentEncryptionKeySpec.length);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcRSAKeyTransEnvelopedRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcRSAKeyTransEnvelopedRecipient.java
new file mode 100644
index 000000000..601de8413
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcRSAKeyTransEnvelopedRecipient.java
@@ -0,0 +1,50 @@
+package org.spongycastle.cms.bc;
+
+import java.io.InputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.RecipientOperator;
+import org.spongycastle.crypto.BufferedBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.StreamCipher;
+import org.spongycastle.crypto.io.CipherInputStream;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.operator.InputDecryptor;
+
+public class BcRSAKeyTransEnvelopedRecipient
+ extends BcKeyTransRecipient
+{
+ public BcRSAKeyTransEnvelopedRecipient(AsymmetricKeyParameter key)
+ {
+ super(key);
+ }
+
+ public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey)
+ throws CMSException
+ {
+ CipherParameters secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, encryptedContentEncryptionKey);
+
+ final Object dataCipher = EnvelopedDataHelper.createContentCipher(false, secretKey, contentEncryptionAlgorithm);
+
+ return new RecipientOperator(new InputDecryptor()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return contentEncryptionAlgorithm;
+ }
+
+ public InputStream getInputStream(InputStream dataIn)
+ {
+ if (dataCipher instanceof BufferedBlockCipher)
+ {
+ return new CipherInputStream(dataIn, (BufferedBlockCipher)dataCipher);
+ }
+ else
+ {
+ return new CipherInputStream(dataIn, (StreamCipher)dataCipher);
+ }
+ }
+ });
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcRSAKeyTransRecipientInfoGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcRSAKeyTransRecipientInfoGenerator.java
new file mode 100644
index 000000000..09f7f8d0f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcRSAKeyTransRecipientInfoGenerator.java
@@ -0,0 +1,23 @@
+package org.spongycastle.cms.bc;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.operator.bc.BcRSAAsymmetricKeyWrapper;
+
+public class BcRSAKeyTransRecipientInfoGenerator
+ extends BcKeyTransRecipientInfoGenerator
+{
+ public BcRSAKeyTransRecipientInfoGenerator(byte[] subjectKeyIdentifier, AlgorithmIdentifier encAlgId, AsymmetricKeyParameter publicKey)
+ {
+ super(subjectKeyIdentifier, new BcRSAAsymmetricKeyWrapper(encAlgId, publicKey));
+ }
+
+ public BcRSAKeyTransRecipientInfoGenerator(X509CertificateHolder recipientCert)
+ throws IOException
+ {
+ super(recipientCert, new BcRSAAsymmetricKeyWrapper(recipientCert.getSubjectPublicKeyInfo().getAlgorithmId(), recipientCert.getSubjectPublicKeyInfo()));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcRSASignerInfoVerifierBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcRSASignerInfoVerifierBuilder.java
new file mode 100644
index 000000000..26028e1af
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/BcRSASignerInfoVerifierBuilder.java
@@ -0,0 +1,39 @@
+package org.spongycastle.cms.bc;
+
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cms.CMSSignatureAlgorithmNameGenerator;
+import org.spongycastle.cms.SignerInformationVerifier;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.operator.DigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.SignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.bc.BcRSAContentVerifierProviderBuilder;
+
+public class BcRSASignerInfoVerifierBuilder
+{
+ private BcRSAContentVerifierProviderBuilder contentVerifierProviderBuilder;
+ private DigestCalculatorProvider digestCalculatorProvider;
+ private CMSSignatureAlgorithmNameGenerator sigAlgNameGen;
+ private SignatureAlgorithmIdentifierFinder sigAlgIdFinder;
+
+ public BcRSASignerInfoVerifierBuilder(CMSSignatureAlgorithmNameGenerator sigAlgNameGen, SignatureAlgorithmIdentifierFinder sigAlgIdFinder, DigestAlgorithmIdentifierFinder digestAlgorithmFinder, DigestCalculatorProvider digestCalculatorProvider)
+ {
+ this.sigAlgNameGen = sigAlgNameGen;
+ this.sigAlgIdFinder = sigAlgIdFinder;
+ this.contentVerifierProviderBuilder = new BcRSAContentVerifierProviderBuilder(digestAlgorithmFinder);
+ this.digestCalculatorProvider = digestCalculatorProvider;
+ }
+
+ public SignerInformationVerifier build(X509CertificateHolder certHolder)
+ throws OperatorCreationException
+ {
+ return new SignerInformationVerifier(sigAlgNameGen, sigAlgIdFinder, contentVerifierProviderBuilder.build(certHolder), digestCalculatorProvider);
+ }
+
+ public SignerInformationVerifier build(AsymmetricKeyParameter pubKey)
+ throws OperatorCreationException
+ {
+ return new SignerInformationVerifier(sigAlgNameGen, sigAlgIdFinder, contentVerifierProviderBuilder.build(pubKey), digestCalculatorProvider);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/CMSUtils.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/CMSUtils.java
new file mode 100644
index 000000000..90035ec1c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/CMSUtils.java
@@ -0,0 +1,23 @@
+package org.spongycastle.cms.bc;
+
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.operator.GenericKey;
+
+class CMSUtils
+{
+ static CipherParameters getBcKey(GenericKey key)
+ {
+ if (key.getRepresentation() instanceof CipherParameters)
+ {
+ return (CipherParameters)key.getRepresentation();
+ }
+
+ if (key.getRepresentation() instanceof byte[])
+ {
+ return new KeyParameter((byte[])key.getRepresentation());
+ }
+
+ throw new IllegalArgumentException("unknown generic key type");
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/EnvelopedDataHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/EnvelopedDataHelper.java
new file mode 100644
index 000000000..db65fd098
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/bc/EnvelopedDataHelper.java
@@ -0,0 +1,378 @@
+package org.spongycastle.cms.bc;
+
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1Null;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.kisa.KISAObjectIdentifiers;
+import org.spongycastle.asn1.misc.CAST5CBCParameters;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.ntt.NTTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RC2CBCParameter;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.BufferedBlockCipher;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.KeyGenerationParameters;
+import org.spongycastle.crypto.StreamCipher;
+import org.spongycastle.crypto.Wrapper;
+import org.spongycastle.crypto.engines.AESEngine;
+import org.spongycastle.crypto.engines.DESEngine;
+import org.spongycastle.crypto.engines.DESedeEngine;
+import org.spongycastle.crypto.engines.RC2Engine;
+import org.spongycastle.crypto.engines.RC4Engine;
+import org.spongycastle.crypto.engines.RFC3211WrapEngine;
+import org.spongycastle.crypto.generators.DESKeyGenerator;
+import org.spongycastle.crypto.generators.DESedeKeyGenerator;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.crypto.paddings.PKCS7Padding;
+import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithIV;
+import org.spongycastle.crypto.params.RC2Parameters;
+
+class EnvelopedDataHelper
+{
+ protected static final Map BASE_CIPHER_NAMES = new HashMap();
+ protected static final Map CIPHER_ALG_NAMES = new HashMap();
+ protected static final Map MAC_ALG_NAMES = new HashMap();
+
+ static
+ {
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.AES128_CBC, "AES");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.AES192_CBC, "AES");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.AES256_CBC, "AES");
+
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, "AES/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AES/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AES/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(new ASN1ObjectIdentifier(PKCSObjectIdentifiers.rsaEncryption.getId()), "RSA/ECB/PKCS1Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.CAST5_CBC, "CAST5/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA128_CBC, "Camellia/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA192_CBC, "Camellia/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA256_CBC, "Camellia/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.SEED_CBC, "SEED/CBC/PKCS5Padding");
+
+ MAC_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDEMac");
+ MAC_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, "AESMac");
+ MAC_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AESMac");
+ MAC_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AESMac");
+ MAC_ALG_NAMES.put(CMSAlgorithm.RC2_CBC, "RC2Mac");
+ }
+
+ private static final short[] rc2Table = {
+ 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[] rc2Ekb = {
+ 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
+ };
+
+ EnvelopedDataHelper()
+ {
+ }
+
+ String getBaseCipherName(ASN1ObjectIdentifier algorithm)
+ {
+ String name = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (name == null)
+ {
+ return algorithm.getId();
+ }
+
+ return name;
+ }
+
+ static BufferedBlockCipher createCipher(ASN1ObjectIdentifier algorithm)
+ throws CMSException
+ {
+ BlockCipher cipher;
+
+ if (NISTObjectIdentifiers.id_aes128_CBC.equals(algorithm)
+ || NISTObjectIdentifiers.id_aes192_CBC.equals(algorithm)
+ || NISTObjectIdentifiers.id_aes256_CBC.equals(algorithm))
+ {
+ cipher = new CBCBlockCipher(new AESEngine());
+ }
+ else if (PKCSObjectIdentifiers.des_EDE3_CBC.equals(algorithm))
+ {
+ cipher = new CBCBlockCipher(new DESedeEngine());
+ }
+ else if (OIWObjectIdentifiers.desCBC.equals(algorithm))
+ {
+ cipher = new CBCBlockCipher(new DESEngine());
+ }
+ else if (PKCSObjectIdentifiers.RC2_CBC.equals(algorithm))
+ {
+ cipher = new CBCBlockCipher(new RC2Engine());
+ }
+ else
+ {
+ throw new CMSException("cannot recognise cipher: " + algorithm);
+ }
+
+ return new PaddedBufferedBlockCipher(cipher, new PKCS7Padding());
+ }
+
+ static Wrapper createRFC3211Wrapper(ASN1ObjectIdentifier algorithm)
+ throws CMSException
+ {
+ if (NISTObjectIdentifiers.id_aes128_CBC.equals(algorithm)
+ || NISTObjectIdentifiers.id_aes192_CBC.equals(algorithm)
+ || NISTObjectIdentifiers.id_aes256_CBC.equals(algorithm))
+ {
+ return new RFC3211WrapEngine(new AESEngine());
+ }
+ else if (PKCSObjectIdentifiers.des_EDE3_CBC.equals(algorithm))
+ {
+ return new RFC3211WrapEngine(new DESedeEngine());
+ }
+ else if (OIWObjectIdentifiers.desCBC.equals(algorithm))
+ {
+ return new RFC3211WrapEngine(new DESEngine());
+ }
+ else if (PKCSObjectIdentifiers.RC2_CBC.equals(algorithm))
+ {
+ return new RFC3211WrapEngine(new RC2Engine());
+ }
+ else
+ {
+ throw new CMSException("cannot recognise wrapper: " + algorithm);
+ }
+ }
+
+ static Object createContentCipher(boolean forEncryption, CipherParameters encKey, AlgorithmIdentifier encryptionAlgID)
+ throws CMSException
+ {
+ ASN1ObjectIdentifier encAlg = encryptionAlgID.getAlgorithm();
+
+ if (encAlg.equals(PKCSObjectIdentifiers.rc4))
+ {
+ StreamCipher cipher = new RC4Engine();
+
+ cipher.init(forEncryption, encKey);
+
+ return cipher;
+ }
+ else
+ {
+ BufferedBlockCipher cipher = createCipher(encryptionAlgID.getAlgorithm());
+ ASN1Primitive sParams = encryptionAlgID.getParameters().toASN1Primitive();
+
+ if (sParams != null && !(sParams instanceof ASN1Null))
+ {
+ if (encAlg.equals(CMSAlgorithm.DES_EDE3_CBC)
+ || encAlg.equals(CMSAlgorithm.IDEA_CBC)
+ || encAlg.equals(CMSAlgorithm.AES128_CBC)
+ || encAlg.equals(CMSAlgorithm.AES192_CBC)
+ || encAlg.equals(CMSAlgorithm.AES256_CBC)
+ || encAlg.equals(CMSAlgorithm.CAMELLIA128_CBC)
+ || encAlg.equals(CMSAlgorithm.CAMELLIA192_CBC)
+ || encAlg.equals(CMSAlgorithm.CAMELLIA256_CBC)
+ || encAlg.equals(CMSAlgorithm.SEED_CBC)
+ || encAlg.equals(OIWObjectIdentifiers.desCBC))
+ {
+ cipher.init(forEncryption, new ParametersWithIV(encKey,
+ ASN1OctetString.getInstance(sParams).getOctets()));
+ }
+ else if (encAlg.equals(CMSAlgorithm.CAST5_CBC))
+ {
+ CAST5CBCParameters cbcParams = CAST5CBCParameters.getInstance(sParams);
+
+ cipher.init(forEncryption, new ParametersWithIV(encKey, cbcParams.getIV()));
+ }
+ else if (encAlg.equals(CMSAlgorithm.RC2_CBC))
+ {
+ RC2CBCParameter cbcParams = RC2CBCParameter.getInstance(sParams);
+
+ cipher.init(forEncryption, new ParametersWithIV(new RC2Parameters(((KeyParameter)encKey).getKey(), rc2Ekb[cbcParams.getRC2ParameterVersion().intValue()]), cbcParams.getIV()));
+ }
+ else
+ {
+ throw new CMSException("cannot match parameters");
+ }
+ }
+ else
+ {
+ if (encAlg.equals(CMSAlgorithm.DES_EDE3_CBC)
+ || encAlg.equals(CMSAlgorithm.IDEA_CBC)
+ || encAlg.equals(CMSAlgorithm.CAST5_CBC))
+ {
+ cipher.init(forEncryption, new ParametersWithIV(encKey, new byte[8]));
+ }
+ else
+ {
+ cipher.init(forEncryption, encKey);
+ }
+ }
+
+ return cipher;
+ }
+ }
+
+ AlgorithmIdentifier generateAlgorithmIdentifier(ASN1ObjectIdentifier encryptionOID, CipherParameters encKey, SecureRandom random)
+ throws CMSException
+ {
+ if (encryptionOID.equals(CMSAlgorithm.AES128_CBC)
+ || encryptionOID.equals(CMSAlgorithm.AES192_CBC)
+ || encryptionOID.equals(CMSAlgorithm.AES256_CBC)
+ || encryptionOID.equals(CMSAlgorithm.CAMELLIA128_CBC)
+ || encryptionOID.equals(CMSAlgorithm.CAMELLIA192_CBC)
+ || encryptionOID.equals(CMSAlgorithm.CAMELLIA256_CBC)
+ || encryptionOID.equals(CMSAlgorithm.SEED_CBC))
+ {
+ byte[] iv = new byte[16];
+
+ random.nextBytes(iv);
+
+ return new AlgorithmIdentifier(encryptionOID, new DEROctetString(iv));
+ }
+ else if (encryptionOID.equals(CMSAlgorithm.DES_EDE3_CBC)
+ || encryptionOID.equals(CMSAlgorithm.IDEA_CBC)
+ || encryptionOID.equals(OIWObjectIdentifiers.desCBC))
+ {
+ byte[] iv = new byte[8];
+
+ random.nextBytes(iv);
+
+ return new AlgorithmIdentifier(encryptionOID, new DEROctetString(iv));
+ }
+ else if (encryptionOID.equals(CMSAlgorithm.CAST5_CBC))
+ {
+ byte[] iv = new byte[8];
+
+ random.nextBytes(iv);
+
+ CAST5CBCParameters cbcParams = new CAST5CBCParameters(iv, ((KeyParameter)encKey).getKey().length * 8);
+
+ return new AlgorithmIdentifier(encryptionOID, cbcParams);
+ }
+ else if (encryptionOID.equals(PKCSObjectIdentifiers.rc4))
+ {
+ return new AlgorithmIdentifier(encryptionOID, DERNull.INSTANCE);
+ }
+ else
+ {
+ throw new CMSException("unable to match algorithm");
+ }
+ }
+
+ CipherKeyGenerator createKeyGenerator(ASN1ObjectIdentifier algorithm, SecureRandom random)
+ throws CMSException
+ {
+ if (NISTObjectIdentifiers.id_aes128_CBC.equals(algorithm))
+ {
+ return createCipherKeyGenerator(random, 128);
+ }
+ else if (NISTObjectIdentifiers.id_aes192_CBC.equals(algorithm))
+ {
+ return createCipherKeyGenerator(random, 192);
+ }
+ else if (NISTObjectIdentifiers.id_aes256_CBC.equals(algorithm))
+ {
+ return createCipherKeyGenerator(random, 256);
+ }
+ else if (PKCSObjectIdentifiers.des_EDE3_CBC.equals(algorithm))
+ {
+ DESedeKeyGenerator keyGen = new DESedeKeyGenerator();
+
+ keyGen.init(new KeyGenerationParameters(random, 192));
+
+ return keyGen;
+ }
+ else if (NTTObjectIdentifiers.id_camellia128_cbc.equals(algorithm))
+ {
+ return createCipherKeyGenerator(random, 128);
+ }
+ else if (NTTObjectIdentifiers.id_camellia192_cbc.equals(algorithm))
+ {
+ return createCipherKeyGenerator(random, 192);
+ }
+ else if (NTTObjectIdentifiers.id_camellia256_cbc.equals(algorithm))
+ {
+ return createCipherKeyGenerator(random, 256);
+ }
+ else if (KISAObjectIdentifiers.id_seedCBC.equals(algorithm))
+ {
+ return createCipherKeyGenerator(random, 128);
+ }
+ else if (CMSAlgorithm.CAST5_CBC.equals(algorithm))
+ {
+ return createCipherKeyGenerator(random, 128);
+ }
+ else if (OIWObjectIdentifiers.desCBC.equals(algorithm))
+ {
+ DESKeyGenerator keyGen = new DESKeyGenerator();
+
+ keyGen.init(new KeyGenerationParameters(random, 64));
+
+ return keyGen;
+ }
+ else if (PKCSObjectIdentifiers.rc4.equals(algorithm))
+ {
+ return createCipherKeyGenerator(random, 128);
+ }
+// else if (PKCSObjectIdentifiers.RC2_CBC.equals(algorithm))
+// {
+// cipher = new CBCBlockCipher(new RC2Engine());
+// }
+ else
+ {
+ throw new CMSException("cannot recognise cipher: " + algorithm);
+ }
+
+ }
+
+ private CipherKeyGenerator createCipherKeyGenerator(SecureRandom random, int keySize)
+ {
+ CipherKeyGenerator keyGen = new CipherKeyGenerator();
+
+ keyGen.init(new KeyGenerationParameters(random, keySize));
+
+ return keyGen;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/CMSUtils.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/CMSUtils.java
new file mode 100644
index 000000000..a0a0812cb
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/CMSUtils.java
@@ -0,0 +1,99 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.Provider;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.cms.IssuerAndSerialNumber;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.TBSCertificateStructure;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.jcajce.JcaJceUtils;
+
+class CMSUtils
+{
+ static TBSCertificateStructure getTBSCertificateStructure(
+ X509Certificate cert)
+ throws CertificateEncodingException
+ {
+ return TBSCertificateStructure.getInstance(cert.getTBSCertificate());
+ }
+
+ static IssuerAndSerialNumber getIssuerAndSerialNumber(X509Certificate cert)
+ throws CertificateEncodingException
+ {
+ Certificate certStruct = Certificate.getInstance(cert.getEncoded());
+
+ return new IssuerAndSerialNumber(certStruct.getIssuer(), cert.getSerialNumber());
+ }
+
+
+ static byte[] getSubjectKeyId(X509Certificate cert)
+ {
+ byte[] ext = cert.getExtensionValue(Extension.subjectKeyIdentifier.getId());
+
+ if (ext != null)
+ {
+ return ASN1OctetString.getInstance(ASN1OctetString.getInstance(ext).getOctets()).getOctets();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ static EnvelopedDataHelper createContentHelper(Provider provider)
+ {
+ if (provider != null)
+ {
+ return new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
+ }
+ else
+ {
+ return new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+ }
+ }
+
+ static EnvelopedDataHelper createContentHelper(String providerName)
+ {
+ if (providerName != null)
+ {
+ return new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
+ }
+ else
+ {
+ return new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+ }
+ }
+
+ static ASN1Encodable extractParameters(AlgorithmParameters params)
+ throws CMSException
+ {
+ try
+ {
+ return JcaJceUtils.extractParameters(params);
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("cannot extract parameters: " + e.getMessage(), e);
+ }
+ }
+
+ static void loadParameters(AlgorithmParameters params, ASN1Encodable sParams)
+ throws CMSException
+ {
+ try
+ {
+ JcaJceUtils.loadParameters(params, sParams);
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("error encoding algorithm parameters.", e);
+ }
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/DefaultJcaJceExtHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/DefaultJcaJceExtHelper.java
new file mode 100644
index 000000000..c0dfc3e80
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/DefaultJcaJceExtHelper.java
@@ -0,0 +1,26 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.PrivateKey;
+
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.operator.SymmetricKeyUnwrapper;
+import org.spongycastle.operator.jcajce.JceAsymmetricKeyUnwrapper;
+import org.spongycastle.operator.jcajce.JceSymmetricKeyUnwrapper;
+
+class DefaultJcaJceExtHelper
+ extends DefaultJcaJceHelper
+ implements JcaJceExtHelper
+{
+ public JceAsymmetricKeyUnwrapper createAsymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, PrivateKey keyEncryptionKey)
+ {
+ return new JceAsymmetricKeyUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey);
+ }
+
+ public SymmetricKeyUnwrapper createSymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, SecretKey keyEncryptionKey)
+ {
+ return new JceSymmetricKeyUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/EnvelopedDataHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/EnvelopedDataHelper.java
new file mode 100644
index 000000000..93de500e7
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/EnvelopedDataHelper.java
@@ -0,0 +1,668 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+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.InvalidParameterSpecException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Null;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+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.RC2CBCParameter;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSEnvelopedDataGenerator;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.operator.DefaultSecretKeySizeProvider;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.SecretKeySizeProvider;
+import org.spongycastle.operator.SymmetricKeyUnwrapper;
+import org.spongycastle.operator.jcajce.JceAsymmetricKeyUnwrapper;
+
+public class EnvelopedDataHelper
+{
+ protected static final SecretKeySizeProvider KEY_SIZE_PROVIDER = DefaultSecretKeySizeProvider.INSTANCE;
+
+ protected static final Map BASE_CIPHER_NAMES = new HashMap();
+ protected static final Map CIPHER_ALG_NAMES = new HashMap();
+ protected static final Map MAC_ALG_NAMES = new HashMap();
+
+ static
+ {
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.DES_CBC, "DES");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.AES128_CBC, "AES");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.AES192_CBC, "AES");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.AES256_CBC, "AES");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.RC2_CBC, "RC2");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.CAST5_CBC, "CAST5");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.CAMELLIA128_CBC, "Camellia");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.CAMELLIA192_CBC, "Camellia");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.CAMELLIA256_CBC, "Camellia");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.SEED_CBC, "SEED");
+ BASE_CIPHER_NAMES.put(PKCSObjectIdentifiers.rc4, "RC4");
+
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.DES_CBC, "DES/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.RC2_CBC, "RC2/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, "AES/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AES/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AES/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(PKCSObjectIdentifiers.rsaEncryption, "RSA/ECB/PKCS1Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.CAST5_CBC, "CAST5/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA128_CBC, "Camellia/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA192_CBC, "Camellia/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA256_CBC, "Camellia/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.SEED_CBC, "SEED/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(PKCSObjectIdentifiers.rc4, "RC4");
+
+ MAC_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDEMac");
+ MAC_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, "AESMac");
+ MAC_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AESMac");
+ MAC_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AESMac");
+ MAC_ALG_NAMES.put(CMSAlgorithm.RC2_CBC, "RC2Mac");
+ }
+
+ private static final short[] rc2Table = {
+ 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[] rc2Ekb = {
+ 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 JcaJceExtHelper helper;
+
+ EnvelopedDataHelper(JcaJceExtHelper helper)
+ {
+ this.helper = helper;
+ }
+
+ String getBaseCipherName(ASN1ObjectIdentifier algorithm)
+ {
+ String name = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (name == null)
+ {
+ return algorithm.getId();
+ }
+
+ return name;
+ }
+
+ Key getJceKey(GenericKey key)
+ {
+ if (key.getRepresentation() instanceof Key)
+ {
+ return (Key)key.getRepresentation();
+ }
+
+ if (key.getRepresentation() instanceof byte[])
+ {
+ return new SecretKeySpec((byte[])key.getRepresentation(), "ENC");
+ }
+
+ throw new IllegalArgumentException("unknown generic key type");
+ }
+
+ public Key getJceKey(ASN1ObjectIdentifier algorithm, GenericKey key)
+ {
+ if (key.getRepresentation() instanceof Key)
+ {
+ return (Key)key.getRepresentation();
+ }
+
+ if (key.getRepresentation() instanceof byte[])
+ {
+ return new SecretKeySpec((byte[])key.getRepresentation(), getBaseCipherName(algorithm));
+ }
+
+ throw new IllegalArgumentException("unknown generic key type");
+ }
+
+ public void keySizeCheck(AlgorithmIdentifier keyAlgorithm, Key key)
+ throws CMSException
+ {
+ int expectedKeySize = EnvelopedDataHelper.KEY_SIZE_PROVIDER.getKeySize(keyAlgorithm);
+ if (expectedKeySize > 0)
+ {
+ byte[] keyEnc = null;
+
+ try
+ {
+ keyEnc = key.getEncoded();
+ }
+ catch (Exception e)
+ {
+ // ignore - we're using a HSM...
+ }
+
+ if (keyEnc != null)
+ {
+ if (keyEnc.length * 8 != expectedKeySize)
+ {
+ throw new CMSException("Expected key size for algorithm OID not found in recipient.");
+ }
+ }
+ }
+ }
+
+ Cipher createCipher(ASN1ObjectIdentifier algorithm)
+ throws CMSException
+ {
+ try
+ {
+ String cipherName = (String)CIPHER_ALG_NAMES.get(algorithm);
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createCipher(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createCipher(algorithm.getId());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("cannot create cipher: " + e.getMessage(), e);
+ }
+ }
+
+ Mac createMac(ASN1ObjectIdentifier algorithm)
+ throws CMSException
+ {
+ try
+ {
+ String macName = (String)MAC_ALG_NAMES.get(algorithm);
+
+ if (macName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createMac(macName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createMac(algorithm.getId());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("cannot create mac: " + e.getMessage(), e);
+ }
+ }
+
+ Cipher createRFC3211Wrapper(ASN1ObjectIdentifier algorithm)
+ throws CMSException
+ {
+ String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (cipherName == null)
+ {
+ throw new CMSException("no name for " + algorithm);
+ }
+
+ cipherName += "RFC3211Wrap";
+
+ try
+ {
+ return helper.createCipher(cipherName);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("cannot create cipher: " + e.getMessage(), e);
+ }
+ }
+
+ KeyAgreement createKeyAgreement(ASN1ObjectIdentifier algorithm)
+ throws CMSException
+ {
+ try
+ {
+ String agreementName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (agreementName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createKeyAgreement(agreementName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createKeyAgreement(algorithm.getId());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("cannot create key pair generator: " + e.getMessage(), e);
+ }
+ }
+
+ AlgorithmParameterGenerator createAlgorithmParameterGenerator(ASN1ObjectIdentifier algorithm)
+ throws GeneralSecurityException
+ {
+ String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (algorithmName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createAlgorithmParameterGenerator(algorithmName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createAlgorithmParameterGenerator(algorithm.getId());
+ }
+
+ public Cipher createContentCipher(final Key sKey, final AlgorithmIdentifier encryptionAlgID)
+ throws CMSException
+ {
+ return (Cipher)execute(new JCECallback()
+ {
+ public Object doInJCE()
+ throws CMSException, InvalidAlgorithmParameterException,
+ InvalidKeyException, InvalidParameterSpecException, NoSuchAlgorithmException,
+ NoSuchPaddingException, NoSuchProviderException
+ {
+ Cipher cipher = createCipher(encryptionAlgID.getAlgorithm());
+ ASN1Encodable sParams = encryptionAlgID.getParameters();
+ String encAlg = encryptionAlgID.getAlgorithm().getId();
+
+ if (sParams != null && !(sParams instanceof ASN1Null))
+ {
+ try
+ {
+ AlgorithmParameters params = createAlgorithmParameters(encryptionAlgID.getAlgorithm());
+
+ CMSUtils.loadParameters(params, sParams);
+
+ cipher.init(Cipher.DECRYPT_MODE, sKey, params);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ if (encAlg.equals(CMSAlgorithm.DES_CBC.getId())
+ || encAlg.equals(CMSEnvelopedDataGenerator.DES_EDE3_CBC)
+ || encAlg.equals(CMSEnvelopedDataGenerator.IDEA_CBC)
+ || encAlg.equals(CMSEnvelopedDataGenerator.AES128_CBC)
+ || encAlg.equals(CMSEnvelopedDataGenerator.AES192_CBC)
+ || encAlg.equals(CMSEnvelopedDataGenerator.AES256_CBC))
+ {
+ cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec(
+ ASN1OctetString.getInstance(sParams).getOctets()));
+ }
+ else
+ {
+ throw e;
+ }
+ }
+ }
+ else
+ {
+ if (encAlg.equals(CMSAlgorithm.DES_CBC.getId())
+ || encAlg.equals(CMSEnvelopedDataGenerator.DES_EDE3_CBC)
+ || encAlg.equals(CMSEnvelopedDataGenerator.IDEA_CBC)
+ || encAlg.equals(CMSEnvelopedDataGenerator.CAST5_CBC))
+ {
+ cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec(new byte[8]));
+ }
+ else
+ {
+ cipher.init(Cipher.DECRYPT_MODE, sKey);
+ }
+ }
+
+ return cipher;
+ }
+ });
+ }
+
+ Mac createContentMac(final Key sKey, final AlgorithmIdentifier macAlgId)
+ throws CMSException
+ {
+ return (Mac)execute(new JCECallback()
+ {
+ public Object doInJCE()
+ throws CMSException, InvalidAlgorithmParameterException,
+ InvalidKeyException, InvalidParameterSpecException, NoSuchAlgorithmException,
+ NoSuchPaddingException, NoSuchProviderException
+ {
+ Mac mac = createMac(macAlgId.getAlgorithm());
+ ASN1Encodable sParams = macAlgId.getParameters();
+ String macAlg = macAlgId.getAlgorithm().getId();
+
+ if (sParams != null && !(sParams instanceof ASN1Null))
+ {
+ try
+ {
+ AlgorithmParameters params = createAlgorithmParameters(macAlgId.getAlgorithm());
+
+ CMSUtils.loadParameters(params, sParams);
+
+ mac.init(sKey, params.getParameterSpec(IvParameterSpec.class));
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw e;
+ }
+ }
+ else
+ {
+ mac.init(sKey);
+ }
+
+ return mac;
+ }
+ });
+ }
+
+ AlgorithmParameters createAlgorithmParameters(ASN1ObjectIdentifier algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (algorithmName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createAlgorithmParameters(algorithmName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createAlgorithmParameters(algorithm.getId());
+ }
+
+
+ KeyPairGenerator createKeyPairGenerator(ASN1ObjectIdentifier algorithm)
+ throws CMSException
+ {
+ try
+ {
+ String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createKeyPairGenerator(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createKeyPairGenerator(algorithm.getId());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("cannot create key pair generator: " + e.getMessage(), e);
+ }
+ }
+
+ public KeyGenerator createKeyGenerator(ASN1ObjectIdentifier algorithm)
+ throws CMSException
+ {
+ try
+ {
+ String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createKeyGenerator(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createKeyGenerator(algorithm.getId());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("cannot create key generator: " + e.getMessage(), e);
+ }
+ }
+
+ AlgorithmParameters generateParameters(ASN1ObjectIdentifier encryptionOID, SecretKey encKey, SecureRandom rand)
+ throws CMSException
+ {
+ try
+ {
+ AlgorithmParameterGenerator pGen = createAlgorithmParameterGenerator(encryptionOID);
+
+ if (encryptionOID.equals(CMSAlgorithm.RC2_CBC))
+ {
+ byte[] iv = new byte[8];
+
+ rand.nextBytes(iv);
+
+ try
+ {
+ pGen.init(new RC2ParameterSpec(encKey.getEncoded().length * 8, iv), rand);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new CMSException("parameters generation error: " + e, e);
+ }
+ }
+
+ return pGen.generateParameters();
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ return null;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("exception creating algorithm parameter generator: " + e, e);
+ }
+ }
+
+ AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier encryptionOID, AlgorithmParameters params)
+ throws CMSException
+ {
+ ASN1Encodable asn1Params;
+ if (params != null)
+ {
+ asn1Params = CMSUtils.extractParameters(params);
+ }
+ else
+ {
+ asn1Params = DERNull.INSTANCE;
+ }
+
+ return new AlgorithmIdentifier(
+ encryptionOID,
+ asn1Params);
+ }
+
+ static Object execute(JCECallback callback) throws CMSException
+ {
+ try
+ {
+ return callback.doInJCE();
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new CMSException("can't find algorithm.", e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CMSException("key invalid in message.", e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new CMSException("can't find provider.", e);
+ }
+ catch (NoSuchPaddingException e)
+ {
+ throw new CMSException("required padding not supported.", e);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new CMSException("algorithm parameters invalid.", e);
+ }
+ catch (InvalidParameterSpecException e)
+ {
+ throw new CMSException("MAC algorithm parameter spec invalid.", e);
+ }
+ }
+
+ public KeyFactory createKeyFactory(ASN1ObjectIdentifier algorithm)
+ throws CMSException
+ {
+ try
+ {
+ String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createKeyFactory(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createKeyFactory(algorithm.getId());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("cannot create key factory: " + e.getMessage(), e);
+ }
+ }
+
+ public JceAsymmetricKeyUnwrapper createAsymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, PrivateKey keyEncryptionKey)
+ {
+ return helper.createAsymmetricUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey);
+ }
+
+ public SymmetricKeyUnwrapper createSymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, SecretKey keyEncryptionKey)
+ {
+ return helper.createSymmetricUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey);
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier macOID, AlgorithmParameterSpec paramSpec)
+ {
+ if (paramSpec instanceof IvParameterSpec)
+ {
+ return new AlgorithmIdentifier(macOID, new DEROctetString(((IvParameterSpec)paramSpec).getIV()));
+ }
+
+ if (paramSpec instanceof RC2ParameterSpec)
+ {
+ RC2ParameterSpec rc2Spec = (RC2ParameterSpec)paramSpec;
+
+ int effKeyBits = ((RC2ParameterSpec)paramSpec).getEffectiveKeyBits();
+
+ if (effKeyBits != -1)
+ {
+ int parameterVersion;
+
+ if (effKeyBits < 256)
+ {
+ parameterVersion = rc2Table[effKeyBits];
+ }
+ else
+ {
+ parameterVersion = effKeyBits;
+ }
+
+ return new AlgorithmIdentifier(macOID, new RC2CBCParameter(parameterVersion, rc2Spec.getIV()));
+ }
+
+ return new AlgorithmIdentifier(macOID, new RC2CBCParameter(rc2Spec.getIV()));
+ }
+
+ throw new IllegalStateException("unknown parameter spec: " + paramSpec);
+ }
+
+ static interface JCECallback
+ {
+ Object doInJCE()
+ throws CMSException, InvalidAlgorithmParameterException, InvalidKeyException, InvalidParameterSpecException,
+ NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaJceExtHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaJceExtHelper.java
new file mode 100644
index 000000000..e4dd991c0
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaJceExtHelper.java
@@ -0,0 +1,18 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.PrivateKey;
+
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.JcaJceHelper;
+import org.spongycastle.operator.SymmetricKeyUnwrapper;
+import org.spongycastle.operator.jcajce.JceAsymmetricKeyUnwrapper;
+
+public interface JcaJceExtHelper
+ extends JcaJceHelper
+{
+ JceAsymmetricKeyUnwrapper createAsymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, PrivateKey keyEncryptionKey);
+
+ SymmetricKeyUnwrapper createSymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, SecretKey keyEncryptionKey);
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSelectorConverter.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSelectorConverter.java
new file mode 100644
index 000000000..6dc5c9a87
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSelectorConverter.java
@@ -0,0 +1,55 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.IOException;
+import java.security.cert.X509CertSelector;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cms.KeyTransRecipientId;
+import org.spongycastle.cms.SignerId;
+
+public class JcaSelectorConverter
+{
+ public JcaSelectorConverter()
+ {
+
+ }
+
+ public SignerId getSignerId(X509CertSelector certSelector)
+ {
+ try
+ {
+ if (certSelector.getSubjectKeyIdentifier() != null)
+ {
+ return new SignerId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber(), ASN1OctetString.getInstance(certSelector.getSubjectKeyIdentifier()).getOctets());
+ }
+ else
+ {
+ return new SignerId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber());
+ }
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage());
+ }
+ }
+
+ public KeyTransRecipientId getKeyTransRecipientId(X509CertSelector certSelector)
+ {
+ try
+ {
+ if (certSelector.getSubjectKeyIdentifier() != null)
+ {
+ return new KeyTransRecipientId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber(), ASN1OctetString.getInstance(certSelector.getSubjectKeyIdentifier()).getOctets());
+ }
+ else
+ {
+ return new KeyTransRecipientId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber());
+ }
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage());
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerId.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerId.java
new file mode 100644
index 000000000..27934bf65
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerId.java
@@ -0,0 +1,56 @@
+package org.spongycastle.cms.jcajce;
+
+import java.math.BigInteger;
+import java.security.cert.X509Certificate;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cms.SignerId;
+
+public class JcaSignerId
+ extends SignerId
+{
+ /**
+ * Construct a signer identifier based on the issuer, serial number and subject key identifier (if present) of the passed in
+ * certificate.
+ *
+ * @param certificate certificate providing the issue and serial number and subject key identifier.
+ */
+ public JcaSignerId(X509Certificate certificate)
+ {
+ super(convertPrincipal(certificate.getIssuerX500Principal()), certificate.getSerialNumber(), CMSUtils.getSubjectKeyId(certificate));
+ }
+
+ /**
+ * Construct a signer identifier based on the provided issuer and serial number..
+ *
+ * @param issuer the issuer to use.
+ * @param serialNumber the serial number to use.
+ */
+ public JcaSignerId(X500Principal issuer, BigInteger serialNumber)
+ {
+ super(convertPrincipal(issuer), serialNumber);
+ }
+
+ /**
+ * Construct a signer identifier based on the provided issuer, serial number, and subjectKeyId..
+ *
+ * @param issuer the issuer to use.
+ * @param serialNumber the serial number to use.
+ * @param subjectKeyId the subject key ID to use.
+ */
+ public JcaSignerId(X500Principal issuer, BigInteger serialNumber, byte[] subjectKeyId)
+ {
+ super(convertPrincipal(issuer), serialNumber, subjectKeyId);
+ }
+
+ private static X500Name convertPrincipal(X500Principal issuer)
+ {
+ if (issuer == null)
+ {
+ return null;
+ }
+ return X500Name.getInstance(issuer.getEncoded());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerInfoGeneratorBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerInfoGeneratorBuilder.java
new file mode 100644
index 000000000..79ad9070e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerInfoGeneratorBuilder.java
@@ -0,0 +1,68 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.cms.CMSAttributeTableGenerator;
+import org.spongycastle.cms.SignerInfoGenerator;
+import org.spongycastle.cms.SignerInfoGeneratorBuilder;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+
+public class JcaSignerInfoGeneratorBuilder
+{
+ private SignerInfoGeneratorBuilder builder;
+
+ public JcaSignerInfoGeneratorBuilder(DigestCalculatorProvider digestProvider)
+ {
+ builder = new SignerInfoGeneratorBuilder(digestProvider);
+ }
+
+ /**
+ * If the passed in flag is true, the signer signature will be based on the data, not
+ * a collection of signed attributes, and no signed attributes will be included.
+ *
+ * @return the builder object
+ */
+ public JcaSignerInfoGeneratorBuilder setDirectSignature(boolean hasNoSignedAttributes)
+ {
+ builder.setDirectSignature(hasNoSignedAttributes);
+
+ return this;
+ }
+
+ public JcaSignerInfoGeneratorBuilder setSignedAttributeGenerator(CMSAttributeTableGenerator signedGen)
+ {
+ builder.setSignedAttributeGenerator(signedGen);
+
+ return this;
+ }
+
+ public JcaSignerInfoGeneratorBuilder setUnsignedAttributeGenerator(CMSAttributeTableGenerator unsignedGen)
+ {
+ builder.setUnsignedAttributeGenerator(unsignedGen);
+
+ return this;
+ }
+
+ public SignerInfoGenerator build(ContentSigner contentSigner, X509CertificateHolder certHolder)
+ throws OperatorCreationException
+ {
+ return builder.build(contentSigner, certHolder);
+ }
+
+ public SignerInfoGenerator build(ContentSigner contentSigner, byte[] keyIdentifier)
+ throws OperatorCreationException
+ {
+ return builder.build(contentSigner, keyIdentifier);
+ }
+
+ public SignerInfoGenerator build(ContentSigner contentSigner, X509Certificate certificate)
+ throws OperatorCreationException, CertificateEncodingException
+ {
+ return this.build(contentSigner, new JcaX509CertificateHolder(certificate));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerInfoVerifierBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerInfoVerifierBuilder.java
new file mode 100644
index 000000000..c50778198
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSignerInfoVerifierBuilder.java
@@ -0,0 +1,180 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cms.CMSSignatureAlgorithmNameGenerator;
+import org.spongycastle.cms.DefaultCMSSignatureAlgorithmNameGenerator;
+import org.spongycastle.cms.SignerInformationVerifier;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.SignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+import org.spongycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+
+public class JcaSignerInfoVerifierBuilder
+{
+ private Helper helper = new Helper();
+ private DigestCalculatorProvider digestProvider;
+ private CMSSignatureAlgorithmNameGenerator sigAlgNameGen = new DefaultCMSSignatureAlgorithmNameGenerator();
+ private SignatureAlgorithmIdentifierFinder sigAlgIDFinder = new DefaultSignatureAlgorithmIdentifierFinder();
+
+ public JcaSignerInfoVerifierBuilder(DigestCalculatorProvider digestProvider)
+ {
+ this.digestProvider = digestProvider;
+ }
+
+ public JcaSignerInfoVerifierBuilder setProvider(Provider provider)
+ {
+ this.helper = new ProviderHelper(provider);
+
+ return this;
+ }
+
+ public JcaSignerInfoVerifierBuilder setProvider(String providerName)
+ {
+ this.helper = new NamedHelper(providerName);
+
+ return this;
+ }
+
+ /**
+ * Override the default signature algorithm name generator.
+ *
+ * @param sigAlgNameGen the algorithm name generator to use.
+ * @return the current builder.
+ */
+ public JcaSignerInfoVerifierBuilder setSignatureAlgorithmNameGenerator(CMSSignatureAlgorithmNameGenerator sigAlgNameGen)
+ {
+ this.sigAlgNameGen = sigAlgNameGen;
+
+ return this;
+ }
+
+ public JcaSignerInfoVerifierBuilder setSignatureAlgorithmFinder(SignatureAlgorithmIdentifierFinder sigAlgIDFinder)
+ {
+ this.sigAlgIDFinder = sigAlgIDFinder;
+
+ return this;
+ }
+
+ public SignerInformationVerifier build(X509CertificateHolder certHolder)
+ throws OperatorCreationException, CertificateException
+ {
+ return new SignerInformationVerifier(sigAlgNameGen, sigAlgIDFinder, helper.createContentVerifierProvider(certHolder), digestProvider);
+ }
+
+ public SignerInformationVerifier build(X509Certificate certificate)
+ throws OperatorCreationException
+ {
+ return new SignerInformationVerifier(sigAlgNameGen, sigAlgIDFinder, helper.createContentVerifierProvider(certificate), digestProvider);
+ }
+
+ public SignerInformationVerifier build(PublicKey pubKey)
+ throws OperatorCreationException
+ {
+ return new SignerInformationVerifier(sigAlgNameGen, sigAlgIDFinder, helper.createContentVerifierProvider(pubKey), digestProvider);
+ }
+
+ private class Helper
+ {
+ ContentVerifierProvider createContentVerifierProvider(PublicKey publicKey)
+ throws OperatorCreationException
+ {
+ return new JcaContentVerifierProviderBuilder().build(publicKey);
+ }
+
+ ContentVerifierProvider createContentVerifierProvider(X509Certificate certificate)
+ throws OperatorCreationException
+ {
+ return new JcaContentVerifierProviderBuilder().build(certificate);
+ }
+
+ ContentVerifierProvider createContentVerifierProvider(X509CertificateHolder certHolder)
+ throws OperatorCreationException, CertificateException
+ {
+ return new JcaContentVerifierProviderBuilder().build(certHolder);
+ }
+
+ DigestCalculatorProvider createDigestCalculatorProvider()
+ throws OperatorCreationException
+ {
+ return new JcaDigestCalculatorProviderBuilder().build();
+ }
+ }
+
+ private class NamedHelper
+ extends Helper
+ {
+ private final String providerName;
+
+ public NamedHelper(String providerName)
+ {
+ this.providerName = providerName;
+ }
+
+ ContentVerifierProvider createContentVerifierProvider(PublicKey publicKey)
+ throws OperatorCreationException
+ {
+ return new JcaContentVerifierProviderBuilder().setProvider(providerName).build(publicKey);
+ }
+
+ ContentVerifierProvider createContentVerifierProvider(X509Certificate certificate)
+ throws OperatorCreationException
+ {
+ return new JcaContentVerifierProviderBuilder().setProvider(providerName).build(certificate);
+ }
+
+ DigestCalculatorProvider createDigestCalculatorProvider()
+ throws OperatorCreationException
+ {
+ return new JcaDigestCalculatorProviderBuilder().setProvider(providerName).build();
+ }
+
+ ContentVerifierProvider createContentVerifierProvider(X509CertificateHolder certHolder)
+ throws OperatorCreationException, CertificateException
+ {
+ return new JcaContentVerifierProviderBuilder().setProvider(providerName).build(certHolder);
+ }
+ }
+
+ private class ProviderHelper
+ extends Helper
+ {
+ private final Provider provider;
+
+ public ProviderHelper(Provider provider)
+ {
+ this.provider = provider;
+ }
+
+ ContentVerifierProvider createContentVerifierProvider(PublicKey publicKey)
+ throws OperatorCreationException
+ {
+ return new JcaContentVerifierProviderBuilder().setProvider(provider).build(publicKey);
+ }
+
+ ContentVerifierProvider createContentVerifierProvider(X509Certificate certificate)
+ throws OperatorCreationException
+ {
+ return new JcaContentVerifierProviderBuilder().setProvider(provider).build(certificate);
+ }
+
+ DigestCalculatorProvider createDigestCalculatorProvider()
+ throws OperatorCreationException
+ {
+ return new JcaDigestCalculatorProviderBuilder().setProvider(provider).build();
+ }
+
+ ContentVerifierProvider createContentVerifierProvider(X509CertificateHolder certHolder)
+ throws OperatorCreationException, CertificateException
+ {
+ return new JcaContentVerifierProviderBuilder().setProvider(provider).build(certHolder);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSimpleSignerInfoGeneratorBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSimpleSignerInfoGeneratorBuilder.java
new file mode 100644
index 000000000..87aca5c77
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSimpleSignerInfoGeneratorBuilder.java
@@ -0,0 +1,202 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.cms.CMSAttributeTableGenerator;
+import org.spongycastle.cms.DefaultSignedAttributeTableGenerator;
+import org.spongycastle.cms.SignerInfoGenerator;
+import org.spongycastle.cms.SignerInfoGeneratorBuilder;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+
+/**
+ * Use this class if you are using a provider that has all the facilities you
+ * need.
+ * <p>
+ * For example:
+ * <pre>
+ * CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+ * ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("SC").build(signKP.getPrivate());
+ *
+ * gen.addSignerInfoGenerator(
+ * new JcaSignerInfoGeneratorBuilder(
+ * new JcaDigestCalculatorProviderBuilder().setProvider("SC").build())
+ * .build(sha1Signer, signCert));
+ * </pre>
+ * becomes:
+ * <pre>
+ * CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+ *
+ * gen.addSignerInfoGenerator(
+ * new JcaSimpleSignerInfoGeneratorBuilder()
+ * .setProvider("SC")
+ * .build("SHA1withRSA", signKP.getPrivate(), signCert));
+ * </pre>
+ */
+public class JcaSimpleSignerInfoGeneratorBuilder
+{
+ private Helper helper;
+
+ private boolean hasNoSignedAttributes;
+ private CMSAttributeTableGenerator signedGen;
+ private CMSAttributeTableGenerator unsignedGen;
+
+ public JcaSimpleSignerInfoGeneratorBuilder()
+ throws OperatorCreationException
+ {
+ this.helper = new Helper();
+ }
+
+ public JcaSimpleSignerInfoGeneratorBuilder setProvider(String providerName)
+ throws OperatorCreationException
+ {
+ this.helper = new NamedHelper(providerName);
+
+ return this;
+ }
+
+ public JcaSimpleSignerInfoGeneratorBuilder setProvider(Provider provider)
+ throws OperatorCreationException
+ {
+ this.helper = new ProviderHelper(provider);
+
+ return this;
+ }
+
+ /**
+ * If the passed in flag is true, the signer signature will be based on the data, not
+ * a collection of signed attributes, and no signed attributes will be included.
+ *
+ * @return the builder object
+ */
+ public JcaSimpleSignerInfoGeneratorBuilder setDirectSignature(boolean hasNoSignedAttributes)
+ {
+ this.hasNoSignedAttributes = hasNoSignedAttributes;
+
+ return this;
+ }
+
+ public JcaSimpleSignerInfoGeneratorBuilder setSignedAttributeGenerator(CMSAttributeTableGenerator signedGen)
+ {
+ this.signedGen = signedGen;
+
+ return this;
+ }
+
+ /**
+ * set up a DefaultSignedAttributeTableGenerator primed with the passed in AttributeTable.
+ *
+ * @param attrTable table of attributes for priming generator
+ * @return this.
+ */
+ public JcaSimpleSignerInfoGeneratorBuilder setSignedAttributeGenerator(AttributeTable attrTable)
+ {
+ this.signedGen = new DefaultSignedAttributeTableGenerator(attrTable);
+
+ return this;
+ }
+
+ public JcaSimpleSignerInfoGeneratorBuilder setUnsignedAttributeGenerator(CMSAttributeTableGenerator unsignedGen)
+ {
+ this.unsignedGen = unsignedGen;
+
+ return this;
+ }
+
+ public SignerInfoGenerator build(String algorithmName, PrivateKey privateKey, X509Certificate certificate)
+ throws OperatorCreationException, CertificateEncodingException
+ {
+ ContentSigner contentSigner = helper.createContentSigner(algorithmName, privateKey);
+
+ return configureAndBuild().build(contentSigner, new JcaX509CertificateHolder(certificate));
+ }
+
+ public SignerInfoGenerator build(String algorithmName, PrivateKey privateKey, byte[] keyIdentifier)
+ throws OperatorCreationException, CertificateEncodingException
+ {
+ ContentSigner contentSigner = helper.createContentSigner(algorithmName, privateKey);
+
+ return configureAndBuild().build(contentSigner, keyIdentifier);
+ }
+
+ private SignerInfoGeneratorBuilder configureAndBuild()
+ throws OperatorCreationException
+ {
+ SignerInfoGeneratorBuilder infoGeneratorBuilder = new SignerInfoGeneratorBuilder(helper.createDigestCalculatorProvider());
+
+ infoGeneratorBuilder.setDirectSignature(hasNoSignedAttributes);
+ infoGeneratorBuilder.setSignedAttributeGenerator(signedGen);
+ infoGeneratorBuilder.setUnsignedAttributeGenerator(unsignedGen);
+
+ return infoGeneratorBuilder;
+ }
+
+ private class Helper
+ {
+ ContentSigner createContentSigner(String algorithm, PrivateKey privateKey)
+ throws OperatorCreationException
+ {
+ return new JcaContentSignerBuilder(algorithm).build(privateKey);
+ }
+
+ DigestCalculatorProvider createDigestCalculatorProvider()
+ throws OperatorCreationException
+ {
+ return new JcaDigestCalculatorProviderBuilder().build();
+ }
+ }
+
+ private class NamedHelper
+ extends Helper
+ {
+ private final String providerName;
+
+ public NamedHelper(String providerName)
+ {
+ this.providerName = providerName;
+ }
+
+ ContentSigner createContentSigner(String algorithm, PrivateKey privateKey)
+ throws OperatorCreationException
+ {
+ return new JcaContentSignerBuilder(algorithm).setProvider(providerName).build(privateKey);
+ }
+
+ DigestCalculatorProvider createDigestCalculatorProvider()
+ throws OperatorCreationException
+ {
+ return new JcaDigestCalculatorProviderBuilder().setProvider(providerName).build();
+ }
+ }
+
+ private class ProviderHelper
+ extends Helper
+ {
+ private final Provider provider;
+
+ public ProviderHelper(Provider provider)
+ {
+ this.provider = provider;
+ }
+
+ ContentSigner createContentSigner(String algorithm, PrivateKey privateKey)
+ throws OperatorCreationException
+ {
+ return new JcaContentSignerBuilder(algorithm).setProvider(provider).build(privateKey);
+ }
+
+ DigestCalculatorProvider createDigestCalculatorProvider()
+ throws OperatorCreationException
+ {
+ return new JcaDigestCalculatorProviderBuilder().setProvider(provider).build();
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSimpleSignerInfoVerifierBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSimpleSignerInfoVerifierBuilder.java
new file mode 100644
index 000000000..4463b0659
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaSimpleSignerInfoVerifierBuilder.java
@@ -0,0 +1,150 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cms.DefaultCMSSignatureAlgorithmNameGenerator;
+import org.spongycastle.cms.SignerInformationVerifier;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+import org.spongycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+
+public class JcaSimpleSignerInfoVerifierBuilder
+{
+ private Helper helper = new Helper();
+
+ public JcaSimpleSignerInfoVerifierBuilder setProvider(Provider provider)
+ {
+ this.helper = new ProviderHelper(provider);
+
+ return this;
+ }
+
+ public JcaSimpleSignerInfoVerifierBuilder setProvider(String providerName)
+ {
+ this.helper = new NamedHelper(providerName);
+
+ return this;
+ }
+
+ public SignerInformationVerifier build(X509CertificateHolder certHolder)
+ throws OperatorCreationException, CertificateException
+ {
+ return new SignerInformationVerifier(new DefaultCMSSignatureAlgorithmNameGenerator(), new DefaultSignatureAlgorithmIdentifierFinder(), helper.createContentVerifierProvider(certHolder), helper.createDigestCalculatorProvider());
+ }
+
+ public SignerInformationVerifier build(X509Certificate certificate)
+ throws OperatorCreationException
+ {
+ return new SignerInformationVerifier(new DefaultCMSSignatureAlgorithmNameGenerator(), new DefaultSignatureAlgorithmIdentifierFinder(), helper.createContentVerifierProvider(certificate), helper.createDigestCalculatorProvider());
+ }
+
+ public SignerInformationVerifier build(PublicKey pubKey)
+ throws OperatorCreationException
+ {
+ return new SignerInformationVerifier(new DefaultCMSSignatureAlgorithmNameGenerator(), new DefaultSignatureAlgorithmIdentifierFinder(), helper.createContentVerifierProvider(pubKey), helper.createDigestCalculatorProvider());
+ }
+
+ private class Helper
+ {
+ ContentVerifierProvider createContentVerifierProvider(PublicKey publicKey)
+ throws OperatorCreationException
+ {
+ return new JcaContentVerifierProviderBuilder().build(publicKey);
+ }
+
+ ContentVerifierProvider createContentVerifierProvider(X509Certificate certificate)
+ throws OperatorCreationException
+ {
+ return new JcaContentVerifierProviderBuilder().build(certificate);
+ }
+
+ ContentVerifierProvider createContentVerifierProvider(X509CertificateHolder certHolder)
+ throws OperatorCreationException, CertificateException
+ {
+ return new JcaContentVerifierProviderBuilder().build(certHolder);
+ }
+
+ DigestCalculatorProvider createDigestCalculatorProvider()
+ throws OperatorCreationException
+ {
+ return new JcaDigestCalculatorProviderBuilder().build();
+ }
+ }
+
+ private class NamedHelper
+ extends Helper
+ {
+ private final String providerName;
+
+ public NamedHelper(String providerName)
+ {
+ this.providerName = providerName;
+ }
+
+ ContentVerifierProvider createContentVerifierProvider(PublicKey publicKey)
+ throws OperatorCreationException
+ {
+ return new JcaContentVerifierProviderBuilder().setProvider(providerName).build(publicKey);
+ }
+
+ ContentVerifierProvider createContentVerifierProvider(X509Certificate certificate)
+ throws OperatorCreationException
+ {
+ return new JcaContentVerifierProviderBuilder().setProvider(providerName).build(certificate);
+ }
+
+ DigestCalculatorProvider createDigestCalculatorProvider()
+ throws OperatorCreationException
+ {
+ return new JcaDigestCalculatorProviderBuilder().setProvider(providerName).build();
+ }
+
+ ContentVerifierProvider createContentVerifierProvider(X509CertificateHolder certHolder)
+ throws OperatorCreationException, CertificateException
+ {
+ return new JcaContentVerifierProviderBuilder().setProvider(providerName).build(certHolder);
+ }
+ }
+
+ private class ProviderHelper
+ extends Helper
+ {
+ private final Provider provider;
+
+ public ProviderHelper(Provider provider)
+ {
+ this.provider = provider;
+ }
+
+ ContentVerifierProvider createContentVerifierProvider(PublicKey publicKey)
+ throws OperatorCreationException
+ {
+ return new JcaContentVerifierProviderBuilder().setProvider(provider).build(publicKey);
+ }
+
+ ContentVerifierProvider createContentVerifierProvider(X509Certificate certificate)
+ throws OperatorCreationException
+ {
+ return new JcaContentVerifierProviderBuilder().setProvider(provider).build(certificate);
+ }
+
+ DigestCalculatorProvider createDigestCalculatorProvider()
+ throws OperatorCreationException
+ {
+ return new JcaDigestCalculatorProviderBuilder().setProvider(provider).build();
+ }
+
+ ContentVerifierProvider createContentVerifierProvider(X509CertificateHolder certHolder)
+ throws OperatorCreationException, CertificateException
+ {
+ return new JcaContentVerifierProviderBuilder().setProvider(provider).build(certHolder);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaX509CertSelectorConverter.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaX509CertSelectorConverter.java
new file mode 100644
index 000000000..ceb138ed6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcaX509CertSelectorConverter.java
@@ -0,0 +1,24 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.cert.X509CertSelector;
+
+import org.spongycastle.cms.KeyTransRecipientId;
+import org.spongycastle.cms.SignerId;
+
+public class JcaX509CertSelectorConverter
+ extends org.spongycastle.cert.selector.jcajce.JcaX509CertSelectorConverter
+{
+ public JcaX509CertSelectorConverter()
+ {
+ }
+
+ public X509CertSelector getCertSelector(KeyTransRecipientId recipientId)
+ {
+ return doConversion(recipientId.getIssuer(), recipientId.getSerialNumber(), recipientId.getSubjectKeyIdentifier());
+ }
+
+ public X509CertSelector getCertSelector(SignerId signerId)
+ {
+ return doConversion(signerId.getIssuer(), signerId.getSerialNumber(), signerId.getSubjectKeyIdentifier());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceAlgorithmIdentifierConverter.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceAlgorithmIdentifierConverter.java
new file mode 100644
index 000000000..32007919e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceAlgorithmIdentifierConverter.java
@@ -0,0 +1,64 @@
+package org.spongycastle.cms.jcajce;
+
+
+import java.security.AlgorithmParameters;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.SecureRandom;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+
+public class JceAlgorithmIdentifierConverter
+{
+ private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+ private SecureRandom random;
+
+ public JceAlgorithmIdentifierConverter()
+ {
+ }
+
+ public JceAlgorithmIdentifierConverter setProvider(Provider provider)
+ {
+ this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
+
+ return this;
+ }
+
+ public JceAlgorithmIdentifierConverter setProvider(String providerName)
+ {
+ this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
+
+ return this;
+ }
+
+ public AlgorithmParameters getAlgorithmParameters(AlgorithmIdentifier algorithmIdentifier)
+ throws CMSException
+ {
+ ASN1Encodable parameters = algorithmIdentifier.getParameters();
+
+ if (parameters == null)
+ {
+ return null;
+ }
+
+ try
+ {
+ AlgorithmParameters params = helper.createAlgorithmParameters(algorithmIdentifier.getAlgorithm());
+
+ CMSUtils.loadParameters(params, algorithmIdentifier.getParameters());
+
+ return params;
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new CMSException("can't find parameters for algorithm", e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new CMSException("can't find provider for algorithm", e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java
new file mode 100644
index 000000000..5711df3d9
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java
@@ -0,0 +1,160 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.OutputStream;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.Provider;
+import java.security.SecureRandom;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.operator.DefaultSecretKeySizeProvider;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OutputEncryptor;
+import org.spongycastle.operator.SecretKeySizeProvider;
+import org.spongycastle.operator.jcajce.JceGenericKey;
+
+public class JceCMSContentEncryptorBuilder
+{
+ private static final SecretKeySizeProvider KEY_SIZE_PROVIDER = DefaultSecretKeySizeProvider.INSTANCE;
+
+
+ private final ASN1ObjectIdentifier encryptionOID;
+ private final int keySize;
+
+ private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+ private SecureRandom random;
+
+ public JceCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID)
+ {
+ this(encryptionOID, KEY_SIZE_PROVIDER.getKeySize(encryptionOID));
+ }
+
+ public JceCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID, int keySize)
+ {
+ this.encryptionOID = encryptionOID;
+ this.keySize = keySize;
+
+ int fixedSize = KEY_SIZE_PROVIDER.getKeySize(encryptionOID);
+
+ if (encryptionOID.equals(PKCSObjectIdentifiers.des_EDE3_CBC))
+ {
+ if (keySize != 168 && keySize != fixedSize)
+ {
+ throw new IllegalArgumentException("incorrect keySize for encryptionOID passed to builder.");
+ }
+ }
+ else
+ {
+ if (fixedSize > 0 && fixedSize != keySize)
+ {
+ throw new IllegalArgumentException("incorrect keySize for encryptionOID passed to builder.");
+ }
+ }
+ }
+
+ public JceCMSContentEncryptorBuilder setProvider(Provider provider)
+ {
+ this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
+
+ return this;
+ }
+
+ public JceCMSContentEncryptorBuilder setProvider(String providerName)
+ {
+ this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
+
+ return this;
+ }
+
+ public JceCMSContentEncryptorBuilder setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public OutputEncryptor build()
+ throws CMSException
+ {
+ return new CMSOutputEncryptor(encryptionOID, keySize, random);
+ }
+
+ private class CMSOutputEncryptor
+ implements OutputEncryptor
+ {
+ private SecretKey encKey;
+ private AlgorithmIdentifier algorithmIdentifier;
+ private Cipher cipher;
+
+ CMSOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, SecureRandom random)
+ throws CMSException
+ {
+ KeyGenerator keyGen = helper.createKeyGenerator(encryptionOID);
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ if (keySize < 0)
+ {
+ keyGen.init(random);
+ }
+ else
+ {
+ if (encryptionOID.equals(PKCSObjectIdentifiers.des_EDE3_CBC) && keySize == 192)
+ {
+ keySize = 168;
+ }
+ keyGen.init(keySize, random);
+ }
+
+ cipher = helper.createCipher(encryptionOID);
+ encKey = keyGen.generateKey();
+ AlgorithmParameters params = helper.generateParameters(encryptionOID, encKey, random);
+
+ try
+ {
+ cipher.init(Cipher.ENCRYPT_MODE, encKey, params, random);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("unable to initialize cipher: " + e.getMessage(), e);
+ }
+
+ //
+ // If params are null we try and second guess on them as some providers don't provide
+ // algorithm parameter generation explicity but instead generate them under the hood.
+ //
+ if (params == null)
+ {
+ params = cipher.getParameters();
+ }
+
+ algorithmIdentifier = helper.getAlgorithmIdentifier(encryptionOID, params);
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmIdentifier;
+ }
+
+ public OutputStream getOutputStream(OutputStream dOut)
+ {
+ return new CipherOutputStream(dOut, cipher);
+ }
+
+ public GenericKey getKey()
+ {
+ return new JceGenericKey(algorithmIdentifier, encKey);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java
new file mode 100644
index 000000000..d60974713
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java
@@ -0,0 +1,155 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.OutputStream;
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.jcajce.io.MacOutputStream;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.MacCalculator;
+import org.spongycastle.operator.jcajce.JceGenericKey;
+
+public class JceCMSMacCalculatorBuilder
+{
+ private final ASN1ObjectIdentifier macOID;
+ private final int keySize;
+
+ private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+ private SecureRandom random;
+
+ public JceCMSMacCalculatorBuilder(ASN1ObjectIdentifier macOID)
+ {
+ this(macOID, -1);
+ }
+
+ public JceCMSMacCalculatorBuilder(ASN1ObjectIdentifier macOID, int keySize)
+ {
+ this.macOID = macOID;
+ this.keySize = keySize;
+ }
+
+ public JceCMSMacCalculatorBuilder setProvider(Provider provider)
+ {
+ this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
+
+ return this;
+ }
+
+ public JceCMSMacCalculatorBuilder setProvider(String providerName)
+ {
+ this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
+
+ return this;
+ }
+
+ public JceCMSMacCalculatorBuilder setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public MacCalculator build()
+ throws CMSException
+ {
+ return new CMSMacCalculator(macOID, keySize, random);
+ }
+
+ private class CMSMacCalculator
+ implements MacCalculator
+ {
+ private SecretKey encKey;
+ private AlgorithmIdentifier algorithmIdentifier;
+ private Mac mac;
+ private SecureRandom random;
+
+ CMSMacCalculator(ASN1ObjectIdentifier macOID, int keySize, SecureRandom random)
+ throws CMSException
+ {
+ KeyGenerator keyGen = helper.createKeyGenerator(macOID);
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ this.random = random;
+
+ if (keySize < 0)
+ {
+ keyGen.init(random);
+ }
+ else
+ {
+ keyGen.init(keySize, random);
+ }
+
+ encKey = keyGen.generateKey();
+
+ AlgorithmParameterSpec paramSpec = generateParameterSpec(macOID, encKey);
+
+ algorithmIdentifier = helper.getAlgorithmIdentifier(macOID, paramSpec);
+ mac = helper.createContentMac(encKey, algorithmIdentifier);
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmIdentifier;
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return new MacOutputStream(mac);
+ }
+
+ public byte[] getMac()
+ {
+ return mac.doFinal();
+ }
+
+ public GenericKey getKey()
+ {
+ return new JceGenericKey(algorithmIdentifier, encKey);
+ }
+
+ protected AlgorithmParameterSpec generateParameterSpec(ASN1ObjectIdentifier macOID, SecretKey encKey)
+ throws CMSException
+ {
+ try
+ {
+ if (macOID.equals(PKCSObjectIdentifiers.RC2_CBC))
+ {
+ byte[] iv = new byte[8];
+
+ random.nextBytes(iv);
+
+ return new RC2ParameterSpec(encKey.getEncoded().length * 8, iv);
+ }
+
+ AlgorithmParameterGenerator pGen = helper.createAlgorithmParameterGenerator(macOID);
+
+ AlgorithmParameters p = pGen.generateParameters();
+
+ return p.getParameterSpec(IvParameterSpec.class);
+ }
+ catch (GeneralSecurityException e)
+ {
+ return null;
+ }
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKAuthenticatedRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKAuthenticatedRecipient.java
new file mode 100644
index 000000000..55a19d548
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKAuthenticatedRecipient.java
@@ -0,0 +1,61 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.OutputStream;
+import java.security.Key;
+
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.RecipientOperator;
+import org.spongycastle.jcajce.io.MacOutputStream;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.MacCalculator;
+import org.spongycastle.operator.jcajce.JceGenericKey;
+
+
+/**
+ * the KeyTransRecipientInformation class for a recipient who has been sent a secret
+ * key encrypted using their public key that needs to be used to
+ * extract the message.
+ */
+public class JceKEKAuthenticatedRecipient
+ extends JceKEKRecipient
+{
+ public JceKEKAuthenticatedRecipient(SecretKey recipientKey)
+ {
+ super(recipientKey);
+ }
+
+ public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentMacAlgorithm, byte[] encryptedContentEncryptionKey)
+ throws CMSException
+ {
+ final Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentMacAlgorithm, encryptedContentEncryptionKey);
+
+ final Mac dataMac = contentHelper.createContentMac(secretKey, contentMacAlgorithm);
+
+ return new RecipientOperator(new MacCalculator()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return contentMacAlgorithm;
+ }
+
+ public GenericKey getKey()
+ {
+ return new JceGenericKey(contentMacAlgorithm, secretKey);
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return new MacOutputStream(dataMac);
+ }
+
+ public byte[] getMac()
+ {
+ return dataMac.doFinal();
+ }
+ });
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKEnvelopedRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKEnvelopedRecipient.java
new file mode 100644
index 000000000..8bf940064
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKEnvelopedRecipient.java
@@ -0,0 +1,43 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.InputStream;
+import java.security.Key;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.RecipientOperator;
+import org.spongycastle.operator.InputDecryptor;
+
+public class JceKEKEnvelopedRecipient
+ extends JceKEKRecipient
+{
+ public JceKEKEnvelopedRecipient(SecretKey recipientKey)
+ {
+ super(recipientKey);
+ }
+
+ public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey)
+ throws CMSException
+ {
+ Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, encryptedContentEncryptionKey);
+
+ final Cipher dataCipher = contentHelper.createContentCipher(secretKey, contentEncryptionAlgorithm);
+
+ return new RecipientOperator(new InputDecryptor()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return contentEncryptionAlgorithm;
+ }
+
+ public InputStream getInputStream(InputStream dataOut)
+ {
+ return new CipherInputStream(dataOut, dataCipher);
+ }
+ });
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKRecipient.java
new file mode 100644
index 000000000..84ad638f9
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKRecipient.java
@@ -0,0 +1,119 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.Key;
+import java.security.Provider;
+
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.KEKRecipient;
+import org.spongycastle.operator.OperatorException;
+import org.spongycastle.operator.SymmetricKeyUnwrapper;
+
+public abstract class JceKEKRecipient
+ implements KEKRecipient
+{
+ private SecretKey recipientKey;
+
+ protected EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+ protected EnvelopedDataHelper contentHelper = helper;
+ protected boolean validateKeySize = false;
+
+ public JceKEKRecipient(SecretKey recipientKey)
+ {
+ this.recipientKey = recipientKey;
+ }
+
+ /**
+ * Set the provider to use for key recovery and content processing.
+ *
+ * @param provider provider to use.
+ * @return this recipient.
+ */
+ public JceKEKRecipient setProvider(Provider provider)
+ {
+ this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
+ this.contentHelper = helper;
+
+ return this;
+ }
+
+ /**
+ * Set the provider to use for key recovery and content processing.
+ *
+ * @param providerName the name of the provider to use.
+ * @return this recipient.
+ */
+ public JceKEKRecipient setProvider(String providerName)
+ {
+ this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
+ this.contentHelper = helper;
+
+ return this;
+ }
+
+ /**
+ * Set the provider to use for content processing.
+ *
+ * @param provider the provider to use.
+ * @return this recipient.
+ */
+ public JceKEKRecipient setContentProvider(Provider provider)
+ {
+ this.contentHelper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
+
+ return this;
+ }
+
+ /**
+ * Set the provider to use for content processing.
+ *
+ * @param providerName the name of the provider to use.
+ * @return this recipient.
+ */
+ public JceKEKRecipient setContentProvider(String providerName)
+ {
+ this.contentHelper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
+
+ return this;
+ }
+
+ /**
+ * Set validation of retrieved key sizes against the algorithm parameters for the encrypted key where possible - default is off.
+ * <p>
+ * This setting will not have any affect if the encryption algorithm in the recipient does not specify a particular key size, or
+ * if the unwrapper is a HSM and the byte encoding of the unwrapped secret key is not available.
+ * </p>
+ * @param doValidate true if unwrapped key's should be validated against the content encryption algorithm, false otherwise.
+ * @return this recipient.
+ */
+ public JceKEKRecipient setKeySizeValidation(boolean doValidate)
+ {
+ this.validateKeySize = doValidate;
+
+ return this;
+ }
+
+ protected Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedContentEncryptionKey)
+ throws CMSException
+ {
+ SymmetricKeyUnwrapper unwrapper = helper.createSymmetricUnwrapper(keyEncryptionAlgorithm, recipientKey);
+
+ try
+ {
+ Key key = helper.getJceKey(encryptedKeyAlgorithm.getAlgorithm(), unwrapper.generateUnwrappedKey(encryptedKeyAlgorithm, encryptedContentEncryptionKey));
+
+ if (validateKeySize)
+ {
+ helper.keySizeCheck(encryptedKeyAlgorithm, key);
+ }
+
+ return key;
+ }
+ catch (OperatorException e)
+ {
+ throw new CMSException("exception unwrapping key: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKRecipientInfoGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKRecipientInfoGenerator.java
new file mode 100644
index 000000000..7a67de4a9
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKEKRecipientInfoGenerator.java
@@ -0,0 +1,45 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.Provider;
+import java.security.SecureRandom;
+
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.cms.KEKIdentifier;
+import org.spongycastle.cms.KEKRecipientInfoGenerator;
+import org.spongycastle.operator.jcajce.JceSymmetricKeyWrapper;
+
+public class JceKEKRecipientInfoGenerator
+ extends KEKRecipientInfoGenerator
+{
+ public JceKEKRecipientInfoGenerator(KEKIdentifier kekIdentifier, SecretKey keyEncryptionKey)
+ {
+ super(kekIdentifier, new JceSymmetricKeyWrapper(keyEncryptionKey));
+ }
+
+ public JceKEKRecipientInfoGenerator(byte[] keyIdentifier, SecretKey keyEncryptionKey)
+ {
+ this(new KEKIdentifier(keyIdentifier, null, null), keyEncryptionKey);
+ }
+
+ public JceKEKRecipientInfoGenerator setProvider(Provider provider)
+ {
+ ((JceSymmetricKeyWrapper)this.wrapper).setProvider(provider);
+
+ return this;
+ }
+
+ public JceKEKRecipientInfoGenerator setProvider(String providerName)
+ {
+ ((JceSymmetricKeyWrapper)this.wrapper).setProvider(providerName);
+
+ return this;
+ }
+
+ public JceKEKRecipientInfoGenerator setSecureRandom(SecureRandom random)
+ {
+ ((JceSymmetricKeyWrapper)this.wrapper).setSecureRandom(random);
+
+ return this;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeAuthenticatedRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeAuthenticatedRecipient.java
new file mode 100644
index 000000000..3186b561c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeAuthenticatedRecipient.java
@@ -0,0 +1,57 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.OutputStream;
+import java.security.Key;
+import java.security.PrivateKey;
+
+import javax.crypto.Mac;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.RecipientOperator;
+import org.spongycastle.jcajce.io.MacOutputStream;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.MacCalculator;
+import org.spongycastle.operator.jcajce.JceGenericKey;
+
+public class JceKeyAgreeAuthenticatedRecipient
+ extends JceKeyAgreeRecipient
+{
+ public JceKeyAgreeAuthenticatedRecipient(PrivateKey recipientKey)
+ {
+ super(recipientKey);
+ }
+
+ public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentMacAlgorithm, SubjectPublicKeyInfo senderPublicKey, ASN1OctetString userKeyingMaterial, byte[] encryptedContentKey)
+ throws CMSException
+ {
+ final Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentMacAlgorithm, senderPublicKey, userKeyingMaterial, encryptedContentKey);
+
+ final Mac dataMac = contentHelper.createContentMac(secretKey, contentMacAlgorithm);
+
+ return new RecipientOperator(new MacCalculator()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return contentMacAlgorithm;
+ }
+
+ public GenericKey getKey()
+ {
+ return new JceGenericKey(contentMacAlgorithm, secretKey);
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return new MacOutputStream(dataMac);
+ }
+
+ public byte[] getMac()
+ {
+ return dataMac.doFinal();
+ }
+ });
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeEnvelopedRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeEnvelopedRecipient.java
new file mode 100644
index 000000000..274d8ed9c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeEnvelopedRecipient.java
@@ -0,0 +1,45 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.InputStream;
+import java.security.Key;
+import java.security.PrivateKey;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.RecipientOperator;
+import org.spongycastle.operator.InputDecryptor;
+
+public class JceKeyAgreeEnvelopedRecipient
+ extends JceKeyAgreeRecipient
+{
+ public JceKeyAgreeEnvelopedRecipient(PrivateKey recipientKey)
+ {
+ super(recipientKey);
+ }
+
+ public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, SubjectPublicKeyInfo senderPublicKey, ASN1OctetString userKeyingMaterial, byte[] encryptedContentKey)
+ throws CMSException
+ {
+ Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, senderPublicKey, userKeyingMaterial, encryptedContentKey);
+
+ final Cipher dataCipher = contentHelper.createContentCipher(secretKey, contentEncryptionAlgorithm);
+
+ return new RecipientOperator(new InputDecryptor()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return contentEncryptionAlgorithm;
+ }
+
+ public InputStream getInputStream(InputStream dataOut)
+ {
+ return new CipherInputStream(dataOut, dataCipher);
+ }
+ });
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipient.java
new file mode 100644
index 000000000..1beea382c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipient.java
@@ -0,0 +1,184 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.cms.ecc.MQVuserKeyingMaterial;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cms.CMSEnvelopedGenerator;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.KeyAgreeRecipient;
+import org.spongycastle.jce.spec.MQVPrivateKeySpec;
+import org.spongycastle.jce.spec.MQVPublicKeySpec;
+
+public abstract class JceKeyAgreeRecipient
+ implements KeyAgreeRecipient
+{
+ private PrivateKey recipientKey;
+ protected EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+ protected EnvelopedDataHelper contentHelper = helper;
+
+ public JceKeyAgreeRecipient(PrivateKey recipientKey)
+ {
+ this.recipientKey = recipientKey;
+ }
+
+ /**
+ * Set the provider to use for key recovery and content processing.
+ *
+ * @param provider provider to use.
+ * @return this recipient.
+ */
+ public JceKeyAgreeRecipient setProvider(Provider provider)
+ {
+ this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
+ this.contentHelper = helper;
+
+ return this;
+ }
+
+ /**
+ * Set the provider to use for key recovery and content processing.
+ *
+ * @param providerName the name of the provider to use.
+ * @return this recipient.
+ */
+ public JceKeyAgreeRecipient setProvider(String providerName)
+ {
+ this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
+ this.contentHelper = helper;
+
+ return this;
+ }
+
+ /**
+ * Set the provider to use for content processing. If providerName is null a "no provider" search will be
+ * used to satisfy getInstance calls.
+ *
+ * @param provider the provider to use.
+ * @return this recipient.
+ */
+ public JceKeyAgreeRecipient setContentProvider(Provider provider)
+ {
+ this.contentHelper = CMSUtils.createContentHelper(provider);
+
+ return this;
+ }
+
+ /**
+ * Set the provider to use for content processing. If providerName is null a "no provider" search will be
+ * used to satisfy getInstance calls.
+ *
+ * @param providerName the name of the provider to use.
+ * @return this recipient.
+ */
+ public JceKeyAgreeRecipient setContentProvider(String providerName)
+ {
+ this.contentHelper = CMSUtils.createContentHelper(providerName);
+
+ return this;
+ }
+
+ private SecretKey calculateAgreedWrapKey(AlgorithmIdentifier keyEncAlg, ASN1ObjectIdentifier wrapAlg,
+ PublicKey senderPublicKey, ASN1OctetString userKeyingMaterial, PrivateKey receiverPrivateKey)
+ throws CMSException, GeneralSecurityException, IOException
+ {
+ String agreeAlg = keyEncAlg.getAlgorithm().getId();
+
+ if (agreeAlg.equals(CMSEnvelopedGenerator.ECMQV_SHA1KDF))
+ {
+ byte[] ukmEncoding = userKeyingMaterial.getOctets();
+ MQVuserKeyingMaterial ukm = MQVuserKeyingMaterial.getInstance(
+ ASN1Primitive.fromByteArray(ukmEncoding));
+
+ SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(
+ getPrivateKeyAlgorithmIdentifier(),
+ ukm.getEphemeralPublicKey().getPublicKey().getBytes());
+
+ X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubInfo.getEncoded());
+ KeyFactory fact = helper.createKeyFactory(keyEncAlg.getAlgorithm());
+ PublicKey ephemeralKey = fact.generatePublic(pubSpec);
+
+ senderPublicKey = new MQVPublicKeySpec(senderPublicKey, ephemeralKey);
+ receiverPrivateKey = new MQVPrivateKeySpec(receiverPrivateKey, receiverPrivateKey);
+ }
+
+ KeyAgreement agreement = helper.createKeyAgreement(keyEncAlg.getAlgorithm());
+
+ agreement.init(receiverPrivateKey);
+ agreement.doPhase(senderPublicKey, true);
+
+ return agreement.generateSecret(wrapAlg.getId());
+ }
+
+ private Key unwrapSessionKey(ASN1ObjectIdentifier wrapAlg, SecretKey agreedKey, ASN1ObjectIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey)
+ throws CMSException, InvalidKeyException, NoSuchAlgorithmException
+ {
+ Cipher keyCipher = helper.createCipher(wrapAlg);
+ keyCipher.init(Cipher.UNWRAP_MODE, agreedKey);
+ return keyCipher.unwrap(encryptedContentEncryptionKey, helper.getBaseCipherName(contentEncryptionAlgorithm), Cipher.SECRET_KEY);
+ }
+
+ protected Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, SubjectPublicKeyInfo senderKey, ASN1OctetString userKeyingMaterial, byte[] encryptedContentEncryptionKey)
+ throws CMSException
+ {
+ try
+ {
+ ASN1ObjectIdentifier wrapAlg =
+ AlgorithmIdentifier.getInstance(keyEncryptionAlgorithm.getParameters()).getAlgorithm();
+
+ X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(senderKey.getEncoded());
+ KeyFactory fact = helper.createKeyFactory(keyEncryptionAlgorithm.getAlgorithm());
+ PublicKey senderPublicKey = fact.generatePublic(pubSpec);
+
+ SecretKey agreedWrapKey = calculateAgreedWrapKey(keyEncryptionAlgorithm, wrapAlg,
+ senderPublicKey, userKeyingMaterial, recipientKey);
+
+ return unwrapSessionKey(wrapAlg, agreedWrapKey, contentEncryptionAlgorithm.getAlgorithm(), encryptedContentEncryptionKey);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new CMSException("can't find algorithm.", e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CMSException("key invalid in message.", e);
+ }
+ catch (InvalidKeySpecException e)
+ {
+ throw new CMSException("originator key spec invalid.", e);
+ }
+ catch (NoSuchPaddingException e)
+ {
+ throw new CMSException("required padding not supported.", e);
+ }
+ catch (Exception e)
+ {
+ throw new CMSException("originator key invalid.", e);
+ }
+ }
+
+ public AlgorithmIdentifier getPrivateKeyAlgorithmIdentifier()
+ {
+ return PrivateKeyInfo.getInstance(recipientKey.getEncoded()).getPrivateKeyAlgorithm();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientId.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientId.java
new file mode 100644
index 000000000..1774b394c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientId.java
@@ -0,0 +1,23 @@
+package org.spongycastle.cms.jcajce;
+
+import java.math.BigInteger;
+import java.security.cert.X509Certificate;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cms.KeyAgreeRecipientId;
+
+public class JceKeyAgreeRecipientId
+ extends KeyAgreeRecipientId
+{
+ public JceKeyAgreeRecipientId(X509Certificate certificate)
+ {
+ this(certificate.getIssuerX500Principal(), certificate.getSerialNumber());
+ }
+
+ public JceKeyAgreeRecipientId(X500Principal issuer, BigInteger serialNumber)
+ {
+ super(X500Name.getInstance(issuer.getEncoded()), serialNumber);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java
new file mode 100644
index 000000000..eb9699f5c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java
@@ -0,0 +1,215 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.cms.KeyAgreeRecipientIdentifier;
+import org.spongycastle.asn1.cms.RecipientEncryptedKey;
+import org.spongycastle.asn1.cms.RecipientKeyIdentifier;
+import org.spongycastle.asn1.cms.ecc.MQVuserKeyingMaterial;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSEnvelopedGenerator;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.KeyAgreeRecipientInfoGenerator;
+import org.spongycastle.jce.spec.MQVPrivateKeySpec;
+import org.spongycastle.jce.spec.MQVPublicKeySpec;
+import org.spongycastle.operator.GenericKey;
+
+public class JceKeyAgreeRecipientInfoGenerator
+ extends KeyAgreeRecipientInfoGenerator
+{
+ private List recipientIDs = new ArrayList();
+ private List recipientKeys = new ArrayList();
+ private PublicKey senderPublicKey;
+ private PrivateKey senderPrivateKey;
+
+ private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+ private SecureRandom random;
+ private KeyPair ephemeralKP;
+
+ public JceKeyAgreeRecipientInfoGenerator(ASN1ObjectIdentifier keyAgreementOID, PrivateKey senderPrivateKey, PublicKey senderPublicKey, ASN1ObjectIdentifier keyEncryptionOID)
+ {
+ super(keyAgreementOID, SubjectPublicKeyInfo.getInstance(senderPublicKey.getEncoded()), keyEncryptionOID);
+
+ this.senderPublicKey = senderPublicKey;
+ this.senderPrivateKey = senderPrivateKey;
+ }
+
+ public JceKeyAgreeRecipientInfoGenerator setProvider(Provider provider)
+ {
+ this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
+
+ return this;
+ }
+
+ public JceKeyAgreeRecipientInfoGenerator setProvider(String providerName)
+ {
+ this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
+
+ return this;
+ }
+
+ public JceKeyAgreeRecipientInfoGenerator setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ /**
+ * Add a recipient based on the passed in certificate's public key and its issuer and serial number.
+ *
+ * @param recipientCert recipient's certificate
+ * @return the current instance.
+ * @throws CertificateEncodingException if the necessary data cannot be extracted from the certificate.
+ */
+ public JceKeyAgreeRecipientInfoGenerator addRecipient(X509Certificate recipientCert)
+ throws CertificateEncodingException
+ {
+ recipientIDs.add(new KeyAgreeRecipientIdentifier(CMSUtils.getIssuerAndSerialNumber(recipientCert)));
+ recipientKeys.add(recipientCert.getPublicKey());
+
+ return this;
+ }
+
+ /**
+ * Add a recipient identified by the passed in subjectKeyID and the for the passed in public key.
+ *
+ * @param subjectKeyID identifier actual recipient will use to match the private key.
+ * @param publicKey the public key for encrypting the secret key.
+ * @return the current instance.
+ * @throws CertificateEncodingException
+ */
+ public JceKeyAgreeRecipientInfoGenerator addRecipient(byte[] subjectKeyID, PublicKey publicKey)
+ throws CertificateEncodingException
+ {
+ recipientIDs.add(new KeyAgreeRecipientIdentifier(new RecipientKeyIdentifier(subjectKeyID)));
+ recipientKeys.add(publicKey);
+
+ return this;
+ }
+
+ public ASN1Sequence generateRecipientEncryptedKeys(AlgorithmIdentifier keyAgreeAlgorithm, AlgorithmIdentifier keyEncryptionAlgorithm, GenericKey contentEncryptionKey)
+ throws CMSException
+ {
+ init(keyAgreeAlgorithm.getAlgorithm());
+
+ PrivateKey senderPrivateKey = this.senderPrivateKey;
+
+ ASN1ObjectIdentifier keyAgreementOID = keyAgreeAlgorithm.getAlgorithm();
+
+ if (keyAgreementOID.getId().equals(CMSEnvelopedGenerator.ECMQV_SHA1KDF))
+ {
+ senderPrivateKey = new MQVPrivateKeySpec(
+ senderPrivateKey, ephemeralKP.getPrivate(), ephemeralKP.getPublic());
+ }
+
+ ASN1EncodableVector recipientEncryptedKeys = new ASN1EncodableVector();
+ for (int i = 0; i != recipientIDs.size(); i++)
+ {
+ PublicKey recipientPublicKey = (PublicKey)recipientKeys.get(i);
+ KeyAgreeRecipientIdentifier karId = (KeyAgreeRecipientIdentifier)recipientIDs.get(i);
+
+ if (keyAgreementOID.getId().equals(CMSEnvelopedGenerator.ECMQV_SHA1KDF))
+ {
+ recipientPublicKey = new MQVPublicKeySpec(recipientPublicKey, recipientPublicKey);
+ }
+
+ try
+ {
+ // Use key agreement to choose a wrap key for this recipient
+ KeyAgreement keyAgreement = helper.createKeyAgreement(keyAgreementOID);
+ keyAgreement.init(senderPrivateKey, random);
+ keyAgreement.doPhase(recipientPublicKey, true);
+ SecretKey keyEncryptionKey = keyAgreement.generateSecret(keyEncryptionAlgorithm.getAlgorithm().getId());
+
+ // Wrap the content encryption key with the agreement key
+ Cipher keyEncryptionCipher = helper.createCipher(keyEncryptionAlgorithm.getAlgorithm());
+
+ keyEncryptionCipher.init(Cipher.WRAP_MODE, keyEncryptionKey, random);
+
+ byte[] encryptedKeyBytes = keyEncryptionCipher.wrap(helper.getJceKey(contentEncryptionKey));
+
+ ASN1OctetString encryptedKey = new DEROctetString(encryptedKeyBytes);
+
+ recipientEncryptedKeys.add(new RecipientEncryptedKey(karId, encryptedKey));
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("cannot perform agreement step: " + e.getMessage(), e);
+ }
+ }
+
+ return new DERSequence(recipientEncryptedKeys);
+ }
+
+ protected ASN1Encodable getUserKeyingMaterial(AlgorithmIdentifier keyAgreeAlg)
+ throws CMSException
+ {
+ init(keyAgreeAlg.getAlgorithm());
+
+ if (ephemeralKP != null)
+ {
+ return new MQVuserKeyingMaterial(
+ createOriginatorPublicKey(SubjectPublicKeyInfo.getInstance(ephemeralKP.getPublic().getEncoded())), null);
+ }
+
+ return null;
+ }
+
+ private void init(ASN1ObjectIdentifier keyAgreementOID)
+ throws CMSException
+ {
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ if (keyAgreementOID.equals(CMSAlgorithm.ECMQV_SHA1KDF))
+ {
+ if (ephemeralKP == null)
+ {
+ try
+ {
+ ECParameterSpec ecParamSpec = ((ECPublicKey)senderPublicKey).getParams();
+
+ KeyPairGenerator ephemKPG = helper.createKeyPairGenerator(keyAgreementOID);
+
+ ephemKPG.initialize(ecParamSpec, random);
+
+ ephemeralKP = ephemKPG.generateKeyPair();
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new CMSException(
+ "cannot determine MQV ephemeral key pair parameters from public key: " + e);
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransAuthenticatedRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransAuthenticatedRecipient.java
new file mode 100644
index 000000000..31b383033
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransAuthenticatedRecipient.java
@@ -0,0 +1,60 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.OutputStream;
+import java.security.Key;
+import java.security.PrivateKey;
+
+import javax.crypto.Mac;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.RecipientOperator;
+import org.spongycastle.jcajce.io.MacOutputStream;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.MacCalculator;
+
+
+/**
+ * the KeyTransRecipientInformation class for a recipient who has been sent a secret
+ * key encrypted using their public key that needs to be used to
+ * extract the message.
+ */
+public class JceKeyTransAuthenticatedRecipient
+ extends JceKeyTransRecipient
+{
+ public JceKeyTransAuthenticatedRecipient(PrivateKey recipientKey)
+ {
+ super(recipientKey);
+ }
+
+ public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentMacAlgorithm, byte[] encryptedContentEncryptionKey)
+ throws CMSException
+ {
+ final Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentMacAlgorithm, encryptedContentEncryptionKey);
+
+ final Mac dataMac = contentHelper.createContentMac(secretKey, contentMacAlgorithm);
+
+ return new RecipientOperator(new MacCalculator()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return contentMacAlgorithm;
+ }
+
+ public GenericKey getKey()
+ {
+ return new GenericKey(secretKey);
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return new MacOutputStream(dataMac);
+ }
+
+ public byte[] getMac()
+ {
+ return dataMac.doFinal();
+ }
+ });
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransEnvelopedRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransEnvelopedRecipient.java
new file mode 100644
index 000000000..8ccc6bf71
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransEnvelopedRecipient.java
@@ -0,0 +1,43 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.InputStream;
+import java.security.Key;
+import java.security.PrivateKey;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.RecipientOperator;
+import org.spongycastle.operator.InputDecryptor;
+
+public class JceKeyTransEnvelopedRecipient
+ extends JceKeyTransRecipient
+{
+ public JceKeyTransEnvelopedRecipient(PrivateKey recipientKey)
+ {
+ super(recipientKey);
+ }
+
+ public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey)
+ throws CMSException
+ {
+ Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, encryptedContentEncryptionKey);
+
+ final Cipher dataCipher = contentHelper.createContentCipher(secretKey, contentEncryptionAlgorithm);
+
+ return new RecipientOperator(new InputDecryptor()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return contentEncryptionAlgorithm;
+ }
+
+ public InputStream getInputStream(InputStream dataIn)
+ {
+ return new CipherInputStream(dataIn, dataCipher);
+ }
+ });
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipient.java
new file mode 100644
index 000000000..e3939611e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipient.java
@@ -0,0 +1,156 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.KeyTransRecipient;
+import org.spongycastle.operator.OperatorException;
+import org.spongycastle.operator.jcajce.JceAsymmetricKeyUnwrapper;
+
+public abstract class JceKeyTransRecipient
+ implements KeyTransRecipient
+{
+ private PrivateKey recipientKey;
+
+ protected EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+ protected EnvelopedDataHelper contentHelper = helper;
+ protected Map extraMappings = new HashMap();
+ protected boolean validateKeySize = false;
+
+ public JceKeyTransRecipient(PrivateKey recipientKey)
+ {
+ this.recipientKey = recipientKey;
+ }
+
+ /**
+ * Set the provider to use for key recovery and content processing.
+ *
+ * @param provider provider to use.
+ * @return this recipient.
+ */
+ public JceKeyTransRecipient setProvider(Provider provider)
+ {
+ this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
+ this.contentHelper = helper;
+
+ return this;
+ }
+
+ /**
+ * Set the provider to use for key recovery and content processing.
+ *
+ * @param providerName the name of the provider to use.
+ * @return this recipient.
+ */
+ public JceKeyTransRecipient setProvider(String providerName)
+ {
+ this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
+ this.contentHelper = helper;
+
+ return this;
+ }
+
+ /**
+ * Internally algorithm ids are converted into cipher names using a lookup table. For some providers
+ * the standard lookup table won't work. Use this method to establish a specific mapping from an
+ * algorithm identifier to a specific algorithm.
+ * <p>
+ * For example:
+ * <pre>
+ * unwrapper.setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ * </pre>
+ * </p>
+ * @param algorithm OID of algorithm in recipient.
+ * @param algorithmName JCE algorithm name to use.
+ * @return the current Recipient.
+ */
+ public JceKeyTransRecipient setAlgorithmMapping(ASN1ObjectIdentifier algorithm, String algorithmName)
+ {
+ extraMappings.put(algorithm, algorithmName);
+
+ return this;
+ }
+
+ /**
+ * Set the provider to use for content processing. If providerName is null a "no provider" search will be
+ * used to satisfy getInstance calls.
+ *
+ * @param provider the provider to use.
+ * @return this recipient.
+ */
+ public JceKeyTransRecipient setContentProvider(Provider provider)
+ {
+ this.contentHelper = CMSUtils.createContentHelper(provider);
+
+ return this;
+ }
+
+ /**
+ * Set the provider to use for content processing. If providerName is null a "no provider" search will be
+ * used to satisfy getInstance calls.
+ *
+ * @param providerName the name of the provider to use.
+ * @return this recipient.
+ */
+ public JceKeyTransRecipient setContentProvider(String providerName)
+ {
+ this.contentHelper = CMSUtils.createContentHelper(providerName);
+
+ return this;
+ }
+
+ /**
+ * Set validation of retrieved key sizes against the algorithm parameters for the encrypted key where possible - default is off.
+ * <p>
+ * This setting will not have any affect if the encryption algorithm in the recipient does not specify a particular key size, or
+ * if the unwrapper is a HSM and the byte encoding of the unwrapped secret key is not available.
+ * </p>
+ * @param doValidate true if unwrapped key's should be validated against the content encryption algorithm, false otherwise.
+ * @return this recipient.
+ */
+ public JceKeyTransRecipient setKeySizeValidation(boolean doValidate)
+ {
+ this.validateKeySize = doValidate;
+
+ return this;
+ }
+
+ protected Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedEncryptionKey)
+ throws CMSException
+ {
+ JceAsymmetricKeyUnwrapper unwrapper = helper.createAsymmetricUnwrapper(keyEncryptionAlgorithm, recipientKey);
+
+ if (!extraMappings.isEmpty())
+ {
+ for (Iterator it = extraMappings.keySet().iterator(); it.hasNext();)
+ {
+ ASN1ObjectIdentifier algorithm = (ASN1ObjectIdentifier)it.next();
+
+ unwrapper.setAlgorithmMapping(algorithm, (String)extraMappings.get(algorithm));
+ }
+ }
+
+ try
+ {
+ Key key = helper.getJceKey(encryptedKeyAlgorithm.getAlgorithm(), unwrapper.generateUnwrappedKey(encryptedKeyAlgorithm, encryptedEncryptionKey));
+
+ if (validateKeySize)
+ {
+ helper.keySizeCheck(encryptedKeyAlgorithm, key);
+ }
+
+ return key;
+ }
+ catch (OperatorException e)
+ {
+ throw new CMSException("exception unwrapping key: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipientId.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipientId.java
new file mode 100644
index 000000000..62ce1feaf
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipientId.java
@@ -0,0 +1,57 @@
+package org.spongycastle.cms.jcajce;
+
+import java.math.BigInteger;
+import java.security.cert.X509Certificate;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cms.KeyTransRecipientId;
+
+public class JceKeyTransRecipientId
+ extends KeyTransRecipientId
+{
+ /**
+ * Construct a recipient id based on the issuer, serial number and subject key identifier (if present) of the passed in
+ * certificate.
+ *
+ * @param certificate certificate providing the issue and serial number and subject key identifier.
+ */
+ public JceKeyTransRecipientId(X509Certificate certificate)
+ {
+ super(convertPrincipal(certificate.getIssuerX500Principal()), certificate.getSerialNumber(), CMSUtils.getSubjectKeyId(certificate));
+ }
+
+ /**
+ * Construct a recipient id based on the provided issuer and serial number..
+ *
+ * @param issuer the issuer to use.
+ * @param serialNumber the serial number to use.
+ */
+ public JceKeyTransRecipientId(X500Principal issuer, BigInteger serialNumber)
+ {
+ super(convertPrincipal(issuer), serialNumber);
+ }
+
+ /**
+ * Construct a recipient id based on the provided issuer, serial number, and subjectKeyId..
+ *
+ * @param issuer the issuer to use.
+ * @param serialNumber the serial number to use.
+ * @param subjectKeyId the subject key ID to use.
+ */
+ public JceKeyTransRecipientId(X500Principal issuer, BigInteger serialNumber, byte[] subjectKeyId)
+ {
+ super(convertPrincipal(issuer), serialNumber, subjectKeyId);
+ }
+
+ private static X500Name convertPrincipal(X500Principal issuer)
+ {
+ if (issuer == null)
+ {
+ return null;
+ }
+
+ return X500Name.getInstance(issuer.getEncoded());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipientInfoGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipientInfoGenerator.java
new file mode 100644
index 000000000..c3cf56939
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JceKeyTransRecipientInfoGenerator.java
@@ -0,0 +1,87 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cms.IssuerAndSerialNumber;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.cms.KeyTransRecipientInfoGenerator;
+import org.spongycastle.operator.jcajce.JceAsymmetricKeyWrapper;
+
+public class JceKeyTransRecipientInfoGenerator
+ extends KeyTransRecipientInfoGenerator
+{
+ public JceKeyTransRecipientInfoGenerator(X509Certificate recipientCert)
+ throws CertificateEncodingException
+ {
+ super(new IssuerAndSerialNumber(new JcaX509CertificateHolder(recipientCert).toASN1Structure()), new JceAsymmetricKeyWrapper(recipientCert));
+ }
+
+ public JceKeyTransRecipientInfoGenerator(byte[] subjectKeyIdentifier, PublicKey publicKey)
+ {
+ super(subjectKeyIdentifier, new JceAsymmetricKeyWrapper(publicKey));
+ }
+
+ /**
+ * Create a generator overriding the algorithm type implied by the public key in the certificate passed in.
+ *
+ * @param recipientCert certificate carrying the public key.
+ * @param algorithmIdentifier the identifier and parameters for the encryption algorithm to be used.
+ */
+ public JceKeyTransRecipientInfoGenerator(X509Certificate recipientCert, AlgorithmIdentifier algorithmIdentifier)
+ throws CertificateEncodingException
+ {
+ super(new IssuerAndSerialNumber(new JcaX509CertificateHolder(recipientCert).toASN1Structure()), new JceAsymmetricKeyWrapper(algorithmIdentifier, recipientCert.getPublicKey()));
+ }
+
+ /**
+ * Create a generator overriding the algorithm type implied by the public key passed in.
+ *
+ * @param subjectKeyIdentifier the subject key identifier value to associate with the public key.
+ * @param algorithmIdentifier the identifier and parameters for the encryption algorithm to be used.
+ * @param publicKey the public key to use.
+ */
+ public JceKeyTransRecipientInfoGenerator(byte[] subjectKeyIdentifier, AlgorithmIdentifier algorithmIdentifier, PublicKey publicKey)
+ {
+ super(subjectKeyIdentifier, new JceAsymmetricKeyWrapper(algorithmIdentifier, publicKey));
+ }
+
+ public JceKeyTransRecipientInfoGenerator setProvider(String providerName)
+ {
+ ((JceAsymmetricKeyWrapper)this.wrapper).setProvider(providerName);
+
+ return this;
+ }
+
+ public JceKeyTransRecipientInfoGenerator setProvider(Provider provider)
+ {
+ ((JceAsymmetricKeyWrapper)this.wrapper).setProvider(provider);
+
+ return this;
+ }
+
+ /**
+ * Internally algorithm ids are converted into cipher names using a lookup table. For some providers
+ * the standard lookup table won't work. Use this method to establish a specific mapping from an
+ * algorithm identifier to a specific algorithm.
+ * <p>
+ * For example:
+ * <pre>
+ * unwrapper.setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ * </pre>
+ * </p>
+ * @param algorithm OID of algorithm in recipient.
+ * @param algorithmName JCE algorithm name to use.
+ * @return the current RecipientInfoGenerator.
+ */
+ public JceKeyTransRecipientInfoGenerator setAlgorithmMapping(ASN1ObjectIdentifier algorithm, String algorithmName)
+ {
+ ((JceAsymmetricKeyWrapper)this.wrapper).setAlgorithmMapping(algorithm, algorithmName);
+
+ return this;
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordAuthenticatedRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordAuthenticatedRecipient.java
new file mode 100644
index 000000000..12b8c3621
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordAuthenticatedRecipient.java
@@ -0,0 +1,54 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.OutputStream;
+import java.security.Key;
+
+import javax.crypto.Mac;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.RecipientOperator;
+import org.spongycastle.jcajce.io.MacOutputStream;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.MacCalculator;
+import org.spongycastle.operator.jcajce.JceGenericKey;
+
+public class JcePasswordAuthenticatedRecipient
+ extends JcePasswordRecipient
+{
+ public JcePasswordAuthenticatedRecipient(char[] password)
+ {
+ super(password);
+ }
+
+ public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentMacAlgorithm, byte[] derivedKey, byte[] encryptedContentEncryptionKey)
+ throws CMSException
+ {
+ final Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentMacAlgorithm, derivedKey, encryptedContentEncryptionKey);
+
+ final Mac dataMac = helper.createContentMac(secretKey, contentMacAlgorithm);
+
+ return new RecipientOperator(new MacCalculator()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return contentMacAlgorithm;
+ }
+
+ public GenericKey getKey()
+ {
+ return new JceGenericKey(contentMacAlgorithm, secretKey);
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return new MacOutputStream(dataMac);
+ }
+
+ public byte[] getMac()
+ {
+ return dataMac.doFinal();
+ }
+ });
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordEnvelopedRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordEnvelopedRecipient.java
new file mode 100644
index 000000000..e46c8ddb6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordEnvelopedRecipient.java
@@ -0,0 +1,42 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.InputStream;
+import java.security.Key;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.RecipientOperator;
+import org.spongycastle.operator.InputDecryptor;
+
+public class JcePasswordEnvelopedRecipient
+ extends JcePasswordRecipient
+{
+ public JcePasswordEnvelopedRecipient(char[] password)
+ {
+ super(password);
+ }
+
+ public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] derivedKey, byte[] encryptedContentEncryptionKey)
+ throws CMSException
+ {
+ Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, derivedKey, encryptedContentEncryptionKey);
+
+ final Cipher dataCipher = helper.createContentCipher(secretKey, contentEncryptionAlgorithm);
+
+ return new RecipientOperator(new InputDecryptor()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return contentEncryptionAlgorithm;
+ }
+
+ public InputStream getInputStream(InputStream dataOut)
+ {
+ return new CipherInputStream(dataOut, dataCipher);
+ }
+ });
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordRecipient.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordRecipient.java
new file mode 100644
index 000000000..12f3a0673
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordRecipient.java
@@ -0,0 +1,82 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.Provider;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.PasswordRecipient;
+
+/**
+ * the RecipientInfo class for a recipient who has been sent a message
+ * encrypted using a password.
+ */
+public abstract class JcePasswordRecipient
+ implements PasswordRecipient
+{
+ private int schemeID = PasswordRecipient.PKCS5_SCHEME2_UTF8;
+ protected EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+ private char[] password;
+
+ JcePasswordRecipient(
+ char[] password)
+ {
+ this.password = password;
+ }
+
+ public JcePasswordRecipient setPasswordConversionScheme(int schemeID)
+ {
+ this.schemeID = schemeID;
+
+ return this;
+ }
+
+ public JcePasswordRecipient setProvider(Provider provider)
+ {
+ this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
+
+ return this;
+ }
+
+ public JcePasswordRecipient setProvider(String providerName)
+ {
+ this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
+
+ return this;
+ }
+
+ protected Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] derivedKey, byte[] encryptedContentEncryptionKey)
+ throws CMSException
+ {
+ Cipher keyEncryptionCipher = helper.createRFC3211Wrapper(keyEncryptionAlgorithm.getAlgorithm());
+
+ try
+ {
+ IvParameterSpec ivSpec = new IvParameterSpec(ASN1OctetString.getInstance(keyEncryptionAlgorithm.getParameters()).getOctets());
+
+ keyEncryptionCipher.init(Cipher.UNWRAP_MODE, new SecretKeySpec(derivedKey, keyEncryptionCipher.getAlgorithm()), ivSpec);
+
+ return keyEncryptionCipher.unwrap(encryptedContentEncryptionKey, contentEncryptionAlgorithm.getAlgorithm().getId(), Cipher.SECRET_KEY);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("cannot process content encryption key: " + e.getMessage(), e);
+ }
+ }
+
+ public int getPasswordConversionScheme()
+ {
+ return schemeID;
+ }
+
+ public char[] getPassword()
+ {
+ return password;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordRecipientInfoGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordRecipientInfoGenerator.java
new file mode 100644
index 000000000..e96fd804f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/JcePasswordRecipientInfoGenerator.java
@@ -0,0 +1,61 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.Provider;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.PasswordRecipientInfoGenerator;
+import org.spongycastle.operator.GenericKey;
+
+public class JcePasswordRecipientInfoGenerator
+ extends PasswordRecipientInfoGenerator
+{
+ private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+
+ public JcePasswordRecipientInfoGenerator(ASN1ObjectIdentifier kekAlgorithm, char[] password)
+ {
+ super(kekAlgorithm, password);
+ }
+
+ public JcePasswordRecipientInfoGenerator setProvider(Provider provider)
+ {
+ this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
+
+ return this;
+ }
+
+ public JcePasswordRecipientInfoGenerator setProvider(String providerName)
+ {
+ this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
+
+ return this;
+ }
+
+ public byte[] generateEncryptedBytes(AlgorithmIdentifier keyEncryptionAlgorithm, byte[] derivedKey, GenericKey contentEncryptionKey)
+ throws CMSException
+ {
+ Key contentEncryptionKeySpec = helper.getJceKey(contentEncryptionKey);
+ Cipher keyEncryptionCipher = helper.createRFC3211Wrapper(keyEncryptionAlgorithm.getAlgorithm());
+
+ try
+ {
+ IvParameterSpec ivSpec = new IvParameterSpec(ASN1OctetString.getInstance(keyEncryptionAlgorithm.getParameters()).getOctets());
+
+ keyEncryptionCipher.init(Cipher.WRAP_MODE, new SecretKeySpec(derivedKey, keyEncryptionCipher.getAlgorithm()), ivSpec);
+
+ return keyEncryptionCipher.wrap(contentEncryptionKeySpec);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("cannot process content encryption key: " + e.getMessage(), e);
+ }
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/NamedJcaJceExtHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/NamedJcaJceExtHelper.java
new file mode 100644
index 000000000..ce24fe092
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/NamedJcaJceExtHelper.java
@@ -0,0 +1,31 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.PrivateKey;
+
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.operator.SymmetricKeyUnwrapper;
+import org.spongycastle.operator.jcajce.JceAsymmetricKeyUnwrapper;
+import org.spongycastle.operator.jcajce.JceSymmetricKeyUnwrapper;
+
+class NamedJcaJceExtHelper
+ extends NamedJcaJceHelper
+ implements JcaJceExtHelper
+{
+ public NamedJcaJceExtHelper(String providerName)
+ {
+ super(providerName);
+ }
+
+ public JceAsymmetricKeyUnwrapper createAsymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, PrivateKey keyEncryptionKey)
+ {
+ return new JceAsymmetricKeyUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey).setProvider(providerName);
+ }
+
+ public SymmetricKeyUnwrapper createSymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, SecretKey keyEncryptionKey)
+ {
+ return new JceSymmetricKeyUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey).setProvider(providerName);
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/ProviderJcaJceExtHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/ProviderJcaJceExtHelper.java
new file mode 100644
index 000000000..7bb3c37c1
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/ProviderJcaJceExtHelper.java
@@ -0,0 +1,32 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.PrivateKey;
+import java.security.Provider;
+
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.SymmetricKeyUnwrapper;
+import org.spongycastle.operator.jcajce.JceAsymmetricKeyUnwrapper;
+import org.spongycastle.operator.jcajce.JceSymmetricKeyUnwrapper;
+
+class ProviderJcaJceExtHelper
+ extends ProviderJcaJceHelper
+ implements JcaJceExtHelper
+{
+ public ProviderJcaJceExtHelper(Provider provider)
+ {
+ super(provider);
+ }
+
+ public JceAsymmetricKeyUnwrapper createAsymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, PrivateKey keyEncryptionKey)
+ {
+ return new JceAsymmetricKeyUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey).setProvider(provider);
+ }
+
+ public SymmetricKeyUnwrapper createSymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, SecretKey keyEncryptionKey)
+ {
+ return new JceSymmetricKeyUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey).setProvider(provider);
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/ZlibCompressor.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/ZlibCompressor.java
new file mode 100644
index 000000000..a4787f45f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/ZlibCompressor.java
@@ -0,0 +1,24 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.OutputStream;
+import java.util.zip.DeflaterOutputStream;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.OutputCompressor;
+
+public class ZlibCompressor
+ implements OutputCompressor
+{
+ private static final String ZLIB = "1.2.840.113549.1.9.16.3.8";
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return new AlgorithmIdentifier(new ASN1ObjectIdentifier(ZLIB));
+ }
+
+ public OutputStream getOutputStream(OutputStream comOut)
+ {
+ return new DeflaterOutputStream(comOut);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/ZlibExpanderProvider.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/ZlibExpanderProvider.java
new file mode 100644
index 000000000..adc012068
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cms/jcajce/ZlibExpanderProvider.java
@@ -0,0 +1,116 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.InflaterInputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.InputExpander;
+import org.spongycastle.operator.InputExpanderProvider;
+import org.spongycastle.util.io.StreamOverflowException;
+
+public class ZlibExpanderProvider
+ implements InputExpanderProvider
+{
+ private final long limit;
+
+ /**
+ * Base constructor. Create an expander which will not limit the size of any objects expanded in the stream.
+ */
+ public ZlibExpanderProvider()
+ {
+ this.limit = -1;
+ }
+
+ /**
+ * Create a provider which caps the number of expanded bytes that can be produced when the
+ * compressed stream is parsed.
+ *
+ * @param limit max number of bytes allowed in an expanded stream.
+ */
+ public ZlibExpanderProvider(long limit)
+ {
+ this.limit = limit;
+ }
+
+ public InputExpander get(final AlgorithmIdentifier algorithm)
+ {
+ return new InputExpander()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithm;
+ }
+
+ public InputStream getInputStream(InputStream comIn)
+ {
+ InputStream s = new InflaterInputStream(comIn);
+ if (limit >= 0)
+ {
+ s = new LimitedInputStream(s, limit);
+ }
+ return s;
+ }
+ };
+ }
+
+ private static class LimitedInputStream
+ extends FilterInputStream
+ {
+ private long remaining;
+
+ public LimitedInputStream(InputStream input, long limit)
+ {
+ super(input);
+
+ this.remaining = limit;
+ }
+
+ public int read()
+ throws IOException
+ {
+ // Only a single 'extra' byte will ever be read
+ if (remaining >= 0)
+ {
+ int b = super.in.read();
+ if (b < 0 || --remaining >= 0)
+ {
+ return b;
+ }
+ }
+
+ throw new StreamOverflowException("expanded byte limit exceeded");
+ }
+
+ public int read(byte[] buf, int off, int len)
+ throws IOException
+ {
+ if (len < 1)
+ {
+ // This will give correct exceptions/returns for strange lengths
+ return super.read(buf, off, len);
+ }
+
+ if (remaining < 1)
+ {
+ // Will either return EOF or throw exception
+ read();
+ return -1;
+ }
+
+ /*
+ * Limit the underlying request to 'remaining' bytes. This ensures the
+ * caller will see the full 'limit' bytes before getting an exception.
+ * Also, only one extra byte will ever be read.
+ */
+ int actualLen = (remaining > len ? len : (int)remaining);
+ int numRead = super.in.read(buf, off, actualLen);
+ if (numRead > 0)
+ {
+ remaining -= numRead;
+ }
+ return numRead;
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestBuilder.java
new file mode 100644
index 000000000..e48dd2a3c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestBuilder.java
@@ -0,0 +1,32 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.dvcs.DVCSRequestInformationBuilder;
+import org.spongycastle.asn1.dvcs.Data;
+import org.spongycastle.asn1.dvcs.ServiceType;
+
+/**
+ * Builder of CCPD requests (Certify Claim of Possession of Data).
+ */
+public class CCPDRequestBuilder
+ extends DVCSRequestBuilder
+{
+ public CCPDRequestBuilder()
+ {
+ super(new DVCSRequestInformationBuilder(ServiceType.CCPD));
+ }
+
+ /**
+ * Builds CCPD request.
+ *
+ * @param messageImprint - the message imprint to include.
+ * @return
+ * @throws DVCSException
+ */
+ public DVCSRequest build(MessageImprint messageImprint)
+ throws DVCSException
+ {
+ Data data = new Data(messageImprint.toASN1Structure());
+
+ return createDVCRequest(data);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestData.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestData.java
new file mode 100644
index 000000000..202dd774a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/CCPDRequestData.java
@@ -0,0 +1,48 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.dvcs.Data;
+
+/**
+ * Data piece of DVCRequest for CCPD service (Certify Claim of Possession of Data).
+ * It contains CCPD-specific selector interface.
+ * <p/>
+ * This objects are constructed internally,
+ * to build DVCS request to CCPD service use CCPDRequestBuilder.
+ */
+public class CCPDRequestData
+ extends DVCSRequestData
+{
+ /**
+ * Construct from corresponding ASN.1 Data structure.
+ * Note, that data should have messageImprint choice,
+ * otherwise DVCSConstructionException is thrown.
+ *
+ * @param data
+ * @throws DVCSConstructionException
+ */
+ CCPDRequestData(Data data)
+ throws DVCSConstructionException
+ {
+ super(data);
+ initDigest();
+ }
+
+ private void initDigest()
+ throws DVCSConstructionException
+ {
+ if (data.getMessageImprint() == null)
+ {
+ throw new DVCSConstructionException("DVCSRequest.data.messageImprint should be specified for CCPD service");
+ }
+ }
+
+ /**
+ * Get MessageImprint value
+ *
+ * @return
+ */
+ public MessageImprint getMessageImprint()
+ {
+ return new MessageImprint(data.getMessageImprint());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestBuilder.java
new file mode 100644
index 000000000..0b0b81890
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestBuilder.java
@@ -0,0 +1,34 @@
+package org.spongycastle.dvcs;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.dvcs.DVCSRequestInformationBuilder;
+import org.spongycastle.asn1.dvcs.Data;
+import org.spongycastle.asn1.dvcs.ServiceType;
+
+/**
+ * Builder of DVCSRequests to CPD service (Certify Possession of Data).
+ */
+public class CPDRequestBuilder
+ extends DVCSRequestBuilder
+{
+ public CPDRequestBuilder()
+ {
+ super(new DVCSRequestInformationBuilder(ServiceType.CPD));
+ }
+
+ /**
+ * Build CPD request.
+ *
+ * @param messageBytes - data to be certified
+ * @return
+ * @throws DVCSException
+ */
+ public DVCSRequest build(byte[] messageBytes)
+ throws DVCSException, IOException
+ {
+ Data data = new Data(messageBytes);
+
+ return createDVCRequest(data);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestData.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestData.java
new file mode 100644
index 000000000..a7c1f5a81
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/CPDRequestData.java
@@ -0,0 +1,40 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.dvcs.Data;
+
+/**
+ * Data piece of DVCRequest for CPD service (Certify Possession of Data).
+ * It contains CPD-specific selector interface.
+ * <p/>
+ * This objects are constructed internally,
+ * to build DVCS request to CPD service use CPDRequestBuilder.
+ */
+public class CPDRequestData
+ extends DVCSRequestData
+{
+ CPDRequestData(Data data)
+ throws DVCSConstructionException
+ {
+ super(data);
+ initMessage();
+ }
+
+ private void initMessage()
+ throws DVCSConstructionException
+ {
+ if (data.getMessage() == null)
+ {
+ throw new DVCSConstructionException("DVCSRequest.data.message should be specified for CPD service");
+ }
+ }
+
+ /**
+ * Get contained message (data to be certified).
+ *
+ * @return
+ */
+ public byte[] getMessage()
+ {
+ return data.getMessage().getOctets();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSConstructionException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSConstructionException.java
new file mode 100644
index 000000000..73e6b0dc6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSConstructionException.java
@@ -0,0 +1,20 @@
+package org.spongycastle.dvcs;
+
+/**
+ * Exception thrown when failed to initialize some DVCS-related staff.
+ */
+public class DVCSConstructionException
+ extends DVCSException
+{
+ private static final long serialVersionUID = 660035299653583980L;
+
+ public DVCSConstructionException(String message)
+ {
+ super(message);
+ }
+
+ public DVCSConstructionException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSException.java
new file mode 100644
index 000000000..5aa8f51e7
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSException.java
@@ -0,0 +1,28 @@
+package org.spongycastle.dvcs;
+
+/**
+ * General DVCSException.
+ */
+public class DVCSException
+ extends Exception
+{
+ private static final long serialVersionUID = 389345256020131488L;
+
+ private Throwable cause;
+
+ public DVCSException(String message)
+ {
+ super(message);
+ }
+
+ public DVCSException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSMessage.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSMessage.java
new file mode 100644
index 000000000..6758f3599
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSMessage.java
@@ -0,0 +1,22 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cms.ContentInfo;
+
+public abstract class DVCSMessage
+{
+ private final ContentInfo contentInfo;
+
+ protected DVCSMessage(ContentInfo contentInfo)
+ {
+ this.contentInfo = contentInfo;
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return contentInfo.getContentType();
+ }
+
+ public abstract ASN1Encodable getContent();
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSParsingException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSParsingException.java
new file mode 100644
index 000000000..e14525768
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSParsingException.java
@@ -0,0 +1,20 @@
+package org.spongycastle.dvcs;
+
+/**
+ * DVCS parsing exception - thrown when failed to parse DVCS message.
+ */
+public class DVCSParsingException
+ extends DVCSException
+{
+ private static final long serialVersionUID = -7895880961377691266L;
+
+ public DVCSParsingException(String message)
+ {
+ super(message);
+ }
+
+ public DVCSParsingException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequest.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequest.java
new file mode 100644
index 000000000..f8658ab54
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequest.java
@@ -0,0 +1,134 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.SignedData;
+import org.spongycastle.asn1.dvcs.DVCSObjectIdentifiers;
+import org.spongycastle.asn1.dvcs.ServiceType;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.cms.CMSSignedData;
+
+/**
+ * DVCRequest is general request to DVCS (RFC 3029).
+ * It represents requests for all types of services.
+ * Requests for different services differ in DVCData structure.
+ */
+public class DVCSRequest
+ extends DVCSMessage
+{
+ private org.spongycastle.asn1.dvcs.DVCSRequest asn1;
+ private DVCSRequestInfo reqInfo;
+ private DVCSRequestData data;
+
+ /**
+ * Constructs DVCRequest from CMS SignedData object.
+ *
+ * @param signedData the CMS SignedData object containing the request
+ * @throws DVCSConstructionException
+ */
+ public DVCSRequest(CMSSignedData signedData)
+ throws DVCSConstructionException
+ {
+ this(SignedData.getInstance(signedData.toASN1Structure().getContent()).getEncapContentInfo());
+ }
+
+ /**
+ * Construct a DVCS Request from a ContentInfo
+ *
+ * @param contentInfo the contentInfo representing the DVCSRequest
+ * @throws DVCSConstructionException
+ */
+ public DVCSRequest(ContentInfo contentInfo)
+ throws DVCSConstructionException
+ {
+ super(contentInfo);
+
+ if (!DVCSObjectIdentifiers.id_ct_DVCSRequestData.equals(contentInfo.getContentType()))
+ {
+ throw new DVCSConstructionException("ContentInfo not a DVCS Request");
+ }
+
+ try
+ {
+ if (contentInfo.getContent().toASN1Primitive() instanceof ASN1Sequence)
+ {
+ this.asn1 = org.spongycastle.asn1.dvcs.DVCSRequest.getInstance(contentInfo.getContent());
+ }
+ else
+ {
+ this.asn1 = org.spongycastle.asn1.dvcs.DVCSRequest.getInstance(ASN1OctetString.getInstance(contentInfo.getContent()).getOctets());
+ }
+ }
+ catch (Exception e)
+ {
+ throw new DVCSConstructionException("Unable to parse content: " + e.getMessage(), e);
+ }
+
+ this.reqInfo = new DVCSRequestInfo(asn1.getRequestInformation());
+
+ int service = reqInfo.getServiceType();
+ if (service == ServiceType.CPD.getValue().intValue())
+ {
+ this.data = new CPDRequestData(asn1.getData());
+ }
+ else if (service == ServiceType.VSD.getValue().intValue())
+ {
+ this.data = new VSDRequestData(asn1.getData());
+ }
+ else if (service == ServiceType.VPKC.getValue().intValue())
+ {
+ this.data = new VPKCRequestData(asn1.getData());
+ }
+ else if (service == ServiceType.CCPD.getValue().intValue())
+ {
+ this.data = new CCPDRequestData(asn1.getData());
+ }
+ else
+ {
+ throw new DVCSConstructionException("Unknown service type: " + service);
+ }
+ }
+
+ /**
+ * Return the ASN.1 DVCSRequest structure making up the body of this request.
+ *
+ * @return an org.spongycastle.asn1.dvcs.DVCSRequest object.
+ */
+ public ASN1Encodable getContent()
+ {
+ return asn1;
+ }
+
+ /**
+ * Get RequestInformation envelope.
+ *
+ * @return the request info object.
+ */
+ public DVCSRequestInfo getRequestInfo()
+ {
+ return reqInfo;
+ }
+
+ /**
+ * Get data of DVCRequest.
+ * Depending on type of the request it could be different subclasses of DVCRequestData.
+ *
+ * @return the request Data object.
+ */
+ public DVCSRequestData getData()
+ {
+ return data;
+ }
+
+ /**
+ * Get the transaction identifier of request.
+ *
+ * @return the GeneralName representing the Transaction Identifier.
+ */
+ public GeneralName getTransactionIdentifier()
+ {
+ return asn1.getTransactionIdentifier();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestBuilder.java
new file mode 100644
index 000000000..f1982b91f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestBuilder.java
@@ -0,0 +1,131 @@
+package org.spongycastle.dvcs;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.dvcs.DVCSObjectIdentifiers;
+import org.spongycastle.asn1.dvcs.DVCSRequestInformationBuilder;
+import org.spongycastle.asn1.dvcs.Data;
+import org.spongycastle.asn1.x509.ExtensionsGenerator;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.cms.CMSSignedDataGenerator;
+
+/**
+ * Common base class for client DVCRequest builders.
+ * This class aims at DVCSRequestInformation and TransactionIdentifier construction,
+ * and its subclasses - for Data field construction (as it is specific for the requested service).
+ */
+public abstract class DVCSRequestBuilder
+{
+ private final ExtensionsGenerator extGenerator = new ExtensionsGenerator();
+ private final CMSSignedDataGenerator signedDataGen = new CMSSignedDataGenerator();
+
+ protected final DVCSRequestInformationBuilder requestInformationBuilder;
+
+ protected DVCSRequestBuilder(DVCSRequestInformationBuilder requestInformationBuilder)
+ {
+ this.requestInformationBuilder = requestInformationBuilder;
+ }
+
+ /**
+ * Set a nonce for this request,
+ *
+ * @param nonce
+ */
+ public void setNonce(BigInteger nonce)
+ {
+ requestInformationBuilder.setNonce(nonce);
+ }
+
+ /**
+ * Set requester name.
+ *
+ * @param requester
+ */
+ public void setRequester(GeneralName requester)
+ {
+ requestInformationBuilder.setRequester(requester);
+ }
+
+ /**
+ * Set DVCS name to generated requests.
+ *
+ * @param dvcs
+ */
+ public void setDVCS(GeneralName dvcs)
+ {
+ requestInformationBuilder.setDVCS(dvcs);
+ }
+
+ /**
+ * Set DVCS name to generated requests.
+ *
+ * @param dvcs
+ */
+ public void setDVCS(GeneralNames dvcs)
+ {
+ requestInformationBuilder.setDVCS(dvcs);
+ }
+
+ /**
+ * Set data location to generated requests.
+ *
+ * @param dataLocation
+ */
+ public void setDataLocations(GeneralName dataLocation)
+ {
+ requestInformationBuilder.setDataLocations(dataLocation);
+ }
+
+ /**
+ * Set data location to generated requests.
+ *
+ * @param dataLocations
+ */
+ public void setDataLocations(GeneralNames dataLocations)
+ {
+ requestInformationBuilder.setDataLocations(dataLocations);
+ }
+
+ /**
+ * Add a given extension field.
+ *
+ * @param oid the OID defining the extension type.
+ * @param isCritical true if the extension is critical, false otherwise.
+ * @param value the ASN.1 structure that forms the extension's value.
+ * @return this builder object.
+ * @throws DVCSException if there is an issue encoding the extension for adding.
+ */
+ public void addExtension(
+ ASN1ObjectIdentifier oid,
+ boolean isCritical,
+ ASN1Encodable value)
+ throws DVCSException
+ {
+ try
+ {
+ extGenerator.addExtension(oid, isCritical, value);
+ }
+ catch (IOException e)
+ {
+ throw new DVCSException("cannot encode extension: " + e.getMessage(), e);
+ }
+ }
+
+ protected DVCSRequest createDVCRequest(Data data)
+ throws DVCSException
+ {
+ if (!extGenerator.isEmpty())
+ {
+ requestInformationBuilder.setExtensions(extGenerator.generate());
+ }
+
+ org.spongycastle.asn1.dvcs.DVCSRequest request = new org.spongycastle.asn1.dvcs.DVCSRequest(requestInformationBuilder.build(), data);
+
+ return new DVCSRequest(new ContentInfo(DVCSObjectIdentifiers.id_ct_DVCSRequestData, request));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestData.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestData.java
new file mode 100644
index 000000000..35cdd325e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestData.java
@@ -0,0 +1,38 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.dvcs.Data;
+
+/**
+ * Data piece of DVCRequest object (DVCS Data structure).
+ * Its contents depend on the service type.
+ * Its subclasses define the service-specific interface.
+ * <p/>
+ * The concrete objects of DVCRequestData are created by buildDVCRequestData static method.
+ */
+public abstract class DVCSRequestData
+{
+ /**
+ * The underlying data object is accessible by subclasses.
+ */
+ protected Data data;
+
+ /**
+ * The constructor is accessible by subclasses.
+ *
+ * @param data
+ */
+ protected DVCSRequestData(Data data)
+ {
+ this.data = data;
+ }
+
+ /**
+ * Convert to ASN.1 structure (Data).
+ *
+ * @return
+ */
+ public Data toASN1Structure()
+ {
+ return data;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestInfo.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestInfo.java
new file mode 100644
index 000000000..1f51e3e69
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSRequestInfo.java
@@ -0,0 +1,237 @@
+package org.spongycastle.dvcs;
+
+import java.math.BigInteger;
+import java.util.Date;
+
+import org.spongycastle.asn1.dvcs.DVCSRequestInformation;
+import org.spongycastle.asn1.dvcs.DVCSTime;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.PolicyInformation;
+import org.spongycastle.tsp.TimeStampToken;
+import org.spongycastle.util.Arrays;
+
+/**
+ * Information piece of DVCS requests.
+ * It is common for all types of DVCS requests.
+ */
+public class DVCSRequestInfo
+{
+ private DVCSRequestInformation data;
+
+ /**
+ * Constructs DVCRequestInfo from byte array (DER encoded DVCSRequestInformation).
+ *
+ * @param in
+ */
+ public DVCSRequestInfo(byte[] in)
+ {
+ this(DVCSRequestInformation.getInstance(in));
+ }
+
+ /**
+ * Constructs DVCRequestInfo from DVCSRequestInformation ASN.1 structure.
+ *
+ * @param data
+ */
+ public DVCSRequestInfo(DVCSRequestInformation data)
+ {
+ this.data = data;
+ }
+
+ /**
+ * Converts to corresponding ASN.1 structure (DVCSRequestInformation).
+ *
+ * @return
+ */
+ public DVCSRequestInformation toASN1Structure()
+ {
+ return data;
+ }
+
+ //
+ // DVCRequestInfo selector interface
+ //
+
+ /**
+ * Get DVCS version of request.
+ *
+ * @return
+ */
+ public int getVersion()
+ {
+ return data.getVersion();
+ }
+
+ /**
+ * Get requested service type.
+ *
+ * @return one of CPD, VSD, VPKC, CCPD (see constants).
+ */
+ public int getServiceType()
+ {
+ return data.getService().getValue().intValue();
+ }
+
+ /**
+ * Get nonce if it is set.
+ * Note: this field can be set (if not present) or extended (if present) by DVCS.
+ *
+ * @return nonce value, or null if it is not set.
+ */
+ public BigInteger getNonce()
+ {
+ return data.getNonce();
+ }
+
+ /**
+ * Get request generation time if it is set.
+ *
+ * @return time of request, or null if it is not set.
+ * @throws DVCSParsingException if a request time is present but cannot be extracted.
+ */
+ public Date getRequestTime()
+ throws DVCSParsingException
+ {
+ DVCSTime time = data.getRequestTime();
+
+ if (time == null)
+ {
+ return null;
+ }
+
+ try
+ {
+ if (time.getGenTime() != null)
+ {
+ return time.getGenTime().getDate();
+ }
+ else
+ {
+ TimeStampToken token = new TimeStampToken(time.getTimeStampToken());
+
+ return token.getTimeStampInfo().getGenTime();
+ }
+ }
+ catch (Exception e)
+ {
+ throw new DVCSParsingException("unable to extract time: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Get names of requesting entity, if set.
+ *
+ * @return
+ */
+ public GeneralNames getRequester()
+ {
+ return data.getRequester();
+ }
+
+ /**
+ * Get policy, under which the validation is requested.
+ *
+ * @return policy identifier or null, if any policy is acceptable.
+ */
+ public PolicyInformation getRequestPolicy()
+ {
+ if (data.getRequestPolicy() != null)
+ {
+ return data.getRequestPolicy();
+ }
+ return null;
+ }
+
+ /**
+ * Get names of DVCS servers.
+ * Note: this field can be set by DVCS.
+ *
+ * @return
+ */
+ public GeneralNames getDVCSNames()
+ {
+ return data.getDVCS();
+ }
+
+ /**
+ * Get data locations, where the copy of request Data can be obtained.
+ * Note: the exact meaning of field is up to applications.
+ * Note: this field can be set by DVCS.
+ *
+ * @return
+ */
+ public GeneralNames getDataLocations()
+ {
+ return data.getDataLocations();
+ }
+
+ /**
+ * Compares two DVCRequestInfo structures: one from DVCRequest, and one from DVCResponse.
+ * This function implements RFC 3029, 9.1 checks of reqInfo.
+ *
+ * @param requestInfo - DVCRequestInfo of DVCRequest
+ * @param responseInfo - DVCRequestInfo of DVCResponse
+ * @return true if server's requestInfo matches client's requestInfo
+ */
+ public static boolean validate(DVCSRequestInfo requestInfo, DVCSRequestInfo responseInfo)
+ {
+ // RFC 3029, 9.1
+ // The DVCS MAY modify the fields:
+ // 'dvcs', 'requester', 'dataLocations', and 'nonce' of the ReqInfo structure.
+
+ DVCSRequestInformation clientInfo = requestInfo.data;
+ DVCSRequestInformation serverInfo = responseInfo.data;
+
+ if (clientInfo.getVersion() != serverInfo.getVersion())
+ {
+ return false;
+ }
+ if (!clientEqualsServer(clientInfo.getService(), serverInfo.getService()))
+ {
+ return false;
+ }
+ if (!clientEqualsServer(clientInfo.getRequestTime(), serverInfo.getRequestTime()))
+ {
+ return false;
+ }
+ if (!clientEqualsServer(clientInfo.getRequestPolicy(), serverInfo.getRequestPolicy()))
+ {
+ return false;
+ }
+ if (!clientEqualsServer(clientInfo.getExtensions(), serverInfo.getExtensions()))
+ {
+ return false;
+ }
+
+ // RFC 3029, 9.1. The only modification allowed to a 'nonce'
+ // is the inclusion of a new field if it was not present,
+ // or to concatenate other data to the end (right) of an existing value.
+
+ if (clientInfo.getNonce() != null)
+ {
+ if (serverInfo.getNonce() == null)
+ {
+ return false;
+ }
+ byte[] clientNonce = clientInfo.getNonce().toByteArray();
+ byte[] serverNonce = serverInfo.getNonce().toByteArray();
+ if (serverNonce.length < clientNonce.length)
+ {
+ return false;
+ }
+ if (!Arrays.areEqual(clientNonce, Arrays.copyOfRange(serverNonce, 0, clientNonce.length)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ // null-protected compare of any two objects
+ private static boolean clientEqualsServer(Object client, Object server)
+ {
+ return (client == null && server == null) || (client != null && client.equals(server));
+ }
+}
+
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSResponse.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSResponse.java
new file mode 100644
index 000000000..f71855195
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/DVCSResponse.java
@@ -0,0 +1,74 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.SignedData;
+import org.spongycastle.asn1.dvcs.DVCSObjectIdentifiers;
+import org.spongycastle.cms.CMSSignedData;
+
+/**
+ * DVCResponse is general response to DVCS (RFC 3029).
+ * It represents responses for all types of services.
+ */
+public class DVCSResponse
+ extends DVCSMessage
+{
+ private org.spongycastle.asn1.dvcs.DVCSResponse asn1;
+
+ /**
+ * Constructs DVCRequest from CMS SignedData object.
+ *
+ * @param signedData the CMS SignedData object containing the request
+ * @throws org.spongycastle.dvcs.DVCSConstructionException
+ */
+ public DVCSResponse(CMSSignedData signedData)
+ throws DVCSConstructionException
+ {
+ this(SignedData.getInstance(signedData.toASN1Structure().getContent()).getEncapContentInfo());
+ }
+
+ /**
+ * Construct a DVCS Request from a ContentInfo
+ *
+ * @param contentInfo the contentInfo representing the DVCSRequest
+ * @throws org.spongycastle.dvcs.DVCSConstructionException
+ */
+ public DVCSResponse(ContentInfo contentInfo)
+ throws DVCSConstructionException
+ {
+ super(contentInfo);
+
+ if (!DVCSObjectIdentifiers.id_ct_DVCSResponseData.equals(contentInfo.getContentType()))
+ {
+ throw new DVCSConstructionException("ContentInfo not a DVCS Request");
+ }
+
+ try
+ {
+ if (contentInfo.getContent().toASN1Primitive() instanceof ASN1Sequence)
+ {
+ this.asn1 = org.spongycastle.asn1.dvcs.DVCSResponse.getInstance(contentInfo.getContent());
+ }
+ else
+ {
+ this.asn1 = org.spongycastle.asn1.dvcs.DVCSResponse.getInstance(ASN1OctetString.getInstance(contentInfo.getContent()).getOctets());
+ }
+ }
+ catch (Exception e)
+ {
+ throw new DVCSConstructionException("Unable to parse content: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Return the ASN.1 DVCSResponse structure making up the body of this response.
+ *
+ * @return an org.spongycastle.asn1.dvcs.DVCSResponse object.
+ */
+ public ASN1Encodable getContent()
+ {
+ return asn1;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/MessageImprint.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/MessageImprint.java
new file mode 100644
index 000000000..c9793880b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/MessageImprint.java
@@ -0,0 +1,38 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.x509.DigestInfo;
+
+public class MessageImprint
+{
+ private final DigestInfo messageImprint;
+
+ public MessageImprint(DigestInfo messageImprint)
+ {
+ this.messageImprint = messageImprint;
+ }
+
+ public DigestInfo toASN1Structure()
+ {
+ return messageImprint;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (o instanceof MessageImprint)
+ {
+ return messageImprint.equals(((MessageImprint)o).messageImprint);
+ }
+
+ return false;
+ }
+
+ public int hashCode()
+ {
+ return messageImprint.hashCode();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/MessageImprintBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/MessageImprintBuilder.java
new file mode 100644
index 000000000..f7dc987e0
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/MessageImprintBuilder.java
@@ -0,0 +1,35 @@
+package org.spongycastle.dvcs;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.x509.DigestInfo;
+import org.spongycastle.operator.DigestCalculator;
+
+public class MessageImprintBuilder
+{
+ private final DigestCalculator digestCalculator;
+
+ public MessageImprintBuilder(DigestCalculator digestCalculator)
+ {
+ this.digestCalculator = digestCalculator;
+ }
+
+ public MessageImprint build(byte[] message)
+ throws DVCSException
+ {
+ try
+ {
+ OutputStream dOut = digestCalculator.getOutputStream();
+
+ dOut.write(message);
+
+ dOut.close();
+
+ return new MessageImprint(new DigestInfo(digestCalculator.getAlgorithmIdentifier(), digestCalculator.getDigest()));
+ }
+ catch (Exception e)
+ {
+ throw new DVCSException("unable to build MessageImprint: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/SignedDVCSMessageGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/SignedDVCSMessageGenerator.java
new file mode 100644
index 000000000..2378bcf2d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/SignedDVCSMessageGenerator.java
@@ -0,0 +1,45 @@
+package org.spongycastle.dvcs;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.CMSSignedData;
+import org.spongycastle.cms.CMSSignedDataGenerator;
+
+public class SignedDVCSMessageGenerator
+{
+ private final CMSSignedDataGenerator signedDataGen;
+
+ public SignedDVCSMessageGenerator(CMSSignedDataGenerator signedDataGen)
+ {
+ this.signedDataGen = signedDataGen;
+ }
+
+ /**
+ * Creates a CMSSignedData object containing the passed in DVCSMessage
+ *
+ * @param message the request to be signed.
+ * @return an encapsulating SignedData object.
+ * @throws DVCSException in the event of failure to encode the request or sign it.
+ */
+ public CMSSignedData build(DVCSMessage message)
+ throws DVCSException
+ {
+ try
+ {
+ byte[] encapsulatedData = message.getContent().toASN1Primitive().getEncoded(ASN1Encoding.DER);
+
+ return signedDataGen.generate(new CMSProcessableByteArray(message.getContentType(), encapsulatedData), true);
+ }
+ catch (CMSException e)
+ {
+ throw new DVCSException("Could not sign DVCS request", e);
+ }
+ catch (IOException e)
+ {
+ throw new DVCSException("Could not encode DVCS request", e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/TargetChain.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/TargetChain.java
new file mode 100644
index 000000000..d45714f32
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/TargetChain.java
@@ -0,0 +1,18 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.dvcs.TargetEtcChain;
+
+public class TargetChain
+{
+ private final TargetEtcChain certs;
+
+ public TargetChain(TargetEtcChain certs)
+ {
+ this.certs = certs;
+ }
+
+ public TargetEtcChain toASN1Structure()
+ {
+ return certs;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestBuilder.java
new file mode 100644
index 000000000..9a68b7d3b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestBuilder.java
@@ -0,0 +1,76 @@
+package org.spongycastle.dvcs;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.spongycastle.asn1.dvcs.CertEtcToken;
+import org.spongycastle.asn1.dvcs.DVCSRequestInformationBuilder;
+import org.spongycastle.asn1.dvcs.DVCSTime;
+import org.spongycastle.asn1.dvcs.Data;
+import org.spongycastle.asn1.dvcs.ServiceType;
+import org.spongycastle.asn1.dvcs.TargetEtcChain;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.cert.X509CertificateHolder;
+
+/**
+ * Builder of DVC requests to VPKC service (Verify Public Key Certificates).
+ */
+public class VPKCRequestBuilder
+ extends DVCSRequestBuilder
+{
+ private List chains = new ArrayList();
+
+ public VPKCRequestBuilder()
+ {
+ super(new DVCSRequestInformationBuilder(ServiceType.VPKC));
+ }
+
+ /**
+ * Adds a TargetChain representing a X.509 certificate to the request.
+ *
+ * @param cert the certificate to be added
+ */
+ public void addTargetChain(X509CertificateHolder cert)
+ {
+ chains.add(new TargetEtcChain(new CertEtcToken(CertEtcToken.TAG_CERTIFICATE, cert.toASN1Structure())));
+ }
+
+ /**
+ * Adds a TargetChain representing a single X.509 Extension to the request
+ *
+ * @param extension the extension to be added.
+ */
+ public void addTargetChain(Extension extension)
+ {
+ chains.add(new TargetEtcChain(new CertEtcToken(extension)));
+ }
+
+ /**
+ * Adds a X.509 certificate to the request.
+ *
+ * @param targetChain the CertChain object to be added.
+ */
+ public void addTargetChain(TargetChain targetChain)
+ {
+ chains.add(targetChain.toASN1Structure());
+ }
+
+ public void setRequestTime(Date requestTime)
+ {
+ requestInformationBuilder.setRequestTime(new DVCSTime(requestTime));
+ }
+
+ /**
+ * Build DVCS request to VPKC service.
+ *
+ * @throws DVCSException
+ */
+ public DVCSRequest build()
+ throws DVCSException
+ {
+ Data data = new Data((TargetEtcChain[])chains.toArray(new TargetEtcChain[chains.size()]));
+
+ return createDVCRequest(data);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestData.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestData.java
new file mode 100644
index 000000000..561f93bfd
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/VPKCRequestData.java
@@ -0,0 +1,51 @@
+package org.spongycastle.dvcs;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.spongycastle.asn1.dvcs.Data;
+import org.spongycastle.asn1.dvcs.TargetEtcChain;
+
+/**
+ * Data piece of DVCS request to VPKC service (Verify Public Key Certificates).
+ * It contains VPKC-specific interface.
+ * <p/>
+ * This objects are constructed internally,
+ * to build DVCS request to VPKC service use VPKCRequestBuilder.
+ */
+public class VPKCRequestData
+ extends DVCSRequestData
+{
+ private List chains;
+
+ VPKCRequestData(Data data)
+ throws DVCSConstructionException
+ {
+ super(data);
+
+ TargetEtcChain[] certs = data.getCerts();
+
+ if (certs == null)
+ {
+ throw new DVCSConstructionException("DVCSRequest.data.certs should be specified for VPKC service");
+ }
+
+ chains = new ArrayList(certs.length);
+
+ for (int i = 0; i != certs.length; i++)
+ {
+ chains.add(new TargetChain(certs[i]));
+ }
+ }
+
+ /**
+ * Get contained certs choice data..
+ *
+ * @return a list of CertChain objects.
+ */
+ public List getCerts()
+ {
+ return Collections.unmodifiableList(chains);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestBuilder.java
new file mode 100644
index 000000000..f2f7df54e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestBuilder.java
@@ -0,0 +1,49 @@
+package org.spongycastle.dvcs;
+
+import java.io.IOException;
+import java.util.Date;
+
+import org.spongycastle.asn1.dvcs.DVCSRequestInformationBuilder;
+import org.spongycastle.asn1.dvcs.DVCSTime;
+import org.spongycastle.asn1.dvcs.Data;
+import org.spongycastle.asn1.dvcs.ServiceType;
+import org.spongycastle.cms.CMSSignedData;
+
+/**
+ * Builder of DVCS requests to VSD service (Verify Signed Document).
+ */
+public class VSDRequestBuilder
+ extends DVCSRequestBuilder
+{
+ public VSDRequestBuilder()
+ {
+ super(new DVCSRequestInformationBuilder(ServiceType.VSD));
+ }
+
+ public void setRequestTime(Date requestTime)
+ {
+ requestInformationBuilder.setRequestTime(new DVCSTime(requestTime));
+ }
+
+ /**
+ * Build VSD request from CMS SignedData object.
+ *
+ * @param document
+ * @return
+ * @throws DVCSException
+ */
+ public DVCSRequest build(CMSSignedData document)
+ throws DVCSException
+ {
+ try
+ {
+ Data data = new Data(document.getEncoded());
+
+ return createDVCRequest(data);
+ }
+ catch (IOException e)
+ {
+ throw new DVCSException("Failed to encode CMS signed data", e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestData.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestData.java
new file mode 100644
index 000000000..21adaa3f4
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/dvcs/VSDRequestData.java
@@ -0,0 +1,66 @@
+package org.spongycastle.dvcs;
+
+import org.spongycastle.asn1.dvcs.Data;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.CMSSignedData;
+
+/**
+ * Data piece of DVCS request to VSD service (Verify Signed Document).
+ * It contains VSD-specific selector interface.
+ * Note: the request should contain CMS SignedData object as message.
+ * <p/>
+ * This objects are constructed internally,
+ * to build DVCS request to VSD service use VSDRequestBuilder.
+ */
+public class VSDRequestData
+ extends DVCSRequestData
+{
+ private CMSSignedData doc;
+
+ VSDRequestData(Data data)
+ throws DVCSConstructionException
+ {
+ super(data);
+ initDocument();
+ }
+
+ private void initDocument()
+ throws DVCSConstructionException
+ {
+ if (doc == null)
+ {
+ if (data.getMessage() == null)
+ {
+ throw new DVCSConstructionException("DVCSRequest.data.message should be specified for VSD service");
+ }
+ try
+ {
+ doc = new CMSSignedData(data.getMessage().getOctets());
+ }
+ catch (CMSException e)
+ {
+ throw new DVCSConstructionException("Can't read CMS SignedData from input", e);
+ }
+ }
+ }
+
+ /**
+ * Get contained message (data to be certified).
+ *
+ * @return
+ */
+ public byte[] getMessage()
+ {
+ return data.getMessage().getOctets();
+ }
+
+ /**
+ * Get the CMS SignedData object represented by the encoded message.
+ *
+ * @return
+ */
+ public CMSSignedData getParsedMessage()
+ {
+ return doc;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACCertificateBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACCertificateBuilder.java
new file mode 100644
index 000000000..b3ca48e8c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACCertificateBuilder.java
@@ -0,0 +1,83 @@
+package org.spongycastle.eac;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.DERApplicationSpecific;
+import org.spongycastle.asn1.eac.CVCertificate;
+import org.spongycastle.asn1.eac.CertificateBody;
+import org.spongycastle.asn1.eac.CertificateHolderAuthorization;
+import org.spongycastle.asn1.eac.CertificateHolderReference;
+import org.spongycastle.asn1.eac.CertificationAuthorityReference;
+import org.spongycastle.asn1.eac.EACTags;
+import org.spongycastle.asn1.eac.PackedDate;
+import org.spongycastle.asn1.eac.PublicKeyDataObject;
+import org.spongycastle.eac.operator.EACSigner;
+
+public class EACCertificateBuilder
+{
+ private static final byte [] ZeroArray = new byte [] {0};
+
+ private PublicKeyDataObject publicKey;
+ private CertificateHolderAuthorization certificateHolderAuthorization;
+ private PackedDate certificateEffectiveDate;
+ private PackedDate certificateExpirationDate;
+ private CertificateHolderReference certificateHolderReference;
+ private CertificationAuthorityReference certificationAuthorityReference;
+
+ public EACCertificateBuilder(
+ CertificationAuthorityReference certificationAuthorityReference,
+ PublicKeyDataObject publicKey,
+ CertificateHolderReference certificateHolderReference,
+ CertificateHolderAuthorization certificateHolderAuthorization,
+ PackedDate certificateEffectiveDate,
+ PackedDate certificateExpirationDate)
+ {
+ this.certificationAuthorityReference = certificationAuthorityReference;
+ this.publicKey = publicKey;
+ this.certificateHolderReference = certificateHolderReference;
+ this.certificateHolderAuthorization = certificateHolderAuthorization;
+ this.certificateEffectiveDate = certificateEffectiveDate;
+ this.certificateExpirationDate = certificateExpirationDate;
+ }
+
+ private CertificateBody buildBody()
+ {
+ DERApplicationSpecific certificateProfileIdentifier;
+
+ certificateProfileIdentifier = new DERApplicationSpecific(
+ EACTags.INTERCHANGE_PROFILE, ZeroArray);
+
+ CertificateBody body = new CertificateBody(
+ certificateProfileIdentifier,
+ certificationAuthorityReference,
+ publicKey,
+ certificateHolderReference,
+ certificateHolderAuthorization,
+ certificateEffectiveDate,
+ certificateExpirationDate);
+
+ return body;
+ }
+
+ public EACCertificateHolder build(EACSigner signer)
+ throws EACException
+ {
+ try
+ {
+ CertificateBody body = buildBody();
+
+ OutputStream vOut = signer.getOutputStream();
+
+ vOut.write(body.getEncoded(ASN1Encoding.DER));
+
+ vOut.close();
+
+ return new EACCertificateHolder(new CVCertificate(body, signer.getSignature()));
+ }
+ catch (Exception e)
+ {
+ throw new EACException("unable to process signature: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACCertificateHolder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACCertificateHolder.java
new file mode 100644
index 000000000..edc75a6d3
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACCertificateHolder.java
@@ -0,0 +1,88 @@
+package org.spongycastle.eac;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ParsingException;
+import org.spongycastle.asn1.eac.CVCertificate;
+import org.spongycastle.asn1.eac.PublicKeyDataObject;
+import org.spongycastle.eac.operator.EACSignatureVerifier;
+
+public class EACCertificateHolder
+{
+ private CVCertificate cvCertificate;
+
+ private static CVCertificate parseBytes(byte[] certEncoding)
+ throws IOException
+ {
+ try
+ {
+ return CVCertificate.getInstance(certEncoding);
+ }
+ catch (ClassCastException e)
+ {
+ throw new EACIOException("malformed data: " + e.getMessage(), e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new EACIOException("malformed data: " + e.getMessage(), e);
+ }
+ catch (ASN1ParsingException e)
+ {
+ if (e.getCause() instanceof IOException)
+ {
+ throw (IOException)e.getCause();
+ }
+ else
+ {
+ throw new EACIOException("malformed data: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ public EACCertificateHolder(byte[] certEncoding)
+ throws IOException
+ {
+ this(parseBytes(certEncoding));
+ }
+
+ public EACCertificateHolder(CVCertificate cvCertificate)
+ {
+ this.cvCertificate = cvCertificate;
+ }
+
+ /**
+ * Return the underlying ASN.1 structure for the certificate in this holder.
+ *
+ * @return a X509CertificateStructure object.
+ */
+ public CVCertificate toASN1Structure()
+ {
+ return cvCertificate;
+ }
+
+ public PublicKeyDataObject getPublicKeyDataObject()
+ {
+ return cvCertificate.getBody().getPublicKey();
+ }
+
+ public boolean isSignatureValid(EACSignatureVerifier verifier)
+ throws EACException
+ {
+ try
+ {
+ OutputStream vOut = verifier.getOutputStream();
+
+ vOut.write(cvCertificate.getBody().getEncoded(ASN1Encoding.DER));
+
+ vOut.close();
+
+ return verifier.verify(cvCertificate.getSignature());
+ }
+ catch (Exception e)
+ {
+ throw new EACException("unable to process signature: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACCertificateRequestHolder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACCertificateRequestHolder.java
new file mode 100644
index 000000000..77b01e4d1
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACCertificateRequestHolder.java
@@ -0,0 +1,88 @@
+package org.spongycastle.eac;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ParsingException;
+import org.spongycastle.asn1.eac.CVCertificateRequest;
+import org.spongycastle.asn1.eac.PublicKeyDataObject;
+import org.spongycastle.eac.operator.EACSignatureVerifier;
+
+public class EACCertificateRequestHolder
+{
+ private CVCertificateRequest request;
+
+ private static CVCertificateRequest parseBytes(byte[] requestEncoding)
+ throws IOException
+ {
+ try
+ {
+ return CVCertificateRequest.getInstance(requestEncoding);
+ }
+ catch (ClassCastException e)
+ {
+ throw new EACIOException("malformed data: " + e.getMessage(), e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new EACIOException("malformed data: " + e.getMessage(), e);
+ }
+ catch (ASN1ParsingException e)
+ {
+ if (e.getCause() instanceof IOException)
+ {
+ throw (IOException)e.getCause();
+ }
+ else
+ {
+ throw new EACIOException("malformed data: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ public EACCertificateRequestHolder(byte[] certEncoding)
+ throws IOException
+ {
+ this(parseBytes(certEncoding));
+ }
+
+ public EACCertificateRequestHolder(CVCertificateRequest request)
+ {
+ this.request = request;
+ }
+
+ /**
+ * Return the underlying ASN.1 structure for the certificate in this holder.
+ *
+ * @return a X509CertificateStructure object.
+ */
+ public CVCertificateRequest toASN1Structure()
+ {
+ return request;
+ }
+
+ public PublicKeyDataObject getPublicKeyDataObject()
+ {
+ return request.getPublicKey();
+ }
+
+ public boolean isInnerSignatureValid(EACSignatureVerifier verifier)
+ throws EACException
+ {
+ try
+ {
+ OutputStream vOut = verifier.getOutputStream();
+
+ vOut.write(request.getCertificateBody().getEncoded(ASN1Encoding.DER));
+
+ vOut.close();
+
+ return verifier.verify(request.getInnerSignature());
+ }
+ catch (Exception e)
+ {
+ throw new EACException("unable to process signature: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACException.java
new file mode 100644
index 000000000..d8e1612a8
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACException.java
@@ -0,0 +1,27 @@
+package org.spongycastle.eac;
+
+/**
+ * General checked Exception thrown in the cert package and its sub-packages.
+ */
+public class EACException
+ extends Exception
+{
+ private Throwable cause;
+
+ public EACException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public EACException(String msg)
+ {
+ super(msg);
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACIOException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACIOException.java
new file mode 100644
index 000000000..857a6f6a7
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/EACIOException.java
@@ -0,0 +1,29 @@
+package org.spongycastle.eac;
+
+import java.io.IOException;
+
+/**
+ * General IOException thrown in the cert package and its sub-packages.
+ */
+public class EACIOException
+ extends IOException
+{
+ private Throwable cause;
+
+ public EACIOException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public EACIOException(String msg)
+ {
+ super(msg);
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/DefaultEACHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/DefaultEACHelper.java
new file mode 100644
index 000000000..703e1405a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/DefaultEACHelper.java
@@ -0,0 +1,14 @@
+package org.spongycastle.eac.jcajce;
+
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+
+class DefaultEACHelper
+ implements EACHelper
+{
+ public KeyFactory createKeyFactory(String type)
+ throws NoSuchAlgorithmException
+ {
+ return KeyFactory.getInstance(type);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/EACHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/EACHelper.java
new file mode 100644
index 000000000..c6f3ffb27
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/EACHelper.java
@@ -0,0 +1,11 @@
+package org.spongycastle.eac.jcajce;
+
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+
+interface EACHelper
+{
+ KeyFactory createKeyFactory(String type)
+ throws NoSuchProviderException, NoSuchAlgorithmException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/JcaPublicKeyConverter.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/JcaPublicKeyConverter.java
new file mode 100644
index 000000000..9e6a7ecae
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/JcaPublicKeyConverter.java
@@ -0,0 +1,168 @@
+package org.spongycastle.eac.jcajce;
+
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECField;
+import java.security.spec.ECFieldFp;
+import java.security.spec.EllipticCurve;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPublicKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.eac.EACObjectIdentifiers;
+import org.spongycastle.asn1.eac.ECDSAPublicKey;
+import org.spongycastle.asn1.eac.PublicKeyDataObject;
+import org.spongycastle.asn1.eac.RSAPublicKey;
+import org.spongycastle.eac.EACException;
+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 JcaPublicKeyConverter
+{
+ private EACHelper helper = new DefaultEACHelper();
+
+ public JcaPublicKeyConverter setProvider(String providerName)
+ {
+ this.helper = new NamedEACHelper(providerName);
+
+ return this;
+ }
+
+ public JcaPublicKeyConverter setProvider(Provider provider)
+ {
+ this.helper = new ProviderEACHelper(provider);
+
+ return this;
+ }
+
+ public PublicKey getKey(PublicKeyDataObject publicKeyDataObject)
+ throws EACException, InvalidKeySpecException
+ {
+ if (publicKeyDataObject.getUsage().on(EACObjectIdentifiers.id_TA_ECDSA))
+ {
+ return getECPublicKeyPublicKey((ECDSAPublicKey)publicKeyDataObject);
+ }
+ else
+ {
+ RSAPublicKey pubKey = (RSAPublicKey)publicKeyDataObject;
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(pubKey.getModulus(), pubKey.getPublicExponent());
+
+ try
+ {
+ KeyFactory factk = helper.createKeyFactory("RSA");
+
+ return factk.generatePublic(pubKeySpec);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new EACException("cannot find provider: " + e.getMessage(), e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new EACException("cannot find algorithm ECDSA: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ private PublicKey getECPublicKeyPublicKey(ECDSAPublicKey key)
+ throws EACException, InvalidKeySpecException
+ {
+ ECParameterSpec spec = getParams(key);
+ ECCurve curve = spec.getCurve();
+
+ ECPoint point = curve.decodePoint(key.getPublicPointY());
+ ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, spec);
+
+ KeyFactory factk;
+ try
+ {
+ factk = helper.createKeyFactory("ECDSA");
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new EACException("cannot find provider: " + e.getMessage(), e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new EACException("cannot find algorithm ECDSA: " + e.getMessage(), e);
+ }
+
+ return factk.generatePublic(pubKeySpec);
+ }
+
+ private ECParameterSpec getParams(ECDSAPublicKey key)
+ {
+ if (!key.hasParameters())
+ {
+ throw new IllegalArgumentException("Public key does not contains EC Params");
+ }
+
+ BigInteger p = key.getPrimeModulusP();
+ ECCurve.Fp curve = new ECCurve.Fp(p, key.getFirstCoefA(), key.getSecondCoefB());
+
+ ECPoint G = curve.decodePoint(key.getBasePointG());
+
+ BigInteger order = key.getOrderOfBasePointR();
+ BigInteger coFactor = key.getCofactorF();
+ // TODO: update to use JDK 1.5 EC API
+ ECParameterSpec ecspec = new ECParameterSpec(curve, G, order, coFactor);
+
+ return ecspec;
+ }
+
+ public PublicKeyDataObject getPublicKeyDataObject(ASN1ObjectIdentifier usage, PublicKey publicKey)
+ {
+ if (publicKey instanceof java.security.interfaces.RSAPublicKey)
+ {
+ java.security.interfaces.RSAPublicKey pubKey = (java.security.interfaces.RSAPublicKey)publicKey;
+
+ return new RSAPublicKey(usage, pubKey.getModulus(), pubKey.getPublicExponent());
+ }
+ else
+ {
+ ECPublicKey pubKey = (ECPublicKey)publicKey;
+ java.security.spec.ECParameterSpec params = pubKey.getParams();
+
+ return new ECDSAPublicKey(
+ usage,
+ ((ECFieldFp)params.getCurve().getField()).getP(),
+ params.getCurve().getA(), params.getCurve().getB(),
+ convertPoint(convertCurve(params.getCurve()), params.getGenerator(), false).getEncoded(),
+ params.getOrder(),
+ convertPoint(convertCurve(params.getCurve()), pubKey.getW(), false).getEncoded(),
+ params.getCofactor());
+ }
+ }
+
+ private static org.spongycastle.math.ec.ECPoint convertPoint(
+ ECCurve curve,
+ java.security.spec.ECPoint point,
+ boolean withCompression)
+ {
+ return curve.createPoint(point.getAffineX(), point.getAffineY(), withCompression);
+ }
+
+ private 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
+ {
+ throw new IllegalStateException("not implemented yet!!!");
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/NamedEACHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/NamedEACHelper.java
new file mode 100644
index 000000000..7e85142d4
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/NamedEACHelper.java
@@ -0,0 +1,22 @@
+package org.spongycastle.eac.jcajce;
+
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+
+class NamedEACHelper
+ implements EACHelper
+{
+ private final String providerName;
+
+ NamedEACHelper(String providerName)
+ {
+ this.providerName = providerName;
+ }
+
+ public KeyFactory createKeyFactory(String type)
+ throws NoSuchProviderException, NoSuchAlgorithmException
+ {
+ return KeyFactory.getInstance(type, providerName);
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/ProviderEACHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/ProviderEACHelper.java
new file mode 100644
index 000000000..2cda60a28
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/jcajce/ProviderEACHelper.java
@@ -0,0 +1,22 @@
+package org.spongycastle.eac.jcajce;
+
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+
+class ProviderEACHelper
+ implements EACHelper
+{
+ private final Provider provider;
+
+ ProviderEACHelper(Provider provider)
+ {
+ this.provider = provider;
+ }
+
+ public KeyFactory createKeyFactory(String type)
+ throws NoSuchAlgorithmException
+ {
+ return KeyFactory.getInstance(type, provider);
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/EACSignatureVerifier.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/EACSignatureVerifier.java
new file mode 100644
index 000000000..3dd967b91
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/EACSignatureVerifier.java
@@ -0,0 +1,30 @@
+package org.spongycastle.eac.operator;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+
+public interface EACSignatureVerifier
+{
+ /**
+ * Return the usage OID specifying the signature type.
+ *
+ * @return algorithm oid.
+ */
+ ASN1ObjectIdentifier getUsageIdentifier();
+
+ /**
+ * Returns a stream that will accept data for the purpose of calculating
+ * a signature for later verification. Use org.spongycastle.util.io.TeeOutputStream if you want to accumulate
+ * the data on the fly as well.
+ *
+ * @return an OutputStream
+ */
+ OutputStream getOutputStream();
+
+ /**
+ * @param expected expected value of the signature on the data.
+ * @return true if the signature verifies, false otherwise
+ */
+ boolean verify(byte[] expected);
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/EACSigner.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/EACSigner.java
new file mode 100644
index 000000000..9a53685a2
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/EACSigner.java
@@ -0,0 +1,27 @@
+package org.spongycastle.eac.operator;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+
+public interface EACSigner
+{
+ ASN1ObjectIdentifier getUsageIdentifier();
+
+ /**
+ * Returns a stream that will accept data for the purpose of calculating
+ * a signature. Use org.spongycastle.util.io.TeeOutputStream if you want to accumulate
+ * the data on the fly as well.
+ *
+ * @return an OutputStream
+ */
+ OutputStream getOutputStream();
+
+ /**
+ * Returns a signature based on the current data written to the stream, since the
+ * start or the last call to getSignature().
+ *
+ * @return bytes representing the signature.
+ */
+ byte[] getSignature();
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/DefaultEACHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/DefaultEACHelper.java
new file mode 100644
index 000000000..3aab05859
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/DefaultEACHelper.java
@@ -0,0 +1,14 @@
+package org.spongycastle.eac.operator.jcajce;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+
+class DefaultEACHelper
+ extends EACHelper
+{
+ protected Signature createSignature(String type)
+ throws NoSuchAlgorithmException
+ {
+ return Signature.getInstance(type);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/EACHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/EACHelper.java
new file mode 100644
index 000000000..213699810
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/EACHelper.java
@@ -0,0 +1,39 @@
+package org.spongycastle.eac.operator.jcajce;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+import java.util.Hashtable;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.eac.EACObjectIdentifiers;
+
+abstract class EACHelper
+{
+ private static final Hashtable sigNames = new Hashtable();
+
+ static
+ {
+ sigNames.put(EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_1, "SHA1withRSA");
+ sigNames.put(EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_256, "SHA256withRSA");
+ sigNames.put(EACObjectIdentifiers.id_TA_RSA_PSS_SHA_1, "SHA1withRSAandMGF1");
+ sigNames.put(EACObjectIdentifiers.id_TA_RSA_PSS_SHA_256, "SHA256withRSAandMGF1");
+ sigNames.put(EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_512, "SHA512withRSA");
+ sigNames.put(EACObjectIdentifiers.id_TA_RSA_PSS_SHA_512, "SHA512withRSAandMGF1");
+
+ sigNames.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_1, "SHA1withECDSA");
+ sigNames.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224withECDSA");
+ sigNames.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_256, "SHA256withECDSA");
+ sigNames.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_384, "SHA384withECDSA");
+ sigNames.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_512, "SHA512withECDSA");
+ }
+
+ public Signature getSignature(ASN1ObjectIdentifier oid)
+ throws NoSuchProviderException, NoSuchAlgorithmException
+ {
+ return createSignature((String)sigNames.get(oid));
+ }
+
+ protected abstract Signature createSignature(String type)
+ throws NoSuchProviderException, NoSuchAlgorithmException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/EACUtil.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/EACUtil.java
new file mode 100644
index 000000000..c21178a5d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/EACUtil.java
@@ -0,0 +1,5 @@
+package org.spongycastle.eac.operator.jcajce;
+
+class EACUtil
+{
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/JcaEACSignatureVerifierBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/JcaEACSignatureVerifierBuilder.java
new file mode 100644
index 000000000..1d124cb23
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/JcaEACSignatureVerifierBuilder.java
@@ -0,0 +1,181 @@
+package org.spongycastle.eac.operator.jcajce;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.eac.EACObjectIdentifiers;
+import org.spongycastle.eac.operator.EACSignatureVerifier;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.OperatorStreamException;
+import org.spongycastle.operator.RuntimeOperatorException;
+
+public class JcaEACSignatureVerifierBuilder
+{
+ private EACHelper helper = new DefaultEACHelper();
+
+ public JcaEACSignatureVerifierBuilder setProvider(String providerName)
+ {
+ this.helper = new NamedEACHelper(providerName);
+
+ return this;
+ }
+
+ public JcaEACSignatureVerifierBuilder setProvider(Provider provider)
+ {
+ this.helper = new ProviderEACHelper(provider);
+
+ return this;
+ }
+
+ public EACSignatureVerifier build(final ASN1ObjectIdentifier usageOid, PublicKey pubKey)
+ throws OperatorCreationException
+ {
+ Signature sig;
+ try
+ {
+ sig = helper.getSignature(usageOid);
+
+ sig.initVerify(pubKey);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new OperatorCreationException("unable to find algorithm: " + e.getMessage(), e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new OperatorCreationException("unable to find provider: " + e.getMessage(), e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new OperatorCreationException("invalid key: " + e.getMessage(), e);
+ }
+
+ final SignatureOutputStream sigStream = new SignatureOutputStream(sig);
+
+ return new EACSignatureVerifier()
+ {
+ public ASN1ObjectIdentifier getUsageIdentifier()
+ {
+ return usageOid;
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return sigStream;
+ }
+
+ public boolean verify(byte[] expected)
+ {
+ try
+ {
+ if (usageOid.on(EACObjectIdentifiers.id_TA_ECDSA))
+ {
+ try
+ {
+ byte[] reencoded = derEncode(expected);
+
+ return sigStream.verify(reencoded);
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return sigStream.verify(expected);
+ }
+ }
+ catch (SignatureException e)
+ {
+ throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e);
+ }
+ }
+ };
+ }
+
+ private static byte[] derEncode(byte[] rawSign) throws IOException
+ {
+ int len = rawSign.length / 2;
+
+ byte[] r = new byte[len];
+ byte[] s = new byte[len];
+ System.arraycopy(rawSign, 0, r, 0, len);
+ System.arraycopy(rawSign, len, s, 0, len);
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ v.add(new DERInteger(new BigInteger(1, r)));
+ v.add(new DERInteger(new BigInteger(1, s)));
+
+ DERSequence seq = new DERSequence(v);
+ return seq.getEncoded();
+ }
+
+ private class SignatureOutputStream
+ extends OutputStream
+ {
+ private Signature sig;
+
+ SignatureOutputStream(Signature sig)
+ {
+ this.sig = sig;
+ }
+
+ public void write(byte[] bytes, int off, int len)
+ throws IOException
+ {
+ try
+ {
+ sig.update(bytes, off, len);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ public void write(byte[] bytes)
+ throws IOException
+ {
+ try
+ {
+ sig.update(bytes);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ try
+ {
+ sig.update((byte)b);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ boolean verify(byte[] expected)
+ throws SignatureException
+ {
+ return sig.verify(expected);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/JcaEACSignerBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/JcaEACSignerBuilder.java
new file mode 100644
index 000000000..460bb5cf1
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/JcaEACSignerBuilder.java
@@ -0,0 +1,234 @@
+package org.spongycastle.eac.operator.jcajce;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.Arrays;
+import java.util.Hashtable;
+
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.eac.EACObjectIdentifiers;
+import org.spongycastle.eac.operator.EACSigner;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.OperatorStreamException;
+import org.spongycastle.operator.RuntimeOperatorException;
+
+public class JcaEACSignerBuilder
+{
+ private static final Hashtable sigNames = new Hashtable();
+
+ static
+ {
+ sigNames.put("SHA1withRSA", EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_1);
+ sigNames.put("SHA256withRSA", EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_256);
+ sigNames.put("SHA1withRSAandMGF1", EACObjectIdentifiers.id_TA_RSA_PSS_SHA_1);
+ sigNames.put("SHA256withRSAandMGF1", EACObjectIdentifiers.id_TA_RSA_PSS_SHA_256);
+ sigNames.put("SHA512withRSA", EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_512);
+ sigNames.put("SHA512withRSAandMGF1", EACObjectIdentifiers.id_TA_RSA_PSS_SHA_512);
+
+ sigNames.put("SHA1withECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
+ sigNames.put("SHA224withECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
+ sigNames.put("SHA256withECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
+ sigNames.put("SHA384withECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_384);
+ sigNames.put("SHA512withECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_512);
+ }
+
+ private EACHelper helper = new DefaultEACHelper();
+
+ public JcaEACSignerBuilder setProvider(String providerName)
+ {
+ this.helper = new NamedEACHelper(providerName);
+
+ return this;
+ }
+
+ public JcaEACSignerBuilder setProvider(Provider provider)
+ {
+ this.helper = new ProviderEACHelper(provider);
+
+ return this;
+ }
+
+ public EACSigner build(String algorithm, PrivateKey privKey)
+ throws OperatorCreationException
+ {
+ return build((ASN1ObjectIdentifier)sigNames.get(algorithm), privKey);
+ }
+
+ public EACSigner build(final ASN1ObjectIdentifier usageOid, PrivateKey privKey)
+ throws OperatorCreationException
+ {
+ Signature sig;
+ try
+ {
+ sig = helper.getSignature(usageOid);
+
+ sig.initSign(privKey);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new OperatorCreationException("unable to find algorithm: " + e.getMessage(), e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new OperatorCreationException("unable to find provider: " + e.getMessage(), e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new OperatorCreationException("invalid key: " + e.getMessage(), e);
+ }
+
+ final SignatureOutputStream sigStream = new SignatureOutputStream(sig);
+
+ return new EACSigner()
+ {
+ public ASN1ObjectIdentifier getUsageIdentifier()
+ {
+ return usageOid;
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return sigStream;
+ }
+
+ public byte[] getSignature()
+ {
+ try
+ {
+ byte[] signature = sigStream.getSignature();
+
+ if (usageOid.on(EACObjectIdentifiers.id_TA_ECDSA))
+ {
+ return reencode(signature);
+ }
+
+ return signature;
+ }
+ catch (SignatureException e)
+ {
+ throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e);
+ }
+ }
+ };
+ }
+
+ public static int max(int el1, int el2)
+ {
+ return el1 > el2 ? el1 : el2;
+ }
+
+ private static byte[] reencode(byte[] rawSign)
+ {
+ ASN1Sequence sData = ASN1Sequence.getInstance(rawSign);
+
+ BigInteger r = ASN1Integer.getInstance(sData.getObjectAt(0)).getValue();
+ BigInteger s = ASN1Integer.getInstance(sData.getObjectAt(1)).getValue();
+
+ byte[] rB = r.toByteArray();
+ byte[] sB = s.toByteArray();
+
+ int rLen = unsignedIntLength(rB);
+ int sLen = unsignedIntLength(sB);
+
+ byte[] ret;
+ int len = max(rLen, sLen);
+
+ ret = new byte[len * 2];
+ Arrays.fill(ret, (byte)0);
+
+ copyUnsignedInt(rB, ret, len - rLen);
+ copyUnsignedInt(sB, ret, 2 * len - sLen);
+
+ return ret;
+ }
+
+ private static int unsignedIntLength(byte[] i)
+ {
+ int len = i.length;
+ if (i[0] == 0)
+ {
+ len--;
+ }
+
+ return len;
+ }
+
+ private static void copyUnsignedInt(byte[] src, byte[] dst, int offset)
+ {
+ int len = src.length;
+ int readoffset = 0;
+ if (src[0] == 0)
+ {
+ len--;
+ readoffset = 1;
+ }
+
+ System.arraycopy(src, readoffset, dst, offset, len);
+ }
+
+ private class SignatureOutputStream
+ extends OutputStream
+ {
+ private Signature sig;
+
+ SignatureOutputStream(Signature sig)
+ {
+ this.sig = sig;
+ }
+
+ public void write(byte[] bytes, int off, int len)
+ throws IOException
+ {
+ try
+ {
+ sig.update(bytes, off, len);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ public void write(byte[] bytes)
+ throws IOException
+ {
+ try
+ {
+ sig.update(bytes);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ try
+ {
+ sig.update((byte)b);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ byte[] getSignature()
+ throws SignatureException
+ {
+ return sig.sign();
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/NamedEACHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/NamedEACHelper.java
new file mode 100644
index 000000000..129356c28
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/NamedEACHelper.java
@@ -0,0 +1,22 @@
+package org.spongycastle.eac.operator.jcajce;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+
+class NamedEACHelper
+ extends EACHelper
+{
+ private final String providerName;
+
+ NamedEACHelper(String providerName)
+ {
+ this.providerName = providerName;
+ }
+
+ protected Signature createSignature(String type)
+ throws NoSuchProviderException, NoSuchAlgorithmException
+ {
+ return Signature.getInstance(type, providerName);
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/ProviderEACHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/ProviderEACHelper.java
new file mode 100644
index 000000000..e222dbdb6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/eac/operator/jcajce/ProviderEACHelper.java
@@ -0,0 +1,22 @@
+package org.spongycastle.eac.operator.jcajce;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.Signature;
+
+class ProviderEACHelper
+ extends EACHelper
+{
+ private final Provider provider;
+
+ ProviderEACHelper(Provider provider)
+ {
+ this.provider = provider;
+ }
+
+ protected Signature createSignature(String type)
+ throws NoSuchAlgorithmException
+ {
+ return Signature.getInstance(type, provider);
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/mozilla/SignedPublicKeyAndChallenge.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/mozilla/SignedPublicKeyAndChallenge.java
new file mode 100644
index 000000000..3244663a3
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/mozilla/SignedPublicKeyAndChallenge.java
@@ -0,0 +1,139 @@
+package org.spongycastle.mozilla;
+
+import java.io.ByteArrayInputStream;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.X509EncodedKeySpec;
+
+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.mozilla.PublicKeyAndChallenge;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+
+/**
+ * This is designed to parse the SignedPublicKeyAndChallenge created by the
+ * KEYGEN tag included by Mozilla based browsers.
+ * <pre>
+ * PublicKeyAndChallenge ::= SEQUENCE {
+ * spki SubjectPublicKeyInfo,
+ * challenge IA5STRING
+ * }
+ *
+ * SignedPublicKeyAndChallenge ::= SEQUENCE {
+ * publicKeyAndChallenge PublicKeyAndChallenge,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING
+ * }
+ * </pre>
+ */
+public class SignedPublicKeyAndChallenge
+ extends ASN1Object
+{
+ private static ASN1Sequence toDERSequence(byte[] bytes)
+ {
+ try
+ {
+ ByteArrayInputStream bIn = new ByteArrayInputStream(bytes);
+ ASN1InputStream aIn = new ASN1InputStream(bIn);
+
+ return (ASN1Sequence)aIn.readObject();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("badly encoded request");
+ }
+ }
+
+ private ASN1Sequence spkacSeq;
+ private PublicKeyAndChallenge pkac;
+ private AlgorithmIdentifier signatureAlgorithm;
+ private DERBitString signature;
+
+ public SignedPublicKeyAndChallenge(byte[] bytes)
+ {
+ spkacSeq = toDERSequence(bytes);
+ pkac = PublicKeyAndChallenge.getInstance(spkacSeq.getObjectAt(0));
+ signatureAlgorithm =
+ AlgorithmIdentifier.getInstance(spkacSeq.getObjectAt(1));
+ signature = (DERBitString)spkacSeq.getObjectAt(2);
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return spkacSeq;
+ }
+
+ public PublicKeyAndChallenge getPublicKeyAndChallenge()
+ {
+ return pkac;
+ }
+
+ public boolean verify()
+ throws NoSuchAlgorithmException, SignatureException,
+ NoSuchProviderException, InvalidKeyException
+ {
+ return verify(null);
+ }
+
+ public boolean verify(String provider)
+ throws NoSuchAlgorithmException, SignatureException,
+ NoSuchProviderException, InvalidKeyException
+ {
+ Signature sig = null;
+ if (provider == null)
+ {
+ sig = Signature.getInstance(signatureAlgorithm.getAlgorithm().getId());
+ }
+ else
+ {
+ sig = Signature.getInstance(signatureAlgorithm.getAlgorithm().getId(), provider);
+ }
+ PublicKey pubKey = this.getPublicKey(provider);
+ sig.initVerify(pubKey);
+ try
+ {
+ DERBitString pkBytes = new DERBitString(pkac);
+ sig.update(pkBytes.getBytes());
+
+ return sig.verify(signature.getBytes());
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("error encoding public key");
+ }
+ }
+
+ public PublicKey getPublicKey(String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException
+ {
+ SubjectPublicKeyInfo subjectPKInfo = pkac.getSubjectPublicKeyInfo();
+ try
+ {
+ DERBitString bStr = new DERBitString(subjectPKInfo);
+ X509EncodedKeySpec xspec = new X509EncodedKeySpec(bStr.getBytes());
+
+
+ AlgorithmIdentifier keyAlg = subjectPKInfo.getAlgorithm();
+
+ KeyFactory factory =
+ KeyFactory.getInstance(keyAlg.getAlgorithm().getId(),provider);
+
+ return factory.generatePublic(xspec);
+
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("error encoding public key");
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/EncryptionException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/EncryptionException.java
new file mode 100644
index 000000000..64ef73eb3
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/EncryptionException.java
@@ -0,0 +1,23 @@
+package org.spongycastle.openssl;
+
+public class EncryptionException
+ extends PEMException
+{
+ private Throwable cause;
+
+ public EncryptionException(String msg)
+ {
+ super(msg);
+ }
+
+ public EncryptionException(String msg, Throwable ex)
+ {
+ super(msg);
+ this.cause = ex;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/MiscPEMGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/MiscPEMGenerator.java
new file mode 100644
index 000000000..4f00d7aec
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/MiscPEMGenerator.java
@@ -0,0 +1,211 @@
+package org.spongycastle.openssl;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.DSAParameter;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.cert.X509CRLHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.pkcs.PKCS10CertificationRequest;
+import org.spongycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
+import org.spongycastle.util.Strings;
+import org.spongycastle.util.io.pem.PemGenerationException;
+import org.spongycastle.util.io.pem.PemHeader;
+import org.spongycastle.util.io.pem.PemObject;
+import org.spongycastle.util.io.pem.PemObjectGenerator;
+
+/**
+ * PEM generator for the original set of PEM objects used in Open SSL.
+ */
+public class MiscPEMGenerator
+ implements PemObjectGenerator
+{
+ private static final ASN1ObjectIdentifier[] dsaOids =
+ {
+ X9ObjectIdentifiers.id_dsa,
+ OIWObjectIdentifiers.dsaWithSHA1
+ };
+
+ private static final byte[] hexEncodingTable =
+ {
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
+ (byte)'8', (byte)'9', (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F'
+ };
+
+ private final Object obj;
+ private final PEMEncryptor encryptor;
+
+ public MiscPEMGenerator(Object o)
+ {
+ this.obj = o; // use of this confuses some earlier JDKs.
+ this.encryptor = null;
+ }
+
+ public MiscPEMGenerator(Object o, PEMEncryptor encryptor)
+ {
+ this.obj = o;
+ this.encryptor = encryptor;
+ }
+
+ private PemObject createPemObject(Object o)
+ throws IOException
+ {
+ String type;
+ byte[] encoding;
+
+ if (o instanceof PemObject)
+ {
+ return (PemObject)o;
+ }
+ if (o instanceof PemObjectGenerator)
+ {
+ return ((PemObjectGenerator)o).generate();
+ }
+ if (o instanceof X509CertificateHolder)
+ {
+ type = "CERTIFICATE";
+
+ encoding = ((X509CertificateHolder)o).getEncoded();
+ }
+ else if (o instanceof X509CRLHolder)
+ {
+ type = "X509 CRL";
+
+ encoding = ((X509CRLHolder)o).getEncoded();
+ }
+ else if (o instanceof PrivateKeyInfo)
+ {
+ PrivateKeyInfo info = (PrivateKeyInfo)o;
+ ASN1ObjectIdentifier algOID = info.getPrivateKeyAlgorithm().getAlgorithm();
+
+ if (algOID.equals(PKCSObjectIdentifiers.rsaEncryption))
+ {
+ type = "RSA PRIVATE KEY";
+
+ encoding = info.parsePrivateKey().toASN1Primitive().getEncoded();
+ }
+ else if (algOID.equals(dsaOids[0]) || algOID.equals(dsaOids[1]))
+ {
+ type = "DSA PRIVATE KEY";
+
+ DSAParameter p = DSAParameter.getInstance(info.getPrivateKeyAlgorithm().getParameters());
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new DERInteger(0));
+ v.add(new DERInteger(p.getP()));
+ v.add(new DERInteger(p.getQ()));
+ v.add(new DERInteger(p.getG()));
+
+ BigInteger x = ASN1Integer.getInstance(info.parsePrivateKey()).getValue();
+ BigInteger y = p.getG().modPow(x, p.getP());
+
+ v.add(new DERInteger(y));
+ v.add(new DERInteger(x));
+
+ encoding = new DERSequence(v).getEncoded();
+ }
+ else if (algOID.equals(X9ObjectIdentifiers.id_ecPublicKey))
+ {
+ type = "EC PRIVATE KEY";
+
+ encoding = info.parsePrivateKey().toASN1Primitive().getEncoded();
+ }
+ else
+ {
+ throw new IOException("Cannot identify private key");
+ }
+ }
+ else if (o instanceof SubjectPublicKeyInfo)
+ {
+ type = "PUBLIC KEY";
+
+ encoding = ((SubjectPublicKeyInfo)o).getEncoded();
+ }
+ else if (o instanceof X509AttributeCertificateHolder)
+ {
+ type = "ATTRIBUTE CERTIFICATE";
+ encoding = ((X509AttributeCertificateHolder)o).getEncoded();
+ }
+ else if (o instanceof org.spongycastle.pkcs.PKCS10CertificationRequest)
+ {
+ type = "CERTIFICATE REQUEST";
+ encoding = ((PKCS10CertificationRequest)o).getEncoded();
+ }
+ else if (o instanceof ContentInfo)
+ {
+ type = "PKCS7";
+ encoding = ((ContentInfo)o).getEncoded();
+ }
+ else
+ {
+ throw new PemGenerationException("unknown object passed - can't encode.");
+ }
+
+ if (encryptor != null)
+ {
+ String dekAlgName = Strings.toUpperCase(encryptor.getAlgorithm());
+
+ // Note: For backward compatibility
+ if (dekAlgName.equals("DESEDE"))
+ {
+ dekAlgName = "DES-EDE3-CBC";
+ }
+
+
+ byte[] iv = encryptor.getIV();
+
+ byte[] encData = encryptor.encrypt(encoding);
+
+ List headers = new ArrayList(2);
+
+ headers.add(new PemHeader("Proc-Type", "4,ENCRYPTED"));
+ headers.add(new PemHeader("DEK-Info", dekAlgName + "," + getHexEncoded(iv)));
+
+ return new PemObject(type, headers, encData);
+ }
+ return new PemObject(type, encoding);
+ }
+
+ private String getHexEncoded(byte[] bytes)
+ throws IOException
+ {
+ char[] chars = new char[bytes.length * 2];
+
+ for (int i = 0; i != bytes.length; i++)
+ {
+ int v = bytes[i] & 0xff;
+
+ chars[2 * i] = (char)(hexEncodingTable[(v >>> 4)]);
+ chars[2 * i + 1] = (char)(hexEncodingTable[v & 0xf]);
+ }
+
+ return new String(chars);
+ }
+
+ public PemObject generate()
+ throws PemGenerationException
+ {
+ try
+ {
+ return createPemObject(obj);
+ }
+ catch (IOException e)
+ {
+ throw new PemGenerationException("encoding exception: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMDecryptor.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMDecryptor.java
new file mode 100644
index 000000000..3bd54df68
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMDecryptor.java
@@ -0,0 +1,7 @@
+package org.spongycastle.openssl;
+
+public interface PEMDecryptor
+{
+ byte[] decrypt(byte[] keyBytes, byte[] iv)
+ throws PEMException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMDecryptorProvider.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMDecryptorProvider.java
new file mode 100644
index 000000000..0d0b1e5c7
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMDecryptorProvider.java
@@ -0,0 +1,9 @@
+package org.spongycastle.openssl;
+
+import org.spongycastle.operator.OperatorCreationException;
+
+public interface PEMDecryptorProvider
+{
+ PEMDecryptor get(String dekAlgName)
+ throws OperatorCreationException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMEncryptedKeyPair.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMEncryptedKeyPair.java
new file mode 100644
index 000000000..4a04de149
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMEncryptedKeyPair.java
@@ -0,0 +1,44 @@
+package org.spongycastle.openssl;
+
+import java.io.IOException;
+
+import org.spongycastle.operator.OperatorCreationException;
+
+public class PEMEncryptedKeyPair
+{
+ private final String dekAlgName;
+ private final byte[] iv;
+ private final byte[] keyBytes;
+ private final PEMKeyPairParser parser;
+
+ PEMEncryptedKeyPair(String dekAlgName, byte[] iv, byte[] keyBytes, PEMKeyPairParser parser)
+ {
+ this.dekAlgName = dekAlgName;
+ this.iv = iv;
+ this.keyBytes = keyBytes;
+ this.parser = parser;
+ }
+
+ public PEMKeyPair decryptKeyPair(PEMDecryptorProvider keyDecryptorProvider)
+ throws IOException
+ {
+ try
+ {
+ PEMDecryptor keyDecryptor = keyDecryptorProvider.get(dekAlgName);
+
+ return parser.parse(keyDecryptor.decrypt(keyBytes, iv));
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new PEMException("cannot create extraction operator: " + e.getMessage(), e);
+ }
+ catch (Exception e)
+ {
+ throw new PEMException("exception processing key pair: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMEncryptor.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMEncryptor.java
new file mode 100644
index 000000000..63b42b2dd
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMEncryptor.java
@@ -0,0 +1,11 @@
+package org.spongycastle.openssl;
+
+public interface PEMEncryptor
+{
+ String getAlgorithm();
+
+ byte[] getIV();
+
+ byte[] encrypt(byte[] encoding)
+ throws PEMException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMException.java
new file mode 100644
index 000000000..5df7b5f53
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMException.java
@@ -0,0 +1,34 @@
+package org.spongycastle.openssl;
+
+import java.io.IOException;
+
+public class PEMException
+ extends IOException
+{
+ Exception underlying;
+
+ public PEMException(
+ String message)
+ {
+ super(message);
+ }
+
+ public PEMException(
+ String message,
+ Exception underlying)
+ {
+ super(message);
+ this.underlying = underlying;
+ }
+
+ public Exception getUnderlyingException()
+ {
+ return underlying;
+ }
+
+
+ public Throwable getCause()
+ {
+ return underlying;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMKeyPair.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMKeyPair.java
new file mode 100644
index 000000000..ad0106344
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMKeyPair.java
@@ -0,0 +1,26 @@
+package org.spongycastle.openssl;
+
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+
+public class PEMKeyPair
+{
+ private final SubjectPublicKeyInfo publicKeyInfo;
+ private final PrivateKeyInfo privateKeyInfo;
+
+ public PEMKeyPair(SubjectPublicKeyInfo publicKeyInfo, PrivateKeyInfo privateKeyInfo)
+ {
+ this.publicKeyInfo = publicKeyInfo;
+ this.privateKeyInfo = privateKeyInfo;
+ }
+
+ public PrivateKeyInfo getPrivateKeyInfo()
+ {
+ return privateKeyInfo;
+ }
+
+ public SubjectPublicKeyInfo getPublicKeyInfo()
+ {
+ return publicKeyInfo;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMKeyPairParser.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMKeyPairParser.java
new file mode 100644
index 000000000..32583fd99
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMKeyPairParser.java
@@ -0,0 +1,9 @@
+package org.spongycastle.openssl;
+
+import java.io.IOException;
+
+interface PEMKeyPairParser
+{
+ PEMKeyPair parse(byte[] encoding)
+ throws IOException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMParser.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMParser.java
new file mode 100644
index 000000000..91b1cff0b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMParser.java
@@ -0,0 +1,509 @@
+package org.spongycastle.openssl;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.pkcs.RSAPublicKey;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.DSAParameter;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.cert.X509CRLHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.pkcs.PKCS10CertificationRequest;
+import org.spongycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
+import org.spongycastle.util.encoders.Hex;
+import org.spongycastle.util.io.pem.PemHeader;
+import org.spongycastle.util.io.pem.PemObject;
+import org.spongycastle.util.io.pem.PemObjectParser;
+import org.spongycastle.util.io.pem.PemReader;
+
+/**
+ * Class for parsing OpenSSL PEM encoded streams containing
+ * X509 certificates, PKCS8 encoded keys and PKCS7 objects.
+ * <p>
+ * In the case of PKCS7 objects the reader will return a CMS ContentInfo object. Public keys will be returned as
+ * well formed SubjectPublicKeyInfo objects, private keys will be returned as well formed PrivateKeyInfo objects. In the
+ * case of a private key a PEMKeyPair will normally be returned if the encoding contains both the private and public
+ * key definition. CRLs, Certificates, PKCS#10 requests, and Attribute Certificates will generate the appropriate BC holder class.
+ * </p>
+ */
+public class PEMParser
+ extends PemReader
+{
+ private final Map parsers = new HashMap();
+
+ /**
+ * Create a new PEMReader
+ *
+ * @param reader the Reader
+ */
+ public PEMParser(
+ Reader reader)
+ {
+ super(reader);
+
+ parsers.put("CERTIFICATE REQUEST", new PKCS10CertificationRequestParser());
+ parsers.put("NEW CERTIFICATE REQUEST", new PKCS10CertificationRequestParser());
+ parsers.put("CERTIFICATE", new X509CertificateParser());
+ parsers.put("X509 CERTIFICATE", new X509CertificateParser());
+ parsers.put("X509 CRL", new X509CRLParser());
+ parsers.put("PKCS7", new PKCS7Parser());
+ parsers.put("ATTRIBUTE CERTIFICATE", new X509AttributeCertificateParser());
+ parsers.put("EC PARAMETERS", new ECCurveParamsParser());
+ parsers.put("PUBLIC KEY", new PublicKeyParser());
+ parsers.put("RSA PUBLIC KEY", new RSAPublicKeyParser());
+ parsers.put("RSA PRIVATE KEY", new KeyPairParser(new RSAKeyPairParser()));
+ parsers.put("DSA PRIVATE KEY", new KeyPairParser(new DSAKeyPairParser()));
+ parsers.put("EC PRIVATE KEY", new KeyPairParser(new ECDSAKeyPairParser()));
+ parsers.put("ENCRYPTED PRIVATE KEY", new EncryptedPrivateKeyParser());
+ parsers.put("PRIVATE KEY", new PrivateKeyParser());
+ }
+
+ public Object readObject()
+ throws IOException
+ {
+ PemObject obj = readPemObject();
+
+ if (obj != null)
+ {
+ String type = obj.getType();
+ if (parsers.containsKey(type))
+ {
+ return ((PemObjectParser)parsers.get(type)).parseObject(obj);
+ }
+ else
+ {
+ throw new IOException("unrecognised object: " + type);
+ }
+ }
+
+ return null;
+ }
+
+ private class KeyPairParser
+ implements PemObjectParser
+ {
+ private final PEMKeyPairParser pemKeyPairParser;
+
+ public KeyPairParser(PEMKeyPairParser pemKeyPairParser)
+ {
+ this.pemKeyPairParser = pemKeyPairParser;
+ }
+
+ /**
+ * Read a Key Pair
+ */
+ public Object parseObject(
+ PemObject obj)
+ throws IOException
+ {
+ boolean isEncrypted = false;
+ String dekInfo = null;
+ List headers = obj.getHeaders();
+
+ for (Iterator it = headers.iterator(); it.hasNext();)
+ {
+ PemHeader hdr = (PemHeader)it.next();
+
+ if (hdr.getName().equals("Proc-Type") && hdr.getValue().equals("4,ENCRYPTED"))
+ {
+ isEncrypted = true;
+ }
+ else if (hdr.getName().equals("DEK-Info"))
+ {
+ dekInfo = hdr.getValue();
+ }
+ }
+
+ //
+ // extract the key
+ //
+ byte[] keyBytes = obj.getContent();
+
+ try
+ {
+ if (isEncrypted)
+ {
+ StringTokenizer tknz = new StringTokenizer(dekInfo, ",");
+ String dekAlgName = tknz.nextToken();
+ byte[] iv = Hex.decode(tknz.nextToken());
+
+ return new PEMEncryptedKeyPair(dekAlgName, iv, keyBytes, pemKeyPairParser);
+ }
+
+ return pemKeyPairParser.parse(keyBytes);
+ }
+ catch (IOException e)
+ {
+ if (isEncrypted)
+ {
+ throw new PEMException("exception decoding - please check password and data.", e);
+ }
+ else
+ {
+ throw new PEMException(e.getMessage(), e);
+ }
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (isEncrypted)
+ {
+ throw new PEMException("exception decoding - please check password and data.", e);
+ }
+ else
+ {
+ throw new PEMException(e.getMessage(), e);
+ }
+ }
+ }
+ }
+
+ private class DSAKeyPairParser
+ implements PEMKeyPairParser
+ {
+ public PEMKeyPair parse(byte[] encoding)
+ throws IOException
+ {
+ try
+ {
+ ASN1Sequence seq = ASN1Sequence.getInstance(encoding);
+
+ if (seq.size() != 6)
+ {
+ throw new PEMException("malformed sequence in DSA private key");
+ }
+
+ // ASN1Integer v = (ASN1Integer)seq.getObjectAt(0);
+ ASN1Integer p = ASN1Integer.getInstance(seq.getObjectAt(1));
+ ASN1Integer q = ASN1Integer.getInstance(seq.getObjectAt(2));
+ ASN1Integer g = ASN1Integer.getInstance(seq.getObjectAt(3));
+ ASN1Integer y = ASN1Integer.getInstance(seq.getObjectAt(4));
+ ASN1Integer x = ASN1Integer.getInstance(seq.getObjectAt(5));
+
+ return new PEMKeyPair(
+ new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(p.getValue(), q.getValue(), g.getValue())), y),
+ new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(p.getValue(), q.getValue(), g.getValue())), x));
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PEMException(
+ "problem creating DSA private key: " + e.toString(), e);
+ }
+ }
+ }
+
+ private class ECDSAKeyPairParser
+ implements PEMKeyPairParser
+ {
+ public PEMKeyPair parse(byte[] encoding)
+ throws IOException
+ {
+ try
+ {
+ ASN1Sequence seq = ASN1Sequence.getInstance(encoding);
+
+ org.spongycastle.asn1.sec.ECPrivateKey pKey = org.spongycastle.asn1.sec.ECPrivateKey.getInstance(seq);
+ AlgorithmIdentifier algId = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, pKey.getParameters());
+ PrivateKeyInfo privInfo = new PrivateKeyInfo(algId, pKey);
+ SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(algId, pKey.getPublicKey().getBytes());
+
+ return new PEMKeyPair(pubInfo, privInfo);
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PEMException(
+ "problem creating EC private key: " + e.toString(), e);
+ }
+ }
+ }
+
+ private class RSAKeyPairParser
+ implements PEMKeyPairParser
+ {
+ public PEMKeyPair parse(byte[] encoding)
+ throws IOException
+ {
+ try
+ {
+ ASN1Sequence seq = ASN1Sequence.getInstance(encoding);
+
+ if (seq.size() != 9)
+ {
+ throw new PEMException("malformed sequence in RSA private key");
+ }
+
+ org.spongycastle.asn1.pkcs.RSAPrivateKey keyStruct = org.spongycastle.asn1.pkcs.RSAPrivateKey.getInstance(seq);
+
+ RSAPublicKey pubSpec = new RSAPublicKey(
+ keyStruct.getModulus(), keyStruct.getPublicExponent());
+
+ AlgorithmIdentifier algId = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE);
+
+ return new PEMKeyPair(new SubjectPublicKeyInfo(algId, pubSpec), new PrivateKeyInfo(algId, keyStruct));
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PEMException(
+ "problem creating RSA private key: " + e.toString(), e);
+ }
+ }
+ }
+
+ private class PublicKeyParser
+ implements PemObjectParser
+ {
+ public PublicKeyParser()
+ {
+ }
+
+ public Object parseObject(PemObject obj)
+ throws IOException
+ {
+ return SubjectPublicKeyInfo.getInstance(obj.getContent());
+ }
+ }
+
+ private class RSAPublicKeyParser
+ implements PemObjectParser
+ {
+ public RSAPublicKeyParser()
+ {
+ }
+
+ public Object parseObject(PemObject obj)
+ throws IOException
+ {
+ try
+ {
+ RSAPublicKey rsaPubStructure = RSAPublicKey.getInstance(obj.getContent());
+
+ return new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), rsaPubStructure);
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PEMException("problem extracting key: " + e.toString(), e);
+ }
+ }
+ }
+
+ private class X509CertificateParser
+ implements PemObjectParser
+ {
+ /**
+ * Reads in a X509Certificate.
+ *
+ * @return the X509Certificate
+ * @throws java.io.IOException if an I/O error occured
+ */
+ public Object parseObject(PemObject obj)
+ throws IOException
+ {
+ try
+ {
+ return new X509CertificateHolder(obj.getContent());
+ }
+ catch (Exception e)
+ {
+ throw new PEMException("problem parsing cert: " + e.toString(), e);
+ }
+ }
+ }
+
+ private class X509CRLParser
+ implements PemObjectParser
+ {
+ /**
+ * Reads in a X509CRL.
+ *
+ * @return the X509Certificate
+ * @throws java.io.IOException if an I/O error occured
+ */
+ public Object parseObject(PemObject obj)
+ throws IOException
+ {
+ try
+ {
+ return new X509CRLHolder(obj.getContent());
+ }
+ catch (Exception e)
+ {
+ throw new PEMException("problem parsing cert: " + e.toString(), e);
+ }
+ }
+ }
+
+ private class PKCS10CertificationRequestParser
+ implements PemObjectParser
+ {
+ /**
+ * Reads in a PKCS10 certification request.
+ *
+ * @return the certificate request.
+ * @throws java.io.IOException if an I/O error occured
+ */
+ public Object parseObject(PemObject obj)
+ throws IOException
+ {
+ try
+ {
+ return new PKCS10CertificationRequest(obj.getContent());
+ }
+ catch (Exception e)
+ {
+ throw new PEMException("problem parsing certrequest: " + e.toString(), e);
+ }
+ }
+ }
+
+ private class PKCS7Parser
+ implements PemObjectParser
+ {
+ /**
+ * Reads in a PKCS7 object. This returns a ContentInfo object suitable for use with the CMS
+ * API.
+ *
+ * @return the X509Certificate
+ * @throws java.io.IOException if an I/O error occured
+ */
+ public Object parseObject(PemObject obj)
+ throws IOException
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(obj.getContent());
+
+ return ContentInfo.getInstance(aIn.readObject());
+ }
+ catch (Exception e)
+ {
+ throw new PEMException("problem parsing PKCS7 object: " + e.toString(), e);
+ }
+ }
+ }
+
+ private class X509AttributeCertificateParser
+ implements PemObjectParser
+ {
+ public Object parseObject(PemObject obj)
+ throws IOException
+ {
+ return new X509AttributeCertificateHolder(obj.getContent());
+ }
+ }
+
+ private class ECCurveParamsParser
+ implements PemObjectParser
+ {
+ public Object parseObject(PemObject obj)
+ throws IOException
+ {
+ try
+ {
+ Object param = ASN1Primitive.fromByteArray(obj.getContent());
+
+ if (param instanceof ASN1ObjectIdentifier)
+ {
+ return ASN1Primitive.fromByteArray(obj.getContent());
+ }
+ else if (param instanceof ASN1Sequence)
+ {
+ return X9ECParameters.getInstance(param);
+ }
+ else
+ {
+ return null; // implicitly CA
+ }
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PEMException("exception extracting EC named curve: " + e.toString());
+ }
+ }
+ }
+
+ private class EncryptedPrivateKeyParser
+ implements PemObjectParser
+ {
+ public EncryptedPrivateKeyParser()
+ {
+ }
+
+ /**
+ * Reads in an EncryptedPrivateKeyInfo
+ *
+ * @return the X509Certificate
+ * @throws java.io.IOException if an I/O error occured
+ */
+ public Object parseObject(PemObject obj)
+ throws IOException
+ {
+ try
+ {
+ return new PKCS8EncryptedPrivateKeyInfo(EncryptedPrivateKeyInfo.getInstance(obj.getContent()));
+ }
+ catch (Exception e)
+ {
+ throw new PEMException("problem parsing ENCRYPTED PRIVATE KEY: " + e.toString(), e);
+ }
+ }
+ }
+
+ private class PrivateKeyParser
+ implements PemObjectParser
+ {
+ public PrivateKeyParser()
+ {
+ }
+
+ public Object parseObject(PemObject obj)
+ throws IOException
+ {
+ try
+ {
+ return PrivateKeyInfo.getInstance(obj.getContent());
+ }
+ catch (Exception e)
+ {
+ throw new PEMException("problem parsing PRIVATE KEY: " + e.toString(), e);
+ }
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMUtilities.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMUtilities.java
new file mode 100644
index 000000000..59f350060
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMUtilities.java
@@ -0,0 +1,65 @@
+package org.spongycastle.openssl;
+
+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.DERObjectIdentifier;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.util.Integers;
+
+public final class PEMUtilities
+{
+ private static final Map KEYSIZES = new HashMap();
+ private static final Set PKCS5_SCHEME_1 = new HashSet();
+ private static final Set PKCS5_SCHEME_2 = new HashSet();
+
+ static
+ {
+ PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC);
+ PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC);
+ PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC);
+ PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC);
+ PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC);
+ PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC);
+
+ PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.id_PBES2);
+ PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.des_EDE3_CBC);
+ PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes128_CBC);
+ PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes192_CBC);
+ PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes256_CBC);
+
+ KEYSIZES.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integers.valueOf(192));
+ KEYSIZES.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), Integers.valueOf(128));
+ KEYSIZES.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), Integers.valueOf(192));
+ KEYSIZES.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), Integers.valueOf(256));
+ }
+
+ static int getKeySize(String algorithm)
+ {
+ if (!KEYSIZES.containsKey(algorithm))
+ {
+ throw new IllegalStateException("no key size for algorithm: " + algorithm);
+ }
+
+ return ((Integer)KEYSIZES.get(algorithm)).intValue();
+ }
+
+ static boolean isPKCS5Scheme1(DERObjectIdentifier algOid)
+ {
+ return PKCS5_SCHEME_1.contains(algOid);
+ }
+
+ public static boolean isPKCS5Scheme2(ASN1ObjectIdentifier algOid)
+ {
+ return PKCS5_SCHEME_2.contains(algOid);
+ }
+
+ public static boolean isPKCS12(DERObjectIdentifier algOid)
+ {
+ return algOid.getId().startsWith(PKCSObjectIdentifiers.pkcs_12PbeIds.getId());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMWriter.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMWriter.java
new file mode 100644
index 000000000..2046d620a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PEMWriter.java
@@ -0,0 +1,60 @@
+package org.spongycastle.openssl;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.spongycastle.openssl.jcajce.JcaMiscPEMGenerator;
+import org.spongycastle.util.io.pem.PemGenerationException;
+import org.spongycastle.util.io.pem.PemObjectGenerator;
+import org.spongycastle.util.io.pem.PemWriter;
+
+/**
+ * General purpose writer for OpenSSL PEM objects.
+ */
+public class PEMWriter
+ extends PemWriter
+{
+ /**
+ * Base constructor.
+ *
+ * @param out output stream to use.
+ */
+ public PEMWriter(Writer out)
+ {
+ super(out);
+ }
+
+ public void writeObject(
+ Object obj)
+ throws IOException
+ {
+ writeObject(obj, null);
+ }
+
+ public void writeObject(
+ Object obj,
+ PEMEncryptor encryptor)
+ throws IOException
+ {
+ try
+ {
+ super.writeObject(new JcaMiscPEMGenerator(obj, encryptor));
+ }
+ catch (PemGenerationException e)
+ {
+ if (e.getCause() instanceof IOException)
+ {
+ throw (IOException)e.getCause();
+ }
+
+ throw e;
+ }
+ }
+
+ public void writeObject(
+ PemObjectGenerator obj)
+ throws IOException
+ {
+ super.writeObject(obj);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PKCS8Generator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PKCS8Generator.java
new file mode 100644
index 000000000..83130d367
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PKCS8Generator.java
@@ -0,0 +1,87 @@
+package org.spongycastle.openssl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.operator.OutputEncryptor;
+import org.spongycastle.util.io.pem.PemGenerationException;
+import org.spongycastle.util.io.pem.PemObject;
+import org.spongycastle.util.io.pem.PemObjectGenerator;
+
+public class PKCS8Generator
+ implements PemObjectGenerator
+{
+ public static final ASN1ObjectIdentifier AES_128_CBC = NISTObjectIdentifiers.id_aes128_CBC;
+ public static final ASN1ObjectIdentifier AES_192_CBC = NISTObjectIdentifiers.id_aes192_CBC;
+ public static final ASN1ObjectIdentifier AES_256_CBC = NISTObjectIdentifiers.id_aes256_CBC;
+
+ public static final ASN1ObjectIdentifier DES3_CBC = PKCSObjectIdentifiers.des_EDE3_CBC;
+
+ public static final ASN1ObjectIdentifier PBE_SHA1_RC4_128 = PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4;
+ public static final ASN1ObjectIdentifier PBE_SHA1_RC4_40 = PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4;
+ public static final ASN1ObjectIdentifier PBE_SHA1_3DES = PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC;
+ public static final ASN1ObjectIdentifier PBE_SHA1_2DES = PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC;
+ public static final ASN1ObjectIdentifier PBE_SHA1_RC2_128 = PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC;
+ public static final ASN1ObjectIdentifier PBE_SHA1_RC2_40 = PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC;
+
+ private PrivateKeyInfo key;
+ private OutputEncryptor outputEncryptor;
+
+ /**
+ * Base constructor.
+ */
+ public PKCS8Generator(PrivateKeyInfo key, OutputEncryptor outputEncryptor)
+ {
+ this.key = key;
+ this.outputEncryptor = outputEncryptor;
+ }
+
+ public PemObject generate()
+ throws PemGenerationException
+ {
+ if (outputEncryptor != null)
+ {
+ return generate(key, outputEncryptor);
+ }
+ else
+ {
+ return generate(key, null);
+ }
+ }
+
+ private PemObject generate(PrivateKeyInfo key, OutputEncryptor encryptor)
+ throws PemGenerationException
+ {
+ try
+ {
+ byte[] keyData = key.getEncoded();
+
+ if (encryptor == null)
+ {
+ return new PemObject("PRIVATE KEY", keyData);
+ }
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ OutputStream cOut = encryptor.getOutputStream(bOut);
+
+ cOut.write(key.getEncoded());
+
+ cOut.close();
+
+ EncryptedPrivateKeyInfo info = new EncryptedPrivateKeyInfo(encryptor.getAlgorithmIdentifier(), bOut.toByteArray());
+
+ return new PemObject("ENCRYPTED PRIVATE KEY", info.getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new PemGenerationException("unable to process encoded key data: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PasswordException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PasswordException.java
new file mode 100644
index 000000000..68de32137
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PasswordException.java
@@ -0,0 +1,10 @@
+package org.spongycastle.openssl;
+
+public class PasswordException
+ extends PEMException
+{
+ public PasswordException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PasswordFinder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PasswordFinder.java
new file mode 100644
index 000000000..eb981fd51
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/PasswordFinder.java
@@ -0,0 +1,9 @@
+package org.spongycastle.openssl;
+
+/**
+ * call back to allow a password to be fetched when one is requested.
+ */
+public interface PasswordFinder
+{
+ public char[] getPassword();
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaMiscPEMGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaMiscPEMGenerator.java
new file mode 100644
index 000000000..88f2a32ec
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaMiscPEMGenerator.java
@@ -0,0 +1,98 @@
+package org.spongycastle.openssl.jcajce;
+
+import java.io.IOException;
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.jcajce.JcaX509AttributeCertificateHolder;
+import org.spongycastle.cert.jcajce.JcaX509CRLHolder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.jce.PKCS10CertificationRequest;
+import org.spongycastle.openssl.MiscPEMGenerator;
+import org.spongycastle.openssl.PEMEncryptor;
+import org.spongycastle.x509.X509AttributeCertificate;
+import org.spongycastle.x509.X509V2AttributeCertificate;
+
+/**
+ * PEM generator for the original set of PEM objects used in Open SSL.
+ */
+public class JcaMiscPEMGenerator
+ extends MiscPEMGenerator
+{
+ private Object obj;
+ private String algorithm;
+ private char[] password;
+ private SecureRandom random;
+ private Provider provider;
+
+ public JcaMiscPEMGenerator(Object o)
+ throws IOException
+ {
+ super(convertObject(o));
+ }
+
+ public JcaMiscPEMGenerator(Object o, PEMEncryptor encryptor)
+ throws IOException
+ {
+ super(convertObject(o), encryptor);
+ }
+
+ private static Object convertObject(Object o)
+ throws IOException
+ {
+ if (o instanceof X509Certificate)
+ {
+ try
+ {
+ return new JcaX509CertificateHolder((X509Certificate)o);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IllegalArgumentException("Cannot encode object: " + e.toString());
+ }
+ }
+ else if (o instanceof X509CRL)
+ {
+ try
+ {
+ return new JcaX509CRLHolder((X509CRL)o);
+ }
+ catch (CRLException e)
+ {
+ throw new IllegalArgumentException("Cannot encode object: " + e.toString());
+ }
+ }
+ else if (o instanceof KeyPair)
+ {
+ return convertObject(((KeyPair)o).getPrivate());
+ }
+ else if (o instanceof PrivateKey)
+ {
+ return PrivateKeyInfo.getInstance(((Key)o).getEncoded());
+ }
+ else if (o instanceof PublicKey)
+ {
+ return SubjectPublicKeyInfo.getInstance(((PublicKey)o).getEncoded());
+ }
+ else if (o instanceof X509AttributeCertificate)
+ {
+ return new JcaX509AttributeCertificateHolder((X509V2AttributeCertificate)o);
+ }
+ else if (o instanceof PKCS10CertificationRequest)
+ {
+ return new org.spongycastle.pkcs.PKCS10CertificationRequest(((PKCS10CertificationRequest)o).getEncoded());
+ }
+
+ return o;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPEMKeyConverter.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPEMKeyConverter.java
new file mode 100644
index 000000000..8fa2b93ed
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPEMKeyConverter.java
@@ -0,0 +1,115 @@
+package org.spongycastle.openssl.jcajce;
+
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.JcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.openssl.PEMException;
+import org.spongycastle.openssl.PEMKeyPair;
+
+public class JcaPEMKeyConverter
+{
+ private JcaJceHelper helper = new DefaultJcaJceHelper();
+
+ private static final Map algorithms = new HashMap();
+
+ static
+ {
+ algorithms.put(X9ObjectIdentifiers.id_ecPublicKey, "ECDSA");
+ algorithms.put(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ algorithms.put(X9ObjectIdentifiers.id_dsa, "DSA");
+ }
+
+ public JcaPEMKeyConverter setProvider(Provider provider)
+ {
+ this.helper = new ProviderJcaJceHelper(provider);
+
+ return this;
+ }
+
+ public JcaPEMKeyConverter setProvider(String providerName)
+ {
+ this.helper = new NamedJcaJceHelper(providerName);
+
+ return this;
+ }
+
+ public KeyPair getKeyPair(PEMKeyPair keyPair)
+ throws PEMException
+ {
+ try
+ {
+ KeyFactory keyFactory = getKeyFactory(keyPair.getPrivateKeyInfo().getPrivateKeyAlgorithm());
+
+ return new KeyPair(keyFactory.generatePublic(new X509EncodedKeySpec(keyPair.getPublicKeyInfo().getEncoded())),
+ keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyPair.getPrivateKeyInfo().getEncoded())));
+ }
+ catch (Exception e)
+ {
+ throw new PEMException("unable to convert key pair: " + e.getMessage(), e);
+ }
+ }
+
+ public PublicKey getPublicKey(SubjectPublicKeyInfo publicKeyInfo)
+ throws PEMException
+ {
+ try
+ {
+ KeyFactory keyFactory = getKeyFactory(publicKeyInfo.getAlgorithm());
+
+ return keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyInfo.getEncoded()));
+ }
+ catch (Exception e)
+ {
+ throw new PEMException("unable to convert key pair: " + e.getMessage(), e);
+ }
+ }
+
+ public PrivateKey getPrivateKey(PrivateKeyInfo privateKeyInfo)
+ throws PEMException
+ {
+ try
+ {
+ KeyFactory keyFactory = getKeyFactory(privateKeyInfo.getPrivateKeyAlgorithm());
+
+ return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyInfo.getEncoded()));
+ }
+ catch (Exception e)
+ {
+ throw new PEMException("unable to convert key pair: " + e.getMessage(), e);
+ }
+ }
+
+ private KeyFactory getKeyFactory(AlgorithmIdentifier algId)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ ASN1ObjectIdentifier algorithm = algId.getAlgorithm();
+
+ String algName = (String)algorithms.get(algorithm);
+
+ if (algName == null)
+ {
+ algName = algorithm.getId();
+ }
+
+ return helper.createKeyFactory(algName);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPKCS8Generator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPKCS8Generator.java
new file mode 100644
index 000000000..9c4e4f46c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcaPKCS8Generator.java
@@ -0,0 +1,18 @@
+package org.spongycastle.openssl.jcajce;
+
+import java.security.PrivateKey;
+
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.openssl.PKCS8Generator;
+import org.spongycastle.operator.OutputEncryptor;
+import org.spongycastle.util.io.pem.PemGenerationException;
+
+public class JcaPKCS8Generator
+ extends PKCS8Generator
+{
+ public JcaPKCS8Generator(PrivateKey key, OutputEncryptor encryptor)
+ throws PemGenerationException
+ {
+ super(PrivateKeyInfo.getInstance(key.getEncoded()), encryptor);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8DecryptorProviderBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8DecryptorProviderBuilder.java
new file mode 100644
index 000000000..2d8e45349
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8DecryptorProviderBuilder.java
@@ -0,0 +1,141 @@
+package org.spongycastle.openssl.jcajce;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.Provider;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.spongycastle.asn1.pkcs.EncryptionScheme;
+import org.spongycastle.asn1.pkcs.KeyDerivationFunc;
+import org.spongycastle.asn1.pkcs.PBEParameter;
+import org.spongycastle.asn1.pkcs.PBES2Parameters;
+import org.spongycastle.asn1.pkcs.PBKDF2Params;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.JcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.openssl.PEMException;
+import org.spongycastle.operator.InputDecryptor;
+import org.spongycastle.operator.InputDecryptorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+
+public class JceOpenSSLPKCS8DecryptorProviderBuilder
+{
+ private JcaJceHelper helper = new DefaultJcaJceHelper();
+
+ public JceOpenSSLPKCS8DecryptorProviderBuilder()
+ {
+ helper = new DefaultJcaJceHelper();
+ }
+
+ public JceOpenSSLPKCS8DecryptorProviderBuilder setProvider(String providerName)
+ {
+ helper = new NamedJcaJceHelper(providerName);
+
+ return this;
+ }
+
+ public JceOpenSSLPKCS8DecryptorProviderBuilder setProvider(Provider provider)
+ {
+ helper = new ProviderJcaJceHelper(provider);
+
+ return this;
+ }
+
+ public InputDecryptorProvider build(final char[] password)
+ throws OperatorCreationException
+ {
+ return new InputDecryptorProvider()
+ {
+ public InputDecryptor get(final AlgorithmIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ final Cipher cipher;
+
+ try
+ {
+ if (PEMUtilities.isPKCS5Scheme2(algorithm.getAlgorithm()))
+ {
+ PBES2Parameters params = PBES2Parameters.getInstance(algorithm.getParameters());
+ KeyDerivationFunc func = params.getKeyDerivationFunc();
+ EncryptionScheme scheme = params.getEncryptionScheme();
+ PBKDF2Params defParams = (PBKDF2Params)func.getParameters();
+
+ int iterationCount = defParams.getIterationCount().intValue();
+ byte[] salt = defParams.getSalt();
+
+ String oid = scheme.getAlgorithm().getId();
+
+ SecretKey key = PEMUtilities.generateSecretKeyForPKCS5Scheme2(oid, password, salt, iterationCount);
+
+ cipher = helper.createCipher(oid);
+ AlgorithmParameters algParams = helper.createAlgorithmParameters(oid);
+
+ algParams.init(scheme.getParameters().toASN1Primitive().getEncoded());
+
+ cipher.init(Cipher.DECRYPT_MODE, key, algParams);
+ }
+ else if (PEMUtilities.isPKCS12(algorithm.getAlgorithm()))
+ {
+ PKCS12PBEParams params = PKCS12PBEParams.getInstance(algorithm.getParameters());
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+
+ SecretKeyFactory secKeyFact = helper.createSecretKeyFactory(algorithm.getAlgorithm().getId());
+ PBEParameterSpec defParams = new PBEParameterSpec(params.getIV(), params.getIterations().intValue());
+
+ cipher = helper.createCipher(algorithm.getAlgorithm().getId());
+
+ cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams);
+ }
+ else if (PEMUtilities.isPKCS5Scheme1(algorithm.getAlgorithm()))
+ {
+ PBEParameter params = PBEParameter.getInstance(algorithm.getParameters());
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+
+ SecretKeyFactory secKeyFact = helper.createSecretKeyFactory(algorithm.getAlgorithm().getId());
+ PBEParameterSpec defParams = new PBEParameterSpec(params.getSalt(), params.getIterationCount().intValue());
+
+ cipher = helper.createCipher(algorithm.getAlgorithm().getId());
+
+ cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams);
+ }
+ else
+ {
+ throw new PEMException("Unknown algorithm: " + algorithm.getAlgorithm());
+ }
+
+ return new InputDecryptor()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithm;
+ }
+
+ public InputStream getInputStream(InputStream encIn)
+ {
+ return new CipherInputStream(encIn, cipher);
+ }
+ };
+ }
+ catch (IOException e)
+ {
+ throw new OperatorCreationException(algorithm.getAlgorithm() + " not available: " + e.getMessage(), e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException(algorithm.getAlgorithm() + " not available: " + e.getMessage(), e);
+ }
+ };
+ };
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java
new file mode 100644
index 000000000..5cfb02b5f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java
@@ -0,0 +1,221 @@
+package org.spongycastle.openssl.jcajce;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.Provider;
+import java.security.SecureRandom;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.KeyDerivationFunc;
+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.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.JcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.OutputEncryptor;
+import org.spongycastle.operator.jcajce.JceGenericKey;
+
+public class JceOpenSSLPKCS8EncryptorBuilder
+{
+ public static final String AES_128_CBC = NISTObjectIdentifiers.id_aes128_CBC.getId();
+ public static final String AES_192_CBC = NISTObjectIdentifiers.id_aes192_CBC.getId();
+ public static final String AES_256_CBC = NISTObjectIdentifiers.id_aes256_CBC.getId();
+
+ public static final String DES3_CBC = PKCSObjectIdentifiers.des_EDE3_CBC.getId();
+
+ public static final String PBE_SHA1_RC4_128 = PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4.getId();
+ public static final String PBE_SHA1_RC4_40 = PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4.getId();
+ public static final String PBE_SHA1_3DES = PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC.getId();
+ public static final String PBE_SHA1_2DES = PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC.getId();
+ public static final String PBE_SHA1_RC2_128 = PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC.getId();
+ public static final String PBE_SHA1_RC2_40 = PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC.getId();
+
+ private JcaJceHelper helper = new DefaultJcaJceHelper();
+
+ private AlgorithmParameters params;
+ private ASN1ObjectIdentifier algOID;
+ byte[] salt;
+ int iterationCount;
+ private Cipher cipher;
+ private SecureRandom random;
+ private AlgorithmParameterGenerator paramGen;
+ private SecretKeyFactory secKeyFact;
+ private char[] password;
+
+ private SecretKey key;
+
+ public JceOpenSSLPKCS8EncryptorBuilder(ASN1ObjectIdentifier algorithm)
+ {
+ algOID = algorithm;
+
+ this.iterationCount = 2048;
+ }
+
+ public JceOpenSSLPKCS8EncryptorBuilder setRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public JceOpenSSLPKCS8EncryptorBuilder setPasssword(char[] password)
+ {
+ this.password = password;
+
+ return this;
+ }
+
+ public JceOpenSSLPKCS8EncryptorBuilder setIterationCount(int iterationCount)
+ {
+ this.iterationCount = iterationCount;
+
+ return this;
+ }
+
+ public JceOpenSSLPKCS8EncryptorBuilder setProvider(String providerName)
+ {
+ helper = new NamedJcaJceHelper(providerName);
+
+ return this;
+ }
+
+ public JceOpenSSLPKCS8EncryptorBuilder setProvider(Provider provider)
+ {
+ helper = new ProviderJcaJceHelper(provider);
+
+ return this;
+ }
+
+ public OutputEncryptor build()
+ throws OperatorCreationException
+ {
+ final AlgorithmIdentifier algID;
+
+ salt = new byte[20];
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(salt);
+
+ try
+ {
+ this.cipher = helper.createCipher(algOID.getId());
+
+ if (PEMUtilities.isPKCS5Scheme2(algOID))
+ {
+ this.paramGen = helper.createAlgorithmParameterGenerator(algOID.getId());
+ }
+ else
+ {
+ this.secKeyFact = helper.createSecretKeyFactory(algOID.getId());
+ }
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException(algOID + " not available: " + e.getMessage(), e);
+ }
+
+ if (PEMUtilities.isPKCS5Scheme2(algOID))
+ {
+ params = paramGen.generateParameters();
+
+ try
+ {
+ KeyDerivationFunc scheme = new KeyDerivationFunc(algOID, ASN1Primitive.fromByteArray(params.getEncoded()));
+ KeyDerivationFunc func = new KeyDerivationFunc(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, iterationCount));
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(func);
+ v.add(scheme);
+
+ algID = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, PBES2Parameters.getInstance(new DERSequence(v)));
+ }
+ catch (IOException e)
+ {
+ throw new OperatorCreationException(e.getMessage(), e);
+ }
+
+ key = PEMUtilities.generateSecretKeyForPKCS5Scheme2(algOID.getId(), password, salt, iterationCount);
+
+ try
+ {
+ cipher.init(Cipher.ENCRYPT_MODE, key, params);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException(e.getMessage(), e);
+ }
+ }
+ else if (PEMUtilities.isPKCS12(algOID))
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new DEROctetString(salt));
+ v.add(new ASN1Integer(iterationCount));
+
+ algID = new AlgorithmIdentifier(algOID, PKCS12PBEParams.getInstance(new DERSequence(v)));
+
+ try
+ {
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount);
+
+ key = secKeyFact.generateSecret(pbeSpec);
+
+ cipher.init(Cipher.ENCRYPT_MODE, key, defParams);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException(e.getMessage(), e);
+ }
+ }
+ else
+ {
+ throw new OperatorCreationException("unknown algorithm: " + algOID, null);
+ }
+
+ return new OutputEncryptor()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algID;
+ }
+
+ public OutputStream getOutputStream(OutputStream encOut)
+ {
+ return new CipherOutputStream(encOut, cipher);
+ }
+
+ public GenericKey getKey()
+ {
+ return new JceGenericKey(algID, key);
+ }
+ };
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMDecryptorProviderBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMDecryptorProviderBuilder.java
new file mode 100644
index 000000000..2a260f236
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMDecryptorProviderBuilder.java
@@ -0,0 +1,54 @@
+package org.spongycastle.openssl.jcajce;
+
+import java.security.Provider;
+
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.JcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.openssl.PEMDecryptor;
+import org.spongycastle.openssl.PEMDecryptorProvider;
+import org.spongycastle.openssl.PEMException;
+import org.spongycastle.openssl.PasswordException;
+
+public class JcePEMDecryptorProviderBuilder
+{
+ private JcaJceHelper helper = new DefaultJcaJceHelper();
+
+ public JcePEMDecryptorProviderBuilder setProvider(Provider provider)
+ {
+ this.helper = new ProviderJcaJceHelper(provider);
+
+ return this;
+ }
+
+ public JcePEMDecryptorProviderBuilder setProvider(String providerName)
+ {
+ this.helper = new NamedJcaJceHelper(providerName);
+
+ return this;
+ }
+
+ public PEMDecryptorProvider build(final char[] password)
+ {
+ return new PEMDecryptorProvider()
+ {
+ public PEMDecryptor get(final String dekAlgName)
+ {
+ return new PEMDecryptor()
+ {
+ public byte[] decrypt(byte[] keyBytes, byte[] iv)
+ throws PEMException
+ {
+ if (password == null)
+ {
+ throw new PasswordException("Password is null, but a password is required");
+ }
+
+ return PEMUtilities.crypt(false, helper, keyBytes, password, dekAlgName, iv);
+ }
+ };
+ }
+ };
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMEncryptorBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMEncryptorBuilder.java
new file mode 100644
index 000000000..4a3f76477
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/JcePEMEncryptorBuilder.java
@@ -0,0 +1,78 @@
+package org.spongycastle.openssl.jcajce;
+
+import java.security.Provider;
+import java.security.SecureRandom;
+
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.JcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.openssl.PEMEncryptor;
+import org.spongycastle.openssl.PEMException;
+
+public class JcePEMEncryptorBuilder
+{
+ private final String algorithm;
+
+ private JcaJceHelper helper = new DefaultJcaJceHelper();
+ private SecureRandom random;
+
+ public JcePEMEncryptorBuilder(String algorithm)
+ {
+ this.algorithm = algorithm;
+ }
+
+ public JcePEMEncryptorBuilder setProvider(Provider provider)
+ {
+ this.helper = new ProviderJcaJceHelper(provider);
+
+ return this;
+ }
+
+ public JcePEMEncryptorBuilder setProvider(String providerName)
+ {
+ this.helper = new NamedJcaJceHelper(providerName);
+
+ return this;
+ }
+
+ public JcePEMEncryptorBuilder setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public PEMEncryptor build(final char[] password)
+ {
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ int ivLength = algorithm.startsWith("AES-") ? 16 : 8;
+
+ final byte[] iv = new byte[ivLength];
+
+ random.nextBytes(iv);
+
+ return new PEMEncryptor()
+ {
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ public byte[] getIV()
+ {
+ return iv;
+ }
+
+ public byte[] encrypt(byte[] encoding)
+ throws PEMException
+ {
+ return PEMUtilities.crypt(true, helper, encoding, password, algorithm, iv);
+ }
+ };
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/PEMUtilities.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/PEMUtilities.java
new file mode 100644
index 000000000..050599dd8
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/openssl/jcajce/PEMUtilities.java
@@ -0,0 +1,258 @@
+package org.spongycastle.openssl.jcajce;
+
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.PBEParametersGenerator;
+import org.spongycastle.crypto.generators.OpenSSLPBEParametersGenerator;
+import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.jcajce.JcaJceHelper;
+import org.spongycastle.openssl.EncryptionException;
+import org.spongycastle.openssl.PEMException;
+import org.spongycastle.util.Integers;
+
+class PEMUtilities
+{
+ private static final Map KEYSIZES = new HashMap();
+ private static final Set PKCS5_SCHEME_1 = new HashSet();
+ private static final Set PKCS5_SCHEME_2 = new HashSet();
+
+ static
+ {
+ PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC);
+ PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC);
+ PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC);
+ PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC);
+ PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC);
+ PKCS5_SCHEME_1.add(PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC);
+
+ PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.id_PBES2);
+ PKCS5_SCHEME_2.add(PKCSObjectIdentifiers.des_EDE3_CBC);
+ PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes128_CBC);
+ PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes192_CBC);
+ PKCS5_SCHEME_2.add(NISTObjectIdentifiers.id_aes256_CBC);
+
+ KEYSIZES.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integers.valueOf(192));
+ KEYSIZES.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), Integers.valueOf(128));
+ KEYSIZES.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), Integers.valueOf(192));
+ KEYSIZES.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), Integers.valueOf(256));
+ }
+
+ static int getKeySize(String algorithm)
+ {
+ if (!KEYSIZES.containsKey(algorithm))
+ {
+ throw new IllegalStateException("no key size for algorithm: " + algorithm);
+ }
+
+ return ((Integer)KEYSIZES.get(algorithm)).intValue();
+ }
+
+ static boolean isPKCS5Scheme1(DERObjectIdentifier algOid)
+ {
+ return PKCS5_SCHEME_1.contains(algOid);
+ }
+
+ static boolean isPKCS5Scheme2(ASN1ObjectIdentifier algOid)
+ {
+ return PKCS5_SCHEME_2.contains(algOid);
+ }
+
+ public static boolean isPKCS12(DERObjectIdentifier algOid)
+ {
+ return algOid.getId().startsWith(PKCSObjectIdentifiers.pkcs_12PbeIds.getId());
+ }
+
+ public static SecretKey generateSecretKeyForPKCS5Scheme2(String algorithm, char[] password, byte[] salt, int iterationCount)
+ {
+ PBEParametersGenerator generator = new PKCS5S2ParametersGenerator();
+
+ generator.init(
+ PBEParametersGenerator.PKCS5PasswordToBytes(password),
+ salt,
+ iterationCount);
+
+ return new SecretKeySpec(((KeyParameter)generator.generateDerivedParameters(PEMUtilities.getKeySize(algorithm))).getKey(), algorithm);
+ }
+
+ static byte[] crypt(
+ boolean encrypt,
+ JcaJceHelper helper,
+ byte[] bytes,
+ char[] password,
+ String dekAlgName,
+ byte[] iv)
+ throws PEMException
+ {
+ AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
+ String alg;
+ String blockMode = "CBC";
+ String padding = "PKCS5Padding";
+ Key sKey;
+
+ // Figure out block mode and padding.
+ if (dekAlgName.endsWith("-CFB"))
+ {
+ blockMode = "CFB";
+ padding = "NoPadding";
+ }
+ if (dekAlgName.endsWith("-ECB") ||
+ "DES-EDE".equals(dekAlgName) ||
+ "DES-EDE3".equals(dekAlgName))
+ {
+ // ECB is actually the default (though seldom used) when OpenSSL
+ // uses DES-EDE (des2) or DES-EDE3 (des3).
+ blockMode = "ECB";
+ paramSpec = null;
+ }
+ if (dekAlgName.endsWith("-OFB"))
+ {
+ blockMode = "OFB";
+ padding = "NoPadding";
+ }
+
+
+ // Figure out algorithm and key size.
+ if (dekAlgName.startsWith("DES-EDE"))
+ {
+ alg = "DESede";
+ // "DES-EDE" is actually des2 in OpenSSL-speak!
+ // "DES-EDE3" is des3.
+ boolean des2 = !dekAlgName.startsWith("DES-EDE3");
+ sKey = getKey(password, alg, 24, iv, des2);
+ }
+ else if (dekAlgName.startsWith("DES-"))
+ {
+ alg = "DES";
+ sKey = getKey(password, alg, 8, iv);
+ }
+ else if (dekAlgName.startsWith("BF-"))
+ {
+ alg = "Blowfish";
+ sKey = getKey(password, alg, 16, iv);
+ }
+ else if (dekAlgName.startsWith("RC2-"))
+ {
+ alg = "RC2";
+ int keyBits = 128;
+ if (dekAlgName.startsWith("RC2-40-"))
+ {
+ keyBits = 40;
+ }
+ else if (dekAlgName.startsWith("RC2-64-"))
+ {
+ keyBits = 64;
+ }
+ sKey = getKey(password, alg, keyBits / 8, iv);
+ if (paramSpec == null) // ECB block mode
+ {
+ paramSpec = new RC2ParameterSpec(keyBits);
+ }
+ else
+ {
+ paramSpec = new RC2ParameterSpec(keyBits, iv);
+ }
+ }
+ else if (dekAlgName.startsWith("AES-"))
+ {
+ alg = "AES";
+ byte[] salt = iv;
+ if (salt.length > 8)
+ {
+ salt = new byte[8];
+ System.arraycopy(iv, 0, salt, 0, 8);
+ }
+
+ int keyBits;
+ if (dekAlgName.startsWith("AES-128-"))
+ {
+ keyBits = 128;
+ }
+ else if (dekAlgName.startsWith("AES-192-"))
+ {
+ keyBits = 192;
+ }
+ else if (dekAlgName.startsWith("AES-256-"))
+ {
+ keyBits = 256;
+ }
+ else
+ {
+ throw new EncryptionException("unknown AES encryption with private key");
+ }
+ sKey = getKey(password, "AES", keyBits / 8, salt);
+ }
+ else
+ {
+ throw new EncryptionException("unknown encryption with private key");
+ }
+
+ String transformation = alg + "/" + blockMode + "/" + padding;
+
+ try
+ {
+ Cipher c = helper.createCipher(transformation);
+ int mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
+
+ if (paramSpec == null) // ECB block mode
+ {
+ c.init(mode, sKey);
+ }
+ else
+ {
+ c.init(mode, sKey, paramSpec);
+ }
+ return c.doFinal(bytes);
+ }
+ catch (Exception e)
+ {
+ throw new EncryptionException("exception using cipher - please check password and data.", e);
+ }
+ }
+
+ private static SecretKey getKey(
+ char[] password,
+ String algorithm,
+ int keyLength,
+ byte[] salt)
+ {
+ return getKey(password, algorithm, keyLength, salt, false);
+ }
+
+ private static SecretKey getKey(
+ char[] password,
+ String algorithm,
+ int keyLength,
+ byte[] salt,
+ boolean des2)
+ {
+ OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator();
+
+ pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(password), salt);
+
+ KeyParameter keyParam;
+ keyParam = (KeyParameter) pGen.generateDerivedParameters(keyLength * 8);
+ byte[] key = keyParam.getKey();
+ if (des2 && key.length >= 24)
+ {
+ // For DES2, we must copy first 8 bytes into the last 8 bytes.
+ System.arraycopy(key, 0, key, 16, 8);
+ }
+ return new SecretKeySpec(key, algorithm);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyUnwrapper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyUnwrapper.java
new file mode 100644
index 000000000..2ed2f1450
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyUnwrapper.java
@@ -0,0 +1,19 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public abstract class AsymmetricKeyUnwrapper
+ implements KeyUnwrapper
+{
+ private AlgorithmIdentifier algorithmId;
+
+ protected AsymmetricKeyUnwrapper(AlgorithmIdentifier algorithmId)
+ {
+ this.algorithmId = algorithmId;
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmId;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyWrapper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyWrapper.java
new file mode 100644
index 000000000..3de802264
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/AsymmetricKeyWrapper.java
@@ -0,0 +1,19 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public abstract class AsymmetricKeyWrapper
+ implements KeyWrapper
+{
+ private AlgorithmIdentifier algorithmId;
+
+ protected AsymmetricKeyWrapper(AlgorithmIdentifier algorithmId)
+ {
+ this.algorithmId = algorithmId;
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmId;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/BufferingContentSigner.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/BufferingContentSigner.java
new file mode 100644
index 000000000..e96a906c3
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/BufferingContentSigner.java
@@ -0,0 +1,70 @@
+package org.spongycastle.operator;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.util.io.BufferingOutputStream;
+
+/**
+ * A class that explicitly buffers the data to be signed, sending it in one
+ * block when ready for signing.
+ */
+public class BufferingContentSigner
+ implements ContentSigner
+{
+ private final ContentSigner contentSigner;
+ private final OutputStream output;
+
+ /**
+ * Base constructor.
+ *
+ * @param contentSigner the content signer to be wrapped.
+ */
+ public BufferingContentSigner(ContentSigner contentSigner)
+ {
+ this.contentSigner = contentSigner;
+ this.output = new BufferingOutputStream(contentSigner.getOutputStream());
+ }
+
+ /**
+ * Base constructor.
+ *
+ * @param contentSigner the content signer to be wrapped.
+ * @param bufferSize the size of the internal buffer to use.
+ */
+ public BufferingContentSigner(ContentSigner contentSigner, int bufferSize)
+ {
+ this.contentSigner = contentSigner;
+ this.output = new BufferingOutputStream(contentSigner.getOutputStream(), bufferSize);
+ }
+
+ /**
+ * Return the algorithm identifier supported by this signer.
+ *
+ * @return algorithm identifier for the signature generated.
+ */
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return contentSigner.getAlgorithmIdentifier();
+ }
+
+ /**
+ * Return the buffering stream.
+ *
+ * @return the output stream used to accumulate the data.
+ */
+ public OutputStream getOutputStream()
+ {
+ return output;
+ }
+
+ /**
+ * Generate signature from internally buffered data.
+ *
+ * @return the signature calculated from the bytes written to the buffering stream.
+ */
+ public byte[] getSignature()
+ {
+ return contentSigner.getSignature();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/ContentSigner.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/ContentSigner.java
new file mode 100644
index 000000000..fcdeefc45
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/ContentSigner.java
@@ -0,0 +1,27 @@
+package org.spongycastle.operator;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface ContentSigner
+{
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ /**
+ * Returns a stream that will accept data for the purpose of calculating
+ * a signature. Use org.spongycastle.util.io.TeeOutputStream if you want to accumulate
+ * the data on the fly as well.
+ *
+ * @return an OutputStream
+ */
+ OutputStream getOutputStream();
+
+ /**
+ * Returns a signature based on the current data written to the stream, since the
+ * start or the last call to getSignature().
+ *
+ * @return bytes representing the signature.
+ */
+ byte[] getSignature();
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/ContentVerifier.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/ContentVerifier.java
new file mode 100644
index 000000000..a139ebb2e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/ContentVerifier.java
@@ -0,0 +1,31 @@
+package org.spongycastle.operator;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface ContentVerifier
+{
+ /**
+ * Return the algorithm identifier describing the signature
+ * algorithm and parameters this expander supports.
+ *
+ * @return algorithm oid and parameters.
+ */
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ /**
+ * Returns a stream that will accept data for the purpose of calculating
+ * a signature for later verification. Use org.spongycastle.util.io.TeeOutputStream if you want to accumulate
+ * the data on the fly as well.
+ *
+ * @return an OutputStream
+ */
+ OutputStream getOutputStream();
+
+ /**
+ * @param expected expected value of the signature on the data.
+ * @return true if the signature verifies, false otherwise
+ */
+ boolean verify(byte[] expected);
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/ContentVerifierProvider.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/ContentVerifierProvider.java
new file mode 100644
index 000000000..9d91304a9
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/ContentVerifierProvider.java
@@ -0,0 +1,34 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.X509CertificateHolder;
+
+/**
+ * General interface for providers of ContentVerifier objects.
+ */
+public interface ContentVerifierProvider
+{
+ /**
+ * Return whether or not this verifier has a certificate associated with it.
+ *
+ * @return true if there is an associated certificate, false otherwise.
+ */
+ boolean hasAssociatedCertificate();
+
+ /**
+ * Return the associated certificate if there is one.
+ *
+ * @return a holder containing the associated certificate if there is one, null if there is not.
+ */
+ X509CertificateHolder getAssociatedCertificate();
+
+ /**
+ * Return a ContentVerifier that matches the passed in algorithm identifier,
+ *
+ * @param verifierAlgorithmIdentifier the algorithm and parameters required.
+ * @return a matching ContentVerifier
+ * @throws OperatorCreationException if the required ContentVerifier cannot be created.
+ */
+ ContentVerifier get(AlgorithmIdentifier verifierAlgorithmIdentifier)
+ throws OperatorCreationException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java
new file mode 100644
index 000000000..42d6665ed
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java
@@ -0,0 +1,97 @@
+package org.spongycastle.operator;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+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;
+
+public class DefaultDigestAlgorithmIdentifierFinder
+ implements DigestAlgorithmIdentifierFinder
+{
+ private static Map digestOids = new HashMap();
+ private static Map digestNameToOids = new HashMap();
+
+ static
+ {
+ //
+ // digests
+ //
+ digestOids.put(OIWObjectIdentifiers.md4WithRSAEncryption, PKCSObjectIdentifiers.md4);
+ digestOids.put(OIWObjectIdentifiers.md4WithRSA, PKCSObjectIdentifiers.md4);
+ digestOids.put(OIWObjectIdentifiers.sha1WithRSA, OIWObjectIdentifiers.idSHA1);
+
+ digestOids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224);
+ digestOids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, NISTObjectIdentifiers.id_sha256);
+ digestOids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, NISTObjectIdentifiers.id_sha384);
+ digestOids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, NISTObjectIdentifiers.id_sha512);
+ digestOids.put(PKCSObjectIdentifiers.md2WithRSAEncryption, PKCSObjectIdentifiers.md2);
+ digestOids.put(PKCSObjectIdentifiers.md4WithRSAEncryption, PKCSObjectIdentifiers.md4);
+ digestOids.put(PKCSObjectIdentifiers.md5WithRSAEncryption, PKCSObjectIdentifiers.md5);
+ digestOids.put(PKCSObjectIdentifiers.sha1WithRSAEncryption, OIWObjectIdentifiers.idSHA1);
+
+ digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, OIWObjectIdentifiers.idSHA1);
+ digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, NISTObjectIdentifiers.id_sha224);
+ digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, NISTObjectIdentifiers.id_sha256);
+ digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, NISTObjectIdentifiers.id_sha384);
+ digestOids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, NISTObjectIdentifiers.id_sha512);
+ digestOids.put(X9ObjectIdentifiers.id_dsa_with_sha1, OIWObjectIdentifiers.idSHA1);
+
+ digestOids.put(NISTObjectIdentifiers.dsa_with_sha224, NISTObjectIdentifiers.id_sha224);
+ digestOids.put(NISTObjectIdentifiers.dsa_with_sha256, NISTObjectIdentifiers.id_sha256);
+ digestOids.put(NISTObjectIdentifiers.dsa_with_sha384, NISTObjectIdentifiers.id_sha384);
+ digestOids.put(NISTObjectIdentifiers.dsa_with_sha512, NISTObjectIdentifiers.id_sha512);
+
+ digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128, TeleTrusTObjectIdentifiers.ripemd128);
+ digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160, TeleTrusTObjectIdentifiers.ripemd160);
+ digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256, TeleTrusTObjectIdentifiers.ripemd256);
+
+ digestOids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, CryptoProObjectIdentifiers.gostR3411);
+ digestOids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, CryptoProObjectIdentifiers.gostR3411);
+
+ digestNameToOids.put("SHA-1", OIWObjectIdentifiers.idSHA1);
+ digestNameToOids.put("SHA-224", NISTObjectIdentifiers.id_sha224);
+ digestNameToOids.put("SHA-256", NISTObjectIdentifiers.id_sha256);
+ digestNameToOids.put("SHA-384", NISTObjectIdentifiers.id_sha384);
+ digestNameToOids.put("SHA-512", NISTObjectIdentifiers.id_sha512);
+
+ digestNameToOids.put("GOST3411", CryptoProObjectIdentifiers.gostR3411);
+
+ digestNameToOids.put("MD2", PKCSObjectIdentifiers.md2);
+ digestNameToOids.put("MD4", PKCSObjectIdentifiers.md4);
+ digestNameToOids.put("MD5", PKCSObjectIdentifiers.md5);
+
+ digestNameToOids.put("RIPEMD128", TeleTrusTObjectIdentifiers.ripemd128);
+ digestNameToOids.put("RIPEMD160", TeleTrusTObjectIdentifiers.ripemd160);
+ digestNameToOids.put("RIPEMD256", TeleTrusTObjectIdentifiers.ripemd256);
+ }
+
+ public AlgorithmIdentifier find(AlgorithmIdentifier sigAlgId)
+ {
+ AlgorithmIdentifier digAlgId;
+
+ if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ digAlgId = RSASSAPSSparams.getInstance(sigAlgId.getParameters()).getHashAlgorithm();
+ }
+ else
+ {
+ digAlgId = new AlgorithmIdentifier((ASN1ObjectIdentifier)digestOids.get(sigAlgId.getAlgorithm()), DERNull.INSTANCE);
+ }
+
+ return digAlgId;
+ }
+
+ public AlgorithmIdentifier find(String digAlgName)
+ {
+ return new AlgorithmIdentifier((ASN1ObjectIdentifier)digestNameToOids.get(digAlgName), DERNull.INSTANCE);
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DefaultSecretKeySizeProvider.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DefaultSecretKeySizeProvider.java
new file mode 100644
index 000000000..d830e5cc3
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DefaultSecretKeySizeProvider.java
@@ -0,0 +1,69 @@
+package org.spongycastle.operator;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.ntt.NTTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.util.Integers;
+
+public class DefaultSecretKeySizeProvider
+ implements SecretKeySizeProvider
+{
+ public static final SecretKeySizeProvider INSTANCE = new DefaultSecretKeySizeProvider();
+
+ private static final Map KEY_SIZES;
+
+ static
+ {
+ Map keySizes = new HashMap();
+
+ keySizes.put(new ASN1ObjectIdentifier("1.2.840.113533.7.66.10"), Integers.valueOf(128));
+
+ keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC, 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)
+ {
+ int keySize = getKeySize(algorithmIdentifier.getAlgorithm());
+
+ // just need the OID
+ if (keySize > 0)
+ {
+ return keySize;
+ }
+
+ // TODO: support OID/Parameter key sizes (e.g. RC2).
+
+ return -1;
+ }
+
+ public int getKeySize(ASN1ObjectIdentifier algorithm)
+ {
+ Integer keySize = (Integer)KEY_SIZES.get(algorithm);
+
+ if (keySize != null)
+ {
+ return keySize.intValue();
+ }
+
+ return -1;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java
new file mode 100644
index 000000000..cd70901c5
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java
@@ -0,0 +1,212 @@
+package org.spongycastle.operator;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+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;
+import org.spongycastle.util.Strings;
+
+public class DefaultSignatureAlgorithmIdentifierFinder
+ implements SignatureAlgorithmIdentifierFinder
+{
+ private static Map algorithms = new HashMap();
+ private static Set noParams = new HashSet();
+ private static Map params = new HashMap();
+ private static Set pkcs15RsaEncryption = new HashSet();
+ private static Map digestOids = new HashMap();
+
+ private static final ASN1ObjectIdentifier ENCRYPTION_RSA = PKCSObjectIdentifiers.rsaEncryption;
+ private static final ASN1ObjectIdentifier ENCRYPTION_DSA = X9ObjectIdentifiers.id_dsa_with_sha1;
+ private static final ASN1ObjectIdentifier ENCRYPTION_ECDSA = X9ObjectIdentifiers.ecdsa_with_SHA1;
+ private static final ASN1ObjectIdentifier ENCRYPTION_RSA_PSS = PKCSObjectIdentifiers.id_RSASSA_PSS;
+ private static final ASN1ObjectIdentifier ENCRYPTION_GOST3410 = CryptoProObjectIdentifiers.gostR3410_94;
+ private static final ASN1ObjectIdentifier ENCRYPTION_ECGOST3410 = CryptoProObjectIdentifiers.gostR3410_2001;
+
+ 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);
+
+ //
+ // PKCS 1.5 encrypted algorithms
+ //
+ pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ pkcs15RsaEncryption.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ pkcs15RsaEncryption.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ pkcs15RsaEncryption.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+
+ //
+ // explicit params
+ //
+ AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
+ params.put("SHA1WITHRSAANDMGF1", createPSSParams(sha1AlgId, 20));
+
+ AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
+ params.put("SHA224WITHRSAANDMGF1", createPSSParams(sha224AlgId, 28));
+
+ AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
+ params.put("SHA256WITHRSAANDMGF1", createPSSParams(sha256AlgId, 32));
+
+ AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, DERNull.INSTANCE);
+ params.put("SHA384WITHRSAANDMGF1", createPSSParams(sha384AlgId, 48));
+
+ AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, DERNull.INSTANCE);
+ params.put("SHA512WITHRSAANDMGF1", createPSSParams(sha512AlgId, 64));
+
+ //
+ // digests
+ //
+ digestOids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224);
+ digestOids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, NISTObjectIdentifiers.id_sha256);
+ digestOids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, NISTObjectIdentifiers.id_sha384);
+ digestOids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, NISTObjectIdentifiers.id_sha512);
+ digestOids.put(PKCSObjectIdentifiers.md2WithRSAEncryption, PKCSObjectIdentifiers.md2);
+ digestOids.put(PKCSObjectIdentifiers.md4WithRSAEncryption, PKCSObjectIdentifiers.md4);
+ digestOids.put(PKCSObjectIdentifiers.md5WithRSAEncryption, PKCSObjectIdentifiers.md5);
+ digestOids.put(PKCSObjectIdentifiers.sha1WithRSAEncryption, OIWObjectIdentifiers.idSHA1);
+ digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128, TeleTrusTObjectIdentifiers.ripemd128);
+ digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160, TeleTrusTObjectIdentifiers.ripemd160);
+ digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256, TeleTrusTObjectIdentifiers.ripemd256);
+ digestOids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, CryptoProObjectIdentifiers.gostR3411);
+ digestOids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, CryptoProObjectIdentifiers.gostR3411);
+ }
+
+ private static AlgorithmIdentifier generate(String signatureAlgorithm)
+ {
+ AlgorithmIdentifier sigAlgId;
+ AlgorithmIdentifier encAlgId;
+ AlgorithmIdentifier digAlgId;
+
+ String algorithmName = Strings.toUpperCase(signatureAlgorithm);
+ ASN1ObjectIdentifier sigOID = (ASN1ObjectIdentifier)algorithms.get(algorithmName);
+ if (sigOID == null)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested: " + algorithmName);
+ }
+
+ if (noParams.contains(sigOID))
+ {
+ sigAlgId = new AlgorithmIdentifier(sigOID);
+ }
+ else if (params.containsKey(algorithmName))
+ {
+ sigAlgId = new AlgorithmIdentifier(sigOID, (ASN1Encodable)params.get(algorithmName));
+ }
+ else
+ {
+ sigAlgId = new AlgorithmIdentifier(sigOID, DERNull.INSTANCE);
+ }
+
+ if (pkcs15RsaEncryption.contains(sigOID))
+ {
+ encAlgId = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE);
+ }
+ else
+ {
+ encAlgId = sigAlgId;
+ }
+
+ if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ digAlgId = ((RSASSAPSSparams)sigAlgId.getParameters()).getHashAlgorithm();
+ }
+ else
+ {
+ digAlgId = new AlgorithmIdentifier((ASN1ObjectIdentifier)digestOids.get(sigOID), DERNull.INSTANCE);
+ }
+
+ return sigAlgId;
+ }
+
+ private static RSASSAPSSparams createPSSParams(AlgorithmIdentifier hashAlgId, int saltSize)
+ {
+ return new RSASSAPSSparams(
+ hashAlgId,
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId),
+ new ASN1Integer(saltSize),
+ new ASN1Integer(1));
+ }
+
+ public AlgorithmIdentifier find(String sigAlgName)
+ {
+ return generate(sigAlgName);
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DigestAlgorithmIdentifierFinder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DigestAlgorithmIdentifierFinder.java
new file mode 100644
index 000000000..1254c38e3
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DigestAlgorithmIdentifierFinder.java
@@ -0,0 +1,24 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface DigestAlgorithmIdentifierFinder
+{
+ /**
+ * Find the digest algorithm identifier that matches with
+ * the passed in signature algorithm identifier.
+ *
+ * @param sigAlgId the signature algorithm of interest.
+ * @return an algorithm identifier for the corresponding digest.
+ */
+ AlgorithmIdentifier find(AlgorithmIdentifier sigAlgId);
+
+ /**
+ * Find the algorithm identifier that matches with
+ * the passed in digest name.
+ *
+ * @param digAlgName the name of the digest algorithm of interest.
+ * @return an algorithm identifier for the digest signature.
+ */
+ AlgorithmIdentifier find(String digAlgName);
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DigestCalculator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DigestCalculator.java
new file mode 100644
index 000000000..0bb4712f5
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DigestCalculator.java
@@ -0,0 +1,36 @@
+package org.spongycastle.operator;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * General interface for an operator that is able to calculate a digest from
+ * a stream of output.
+ */
+public interface DigestCalculator
+{
+ /**
+ * Return the algorithm identifier representing the digest implemented by
+ * this calculator.
+ *
+ * @return algorithm id and parameters.
+ */
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ /**
+ * Returns a stream that will accept data for the purpose of calculating
+ * a digest. Use org.spongycastle.util.io.TeeOutputStream if you want to accumulate
+ * the data on the fly as well.
+ *
+ * @return an OutputStream
+ */
+ OutputStream getOutputStream();
+
+ /**
+ * Return the digest calculated on what has been written to the calculator's output stream.
+ *
+ * @return a digest.
+ */
+ byte[] getDigest();
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DigestCalculatorProvider.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DigestCalculatorProvider.java
new file mode 100644
index 000000000..55a7c1437
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/DigestCalculatorProvider.java
@@ -0,0 +1,9 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface DigestCalculatorProvider
+{
+ DigestCalculator get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ throws OperatorCreationException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/GenericKey.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/GenericKey.java
new file mode 100644
index 000000000..5446ce7bc
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/GenericKey.java
@@ -0,0 +1,41 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public class GenericKey
+{
+ private AlgorithmIdentifier algorithmIdentifier;
+ private Object representation;
+
+ /**
+ * @deprecated provide an AlgorithmIdentifier.
+ * @param representation key data
+ */
+ public GenericKey(Object representation)
+ {
+ this.algorithmIdentifier = null;
+ this.representation = representation;
+ }
+
+ public GenericKey(AlgorithmIdentifier algorithmIdentifier, byte[] representation)
+ {
+ this.algorithmIdentifier = algorithmIdentifier;
+ this.representation = representation;
+ }
+
+ protected GenericKey(AlgorithmIdentifier algorithmIdentifier, Object representation)
+ {
+ this.algorithmIdentifier = algorithmIdentifier;
+ this.representation = representation;
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmIdentifier;
+ }
+
+ public Object getRepresentation()
+ {
+ return representation;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/InputDecryptor.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/InputDecryptor.java
new file mode 100644
index 000000000..c55b3db05
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/InputDecryptor.java
@@ -0,0 +1,29 @@
+package org.spongycastle.operator;
+
+import java.io.InputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * General interface for an operator that is able to produce
+ * an InputStream that will decrypt a stream of encrypted data.
+ */
+public interface InputDecryptor
+{
+ /**
+ * Return the algorithm identifier describing the encryption
+ * algorithm and parameters this decryptor can process.
+ *
+ * @return algorithm oid and parameters.
+ */
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ /**
+ * Wrap the passed in input stream encIn, returning an input stream
+ * that decrypts what it reads from encIn before returning it.
+ *
+ * @param encIn InputStream containing encrypted input.
+ * @return an decrypting InputStream
+ */
+ InputStream getInputStream(InputStream encIn);
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/InputDecryptorProvider.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/InputDecryptorProvider.java
new file mode 100644
index 000000000..4ef7e9c05
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/InputDecryptorProvider.java
@@ -0,0 +1,9 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface InputDecryptorProvider
+{
+ public InputDecryptor get(AlgorithmIdentifier algorithm)
+ throws OperatorCreationException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/InputExpander.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/InputExpander.java
new file mode 100644
index 000000000..870e48079
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/InputExpander.java
@@ -0,0 +1,29 @@
+package org.spongycastle.operator;
+
+import java.io.InputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * General interface for an operator that is able to produce
+ * an InputStream that will produce uncompressed data.
+ */
+public interface InputExpander
+{
+ /**
+ * Return the algorithm identifier describing the compression
+ * algorithm and parameters this expander supports.
+ *
+ * @return algorithm oid and parameters.
+ */
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ /**
+ * Wrap the passed in input stream comIn, returning an input stream
+ * that expands anything read in from comIn.
+ *
+ * @param comIn the compressed input data stream..
+ * @return an expanding InputStream.
+ */
+ InputStream getInputStream(InputStream comIn);
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/InputExpanderProvider.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/InputExpanderProvider.java
new file mode 100644
index 000000000..d38b813ad
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/InputExpanderProvider.java
@@ -0,0 +1,8 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface InputExpanderProvider
+{
+ InputExpander get(AlgorithmIdentifier algorithm);
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/KeyUnwrapper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/KeyUnwrapper.java
new file mode 100644
index 000000000..8e2162308
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/KeyUnwrapper.java
@@ -0,0 +1,11 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface KeyUnwrapper
+{
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptionKeyAlgorithm, byte[] encryptedKey)
+ throws OperatorException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/KeyWrapper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/KeyWrapper.java
new file mode 100644
index 000000000..4b7986df0
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/KeyWrapper.java
@@ -0,0 +1,11 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface KeyWrapper
+{
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ byte[] generateWrappedKey(GenericKey encryptionKey)
+ throws OperatorException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/MacCalculator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/MacCalculator.java
new file mode 100644
index 000000000..df59ed652
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/MacCalculator.java
@@ -0,0 +1,34 @@
+package org.spongycastle.operator;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface MacCalculator
+{
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ /**
+ * Returns a stream that will accept data for the purpose of calculating
+ * the MAC for later verification. Use org.spongycastle.util.io.TeeOutputStream if you want to accumulate
+ * the data on the fly as well.
+ *
+ * @return an OutputStream
+ */
+ OutputStream getOutputStream();
+
+ /**
+ * Return the calculated MAC based on what has been written to the stream.
+ *
+ * @return calculated MAC.
+ */
+ byte[] getMac();
+
+
+ /**
+ * Return the key used for calculating the MAC.
+ *
+ * @return the MAC key.
+ */
+ GenericKey getKey();
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/MacCalculatorProvider.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/MacCalculatorProvider.java
new file mode 100644
index 000000000..a30773f28
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/MacCalculatorProvider.java
@@ -0,0 +1,8 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface MacCalculatorProvider
+{
+ public MacCalculator get(AlgorithmIdentifier algorithm);
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OperatorCreationException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OperatorCreationException.java
new file mode 100644
index 000000000..4e7cadacf
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OperatorCreationException.java
@@ -0,0 +1,15 @@
+package org.spongycastle.operator;
+
+public class OperatorCreationException
+ extends OperatorException
+{
+ public OperatorCreationException(String msg, Throwable cause)
+ {
+ super(msg, cause);
+ }
+
+ public OperatorCreationException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OperatorException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OperatorException.java
new file mode 100644
index 000000000..32ce9e41c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OperatorException.java
@@ -0,0 +1,24 @@
+package org.spongycastle.operator;
+
+public class OperatorException
+ extends Exception
+{
+ private Throwable cause;
+
+ public OperatorException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public OperatorException(String msg)
+ {
+ super(msg);
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OperatorStreamException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OperatorStreamException.java
new file mode 100644
index 000000000..960d292fe
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OperatorStreamException.java
@@ -0,0 +1,21 @@
+package org.spongycastle.operator;
+
+import java.io.IOException;
+
+public class OperatorStreamException
+ extends IOException
+{
+ private Throwable cause;
+
+ public OperatorStreamException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OutputCompressor.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OutputCompressor.java
new file mode 100644
index 000000000..0e10df9a5
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OutputCompressor.java
@@ -0,0 +1,29 @@
+package org.spongycastle.operator;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * General interface for an operator that is able to produce
+ * an OutputStream that will output compressed data.
+ */
+public interface OutputCompressor
+{
+ /**
+ * Return the algorithm identifier describing the compression
+ * algorithm and parameters this compressor uses.
+ *
+ * @return algorithm oid and parameters.
+ */
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ /**
+ * Wrap the passed in output stream comOut, returning an output stream
+ * that compresses anything passed in before sending on to comOut.
+ *
+ * @param comOut output stream for compressed output.
+ * @return a compressing OutputStream
+ */
+ OutputStream getOutputStream(OutputStream comOut);
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OutputEncryptor.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OutputEncryptor.java
new file mode 100644
index 000000000..595e3b75e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/OutputEncryptor.java
@@ -0,0 +1,36 @@
+package org.spongycastle.operator;
+
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * General interface for an operator that is able to produce
+ * an OutputStream that will output encrypted data.
+ */
+public interface OutputEncryptor
+{
+ /**
+ * Return the algorithm identifier describing the encryption
+ * algorithm and parameters this encryptor uses.
+ *
+ * @return algorithm oid and parameters.
+ */
+ AlgorithmIdentifier getAlgorithmIdentifier();
+
+ /**
+ * Wrap the passed in output stream encOut, returning an output stream
+ * that encrypts anything passed in before sending on to encOut.
+ *
+ * @param encOut output stream for encrypted output.
+ * @return an encrypting OutputStream
+ */
+ OutputStream getOutputStream(OutputStream encOut);
+
+ /**
+ * Return the key used for encrypting the output.
+ *
+ * @return the encryption key.
+ */
+ GenericKey getKey();
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/RawContentVerifier.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/RawContentVerifier.java
new file mode 100644
index 000000000..56bfb47f9
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/RawContentVerifier.java
@@ -0,0 +1,17 @@
+package org.spongycastle.operator;
+
+/**
+ * Interface for ContentVerifiers that also support raw signatures that can be
+ * verified using the digest of the calculated data.
+ */
+public interface RawContentVerifier
+{
+ /**
+ * Verify that the expected signature value was derived from the passed in digest.
+ *
+ * @param digest digest calculated from the content.
+ * @param expected expected value of the signature
+ * @return true if the expected signature is derived from the digest, false otherwise.
+ */
+ boolean verify(byte[] digest, byte[] expected);
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/RuntimeOperatorException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/RuntimeOperatorException.java
new file mode 100644
index 000000000..56cab04a7
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/RuntimeOperatorException.java
@@ -0,0 +1,24 @@
+package org.spongycastle.operator;
+
+public class RuntimeOperatorException
+ extends RuntimeException
+{
+ private Throwable cause;
+
+ public RuntimeOperatorException(String msg)
+ {
+ super(msg);
+ }
+
+ public RuntimeOperatorException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/SecretKeySizeProvider.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/SecretKeySizeProvider.java
new file mode 100644
index 000000000..cb2d6561a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/SecretKeySizeProvider.java
@@ -0,0 +1,17 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface SecretKeySizeProvider
+{
+ int getKeySize(AlgorithmIdentifier algorithmIdentifier);
+
+ /**
+ * Return the key size implied by the OID, if one exists.
+ *
+ * @param algorithm the OID of the algorithm of interest.
+ * @return -1 if there is no fixed key size associated with the OID, or more information is required.
+ */
+ int getKeySize(ASN1ObjectIdentifier algorithm);
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/SignatureAlgorithmIdentifierFinder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/SignatureAlgorithmIdentifierFinder.java
new file mode 100644
index 000000000..5c997bdaa
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/SignatureAlgorithmIdentifierFinder.java
@@ -0,0 +1,15 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface SignatureAlgorithmIdentifierFinder
+{
+ /**
+ * Find the signature algorithm identifier that matches with
+ * the passed in signature algorithm name.
+ *
+ * @param sigAlgName the name of the signature algorithm of interest.
+ * @return an algorithm identifier for the corresponding signature.
+ */
+ AlgorithmIdentifier find(String sigAlgName);
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyUnwrapper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyUnwrapper.java
new file mode 100644
index 000000000..705a76713
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyUnwrapper.java
@@ -0,0 +1,19 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public abstract class SymmetricKeyUnwrapper
+ implements KeyUnwrapper
+{
+ private AlgorithmIdentifier algorithmId;
+
+ protected SymmetricKeyUnwrapper(AlgorithmIdentifier algorithmId)
+ {
+ this.algorithmId = algorithmId;
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmId;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyWrapper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyWrapper.java
new file mode 100644
index 000000000..56ac7ef1f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/SymmetricKeyWrapper.java
@@ -0,0 +1,19 @@
+package org.spongycastle.operator;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public abstract class SymmetricKeyWrapper
+ implements KeyWrapper
+{
+ private AlgorithmIdentifier algorithmId;
+
+ protected SymmetricKeyWrapper(AlgorithmIdentifier algorithmId)
+ {
+ this.algorithmId = algorithmId;
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmId;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/AESUtil.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/AESUtil.java
new file mode 100644
index 000000000..7abd31be2
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/AESUtil.java
@@ -0,0 +1,34 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.params.KeyParameter;
+
+class AESUtil
+{
+ static AlgorithmIdentifier determineKeyEncAlg(KeyParameter key)
+ {
+ int length = key.getKey().length * 8;
+ ASN1ObjectIdentifier wrapOid;
+
+ if (length == 128)
+ {
+ wrapOid = NISTObjectIdentifiers.id_aes128_wrap;
+ }
+ else if (length == 192)
+ {
+ wrapOid = NISTObjectIdentifiers.id_aes192_wrap;
+ }
+ else if (length == 256)
+ {
+ wrapOid = NISTObjectIdentifiers.id_aes256_wrap;
+ }
+ else
+ {
+ throw new IllegalArgumentException("illegal keysize in AES");
+ }
+
+ return new AlgorithmIdentifier(wrapOid); // parameters absent
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyUnwrapper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyUnwrapper.java
new file mode 100644
index 000000000..f9b8c09b0
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyUnwrapper.java
@@ -0,0 +1,13 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.crypto.engines.AESWrapEngine;
+import org.spongycastle.crypto.params.KeyParameter;
+
+public class BcAESSymmetricKeyUnwrapper
+ extends BcSymmetricKeyUnwrapper
+{
+ public BcAESSymmetricKeyUnwrapper(KeyParameter wrappingKey)
+ {
+ super(AESUtil.determineKeyEncAlg(wrappingKey), new AESWrapEngine(), wrappingKey);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyWrapper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyWrapper.java
new file mode 100644
index 000000000..62dc062f6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcAESSymmetricKeyWrapper.java
@@ -0,0 +1,13 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.crypto.engines.AESWrapEngine;
+import org.spongycastle.crypto.params.KeyParameter;
+
+public class BcAESSymmetricKeyWrapper
+ extends BcSymmetricKeyWrapper
+{
+ public BcAESSymmetricKeyWrapper(KeyParameter wrappingKey)
+ {
+ super(AESUtil.determineKeyEncAlg(wrappingKey), new AESWrapEngine(), wrappingKey);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyUnwrapper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyUnwrapper.java
new file mode 100644
index 000000000..8fed9debe
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyUnwrapper.java
@@ -0,0 +1,51 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.operator.AsymmetricKeyUnwrapper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+
+public abstract class BcAsymmetricKeyUnwrapper
+ extends AsymmetricKeyUnwrapper
+{
+ private AsymmetricKeyParameter privateKey;
+
+ public BcAsymmetricKeyUnwrapper(AlgorithmIdentifier encAlgId, AsymmetricKeyParameter privateKey)
+ {
+ super(encAlgId);
+
+ this.privateKey = privateKey;
+ }
+
+ public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedKey)
+ throws OperatorException
+ {
+ AsymmetricBlockCipher keyCipher = createAsymmetricUnwrapper(this.getAlgorithmIdentifier().getAlgorithm());
+
+ keyCipher.init(false, privateKey);
+ try
+ {
+ byte[] key = keyCipher.processBlock(encryptedKey, 0, encryptedKey.length);
+
+ if (encryptedKeyAlgorithm.getAlgorithm().equals(PKCSObjectIdentifiers.des_EDE3_CBC))
+ {
+ return new GenericKey(encryptedKeyAlgorithm, key);
+ }
+ else
+ {
+ return new GenericKey(encryptedKeyAlgorithm, key);
+ }
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new OperatorException("unable to recover secret key: " + e.getMessage(), e);
+ }
+ }
+
+ protected abstract AsymmetricBlockCipher createAsymmetricUnwrapper(ASN1ObjectIdentifier algorithm);
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyWrapper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyWrapper.java
new file mode 100644
index 000000000..8b5bb3e8c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcAsymmetricKeyWrapper.java
@@ -0,0 +1,60 @@
+package org.spongycastle.operator.bc;
+
+import java.security.SecureRandom;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.operator.AsymmetricKeyWrapper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+
+public abstract class BcAsymmetricKeyWrapper
+ extends AsymmetricKeyWrapper
+{
+ private AsymmetricKeyParameter publicKey;
+ private SecureRandom random;
+
+ public BcAsymmetricKeyWrapper(AlgorithmIdentifier encAlgId, AsymmetricKeyParameter publicKey)
+ {
+ super(encAlgId);
+
+ this.publicKey = publicKey;
+ }
+
+ public BcAsymmetricKeyWrapper setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public byte[] generateWrappedKey(GenericKey encryptionKey)
+ throws OperatorException
+ {
+ AsymmetricBlockCipher keyEncryptionCipher = createAsymmetricWrapper(getAlgorithmIdentifier().getAlgorithm());
+
+ CipherParameters params = publicKey;
+ if (random != null)
+ {
+ params = new ParametersWithRandom(params, random);
+ }
+
+ try
+ {
+ byte[] keyEnc = OperatorUtils.getKeyBytes(encryptionKey);
+ keyEncryptionCipher.init(true, publicKey);
+ return keyEncryptionCipher.processBlock(keyEnc, 0, keyEnc.length);
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new OperatorException("unable to encrypt contents key", e);
+ }
+ }
+
+ protected abstract AsymmetricBlockCipher createAsymmetricWrapper(ASN1ObjectIdentifier algorithm);
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcContentSignerBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcContentSignerBuilder.java
new file mode 100644
index 000000000..7160adff2
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcContentSignerBuilder.java
@@ -0,0 +1,82 @@
+package org.spongycastle.operator.bc;
+
+import java.io.OutputStream;
+import java.security.SecureRandom;
+import java.util.Map;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.CryptoException;
+import org.spongycastle.crypto.Signer;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.RuntimeOperatorException;
+
+public abstract class BcContentSignerBuilder
+{
+ private SecureRandom random;
+ private AlgorithmIdentifier sigAlgId;
+ private AlgorithmIdentifier digAlgId;
+
+ protected BcDigestProvider digestProvider;
+
+ public BcContentSignerBuilder(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId)
+ {
+ this.sigAlgId = sigAlgId;
+ this.digAlgId = digAlgId;
+ this.digestProvider = BcDefaultDigestProvider.INSTANCE;
+ }
+
+ public BcContentSignerBuilder setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public ContentSigner build(AsymmetricKeyParameter privateKey)
+ throws OperatorCreationException
+ {
+ final Signer sig = createSigner(sigAlgId, digAlgId);
+
+ if (random != null)
+ {
+ sig.init(true, new ParametersWithRandom(privateKey, random));
+ }
+ else
+ {
+ sig.init(true, privateKey);
+ }
+
+ return new ContentSigner()
+ {
+ private BcSignerOutputStream stream = new BcSignerOutputStream(sig);
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return sigAlgId;
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return stream;
+ }
+
+ public byte[] getSignature()
+ {
+ try
+ {
+ return stream.getSignature();
+ }
+ catch (CryptoException e)
+ {
+ throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e);
+ }
+ }
+ };
+ }
+
+ protected abstract Signer createSigner(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier algorithmIdentifier)
+ throws OperatorCreationException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcContentVerifierProviderBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcContentVerifierProviderBuilder.java
new file mode 100644
index 000000000..3b975e4fa
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcContentVerifierProviderBuilder.java
@@ -0,0 +1,144 @@
+package org.spongycastle.operator.bc;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.crypto.Signer;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.operator.ContentVerifier;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.OperatorCreationException;
+
+public abstract class BcContentVerifierProviderBuilder
+{
+ protected BcDigestProvider digestProvider;
+
+ public BcContentVerifierProviderBuilder()
+ {
+ this.digestProvider = BcDefaultDigestProvider.INSTANCE;
+ }
+
+ public ContentVerifierProvider build(final X509CertificateHolder certHolder)
+ throws OperatorCreationException
+ {
+ return new ContentVerifierProvider()
+ {
+ public boolean hasAssociatedCertificate()
+ {
+ return true;
+ }
+
+ public X509CertificateHolder getAssociatedCertificate()
+ {
+ return certHolder;
+ }
+
+ public ContentVerifier get(AlgorithmIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ try
+ {
+ AsymmetricKeyParameter publicKey = extractKeyParameters(certHolder.getSubjectPublicKeyInfo());
+ BcSignerOutputStream stream = createSignatureStream(algorithm, publicKey);
+
+ return new SigVerifier(algorithm, stream);
+ }
+ catch (IOException e)
+ {
+ throw new OperatorCreationException("exception on setup: " + e, e);
+ }
+ }
+ };
+ }
+
+ public ContentVerifierProvider build(final AsymmetricKeyParameter publicKey)
+ throws OperatorCreationException
+ {
+ return new ContentVerifierProvider()
+ {
+ public boolean hasAssociatedCertificate()
+ {
+ return false;
+ }
+
+ public X509CertificateHolder getAssociatedCertificate()
+ {
+ return null;
+ }
+
+ public ContentVerifier get(AlgorithmIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ BcSignerOutputStream stream = createSignatureStream(algorithm, publicKey);
+
+ return new SigVerifier(algorithm, stream);
+ }
+ };
+ }
+
+ private BcSignerOutputStream createSignatureStream(AlgorithmIdentifier algorithm, AsymmetricKeyParameter publicKey)
+ throws OperatorCreationException
+ {
+ Signer sig = createSigner(algorithm);
+
+ sig.init(false, publicKey);
+
+ return new BcSignerOutputStream(sig);
+ }
+
+ /**
+ * Extract an AsymmetricKeyParameter from the passed in SubjectPublicKeyInfo structure.
+ *
+ * @param publicKeyInfo a publicKeyInfo structure describing the public key required.
+ * @return an AsymmetricKeyParameter object containing the appropriate public key.
+ * @throws IOException if the publicKeyInfo data cannot be parsed,
+ */
+ protected abstract AsymmetricKeyParameter extractKeyParameters(SubjectPublicKeyInfo publicKeyInfo)
+ throws IOException;
+
+ /**
+ * Create the correct signer for the algorithm identifier sigAlgId.
+ *
+ * @param sigAlgId the algorithm details for the signature we want to verify.
+ * @return a Signer object.
+ * @throws OperatorCreationException if the Signer cannot be constructed.
+ */
+ protected abstract Signer createSigner(AlgorithmIdentifier sigAlgId)
+ throws OperatorCreationException;
+
+ private class SigVerifier
+ implements ContentVerifier
+ {
+ private BcSignerOutputStream stream;
+ private AlgorithmIdentifier algorithm;
+
+ SigVerifier(AlgorithmIdentifier algorithm, BcSignerOutputStream stream)
+ {
+ this.algorithm = algorithm;
+ this.stream = stream;
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithm;
+ }
+
+ public OutputStream getOutputStream()
+ {
+ if (stream == null)
+ {
+ throw new IllegalStateException("verifier not initialised");
+ }
+
+ return stream;
+ }
+
+ public boolean verify(byte[] expected)
+ {
+ return stream.verify(expected);
+ }
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentSignerBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentSignerBuilder.java
new file mode 100644
index 000000000..db7b608dc
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentSignerBuilder.java
@@ -0,0 +1,25 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.Signer;
+import org.spongycastle.crypto.signers.DSADigestSigner;
+import org.spongycastle.crypto.signers.DSASigner;
+import org.spongycastle.operator.OperatorCreationException;
+
+public class BcDSAContentSignerBuilder
+ extends BcContentSignerBuilder
+{
+ public BcDSAContentSignerBuilder(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId)
+ {
+ super(sigAlgId, digAlgId);
+ }
+
+ protected Signer createSigner(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId)
+ throws OperatorCreationException
+ {
+ Digest dig = digestProvider.get(digAlgId);
+
+ return new DSADigestSigner(new DSASigner(), dig);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentVerifierProviderBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentVerifierProviderBuilder.java
new file mode 100644
index 000000000..aaf25f4d5
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDSAContentVerifierProviderBuilder.java
@@ -0,0 +1,40 @@
+package org.spongycastle.operator.bc;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.Signer;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.signers.DSADigestSigner;
+import org.spongycastle.crypto.signers.DSASigner;
+import org.spongycastle.crypto.util.PublicKeyFactory;
+import org.spongycastle.operator.DigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.OperatorCreationException;
+
+public class BcDSAContentVerifierProviderBuilder
+ extends BcContentVerifierProviderBuilder
+{
+ private DigestAlgorithmIdentifierFinder digestAlgorithmFinder;
+
+ public BcDSAContentVerifierProviderBuilder(DigestAlgorithmIdentifierFinder digestAlgorithmFinder)
+ {
+ this.digestAlgorithmFinder = digestAlgorithmFinder;
+ }
+
+ protected Signer createSigner(AlgorithmIdentifier sigAlgId)
+ throws OperatorCreationException
+ {
+ AlgorithmIdentifier digAlg = digestAlgorithmFinder.find(sigAlgId);
+ Digest dig = digestProvider.get(digAlg);
+
+ return new DSADigestSigner(new DSASigner(), dig);
+ }
+
+ protected AsymmetricKeyParameter extractKeyParameters(SubjectPublicKeyInfo publicKeyInfo)
+ throws IOException
+ {
+ return PublicKeyFactory.createKey(publicKeyInfo);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDefaultDigestProvider.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDefaultDigestProvider.java
new file mode 100644
index 000000000..dce50a9e2
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDefaultDigestProvider.java
@@ -0,0 +1,144 @@
+package org.spongycastle.operator.bc;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+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.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.ExtendedDigest;
+import org.spongycastle.crypto.digests.GOST3411Digest;
+import org.spongycastle.crypto.digests.MD2Digest;
+import org.spongycastle.crypto.digests.MD4Digest;
+import org.spongycastle.crypto.digests.MD5Digest;
+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.operator.OperatorCreationException;
+
+public class BcDefaultDigestProvider
+ implements BcDigestProvider
+{
+ private static final Map lookup = createTable();
+
+ private static Map createTable()
+ {
+ Map table = new HashMap();
+
+ table.put(OIWObjectIdentifiers.idSHA1, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new SHA1Digest();
+ }
+ });
+ table.put(NISTObjectIdentifiers.id_sha224, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new SHA224Digest();
+ }
+ });
+ table.put(NISTObjectIdentifiers.id_sha256, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new SHA256Digest();
+ }
+ });
+ table.put(NISTObjectIdentifiers.id_sha384, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new SHA384Digest();
+ }
+ });
+ table.put(NISTObjectIdentifiers.id_sha512, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new SHA512Digest();
+ }
+ });
+ table.put(PKCSObjectIdentifiers.md5, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new MD5Digest();
+ }
+ });
+ table.put(PKCSObjectIdentifiers.md4, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new MD4Digest();
+ }
+ });
+ table.put(PKCSObjectIdentifiers.md2, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new MD2Digest();
+ }
+ });
+ table.put(CryptoProObjectIdentifiers.gostR3411, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new GOST3411Digest();
+ }
+ });
+ table.put(TeleTrusTObjectIdentifiers.ripemd128, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new RIPEMD128Digest();
+ }
+ });
+ table.put(TeleTrusTObjectIdentifiers.ripemd160, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new RIPEMD160Digest();
+ }
+ });
+ table.put(TeleTrusTObjectIdentifiers.ripemd256, new BcDigestProvider()
+ {
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ {
+ return new RIPEMD256Digest();
+ }
+ });
+
+ return Collections.unmodifiableMap(table);
+ }
+
+ public static final BcDigestProvider INSTANCE = new BcDefaultDigestProvider();
+
+ private BcDefaultDigestProvider()
+ {
+
+ }
+
+ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ throws OperatorCreationException
+ {
+ BcDigestProvider extProv = (BcDigestProvider)lookup.get(digestAlgorithmIdentifier.getAlgorithm());
+
+ if (extProv == null)
+ {
+ throw new OperatorCreationException("cannot recognise digest");
+ }
+
+ return extProv.get(digestAlgorithmIdentifier);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestCalculatorProvider.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestCalculatorProvider.java
new file mode 100644
index 000000000..8e0a12f64
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestCalculatorProvider.java
@@ -0,0 +1,82 @@
+package org.spongycastle.operator.bc;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Map;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.ExtendedDigest;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+
+public class BcDigestCalculatorProvider
+ implements DigestCalculatorProvider
+{
+ private BcDigestProvider digestProvider = BcDefaultDigestProvider.INSTANCE;
+
+ public DigestCalculator get(final AlgorithmIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ Digest dig = digestProvider.get(algorithm);
+
+ final DigestOutputStream stream = new DigestOutputStream(dig);
+
+ return new DigestCalculator()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithm;
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return stream;
+ }
+
+ public byte[] getDigest()
+ {
+ return stream.getDigest();
+ }
+ };
+ }
+
+ private class DigestOutputStream
+ extends OutputStream
+ {
+ private Digest dig;
+
+ DigestOutputStream(Digest dig)
+ {
+ this.dig = dig;
+ }
+
+ public void write(byte[] bytes, int off, int len)
+ throws IOException
+ {
+ dig.update(bytes, off, len);
+ }
+
+ public void write(byte[] bytes)
+ throws IOException
+ {
+ dig.update(bytes, 0, bytes.length);
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ dig.update((byte)b);
+ }
+
+ byte[] getDigest()
+ {
+ byte[] d = new byte[dig.getDigestSize()];
+
+ dig.doFinal(d, 0);
+
+ return d;
+ }
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestProvider.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestProvider.java
new file mode 100644
index 000000000..6eb930ee5
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcDigestProvider.java
@@ -0,0 +1,11 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.ExtendedDigest;
+import org.spongycastle.operator.OperatorCreationException;
+
+public interface BcDigestProvider
+{
+ ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier)
+ throws OperatorCreationException;
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyUnwrapper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyUnwrapper.java
new file mode 100644
index 000000000..997623534
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyUnwrapper.java
@@ -0,0 +1,22 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.encodings.PKCS1Encoding;
+import org.spongycastle.crypto.engines.RSAEngine;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+
+public class BcRSAAsymmetricKeyUnwrapper
+ extends BcAsymmetricKeyUnwrapper
+{
+ public BcRSAAsymmetricKeyUnwrapper(AlgorithmIdentifier encAlgId, AsymmetricKeyParameter privateKey)
+ {
+ super(encAlgId, privateKey);
+ }
+
+ protected AsymmetricBlockCipher createAsymmetricUnwrapper(ASN1ObjectIdentifier algorithm)
+ {
+ return new PKCS1Encoding(new RSAEngine());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyWrapper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyWrapper.java
new file mode 100644
index 000000000..c2153e6d3
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAAsymmetricKeyWrapper.java
@@ -0,0 +1,32 @@
+package org.spongycastle.operator.bc;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.encodings.PKCS1Encoding;
+import org.spongycastle.crypto.engines.RSAEngine;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.util.PublicKeyFactory;
+
+public class BcRSAAsymmetricKeyWrapper
+ extends BcAsymmetricKeyWrapper
+{
+ public BcRSAAsymmetricKeyWrapper(AlgorithmIdentifier encAlgId, AsymmetricKeyParameter publicKey)
+ {
+ super(encAlgId, publicKey);
+ }
+
+ public BcRSAAsymmetricKeyWrapper(AlgorithmIdentifier encAlgId, SubjectPublicKeyInfo publicKeyInfo)
+ throws IOException
+ {
+ super(encAlgId, PublicKeyFactory.createKey(publicKeyInfo));
+ }
+
+ protected AsymmetricBlockCipher createAsymmetricWrapper(ASN1ObjectIdentifier algorithm)
+ {
+ return new PKCS1Encoding(new RSAEngine());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentSignerBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentSignerBuilder.java
new file mode 100644
index 000000000..d62543b00
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentSignerBuilder.java
@@ -0,0 +1,24 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.Signer;
+import org.spongycastle.crypto.signers.RSADigestSigner;
+import org.spongycastle.operator.OperatorCreationException;
+
+public class BcRSAContentSignerBuilder
+ extends BcContentSignerBuilder
+{
+ public BcRSAContentSignerBuilder(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId)
+ {
+ super(sigAlgId, digAlgId);
+ }
+
+ protected Signer createSigner(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId)
+ throws OperatorCreationException
+ {
+ Digest dig = digestProvider.get(digAlgId);
+
+ return new RSADigestSigner(dig);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentVerifierProviderBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentVerifierProviderBuilder.java
new file mode 100644
index 000000000..e1fd6736d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcRSAContentVerifierProviderBuilder.java
@@ -0,0 +1,39 @@
+package org.spongycastle.operator.bc;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.Signer;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.signers.RSADigestSigner;
+import org.spongycastle.crypto.util.PublicKeyFactory;
+import org.spongycastle.operator.DigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.OperatorCreationException;
+
+public class BcRSAContentVerifierProviderBuilder
+ extends BcContentVerifierProviderBuilder
+{
+ private DigestAlgorithmIdentifierFinder digestAlgorithmFinder;
+
+ public BcRSAContentVerifierProviderBuilder(DigestAlgorithmIdentifierFinder digestAlgorithmFinder)
+ {
+ this.digestAlgorithmFinder = digestAlgorithmFinder;
+ }
+
+ protected Signer createSigner(AlgorithmIdentifier sigAlgId)
+ throws OperatorCreationException
+ {
+ AlgorithmIdentifier digAlg = digestAlgorithmFinder.find(sigAlgId);
+ Digest dig = digestProvider.get(digAlg);
+
+ return new RSADigestSigner(dig);
+ }
+
+ protected AsymmetricKeyParameter extractKeyParameters(SubjectPublicKeyInfo publicKeyInfo)
+ throws IOException
+ {
+ return PublicKeyFactory.createKey(publicKeyInfo);
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcSignerOutputStream.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcSignerOutputStream.java
new file mode 100644
index 000000000..f4cdf62b9
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcSignerOutputStream.java
@@ -0,0 +1,47 @@
+package org.spongycastle.operator.bc;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.crypto.CryptoException;
+import org.spongycastle.crypto.Signer;
+
+public class BcSignerOutputStream
+ extends OutputStream
+{
+ private Signer sig;
+
+ BcSignerOutputStream(Signer sig)
+ {
+ this.sig = sig;
+ }
+
+ public void write(byte[] bytes, int off, int len)
+ throws IOException
+ {
+ sig.update(bytes, off, len);
+ }
+
+ public void write(byte[] bytes)
+ throws IOException
+ {
+ sig.update(bytes, 0, bytes.length);
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ sig.update((byte)b);
+ }
+
+ byte[] getSignature()
+ throws CryptoException
+ {
+ return sig.generateSignature();
+ }
+
+ boolean verify(byte[] expected)
+ {
+ return sig.verifySignature(expected);
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyUnwrapper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyUnwrapper.java
new file mode 100644
index 000000000..da37cf1aa
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyUnwrapper.java
@@ -0,0 +1,49 @@
+package org.spongycastle.operator.bc;
+
+import java.security.SecureRandom;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.Wrapper;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+import org.spongycastle.operator.SymmetricKeyUnwrapper;
+
+public class BcSymmetricKeyUnwrapper
+ extends SymmetricKeyUnwrapper
+{
+ private SecureRandom random;
+ private Wrapper wrapper;
+ private KeyParameter wrappingKey;
+
+ public BcSymmetricKeyUnwrapper(AlgorithmIdentifier wrappingAlgorithm, Wrapper wrapper, KeyParameter wrappingKey)
+ {
+ super(wrappingAlgorithm);
+
+ this.wrapper = wrapper;
+ this.wrappingKey = wrappingKey;
+ }
+
+ public BcSymmetricKeyUnwrapper setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedKey)
+ throws OperatorException
+ {
+ wrapper.init(false, wrappingKey);
+
+ try
+ {
+ return new GenericKey(encryptedKeyAlgorithm, wrapper.unwrap(encryptedKey, 0, encryptedKey.length));
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new OperatorException("unable to unwrap key: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyWrapper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyWrapper.java
new file mode 100644
index 000000000..a35de7d71
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/BcSymmetricKeyWrapper.java
@@ -0,0 +1,51 @@
+package org.spongycastle.operator.bc;
+
+import java.security.SecureRandom;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.Wrapper;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+import org.spongycastle.operator.SymmetricKeyWrapper;
+
+public class BcSymmetricKeyWrapper
+ extends SymmetricKeyWrapper
+{
+ private SecureRandom random;
+ private Wrapper wrapper;
+ private KeyParameter wrappingKey;
+
+ public BcSymmetricKeyWrapper(AlgorithmIdentifier wrappingAlgorithm, Wrapper wrapper, KeyParameter wrappingKey)
+ {
+ super(wrappingAlgorithm);
+
+ this.wrapper = wrapper;
+ this.wrappingKey = wrappingKey;
+ }
+
+ public BcSymmetricKeyWrapper setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public byte[] generateWrappedKey(GenericKey encryptionKey)
+ throws OperatorException
+ {
+ byte[] contentEncryptionKeySpec = OperatorUtils.getKeyBytes(encryptionKey);
+
+ if (random == null)
+ {
+ wrapper.init(true, wrappingKey);
+ }
+ else
+ {
+ wrapper.init(true, new ParametersWithRandom(wrappingKey, random));
+ }
+
+ return wrapper.wrap(contentEncryptionKeySpec, 0, contentEncryptionKeySpec.length);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/CamelliaUtil.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/CamelliaUtil.java
new file mode 100644
index 000000000..9b7c9836b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/CamelliaUtil.java
@@ -0,0 +1,36 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ntt.NTTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.params.KeyParameter;
+
+class CamelliaUtil
+{
+ static AlgorithmIdentifier determineKeyEncAlg(KeyParameter key)
+ {
+ int length = key.getKey().length * 8;
+ ASN1ObjectIdentifier wrapOid;
+
+ if (length == 128)
+ {
+ wrapOid = NTTObjectIdentifiers.id_camellia128_wrap;
+ }
+ else if (length == 192)
+ {
+ wrapOid = NTTObjectIdentifiers.id_camellia192_wrap;
+ }
+ else if (length == 256)
+ {
+ wrapOid = NTTObjectIdentifiers.id_camellia256_wrap;
+ }
+ else
+ {
+ throw new IllegalArgumentException(
+ "illegal keysize in Camellia");
+ }
+
+ return new AlgorithmIdentifier(wrapOid); // parameters must be
+ // absent
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/OperatorUtils.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/OperatorUtils.java
new file mode 100644
index 000000000..a53c46923
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/OperatorUtils.java
@@ -0,0 +1,23 @@
+package org.spongycastle.operator.bc;
+
+import java.security.Key;
+
+import org.spongycastle.operator.GenericKey;
+
+class OperatorUtils
+{
+ static byte[] getKeyBytes(GenericKey key)
+ {
+ if (key.getRepresentation() instanceof Key)
+ {
+ return ((Key)key.getRepresentation()).getEncoded();
+ }
+
+ if (key.getRepresentation() instanceof byte[])
+ {
+ return (byte[])key.getRepresentation();
+ }
+
+ throw new IllegalArgumentException("unknown generic key type");
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/SEEDUtil.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/SEEDUtil.java
new file mode 100644
index 000000000..4d9773100
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/bc/SEEDUtil.java
@@ -0,0 +1,14 @@
+package org.spongycastle.operator.bc;
+
+import org.spongycastle.asn1.kisa.KISAObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+class SEEDUtil
+{
+ static AlgorithmIdentifier determineKeyEncAlg()
+ {
+ // parameters absent
+ return new AlgorithmIdentifier(
+ KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaAlgorithmParametersConverter.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaAlgorithmParametersConverter.java
new file mode 100644
index 000000000..98e2b929b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaAlgorithmParametersConverter.java
@@ -0,0 +1,73 @@
+package org.spongycastle.operator.jcajce;
+
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.MGF1ParameterSpec;
+
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSAESOAEPparams;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+
+public class JcaAlgorithmParametersConverter
+{
+ public JcaAlgorithmParametersConverter()
+ {
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier algId, AlgorithmParameters parameters)
+ throws InvalidAlgorithmParameterException
+ {
+ try
+ {
+ ASN1Encodable params = ASN1Primitive.fromByteArray(parameters.getEncoded());
+
+ return new AlgorithmIdentifier(algId, params);
+ }
+ catch (IOException e)
+ {
+ throw new InvalidAlgorithmParameterException("unable to encode parameters object: " + e.getMessage());
+ }
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier algorithm, AlgorithmParameterSpec algorithmSpec)
+ throws InvalidAlgorithmParameterException
+ {
+ if (algorithmSpec instanceof OAEPParameterSpec)
+ {
+ if (algorithmSpec.equals(OAEPParameterSpec.DEFAULT))
+ {
+ return new AlgorithmIdentifier(algorithm,
+ new RSAESOAEPparams(RSAESOAEPparams.DEFAULT_HASH_ALGORITHM, RSAESOAEPparams.DEFAULT_MASK_GEN_FUNCTION, RSAESOAEPparams.DEFAULT_P_SOURCE_ALGORITHM));
+ }
+ else
+ {
+ OAEPParameterSpec oaepSpec = (OAEPParameterSpec)algorithmSpec;
+ PSource pSource = oaepSpec.getPSource();
+
+ if (!oaepSpec.getMGFAlgorithm().equals(OAEPParameterSpec.DEFAULT.getMGFAlgorithm()))
+ {
+ throw new InvalidAlgorithmParameterException("only " + OAEPParameterSpec.DEFAULT.getMGFAlgorithm() + " mask generator supported.");
+ }
+
+ AlgorithmIdentifier hashAlgorithm = new DefaultDigestAlgorithmIdentifierFinder().find(oaepSpec.getDigestAlgorithm());
+ AlgorithmIdentifier mgf1HashAlgorithm = new DefaultDigestAlgorithmIdentifierFinder().find((((MGF1ParameterSpec)oaepSpec.getMGFParameters()).getDigestAlgorithm()));
+ return new AlgorithmIdentifier(algorithm,
+ new RSAESOAEPparams(hashAlgorithm, new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, mgf1HashAlgorithm),
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(((PSource.PSpecified)pSource).getValue()))));
+ }
+ }
+
+ throw new InvalidAlgorithmParameterException("unknown parameter spec passed.");
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentSignerBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentSignerBuilder.java
new file mode 100644
index 000000000..a796bbb89
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentSignerBuilder.java
@@ -0,0 +1,160 @@
+package org.spongycastle.operator.jcajce;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.GeneralSecurityException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.OperatorStreamException;
+import org.spongycastle.operator.RuntimeOperatorException;
+
+public class JcaContentSignerBuilder
+{
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+ private SecureRandom random;
+ private String signatureAlgorithm;
+ private AlgorithmIdentifier sigAlgId;
+
+ public JcaContentSignerBuilder(String signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+ this.sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find(signatureAlgorithm);
+ }
+
+ public JcaContentSignerBuilder setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JcaContentSignerBuilder setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public JcaContentSignerBuilder setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public ContentSigner build(PrivateKey privateKey)
+ throws OperatorCreationException
+ {
+ try
+ {
+ final Signature sig = helper.createSignature(sigAlgId);
+
+ if (random != null)
+ {
+ sig.initSign(privateKey, random);
+ }
+ else
+ {
+ sig.initSign(privateKey);
+ }
+
+ return new ContentSigner()
+ {
+ private SignatureOutputStream stream = new SignatureOutputStream(sig);
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return sigAlgId;
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return stream;
+ }
+
+ public byte[] getSignature()
+ {
+ try
+ {
+ return stream.getSignature();
+ }
+ catch (SignatureException e)
+ {
+ throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e);
+ }
+ }
+ };
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException("cannot create signer: " + e.getMessage(), e);
+ }
+ }
+
+ private class SignatureOutputStream
+ extends OutputStream
+ {
+ private Signature sig;
+
+ SignatureOutputStream(Signature sig)
+ {
+ this.sig = sig;
+ }
+
+ public void write(byte[] bytes, int off, int len)
+ throws IOException
+ {
+ try
+ {
+ sig.update(bytes, off, len);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ public void write(byte[] bytes)
+ throws IOException
+ {
+ try
+ {
+ sig.update(bytes);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ try
+ {
+ sig.update((byte)b);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ byte[] getSignature()
+ throws SignatureException
+ {
+ return sig.sign();
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java
new file mode 100644
index 000000000..5db293186
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java
@@ -0,0 +1,312 @@
+package org.spongycastle.operator.jcajce;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.GeneralSecurityException;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.ContentVerifier;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.OperatorStreamException;
+import org.spongycastle.operator.RawContentVerifier;
+import org.spongycastle.operator.RuntimeOperatorException;
+
+public class JcaContentVerifierProviderBuilder
+{
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+
+ public JcaContentVerifierProviderBuilder()
+ {
+ }
+
+ public JcaContentVerifierProviderBuilder setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JcaContentVerifierProviderBuilder setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public ContentVerifierProvider build(X509CertificateHolder certHolder)
+ throws OperatorCreationException, CertificateException
+ {
+ return build(helper.convertCertificate(certHolder));
+ }
+
+ public ContentVerifierProvider build(final X509Certificate certificate)
+ throws OperatorCreationException
+ {
+ final X509CertificateHolder certHolder;
+
+ try
+ {
+ certHolder = new JcaX509CertificateHolder(certificate);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new OperatorCreationException("cannot process certificate: " + e.getMessage(), e);
+ }
+
+ return new ContentVerifierProvider()
+ {
+ private SignatureOutputStream stream;
+
+ public boolean hasAssociatedCertificate()
+ {
+ return true;
+ }
+
+ public X509CertificateHolder getAssociatedCertificate()
+ {
+ return certHolder;
+ }
+
+ public ContentVerifier get(AlgorithmIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ try
+ {
+ Signature sig = helper.createSignature(algorithm);
+
+ sig.initVerify(certificate.getPublicKey());
+
+ stream = new SignatureOutputStream(sig);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException("exception on setup: " + e, e);
+ }
+
+ Signature rawSig = createRawSig(algorithm, certificate.getPublicKey());
+
+ if (rawSig != null)
+ {
+ return new RawSigVerifier(algorithm, stream, rawSig);
+ }
+ else
+ {
+ return new SigVerifier(algorithm, stream);
+ }
+ }
+ };
+ }
+
+ public ContentVerifierProvider build(final PublicKey publicKey)
+ throws OperatorCreationException
+ {
+ return new ContentVerifierProvider()
+ {
+ public boolean hasAssociatedCertificate()
+ {
+ return false;
+ }
+
+ public X509CertificateHolder getAssociatedCertificate()
+ {
+ return null;
+ }
+
+ public ContentVerifier get(AlgorithmIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ SignatureOutputStream stream = createSignatureStream(algorithm, publicKey);
+
+ Signature rawSig = createRawSig(algorithm, publicKey);
+
+ if (rawSig != null)
+ {
+ return new RawSigVerifier(algorithm, stream, rawSig);
+ }
+ else
+ {
+ return new SigVerifier(algorithm, stream);
+ }
+ }
+ };
+ }
+
+ public ContentVerifierProvider build(SubjectPublicKeyInfo publicKey)
+ throws OperatorCreationException
+ {
+ return this.build(helper.convertPublicKey(publicKey));
+ }
+
+ private SignatureOutputStream createSignatureStream(AlgorithmIdentifier algorithm, PublicKey publicKey)
+ throws OperatorCreationException
+ {
+ try
+ {
+ Signature sig = helper.createSignature(algorithm);
+
+ sig.initVerify(publicKey);
+
+ return new SignatureOutputStream(sig);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException("exception on setup: " + e, e);
+ }
+ }
+
+ private Signature createRawSig(AlgorithmIdentifier algorithm, PublicKey publicKey)
+ {
+ Signature rawSig;
+ try
+ {
+ rawSig = helper.createRawSignature(algorithm);
+
+ if (rawSig != null)
+ {
+ rawSig.initVerify(publicKey);
+ }
+ }
+ catch (Exception e)
+ {
+ rawSig = null;
+ }
+ return rawSig;
+ }
+
+ private class SigVerifier
+ implements ContentVerifier
+ {
+ private SignatureOutputStream stream;
+ private AlgorithmIdentifier algorithm;
+
+ SigVerifier(AlgorithmIdentifier algorithm, SignatureOutputStream stream)
+ {
+ this.algorithm = algorithm;
+ this.stream = stream;
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithm;
+ }
+
+ public OutputStream getOutputStream()
+ {
+ if (stream == null)
+ {
+ throw new IllegalStateException("verifier not initialised");
+ }
+
+ return stream;
+ }
+
+ public boolean verify(byte[] expected)
+ {
+ try
+ {
+ return stream.verify(expected);
+ }
+ catch (SignatureException e)
+ {
+ throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ private class RawSigVerifier
+ extends SigVerifier
+ implements RawContentVerifier
+ {
+ private Signature rawSignature;
+
+ RawSigVerifier(AlgorithmIdentifier algorithm, SignatureOutputStream stream, Signature rawSignature)
+ {
+ super(algorithm, stream);
+ this.rawSignature = rawSignature;
+ }
+
+ public boolean verify(byte[] digest, byte[] expected)
+ {
+ try
+ {
+ rawSignature.update(digest);
+
+ return rawSignature.verify(expected);
+ }
+ catch (SignatureException e)
+ {
+ throw new RuntimeOperatorException("exception obtaining raw signature: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ private class SignatureOutputStream
+ extends OutputStream
+ {
+ private Signature sig;
+
+ SignatureOutputStream(Signature sig)
+ {
+ this.sig = sig;
+ }
+
+ public void write(byte[] bytes, int off, int len)
+ throws IOException
+ {
+ try
+ {
+ sig.update(bytes, off, len);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ public void write(byte[] bytes)
+ throws IOException
+ {
+ try
+ {
+ sig.update(bytes);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ try
+ {
+ sig.update((byte)b);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ boolean verify(byte[] expected)
+ throws SignatureException
+ {
+ return sig.verify(expected);
+ }
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java
new file mode 100644
index 000000000..849126232
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java
@@ -0,0 +1,114 @@
+package org.spongycastle.operator.jcajce;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.security.Provider;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+
+public class JcaDigestCalculatorProviderBuilder
+{
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+
+ public JcaDigestCalculatorProviderBuilder()
+ {
+ }
+
+ public JcaDigestCalculatorProviderBuilder setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JcaDigestCalculatorProviderBuilder setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public DigestCalculatorProvider build()
+ throws OperatorCreationException
+ {
+ return new DigestCalculatorProvider()
+ {
+ public DigestCalculator get(final AlgorithmIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ final DigestOutputStream stream;
+
+ try
+ {
+ MessageDigest dig = helper.createDigest(algorithm);
+
+ stream = new DigestOutputStream(dig);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException("exception on setup: " + e, e);
+ }
+
+ return new DigestCalculator()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithm;
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return stream;
+ }
+
+ public byte[] getDigest()
+ {
+ return stream.getDigest();
+ }
+ };
+ }
+ };
+ }
+
+ private class DigestOutputStream
+ extends OutputStream
+ {
+ private MessageDigest dig;
+
+ DigestOutputStream(MessageDigest dig)
+ {
+ this.dig = dig;
+ }
+
+ public void write(byte[] bytes, int off, int len)
+ throws IOException
+ {
+ dig.update(bytes, off, len);
+ }
+
+ public void write(byte[] bytes)
+ throws IOException
+ {
+ dig.update(bytes);
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ dig.update((byte)b);
+ }
+
+ byte[] getDigest()
+ {
+ return dig.digest();
+ }
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java
new file mode 100644
index 000000000..fd70b040e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java
@@ -0,0 +1,133 @@
+package org.spongycastle.operator.jcajce;
+
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.ProviderException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.AsymmetricKeyUnwrapper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+
+public class JceAsymmetricKeyUnwrapper
+ extends AsymmetricKeyUnwrapper
+{
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+ private Map extraMappings = new HashMap();
+ private PrivateKey privKey;
+
+ public JceAsymmetricKeyUnwrapper(AlgorithmIdentifier algorithmIdentifier, PrivateKey privKey)
+ {
+ super(algorithmIdentifier);
+
+ this.privKey = privKey;
+ }
+
+ public JceAsymmetricKeyUnwrapper setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JceAsymmetricKeyUnwrapper setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ /**
+ * Internally algorithm ids are converted into cipher names using a lookup table. For some providers
+ * the standard lookup table won't work. Use this method to establish a specific mapping from an
+ * algorithm identifier to a specific algorithm.
+ * <p>
+ * For example:
+ * <pre>
+ * unwrapper.setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ * </pre>
+ * </p>
+ * @param algorithm OID of algorithm in recipient.
+ * @param algorithmName JCE algorithm name to use.
+ * @return the current Unwrapper.
+ */
+ public JceAsymmetricKeyUnwrapper setAlgorithmMapping(ASN1ObjectIdentifier algorithm, String algorithmName)
+ {
+ extraMappings.put(algorithm, algorithmName);
+
+ return this;
+ }
+
+ public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedKey)
+ throws OperatorException
+ {
+ try
+ {
+ Key sKey = null;
+
+ Cipher keyCipher = helper.createAsymmetricWrapper(this.getAlgorithmIdentifier().getAlgorithm(), extraMappings);
+ AlgorithmParameters algParams = helper.createAlgorithmParameters(this.getAlgorithmIdentifier());
+
+ try
+ {
+ if (algParams != null)
+ {
+ keyCipher.init(Cipher.UNWRAP_MODE, privKey, algParams);
+ }
+ else
+ {
+ keyCipher.init(Cipher.UNWRAP_MODE, privKey);
+ }
+ sKey = keyCipher.unwrap(encryptedKey, helper.getKeyAlgorithmName(encryptedKeyAlgorithm.getAlgorithm()), Cipher.SECRET_KEY);
+ }
+ catch (GeneralSecurityException e)
+ {
+ }
+ catch (IllegalStateException e)
+ {
+ }
+ catch (UnsupportedOperationException e)
+ {
+ }
+ catch (ProviderException e)
+ {
+ }
+
+ // some providers do not support UNWRAP (this appears to be only for asymmetric algorithms)
+ if (sKey == null)
+ {
+ keyCipher.init(Cipher.DECRYPT_MODE, privKey);
+ sKey = new SecretKeySpec(keyCipher.doFinal(encryptedKey), encryptedKeyAlgorithm.getAlgorithm().getId());
+ }
+
+ return new JceGenericKey(encryptedKeyAlgorithm, sKey);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new OperatorException("key invalid: " + e.getMessage(), e);
+ }
+ catch (IllegalBlockSizeException e)
+ {
+ throw new OperatorException("illegal blocksize: " + e.getMessage(), e);
+ }
+ catch (BadPaddingException e)
+ {
+ throw new OperatorException("bad padding: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyWrapper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyWrapper.java
new file mode 100644
index 000000000..66d31b226
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceAsymmetricKeyWrapper.java
@@ -0,0 +1,157 @@
+package org.spongycastle.operator.jcajce;
+
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.Provider;
+import java.security.ProviderException;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.AsymmetricKeyWrapper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+
+public class JceAsymmetricKeyWrapper
+ extends AsymmetricKeyWrapper
+{
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+ private Map extraMappings = new HashMap();
+ private PublicKey publicKey;
+ private SecureRandom random;
+
+ public JceAsymmetricKeyWrapper(PublicKey publicKey)
+ {
+ super(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()).getAlgorithm());
+
+ this.publicKey = publicKey;
+ }
+
+ public JceAsymmetricKeyWrapper(X509Certificate certificate)
+ {
+ this(certificate.getPublicKey());
+ }
+
+ /**
+ * Create a wrapper, overriding the algorithm type that is stored in the public key.
+ *
+ * @param algorithmIdentifier identifier for encryption algorithm to be used.
+ * @param publicKey the public key to be used.
+ */
+ public JceAsymmetricKeyWrapper(AlgorithmIdentifier algorithmIdentifier, PublicKey publicKey)
+ {
+ super(algorithmIdentifier);
+
+ this.publicKey = publicKey;
+ }
+
+ public JceAsymmetricKeyWrapper setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JceAsymmetricKeyWrapper setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public JceAsymmetricKeyWrapper setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ /**
+ * Internally algorithm ids are converted into cipher names using a lookup table. For some providers
+ * the standard lookup table won't work. Use this method to establish a specific mapping from an
+ * algorithm identifier to a specific algorithm.
+ * <p>
+ * For example:
+ * <pre>
+ * unwrapper.setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ * </pre>
+ * </p>
+ * @param algorithm OID of algorithm in recipient.
+ * @param algorithmName JCE algorithm name to use.
+ * @return the current Wrapper.
+ */
+ public JceAsymmetricKeyWrapper setAlgorithmMapping(ASN1ObjectIdentifier algorithm, String algorithmName)
+ {
+ extraMappings.put(algorithm, algorithmName);
+
+ return this;
+ }
+
+ public byte[] generateWrappedKey(GenericKey encryptionKey)
+ throws OperatorException
+ {
+ Cipher keyEncryptionCipher = helper.createAsymmetricWrapper(getAlgorithmIdentifier().getAlgorithm(), extraMappings);
+ AlgorithmParameters algParams = helper.createAlgorithmParameters(this.getAlgorithmIdentifier());
+
+ byte[] encryptedKeyBytes = null;
+
+ try
+ {
+ if (algParams != null)
+ {
+ keyEncryptionCipher.init(Cipher.WRAP_MODE, publicKey, algParams, random);
+ }
+ else
+ {
+ keyEncryptionCipher.init(Cipher.WRAP_MODE, publicKey, random);
+ }
+ encryptedKeyBytes = keyEncryptionCipher.wrap(OperatorUtils.getJceKey(encryptionKey));
+ }
+ catch (InvalidKeyException e)
+ {
+ }
+ catch (GeneralSecurityException e)
+ {
+ }
+ catch (IllegalStateException e)
+ {
+ }
+ catch (UnsupportedOperationException e)
+ {
+ }
+ catch (ProviderException e)
+ {
+ }
+
+ // some providers do not support WRAP (this appears to be only for asymmetric algorithms)
+ if (encryptedKeyBytes == null)
+ {
+ try
+ {
+ keyEncryptionCipher.init(Cipher.ENCRYPT_MODE, publicKey, random);
+ encryptedKeyBytes = keyEncryptionCipher.doFinal(OperatorUtils.getJceKey(encryptionKey).getEncoded());
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new OperatorException("unable to encrypt contents key", e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorException("unable to encrypt contents key", e);
+ }
+ }
+
+ return encryptedKeyBytes;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceGenericKey.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceGenericKey.java
new file mode 100644
index 000000000..a11a535ec
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceGenericKey.java
@@ -0,0 +1,33 @@
+package org.spongycastle.operator.jcajce;
+
+import java.security.Key;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.GenericKey;
+
+public class JceGenericKey
+ extends GenericKey
+{
+ /**
+ * Attempt to simplify the key representation if possible.
+ *
+ * @param key a provider based key
+ * @return the byte encoding if one exists, key object otherwise.
+ */
+ private static Object getRepresentation(Key key)
+ {
+ byte[] keyBytes = key.getEncoded();
+
+ if (keyBytes != null)
+ {
+ return keyBytes;
+ }
+
+ return key;
+ }
+
+ public JceGenericKey(AlgorithmIdentifier algorithmIdentifier, Key representation)
+ {
+ super(algorithmIdentifier, getRepresentation(representation));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyUnwrapper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyUnwrapper.java
new file mode 100644
index 000000000..74ab54167
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyUnwrapper.java
@@ -0,0 +1,65 @@
+package org.spongycastle.operator.jcajce;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+import org.spongycastle.operator.SymmetricKeyUnwrapper;
+
+public class JceSymmetricKeyUnwrapper
+ extends SymmetricKeyUnwrapper
+{
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+ private SecretKey secretKey;
+
+ public JceSymmetricKeyUnwrapper(AlgorithmIdentifier algorithmIdentifier, SecretKey secretKey)
+ {
+ super(algorithmIdentifier);
+
+ this.secretKey = secretKey;
+ }
+
+ public JceSymmetricKeyUnwrapper setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JceSymmetricKeyUnwrapper setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedKey)
+ throws OperatorException
+ {
+ try
+ {
+ Cipher keyCipher = helper.createSymmetricWrapper(this.getAlgorithmIdentifier().getAlgorithm());
+
+ keyCipher.init(Cipher.UNWRAP_MODE, secretKey);
+
+ return new JceGenericKey(encryptedKeyAlgorithm, keyCipher.unwrap(encryptedKey, helper.getKeyAlgorithmName(encryptedKeyAlgorithm.getAlgorithm()), Cipher.SECRET_KEY));
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new OperatorException("key invalid in message.", e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new OperatorException("can't find algorithm.", e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyWrapper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyWrapper.java
new file mode 100644
index 000000000..55b2287a6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/JceSymmetricKeyWrapper.java
@@ -0,0 +1,154 @@
+package org.spongycastle.operator.jcajce;
+
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.Provider;
+import java.security.SecureRandom;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.kisa.KISAObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.ntt.NTTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+import org.spongycastle.operator.SymmetricKeyWrapper;
+
+public class JceSymmetricKeyWrapper
+ extends SymmetricKeyWrapper
+{
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+ private SecureRandom random;
+ private SecretKey wrappingKey;
+
+ public JceSymmetricKeyWrapper(SecretKey wrappingKey)
+ {
+ super(determineKeyEncAlg(wrappingKey));
+
+ this.wrappingKey = wrappingKey;
+ }
+
+ public JceSymmetricKeyWrapper setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JceSymmetricKeyWrapper setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public JceSymmetricKeyWrapper setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public byte[] generateWrappedKey(GenericKey encryptionKey)
+ throws OperatorException
+ {
+ Key contentEncryptionKeySpec = OperatorUtils.getJceKey(encryptionKey);
+
+ Cipher keyEncryptionCipher = helper.createSymmetricWrapper(this.getAlgorithmIdentifier().getAlgorithm());
+
+ try
+ {
+ keyEncryptionCipher.init(Cipher.WRAP_MODE, wrappingKey, random);
+
+ return keyEncryptionCipher.wrap(contentEncryptionKeySpec);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorException("cannot wrap key: " + e.getMessage(), e);
+ }
+ }
+
+ private static AlgorithmIdentifier determineKeyEncAlg(SecretKey key)
+ {
+ String algorithm = key.getAlgorithm();
+
+ if (algorithm.startsWith("DES"))
+ {
+ return new AlgorithmIdentifier(new ASN1ObjectIdentifier(
+ "1.2.840.113549.1.9.16.3.6"), DERNull.INSTANCE);
+ }
+ else if (algorithm.startsWith("RC2"))
+ {
+ return new AlgorithmIdentifier(new ASN1ObjectIdentifier(
+ "1.2.840.113549.1.9.16.3.7"), new ASN1Integer(58));
+ }
+ else if (algorithm.startsWith("AES"))
+ {
+ int length = key.getEncoded().length * 8;
+ ASN1ObjectIdentifier wrapOid;
+
+ if (length == 128)
+ {
+ wrapOid = NISTObjectIdentifiers.id_aes128_wrap;
+ }
+ else if (length == 192)
+ {
+ wrapOid = NISTObjectIdentifiers.id_aes192_wrap;
+ }
+ else if (length == 256)
+ {
+ wrapOid = NISTObjectIdentifiers.id_aes256_wrap;
+ }
+ else
+ {
+ throw new IllegalArgumentException("illegal keysize in AES");
+ }
+
+ return new AlgorithmIdentifier(wrapOid); // parameters absent
+ }
+ else if (algorithm.startsWith("SEED"))
+ {
+ // parameters absent
+ return new AlgorithmIdentifier(
+ KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap);
+ }
+ else if (algorithm.startsWith("Camellia"))
+ {
+ int length = key.getEncoded().length * 8;
+ ASN1ObjectIdentifier wrapOid;
+
+ if (length == 128)
+ {
+ wrapOid = NTTObjectIdentifiers.id_camellia128_wrap;
+ }
+ else if (length == 192)
+ {
+ wrapOid = NTTObjectIdentifiers.id_camellia192_wrap;
+ }
+ else if (length == 256)
+ {
+ wrapOid = NTTObjectIdentifiers.id_camellia256_wrap;
+ }
+ else
+ {
+ throw new IllegalArgumentException(
+ "illegal keysize in Camellia");
+ }
+
+ return new AlgorithmIdentifier(wrapOid); // parameters must be
+ // absent
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown algorithm");
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorHelper.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorHelper.java
new file mode 100644
index 000000000..2a4ded274
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorHelper.java
@@ -0,0 +1,469 @@
+package org.spongycastle.operator.jcajce;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.MessageDigest;
+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.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PSSParameterSpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.kisa.KISAObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.ntt.NTTObjectIdentifiers;
+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.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.jcajce.JcaJceHelper;
+import org.spongycastle.jcajce.JcaJceUtils;
+import org.spongycastle.operator.OperatorCreationException;
+
+class OperatorHelper
+{
+ private static final Map oids = new HashMap();
+ private static final Map asymmetricWrapperAlgNames = new HashMap();
+ private static final Map symmetricWrapperAlgNames = new HashMap();
+ private static final Map symmetricKeyAlgNames = new HashMap();
+
+ static
+ {
+ //
+ // reverse mappings
+ //
+ oids.put(new ASN1ObjectIdentifier("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 ASN1ObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
+ oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA");
+ oids.put(new ASN1ObjectIdentifier("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");
+
+ oids.put(OIWObjectIdentifiers.idSHA1, "SHA-1");
+ oids.put(NISTObjectIdentifiers.id_sha224, "SHA-224");
+ oids.put(NISTObjectIdentifiers.id_sha256, "SHA-256");
+ oids.put(NISTObjectIdentifiers.id_sha384, "SHA-384");
+ oids.put(NISTObjectIdentifiers.id_sha512, "SHA-512");
+ oids.put(TeleTrusTObjectIdentifiers.ripemd128, "RIPEMD-128");
+ oids.put(TeleTrusTObjectIdentifiers.ripemd160, "RIPEMD-160");
+ oids.put(TeleTrusTObjectIdentifiers.ripemd256, "RIPEMD-256");
+
+ asymmetricWrapperAlgNames.put(PKCSObjectIdentifiers.rsaEncryption, "RSA/ECB/PKCS1Padding");
+
+ symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "DESEDEWrap");
+ symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.id_alg_CMSRC2wrap, "RC2Wrap");
+ symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes128_wrap, "AESWrap");
+ symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes192_wrap, "AESWrap");
+ symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes256_wrap, "AESWrap");
+ symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia128_wrap, "CamelliaWrap");
+ symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia192_wrap, "CamelliaWrap");
+ symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia256_wrap, "CamelliaWrap");
+ symmetricWrapperAlgNames.put(KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap, "SEEDWrap");
+ symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESede");
+
+ symmetricKeyAlgNames.put(NISTObjectIdentifiers.aes, "AES");
+ symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes128_CBC, "AES");
+ symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes192_CBC, "AES");
+ symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes256_CBC, "AES");
+ symmetricKeyAlgNames.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESede");
+ symmetricKeyAlgNames.put(PKCSObjectIdentifiers.RC2_CBC, "RC2");
+ }
+
+ private JcaJceHelper helper;
+
+ OperatorHelper(JcaJceHelper helper)
+ {
+ this.helper = helper;
+ }
+
+ Cipher createAsymmetricWrapper(ASN1ObjectIdentifier algorithm, Map extraAlgNames)
+ throws OperatorCreationException
+ {
+ try
+ {
+ String cipherName = null;
+
+ if (!extraAlgNames.isEmpty())
+ {
+ cipherName = (String)extraAlgNames.get(algorithm);
+ }
+
+ if (cipherName == null)
+ {
+ cipherName = (String)asymmetricWrapperAlgNames.get(algorithm);
+ }
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createCipher(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // try alternate for RSA
+ if (cipherName.equals("RSA/ECB/PKCS1Padding"))
+ {
+ try
+ {
+ return helper.createCipher("RSA/NONE/PKCS1Padding");
+ }
+ catch (NoSuchAlgorithmException ex)
+ {
+ // Ignore
+ }
+ }
+ // Ignore
+ }
+ }
+
+ return helper.createCipher(algorithm.getId());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException("cannot create cipher: " + e.getMessage(), e);
+ }
+ }
+
+ Cipher createSymmetricWrapper(ASN1ObjectIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ try
+ {
+ String cipherName = (String)symmetricWrapperAlgNames.get(algorithm);
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createCipher(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createCipher(algorithm.getId());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException("cannot create cipher: " + e.getMessage(), e);
+ }
+ }
+
+ AlgorithmParameters createAlgorithmParameters(AlgorithmIdentifier cipherAlgId)
+ throws OperatorCreationException
+ {
+ AlgorithmParameters parameters;
+
+ if (cipherAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption))
+ {
+ return null;
+ }
+
+ try
+ {
+ parameters = helper.createAlgorithmParameters(cipherAlgId.getAlgorithm().getId());
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ return null; // There's a good chance there aren't any!
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new OperatorCreationException("cannot create algorithm parameters: " + e.getMessage(), e);
+ }
+
+ try
+ {
+ parameters.init(cipherAlgId.getParameters().toASN1Primitive().getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new OperatorCreationException("cannot initialise algorithm parameters: " + e.getMessage(), e);
+ }
+
+ return parameters;
+ }
+
+ MessageDigest createDigest(AlgorithmIdentifier digAlgId)
+ throws GeneralSecurityException
+ {
+ MessageDigest dig;
+
+ try
+ {
+ dig = helper.createDigest(getDigestAlgName(digAlgId.getAlgorithm()));
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ //
+ // try an alternate
+ //
+ if (oids.get(digAlgId.getAlgorithm()) != null)
+ {
+ String digestAlgorithm = (String)oids.get(digAlgId.getAlgorithm());
+
+ dig = helper.createDigest(digestAlgorithm);
+ }
+ else
+ {
+ throw e;
+ }
+ }
+
+ return dig;
+ }
+
+ Signature createSignature(AlgorithmIdentifier sigAlgId)
+ throws GeneralSecurityException
+ {
+ Signature sig;
+
+ try
+ {
+ sig = helper.createSignature(getSignatureName(sigAlgId));
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ //
+ // try an alternate
+ //
+ if (oids.get(sigAlgId.getAlgorithm()) != null)
+ {
+ String signatureAlgorithm = (String)oids.get(sigAlgId.getAlgorithm());
+
+ sig = helper.createSignature(signatureAlgorithm);
+ }
+ else
+ {
+ throw e;
+ }
+ }
+
+ return sig;
+ }
+
+ public Signature createRawSignature(AlgorithmIdentifier algorithm)
+ {
+ Signature sig;
+
+ try
+ {
+ String algName = getSignatureName(algorithm);
+
+ algName = "NONE" + algName.substring(algName.indexOf("WITH"));
+
+ sig = helper.createSignature(algName);
+
+ // RFC 4056
+ // When the id-RSASSA-PSS algorithm identifier is used for a signature,
+ // the AlgorithmIdentifier parameters field MUST contain RSASSA-PSS-params.
+ if (algorithm.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ AlgorithmParameters params = helper.createAlgorithmParameters(algName);
+
+ JcaJceUtils.loadParameters(params, algorithm.getParameters());
+
+ PSSParameterSpec spec = (PSSParameterSpec)params.getParameterSpec(PSSParameterSpec.class);
+ sig.setParameter(spec);
+ }
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+
+ return sig;
+ }
+
+ private static String getSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ ASN1Encodable params = sigAlgId.getParameters();
+
+ if (params != null && !DERNull.INSTANCE.equals(params))
+ {
+ if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+ return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "WITHRSAANDMGF1";
+ }
+ }
+
+ if (oids.containsKey(sigAlgId.getAlgorithm()))
+ {
+ return (String)oids.get(sigAlgId.getAlgorithm());
+ }
+
+ return sigAlgId.getAlgorithm().getId();
+ }
+
+ 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();
+ }
+ }
+
+ public X509Certificate convertCertificate(X509CertificateHolder certHolder)
+ throws CertificateException
+ {
+
+ try
+ {
+ CertificateFactory certFact = helper.createCertificateFactory("X.509");
+
+ return (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(certHolder.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new OpCertificateException("cannot get encoded form of certificate: " + e.getMessage(), e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new OpCertificateException("cannot create certificate factory: " + e.getMessage(), e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new OpCertificateException("cannot find factory provider: " + e.getMessage(), e);
+ }
+ }
+
+ public PublicKey convertPublicKey(SubjectPublicKeyInfo publicKeyInfo)
+ throws OperatorCreationException
+ {
+ try
+ {
+ KeyFactory keyFact = helper.createKeyFactory(publicKeyInfo.getAlgorithm().getAlgorithm().getId());
+
+ return keyFact.generatePublic(new X509EncodedKeySpec(publicKeyInfo.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new OperatorCreationException("cannot get encoded form of key: " + e.getMessage(), e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new OperatorCreationException("cannot create key factory: " + e.getMessage(), e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new OperatorCreationException("cannot find factory provider: " + e.getMessage(), e);
+ }
+ catch (InvalidKeySpecException e)
+ {
+ throw new OperatorCreationException("cannot create key factory: " + e.getMessage(), e);
+ }
+ }
+
+ // TODO: put somewhere public so cause easily accessed
+ private static class OpCertificateException
+ extends CertificateException
+ {
+ private Throwable cause;
+
+ public OpCertificateException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+
+ String getKeyAlgorithmName(ASN1ObjectIdentifier oid)
+ {
+
+ String name = (String)symmetricKeyAlgNames.get(oid);
+
+ if (name != null)
+ {
+ return name;
+ }
+
+ return oid.getId();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorUtils.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorUtils.java
new file mode 100644
index 000000000..81cb40634
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/operator/jcajce/OperatorUtils.java
@@ -0,0 +1,25 @@
+package org.spongycastle.operator.jcajce;
+
+import java.security.Key;
+
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.operator.GenericKey;
+
+class OperatorUtils
+{
+ static Key getJceKey(GenericKey key)
+ {
+ if (key.getRepresentation() instanceof Key)
+ {
+ return (Key)key.getRepresentation();
+ }
+
+ if (key.getRepresentation() instanceof byte[])
+ {
+ return new SecretKeySpec((byte[])key.getRepresentation(), "ENC");
+ }
+
+ throw new IllegalArgumentException("unknown generic key type");
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/MacDataGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/MacDataGenerator.java
new file mode 100644
index 000000000..c6667d8b1
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/MacDataGenerator.java
@@ -0,0 +1,49 @@
+package org.spongycastle.pkcs;
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.pkcs.MacData;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.DigestInfo;
+import org.spongycastle.operator.MacCalculator;
+
+class MacDataGenerator
+{
+ private PKCS12MacCalculatorBuilder builder;
+
+ MacDataGenerator(PKCS12MacCalculatorBuilder builder)
+ {
+ this.builder = builder;
+ }
+
+ public MacData build(char[] password, byte[] data)
+ throws PKCSException
+ {
+ MacCalculator macCalculator;
+
+ try
+ {
+ macCalculator = builder.build(password);
+
+ OutputStream out = macCalculator.getOutputStream();
+
+ out.write(data);
+
+ out.close();
+ }
+ catch (Exception e)
+ {
+ throw new PKCSException("unable to process data: " + e.getMessage(), e);
+ }
+
+ AlgorithmIdentifier algId = macCalculator.getAlgorithmIdentifier();
+
+ DigestInfo dInfo = new DigestInfo(builder.getDigestAlgorithmIdentifier(), macCalculator.getMac());
+ PKCS12PBEParams params = PKCS12PBEParams.getInstance(algId.getParameters());
+
+ return new MacData(dInfo, params.getIV(), params.getIterations().intValue());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS10CertificationRequest.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS10CertificationRequest.java
new file mode 100644
index 000000000..c4ee749ac
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS10CertificationRequest.java
@@ -0,0 +1,236 @@
+package org.spongycastle.pkcs;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.pkcs.Attribute;
+import org.spongycastle.asn1.pkcs.CertificationRequest;
+import org.spongycastle.asn1.pkcs.CertificationRequestInfo;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.operator.ContentVerifier;
+import org.spongycastle.operator.ContentVerifierProvider;
+
+/**
+ * Holding class for a PKCS#10 certification request.
+ */
+public class PKCS10CertificationRequest
+{
+ private static Attribute[] EMPTY_ARRAY = new Attribute[0];
+
+ private CertificationRequest certificationRequest;
+
+ private static CertificationRequest parseBytes(byte[] encoding)
+ throws IOException
+ {
+ try
+ {
+ return CertificationRequest.getInstance(ASN1Primitive.fromByteArray(encoding));
+ }
+ catch (ClassCastException e)
+ {
+ throw new PKCSIOException("malformed data: " + e.getMessage(), e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new PKCSIOException("malformed data: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Create a PKCS10CertificationRequestHolder from an underlying ASN.1 structure.
+ *
+ * @param certificationRequest the underlying ASN.1 structure representing a request.
+ */
+ public PKCS10CertificationRequest(CertificationRequest certificationRequest)
+ {
+ this.certificationRequest = certificationRequest;
+ }
+
+ /**
+ * Create a PKCS10CertificationRequestHolder from the passed in bytes.
+ *
+ * @param encoded BER/DER encoding of the CertificationRequest structure.
+ * @throws IOException in the event of corrupted data, or an incorrect structure.
+ */
+ public PKCS10CertificationRequest(byte[] encoded)
+ throws IOException
+ {
+ this(parseBytes(encoded));
+ }
+
+ /**
+ * Return the underlying ASN.1 structure for this request.
+ *
+ * @return a CertificateRequest object.
+ */
+ public CertificationRequest toASN1Structure()
+ {
+ return certificationRequest;
+ }
+
+ /**
+ * Return the subject on this request.
+ *
+ * @return the X500Name representing the request's subject.
+ */
+ public X500Name getSubject()
+ {
+ return X500Name.getInstance(certificationRequest.getCertificationRequestInfo().getSubject());
+ }
+
+ /**
+ * Return the details of the signature algorithm used to create this request.
+ *
+ * @return the AlgorithmIdentifier describing the signature algorithm used to create this request.
+ */
+ public AlgorithmIdentifier getSignatureAlgorithm()
+ {
+ return certificationRequest.getSignatureAlgorithm();
+ }
+
+ /**
+ * Return the bytes making up the signature associated with this request.
+ *
+ * @return the request signature bytes.
+ */
+ public byte[] getSignature()
+ {
+ return certificationRequest.getSignature().getBytes();
+ }
+
+ /**
+ * Return the SubjectPublicKeyInfo describing the public key this request is carrying.
+ *
+ * @return the public key ASN.1 structure contained in the request.
+ */
+ public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+ {
+ return certificationRequest.getCertificationRequestInfo().getSubjectPublicKeyInfo();
+ }
+
+ /**
+ * Return the attributes, if any associated with this request.
+ *
+ * @return an array of Attribute, zero length if none present.
+ */
+ public Attribute[] getAttributes()
+ {
+ ASN1Set attrSet = certificationRequest.getCertificationRequestInfo().getAttributes();
+
+ if (attrSet == null)
+ {
+ return EMPTY_ARRAY;
+ }
+
+ Attribute[] attrs = new Attribute[attrSet.size()];
+
+ for (int i = 0; i != attrSet.size(); i++)
+ {
+ attrs[i] = Attribute.getInstance(attrSet.getObjectAt(i));
+ }
+
+ return attrs;
+ }
+
+ /**
+ * Return an array of attributes matching the passed in type OID.
+ *
+ * @param type the type of the attribute being looked for.
+ * @return an array of Attribute of the requested type, zero length if none present.
+ */
+ public Attribute[] getAttributes(ASN1ObjectIdentifier type)
+ {
+ ASN1Set attrSet = certificationRequest.getCertificationRequestInfo().getAttributes();
+
+ if (attrSet == null)
+ {
+ return EMPTY_ARRAY;
+ }
+
+ List list = new ArrayList();
+
+ for (int i = 0; i != attrSet.size(); i++)
+ {
+ Attribute attr = Attribute.getInstance(attrSet.getObjectAt(i));
+ if (attr.getAttrType().equals(type))
+ {
+ list.add(attr);
+ }
+ }
+
+ if (list.size() == 0)
+ {
+ return EMPTY_ARRAY;
+ }
+
+ return (Attribute[])list.toArray(new Attribute[list.size()]);
+ }
+
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return certificationRequest.getEncoded();
+ }
+
+ /**
+ * Validate the signature on the PKCS10 certification request in this holder.
+ *
+ * @param verifierProvider a ContentVerifierProvider that can generate a verifier for the signature.
+ * @return true if the signature is valid, false otherwise.
+ * @throws PKCSException if the signature cannot be processed or is inappropriate.
+ */
+ public boolean isSignatureValid(ContentVerifierProvider verifierProvider)
+ throws PKCSException
+ {
+ CertificationRequestInfo requestInfo = certificationRequest.getCertificationRequestInfo();
+
+ ContentVerifier verifier;
+
+ try
+ {
+ verifier = verifierProvider.get(certificationRequest.getSignatureAlgorithm());
+
+ OutputStream sOut = verifier.getOutputStream();
+
+ sOut.write(requestInfo.getEncoded(ASN1Encoding.DER));
+
+ sOut.close();
+ }
+ catch (Exception e)
+ {
+ throw new PKCSException("unable to process signature: " + e.getMessage(), e);
+ }
+
+ return verifier.verify(certificationRequest.getSignature().getBytes());
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof PKCS10CertificationRequest))
+ {
+ return false;
+ }
+
+ PKCS10CertificationRequest other = (PKCS10CertificationRequest)o;
+
+ return this.toASN1Structure().equals(other.toASN1Structure());
+ }
+
+ public int hashCode()
+ {
+ return this.toASN1Structure().hashCode();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS10CertificationRequestBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS10CertificationRequestBuilder.java
new file mode 100644
index 000000000..d10c6fddd
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS10CertificationRequestBuilder.java
@@ -0,0 +1,156 @@
+package org.spongycastle.pkcs;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.pkcs.Attribute;
+import org.spongycastle.asn1.pkcs.CertificationRequest;
+import org.spongycastle.asn1.pkcs.CertificationRequestInfo;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.operator.ContentSigner;
+
+/**
+ * A class for creating PKCS#10 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>
+ */
+public class PKCS10CertificationRequestBuilder
+{
+ private SubjectPublicKeyInfo publicKeyInfo;
+ private X500Name subject;
+ private List attributes = new ArrayList();
+ private boolean leaveOffEmpty = false;
+
+ /**
+ * Basic constructor.
+ *
+ * @param subject the X.500 Name defining the certificate subject this request is for.
+ * @param publicKeyInfo the info structure for the public key to be associated with this subject.
+ */
+ public PKCS10CertificationRequestBuilder(X500Name subject, SubjectPublicKeyInfo publicKeyInfo)
+ {
+ this.subject = subject;
+ this.publicKeyInfo = publicKeyInfo;
+ }
+
+ /**
+ * Add an attribute to the certification request we are building.
+ *
+ * @param attrType the OID giving the type of the attribute.
+ * @param attrValue the ASN.1 structure that forms the value of the attribute.
+ * @return this builder object.
+ */
+ public PKCS10CertificationRequestBuilder addAttribute(ASN1ObjectIdentifier attrType, ASN1Encodable attrValue)
+ {
+ attributes.add(new Attribute(attrType, new DERSet(attrValue)));
+
+ return this;
+ }
+
+ /**
+ * Add an attribute with multiple values to the certification request we are building.
+ *
+ * @param attrType the OID giving the type of the attribute.
+ * @param attrValues an array of ASN.1 structures that form the value of the attribute.
+ * @return this builder object.
+ */
+ public PKCS10CertificationRequestBuilder addAttribute(ASN1ObjectIdentifier attrType, ASN1Encodable[] attrValues)
+ {
+ attributes.add(new Attribute(attrType, new DERSet(attrValues)));
+
+ return this;
+ }
+
+ /**
+ * The attributes field in PKCS10 should encoded to an empty tagged set if there are
+ * no attributes. Some CAs will reject requests with the attribute field present.
+ *
+ * @param leaveOffEmpty true if empty attributes should be left out of the encoding false otherwise.
+ * @return this builder object.
+ */
+ public PKCS10CertificationRequestBuilder setLeaveOffEmptyAttributes(boolean leaveOffEmpty)
+ {
+ this.leaveOffEmpty = leaveOffEmpty;
+
+ return this;
+ }
+
+ /**
+ * Generate an PKCS#10 request based on the past in signer.
+ *
+ * @param signer the content signer to be used to generate the signature validating the certificate.
+ * @return a holder containing the resulting PKCS#10 certification request.
+ */
+ public PKCS10CertificationRequest build(
+ ContentSigner signer)
+ {
+ CertificationRequestInfo info;
+
+ if (attributes.isEmpty())
+ {
+ if (leaveOffEmpty)
+ {
+ info = new CertificationRequestInfo(subject, publicKeyInfo, null);
+ }
+ else
+ {
+ info = new CertificationRequestInfo(subject, publicKeyInfo, new DERSet());
+ }
+ }
+ else
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ for (Iterator it = attributes.iterator(); it.hasNext();)
+ {
+ v.add(Attribute.getInstance(it.next()));
+ }
+
+ info = new CertificationRequestInfo(subject, publicKeyInfo, new DERSet(v));
+ }
+
+ try
+ {
+ OutputStream sOut = signer.getOutputStream();
+
+ sOut.write(info.getEncoded(ASN1Encoding.DER));
+
+ sOut.close();
+
+ return new PKCS10CertificationRequest(new CertificationRequest(info, signer.getAlgorithmIdentifier(), new DERBitString(signer.getSignature())));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("cannot produce certification request signature");
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12MacCalculatorBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12MacCalculatorBuilder.java
new file mode 100644
index 000000000..be82e9908
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12MacCalculatorBuilder.java
@@ -0,0 +1,13 @@
+package org.spongycastle.pkcs;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.MacCalculator;
+import org.spongycastle.operator.OperatorCreationException;
+
+public interface PKCS12MacCalculatorBuilder
+{
+ MacCalculator build(char[] password)
+ throws OperatorCreationException;
+
+ AlgorithmIdentifier getDigestAlgorithmIdentifier();
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12MacCalculatorBuilderProvider.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12MacCalculatorBuilderProvider.java
new file mode 100644
index 000000000..52c9d1cd3
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12MacCalculatorBuilderProvider.java
@@ -0,0 +1,8 @@
+package org.spongycastle.pkcs;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public interface PKCS12MacCalculatorBuilderProvider
+{
+ PKCS12MacCalculatorBuilder get(AlgorithmIdentifier algorithmIdentifier);
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12PfxPdu.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12PfxPdu.java
new file mode 100644
index 000000000..6a229e486
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12PfxPdu.java
@@ -0,0 +1,161 @@
+package org.spongycastle.pkcs;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.pkcs.ContentInfo;
+import org.spongycastle.asn1.pkcs.MacData;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.pkcs.Pfx;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.CertIOException;
+import org.spongycastle.util.Arrays;
+
+/**
+ * A holding class for the PKCS12 Pfx structure.
+ */
+public class PKCS12PfxPdu
+{
+ private Pfx pfx;
+
+ private static Pfx parseBytes(byte[] pfxEncoding)
+ throws IOException
+ {
+ try
+ {
+ return Pfx.getInstance(ASN1Primitive.fromByteArray(pfxEncoding));
+ }
+ catch (ClassCastException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ }
+
+ public PKCS12PfxPdu(Pfx pfx)
+ {
+ this.pfx = pfx;
+ }
+
+ public PKCS12PfxPdu(byte[] pfx)
+ throws IOException
+ {
+ this(parseBytes(pfx));
+ }
+
+ /**
+ * Return the content infos in the AuthenticatedSafe contained in this Pfx.
+ *
+ * @return an array of ContentInfo.
+ */
+ public ContentInfo[] getContentInfos()
+ {
+ ASN1Sequence seq = ASN1Sequence.getInstance(ASN1OctetString.getInstance(this.pfx.getAuthSafe().getContent()).getOctets());
+ ContentInfo[] content = new ContentInfo[seq.size()];
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ content[i] = ContentInfo.getInstance(seq.getObjectAt(i));
+ }
+
+ return content;
+ }
+
+ /**
+ * Return whether or not there is MAC attached to this file.
+ *
+ * @return true if there is, false otherwise.
+ */
+ public boolean hasMac()
+ {
+ return pfx.getMacData() != null;
+ }
+
+ /**
+ * Return the algorithm identifier describing the MAC algorithm
+ *
+ * @return the AlgorithmIdentifier representing the MAC algorithm, null if none present.
+ */
+ public AlgorithmIdentifier getMacAlgorithmID()
+ {
+ MacData md = pfx.getMacData();
+
+ if (md != null)
+ {
+ return md.getMac().getAlgorithmId();
+ }
+
+ return null;
+ }
+
+ /**
+ * Verify the MacData attached to the PFX is consistent with what is expected.
+ *
+ * @param macCalcProviderBuilder provider builder for the calculator for the MAC
+ * @param password password to use
+ * @return true if mac data is valid, false otherwise.
+ * @throws PKCSException if there is a problem evaluating the MAC.
+ * @throws IllegalStateException if no MAC is actually present
+ */
+ public boolean isMacValid(PKCS12MacCalculatorBuilderProvider macCalcProviderBuilder, char[] password)
+ throws PKCSException
+ {
+ if (hasMac())
+ {
+ MacData pfxmData = pfx.getMacData();
+ MacDataGenerator mdGen = new MacDataGenerator(macCalcProviderBuilder.get(new AlgorithmIdentifier(pfxmData.getMac().getAlgorithmId().getAlgorithm(), new PKCS12PBEParams(pfxmData.getSalt(), pfxmData.getIterationCount().intValue()))));
+
+ try
+ {
+ MacData mData = mdGen.build(
+ password,
+ ASN1OctetString.getInstance(pfx.getAuthSafe().getContent()).getOctets());
+
+ return Arrays.constantTimeAreEqual(mData.getEncoded(), pfx.getMacData().getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new PKCSException("unable to process AuthSafe: " + e.getMessage());
+ }
+ }
+
+ throw new IllegalStateException("no MAC present on PFX");
+ }
+
+ /**
+ * Return the underlying ASN.1 object.
+ *
+ * @return a Pfx object.
+ */
+ public Pfx toASN1Structure()
+ {
+ return pfx;
+ }
+
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return toASN1Structure().getEncoded();
+ }
+
+ /**
+ * Return a Pfx with the outer wrapper encoded as asked for. For example, Pfx is a usually
+ * a BER encoded object, to get one with DefiniteLength encoding use:
+ * <pre>
+ * getEncoded(ASN1Encoding.DL)
+ * </pre>
+ * @param encoding encoding style (ASN1Encoding.DER, ASN1Encoding.DL, ASN1Encoding.BER)
+ * @return a byte array containing the encoded object.
+ * @throws IOException
+ */
+ public byte[] getEncoded(String encoding)
+ throws IOException
+ {
+ return toASN1Structure().getEncoded(encoding);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12PfxPduBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12PfxPduBuilder.java
new file mode 100644
index 000000000..a9cb0b5be
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12PfxPduBuilder.java
@@ -0,0 +1,179 @@
+package org.spongycastle.pkcs;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DLSequence;
+import org.spongycastle.asn1.pkcs.AuthenticatedSafe;
+import org.spongycastle.asn1.pkcs.ContentInfo;
+import org.spongycastle.asn1.pkcs.MacData;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.Pfx;
+import org.spongycastle.cms.CMSEncryptedDataGenerator;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.operator.OutputEncryptor;
+
+/**
+ * A builder for the PKCS#12 Pfx key and certificate store.
+ * <p>
+ * For example: you can build a basic key store for the user owning privKey as follows:
+ * </p>
+ * <pre>
+ * X509Certificate[] chain = ....
+ * PublicKey pubKey = ....
+ * PrivateKey privKey = ....
+ * JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
+ *
+ * PKCS12SafeBagBuilder taCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[2]);
+ *
+ * taCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Bouncy Primary Certificate"));
+ *
+ * PKCS12SafeBagBuilder caCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[1]);
+ *
+ * caCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Bouncy Intermediate Certificate"));
+ *
+ * PKCS12SafeBagBuilder eeCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[0]);
+ *
+ * eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Eric's Key"));
+ * eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, extUtils.createSubjectKeyIdentifier(pubKey));
+ *
+ * PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder(privKey, new BcPKCS12PBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, new CBCBlockCipher(new DESedeEngine())).build(passwd));
+ *
+ * keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Eric's Key"));
+ * keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, extUtils.createSubjectKeyIdentifier(pubKey));
+ *
+ * //
+ * // construct the actual key store
+ * //
+ * PKCS12PfxPduBuilder pfxPduBuilder = new PKCS12PfxPduBuilder();
+ *
+ * PKCS12SafeBag[] certs = new PKCS12SafeBag[3];
+ *
+ * certs[0] = eeCertBagBuilder.build();
+ * certs[1] = caCertBagBuilder.build();
+ * certs[2] = taCertBagBuilder.build();
+ *
+ * pfxPduBuilder.addEncryptedData(new BcPKCS12PBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, new CBCBlockCipher(new RC2Engine())).build(passwd), certs);
+ *
+ * pfxPduBuilder.addData(keyBagBuilder.build());
+ *
+ * PKCS12PfxPdu pfx = pfxPduBuilder.build(new BcPKCS12MacCalculatorBuilder(), passwd);
+ * </pre>
+ *
+ */
+public class PKCS12PfxPduBuilder
+{
+ private ASN1EncodableVector dataVector = new ASN1EncodableVector();
+
+ /**
+ * Add a SafeBag that is to be included as is.
+ *
+ * @param data the SafeBag to add.
+ * @return this builder.
+ * @throws IOException
+ */
+ public PKCS12PfxPduBuilder addData(PKCS12SafeBag data)
+ throws IOException
+ {
+ dataVector.add(new ContentInfo(PKCSObjectIdentifiers.data, new DEROctetString(new DLSequence(data.toASN1Structure()).getEncoded())));
+
+ return this;
+ }
+
+ /**
+ * Add a SafeBag that is to be wrapped in a EncryptedData object.
+ *
+ * @param dataEncryptor the encryptor to use for encoding the data.
+ * @param data the SafeBag to include.
+ * @return this builder.
+ * @throws IOException if a issue occurs processing the data.
+ */
+ public PKCS12PfxPduBuilder addEncryptedData(OutputEncryptor dataEncryptor, PKCS12SafeBag data)
+ throws IOException
+ {
+ return addEncryptedData(dataEncryptor, new DERSequence(data.toASN1Structure()));
+ }
+
+ /**
+ * Add a set of SafeBags that are to be wrapped in a EncryptedData object.
+ *
+ * @param dataEncryptor the encryptor to use for encoding the data.
+ * @param data the SafeBags to include.
+ * @return this builder.
+ * @throws IOException if a issue occurs processing the data.
+ */
+ public PKCS12PfxPduBuilder addEncryptedData(OutputEncryptor dataEncryptor, PKCS12SafeBag[] data)
+ throws IOException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ for (int i = 0; i != data.length; i++)
+ {
+ v.add(data[i].toASN1Structure());
+ }
+
+ return addEncryptedData(dataEncryptor, new DLSequence(v));
+ }
+
+ private PKCS12PfxPduBuilder addEncryptedData(OutputEncryptor dataEncryptor, ASN1Sequence data)
+ throws IOException
+ {
+ CMSEncryptedDataGenerator envGen = new CMSEncryptedDataGenerator();
+
+ try
+ {
+ dataVector.add(envGen.generate(new CMSProcessableByteArray(data.getEncoded()), dataEncryptor).toASN1Structure());
+ }
+ catch (CMSException e)
+ {
+ throw new PKCSIOException(e.getMessage(), e.getCause());
+ }
+
+ return this;
+ }
+
+ /**
+ * Build the Pfx structure, protecting it with a MAC calculated against the passed in password.
+ *
+ * @param macCalcBuilder a builder for a PKCS12 mac calculator.
+ * @param password the password to use.
+ * @return a Pfx object.
+ * @throws PKCSException on a encoding or processing error.
+ */
+ public PKCS12PfxPdu build(PKCS12MacCalculatorBuilder macCalcBuilder, char[] password)
+ throws PKCSException
+ {
+ AuthenticatedSafe auth = AuthenticatedSafe.getInstance(new DLSequence(dataVector));
+ byte[] encAuth;
+
+ try
+ {
+ encAuth = auth.getEncoded();
+ }
+ catch (IOException e)
+ {
+ throw new PKCSException("unable to encode AuthenticatedSafe: " + e.getMessage(), e);
+ }
+
+ ContentInfo mainInfo = new ContentInfo(PKCSObjectIdentifiers.data, new DEROctetString(encAuth));
+ MacData mData = null;
+
+ if (macCalcBuilder != null)
+ {
+ MacDataGenerator mdGen = new MacDataGenerator(macCalcBuilder);
+
+ mData = mdGen.build(password, encAuth);
+ }
+
+ //
+ // output the Pfx
+ //
+ Pfx pfx = new Pfx(mainInfo, mData);
+
+ return new PKCS12PfxPdu(pfx);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBag.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBag.java
new file mode 100644
index 000000000..0ce0887e7
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBag.java
@@ -0,0 +1,93 @@
+package org.spongycastle.pkcs;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.pkcs.Attribute;
+import org.spongycastle.asn1.pkcs.CRLBag;
+import org.spongycastle.asn1.pkcs.CertBag;
+import org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.pkcs.SafeBag;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.cert.X509CRLHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+
+public class PKCS12SafeBag
+{
+ public static final ASN1ObjectIdentifier friendlyNameAttribute = PKCSObjectIdentifiers.pkcs_9_at_friendlyName;
+ public static final ASN1ObjectIdentifier localKeyIdAttribute = PKCSObjectIdentifiers.pkcs_9_at_localKeyId;
+
+ private SafeBag safeBag;
+
+ public PKCS12SafeBag(SafeBag safeBag)
+ {
+ this.safeBag = safeBag;
+ }
+
+ /**
+ * Return the underlying ASN.1 structure for this safe bag.
+ *
+ * @return a SafeBag
+ */
+ public SafeBag toASN1Structure()
+ {
+ return safeBag;
+ }
+
+ /**
+ * Return the BagId giving the type of content in the bag.
+ *
+ * @return the bagId
+ */
+ public ASN1ObjectIdentifier getType()
+ {
+ return safeBag.getBagId();
+ }
+
+ public Attribute[] getAttributes()
+ {
+ ASN1Set attrs = safeBag.getBagAttributes();
+
+ if (attrs == null)
+ {
+ return null;
+ }
+
+ Attribute[] attributes = new Attribute[attrs.size()];
+ for (int i = 0; i != attrs.size(); i++)
+ {
+ attributes[i] = Attribute.getInstance(attrs.getObjectAt(i));
+ }
+
+ return attributes;
+ }
+
+ public Object getBagValue()
+ {
+ if (getType().equals(PKCSObjectIdentifiers.pkcs8ShroudedKeyBag))
+ {
+ return new PKCS8EncryptedPrivateKeyInfo(EncryptedPrivateKeyInfo.getInstance(safeBag.getBagValue()));
+ }
+ if (getType().equals(PKCSObjectIdentifiers.certBag))
+ {
+ CertBag certBag = CertBag.getInstance(safeBag.getBagValue());
+
+ return new X509CertificateHolder(Certificate.getInstance(ASN1OctetString.getInstance(certBag.getCertValue()).getOctets()));
+ }
+ if (getType().equals(PKCSObjectIdentifiers.keyBag))
+ {
+ return PrivateKeyInfo.getInstance(safeBag.getBagValue());
+ }
+ if (getType().equals(PKCSObjectIdentifiers.crlBag))
+ {
+ CRLBag crlBag = CRLBag.getInstance(safeBag.getBagValue());
+
+ return new X509CRLHolder(CertificateList.getInstance(ASN1OctetString.getInstance(crlBag.getCRLValue()).getOctets()));
+ }
+
+ return safeBag.getBagValue();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBagBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBagBuilder.java
new file mode 100644
index 000000000..d60bd5a5c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBagBuilder.java
@@ -0,0 +1,76 @@
+package org.spongycastle.pkcs;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.pkcs.Attribute;
+import org.spongycastle.asn1.pkcs.CertBag;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.pkcs.SafeBag;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.cert.X509CRLHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.operator.OutputEncryptor;
+
+public class PKCS12SafeBagBuilder
+{
+ private ASN1ObjectIdentifier bagType;
+ private ASN1Encodable bagValue;
+ private ASN1EncodableVector bagAttrs = new ASN1EncodableVector();
+
+ public PKCS12SafeBagBuilder(PrivateKeyInfo privateKeyInfo, OutputEncryptor encryptor)
+ {
+ this.bagType = PKCSObjectIdentifiers.pkcs8ShroudedKeyBag;
+ this.bagValue = new PKCS8EncryptedPrivateKeyInfoBuilder(privateKeyInfo).build(encryptor).toASN1Structure();
+ }
+
+ public PKCS12SafeBagBuilder(PrivateKeyInfo privateKeyInfo)
+ {
+ this.bagType = PKCSObjectIdentifiers.keyBag;
+ this.bagValue = privateKeyInfo;
+ }
+
+ public PKCS12SafeBagBuilder(X509CertificateHolder certificate)
+ throws IOException
+ {
+ this(certificate.toASN1Structure());
+ }
+
+ public PKCS12SafeBagBuilder(X509CRLHolder crl)
+ throws IOException
+ {
+ this(crl.toASN1Structure());
+ }
+
+ public PKCS12SafeBagBuilder(Certificate certificate)
+ throws IOException
+ {
+ this.bagType = PKCSObjectIdentifiers.certBag;
+ this.bagValue = new CertBag(PKCSObjectIdentifiers.x509Certificate, new DEROctetString(certificate.getEncoded()));
+ }
+
+ public PKCS12SafeBagBuilder(CertificateList crl)
+ throws IOException
+ {
+ this.bagType = PKCSObjectIdentifiers.crlBag;
+ this.bagValue = new CertBag(PKCSObjectIdentifiers.x509Crl, new DEROctetString(crl.getEncoded()));
+ }
+
+ public PKCS12SafeBagBuilder addBagAttribute(ASN1ObjectIdentifier attrType, ASN1Encodable attrValue)
+ {
+ bagAttrs.add(new Attribute(attrType, new DERSet(attrValue)));
+
+ return this;
+ }
+
+ public PKCS12SafeBag build()
+ {
+ return new PKCS12SafeBag(new SafeBag(bagType, bagValue, new DERSet(bagAttrs)));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBagFactory.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBagFactory.java
new file mode 100644
index 000000000..36f53723a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12SafeBagFactory.java
@@ -0,0 +1,58 @@
+package org.spongycastle.pkcs;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.pkcs.ContentInfo;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.SafeBag;
+import org.spongycastle.cms.CMSEncryptedData;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.operator.InputDecryptorProvider;
+
+public class PKCS12SafeBagFactory
+{
+ private ASN1Sequence safeBagSeq;
+
+ public PKCS12SafeBagFactory(ContentInfo info)
+ {
+ if (info.getContentType().equals(PKCSObjectIdentifiers.encryptedData))
+ {
+ throw new IllegalArgumentException("encryptedData requires constructor with decryptor.");
+ }
+
+ this.safeBagSeq = ASN1Sequence.getInstance(ASN1OctetString.getInstance(info.getContent()).getOctets());
+ }
+
+ public PKCS12SafeBagFactory(ContentInfo info, InputDecryptorProvider inputDecryptorProvider)
+ throws PKCSException
+ {
+ if (info.getContentType().equals(PKCSObjectIdentifiers.encryptedData))
+ {
+ CMSEncryptedData encData = new CMSEncryptedData(org.spongycastle.asn1.cms.ContentInfo.getInstance(info));
+
+ try
+ {
+ this.safeBagSeq = ASN1Sequence.getInstance(encData.getContent(inputDecryptorProvider));
+ }
+ catch (CMSException e)
+ {
+ throw new PKCSException("unable to extract data: " + e.getMessage(), e);
+ }
+ return;
+ }
+
+ throw new IllegalArgumentException("encryptedData requires constructor with decryptor.");
+ }
+
+ public PKCS12SafeBag[] getSafeBags()
+ {
+ PKCS12SafeBag[] safeBags = new PKCS12SafeBag[safeBagSeq.size()];
+
+ for (int i = 0; i != safeBagSeq.size(); i++)
+ {
+ safeBags[i] = new PKCS12SafeBag(SafeBag.getInstance(safeBagSeq.getObjectAt(i)));
+ }
+
+ return safeBags;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS8EncryptedPrivateKeyInfo.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS8EncryptedPrivateKeyInfo.java
new file mode 100644
index 000000000..1f41fb677
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS8EncryptedPrivateKeyInfo.java
@@ -0,0 +1,76 @@
+package org.spongycastle.pkcs;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.cert.CertIOException;
+import org.spongycastle.operator.InputDecryptor;
+import org.spongycastle.operator.InputDecryptorProvider;
+import org.spongycastle.util.io.Streams;
+
+/**
+ * Holding class for a PKCS#8 EncryptedPrivateKeyInfo structure.
+ */
+public class PKCS8EncryptedPrivateKeyInfo
+{
+ private EncryptedPrivateKeyInfo encryptedPrivateKeyInfo;
+
+ private static EncryptedPrivateKeyInfo parseBytes(byte[] pkcs8Encoding)
+ throws IOException
+ {
+ try
+ {
+ return EncryptedPrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(pkcs8Encoding));
+ }
+ catch (ClassCastException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ }
+
+ public PKCS8EncryptedPrivateKeyInfo(EncryptedPrivateKeyInfo encryptedPrivateKeyInfo)
+ {
+ this.encryptedPrivateKeyInfo = encryptedPrivateKeyInfo;
+ }
+
+ public PKCS8EncryptedPrivateKeyInfo(byte[] encryptedPrivateKeyInfo)
+ throws IOException
+ {
+ this(parseBytes(encryptedPrivateKeyInfo));
+ }
+
+ public EncryptedPrivateKeyInfo toASN1Structure()
+ {
+ return encryptedPrivateKeyInfo;
+ }
+
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return encryptedPrivateKeyInfo.getEncoded();
+ }
+
+ public PrivateKeyInfo decryptPrivateKeyInfo(InputDecryptorProvider inputDecryptorProvider)
+ throws PKCSException
+ {
+ try
+ {
+ InputDecryptor decrytor = inputDecryptorProvider.get(encryptedPrivateKeyInfo.getEncryptionAlgorithm());
+
+ ByteArrayInputStream encIn = new ByteArrayInputStream(encryptedPrivateKeyInfo.getEncryptedData());
+
+ return PrivateKeyInfo.getInstance(Streams.readAll(decrytor.getInputStream(encIn)));
+ }
+ catch (Exception e)
+ {
+ throw new PKCSException("unable to read encrypted data: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS8EncryptedPrivateKeyInfoBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS8EncryptedPrivateKeyInfoBuilder.java
new file mode 100644
index 000000000..3897c40ae
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS8EncryptedPrivateKeyInfoBuilder.java
@@ -0,0 +1,54 @@
+package org.spongycastle.pkcs;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.operator.OutputEncryptor;
+
+/**
+ * A class for creating EncryptedPrivateKeyInfo structures.
+ * <pre>
+ * EncryptedPrivateKeyInfo ::= SEQUENCE {
+ * encryptionAlgorithm AlgorithmIdentifier {{KeyEncryptionAlgorithms}},
+ * encryptedData EncryptedData
+ * }
+ *
+ * EncryptedData ::= OCTET STRING
+ *
+ * KeyEncryptionAlgorithms ALGORITHM-IDENTIFIER ::= {
+ * ... -- For local profiles
+ * }
+ * </pre>
+ */
+public class PKCS8EncryptedPrivateKeyInfoBuilder
+{
+ private PrivateKeyInfo privateKeyInfo;
+
+ public PKCS8EncryptedPrivateKeyInfoBuilder(PrivateKeyInfo privateKeyInfo)
+ {
+ this.privateKeyInfo = privateKeyInfo;
+ }
+
+ public PKCS8EncryptedPrivateKeyInfo build(
+ OutputEncryptor encryptor)
+ {
+ try
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ OutputStream cOut = encryptor.getOutputStream(bOut);
+
+ cOut.write(privateKeyInfo.getEncoded());
+
+ cOut.close();
+
+ return new PKCS8EncryptedPrivateKeyInfo(new EncryptedPrivateKeyInfo(encryptor.getAlgorithmIdentifier(), bOut.toByteArray()));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("cannot encode privateKeyInfo");
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCSException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCSException.java
new file mode 100644
index 000000000..201dde938
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCSException.java
@@ -0,0 +1,27 @@
+package org.spongycastle.pkcs;
+
+/**
+ * General checked Exception thrown in the cert package and its sub-packages.
+ */
+public class PKCSException
+ extends Exception
+{
+ private Throwable cause;
+
+ public PKCSException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public PKCSException(String msg)
+ {
+ super(msg);
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCSIOException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCSIOException.java
new file mode 100644
index 000000000..0352829b9
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCSIOException.java
@@ -0,0 +1,29 @@
+package org.spongycastle.pkcs;
+
+import java.io.IOException;
+
+/**
+ * General IOException thrown in the cert package and its sub-packages.
+ */
+public class PKCSIOException
+ extends IOException
+{
+ private Throwable cause;
+
+ public PKCSIOException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public PKCSIOException(String msg)
+ {
+ super(msg);
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS10CertificationRequest.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS10CertificationRequest.java
new file mode 100644
index 000000000..6ac22464c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS10CertificationRequest.java
@@ -0,0 +1,42 @@
+package org.spongycastle.pkcs.bc;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.pkcs.CertificationRequest;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.util.PublicKeyFactory;
+import org.spongycastle.pkcs.PKCS10CertificationRequest;
+import org.spongycastle.pkcs.PKCSException;
+
+public class BcPKCS10CertificationRequest
+ extends PKCS10CertificationRequest
+{
+ public BcPKCS10CertificationRequest(CertificationRequest certificationRequest)
+ {
+ super(certificationRequest);
+ }
+
+ public BcPKCS10CertificationRequest(byte[] encoding)
+ throws IOException
+ {
+ super(encoding);
+ }
+
+ public BcPKCS10CertificationRequest(PKCS10CertificationRequest requestHolder)
+ {
+ super(requestHolder.toASN1Structure());
+ }
+
+ public AsymmetricKeyParameter getPublicKey()
+ throws PKCSException
+ {
+ try
+ {
+ return PublicKeyFactory.createKey(this.getSubjectPublicKeyInfo());
+ }
+ catch (IOException e)
+ {
+ throw new PKCSException("error extracting key encoding: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS10CertificationRequestBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS10CertificationRequestBuilder.java
new file mode 100644
index 000000000..1590a6634
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS10CertificationRequestBuilder.java
@@ -0,0 +1,28 @@
+package org.spongycastle.pkcs.bc;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.util.SubjectPublicKeyInfoFactory;
+import org.spongycastle.pkcs.PKCS10CertificationRequestBuilder;
+
+/**
+ * Extension of the PKCS#10 builder to support AsymmetricKey objects.
+ */
+public class BcPKCS10CertificationRequestBuilder
+ extends PKCS10CertificationRequestBuilder
+{
+ /**
+ * Create a PKCS#10 builder for the passed in subject and JCA public key.
+ *
+ * @param subject an X500Name containing the subject associated with the request we are building.
+ * @param publicKey a JCA public key that is to be associated with the request we are building.
+ * @throws IOException if there is a problem encoding the public key.
+ */
+ public BcPKCS10CertificationRequestBuilder(X500Name subject, AsymmetricKeyParameter publicKey)
+ throws IOException
+ {
+ super(subject, SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12MacCalculatorBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12MacCalculatorBuilder.java
new file mode 100644
index 000000000..456d5b080
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12MacCalculatorBuilder.java
@@ -0,0 +1,54 @@
+package org.spongycastle.pkcs.bc;
+
+import java.security.SecureRandom;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.ExtendedDigest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.operator.MacCalculator;
+import org.spongycastle.pkcs.PKCS12MacCalculatorBuilder;
+
+public class BcPKCS12MacCalculatorBuilder
+ implements PKCS12MacCalculatorBuilder
+{
+ private ExtendedDigest digest;
+ private AlgorithmIdentifier algorithmIdentifier;
+
+ private SecureRandom random;
+ private int saltLength;
+ private int iterationCount = 1024;
+
+ public BcPKCS12MacCalculatorBuilder()
+ {
+ this(new SHA1Digest(), new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE));
+ }
+
+ public BcPKCS12MacCalculatorBuilder(ExtendedDigest digest, AlgorithmIdentifier algorithmIdentifier)
+ {
+ this.digest = digest;
+ this.algorithmIdentifier = algorithmIdentifier;
+ this.saltLength = digest.getDigestSize();
+ }
+
+ public AlgorithmIdentifier getDigestAlgorithmIdentifier()
+ {
+ return algorithmIdentifier;
+ }
+
+ public MacCalculator build(final char[] password)
+ {
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ byte[] salt = new byte[saltLength];
+
+ random.nextBytes(salt);
+
+ return PKCS12PBEUtils.createMacCalculator(algorithmIdentifier.getAlgorithm(), digest, new PKCS12PBEParams(salt, iterationCount), password);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12MacCalculatorBuilderProvider.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12MacCalculatorBuilderProvider.java
new file mode 100644
index 000000000..d5533753a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12MacCalculatorBuilderProvider.java
@@ -0,0 +1,40 @@
+package org.spongycastle.pkcs.bc;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.MacCalculator;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.bc.BcDigestProvider;
+import org.spongycastle.pkcs.PKCS12MacCalculatorBuilder;
+import org.spongycastle.pkcs.PKCS12MacCalculatorBuilderProvider;
+
+public class BcPKCS12MacCalculatorBuilderProvider
+ implements PKCS12MacCalculatorBuilderProvider
+{
+ private BcDigestProvider digestProvider;
+
+ public BcPKCS12MacCalculatorBuilderProvider(BcDigestProvider digestProvider)
+ {
+ this.digestProvider = digestProvider;
+ }
+
+ public PKCS12MacCalculatorBuilder get(final AlgorithmIdentifier algorithmIdentifier)
+ {
+ return new PKCS12MacCalculatorBuilder()
+ {
+ public MacCalculator build(final char[] password)
+ throws OperatorCreationException
+ {
+ PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algorithmIdentifier.getParameters());
+
+ return PKCS12PBEUtils.createMacCalculator(algorithmIdentifier.getAlgorithm(), digestProvider.get(algorithmIdentifier), pbeParams, password);
+ }
+
+ public AlgorithmIdentifier getDigestAlgorithmIdentifier()
+ {
+ return new AlgorithmIdentifier(algorithmIdentifier.getAlgorithm(), DERNull.INSTANCE);
+ }
+ };
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12PBEInputDecryptorProviderBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12PBEInputDecryptorProviderBuilder.java
new file mode 100644
index 000000000..a4618c042
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12PBEInputDecryptorProviderBuilder.java
@@ -0,0 +1,66 @@
+package org.spongycastle.pkcs.bc;
+
+import java.io.InputStream;
+
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.ExtendedDigest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.generators.PKCS12ParametersGenerator;
+import org.spongycastle.crypto.io.CipherInputStream;
+import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.InputDecryptor;
+import org.spongycastle.operator.InputDecryptorProvider;
+
+public class BcPKCS12PBEInputDecryptorProviderBuilder
+{
+ private ExtendedDigest digest;
+
+ public BcPKCS12PBEInputDecryptorProviderBuilder()
+ {
+ this(new SHA1Digest());
+ }
+
+ public BcPKCS12PBEInputDecryptorProviderBuilder(ExtendedDigest digest)
+ {
+ this.digest = digest;
+ }
+
+ public InputDecryptorProvider build(final char[] password)
+ {
+ return new InputDecryptorProvider()
+ {
+ public InputDecryptor get(final AlgorithmIdentifier algorithmIdentifier)
+ {
+ final PaddedBufferedBlockCipher engine = PKCS12PBEUtils.getEngine(algorithmIdentifier.getAlgorithm());
+
+ PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algorithmIdentifier.getParameters());
+
+ CipherParameters params = PKCS12PBEUtils.createCipherParameters(algorithmIdentifier.getAlgorithm(), digest, engine.getBlockSize(), pbeParams, password);
+
+ engine.init(false, params);
+
+ return new InputDecryptor()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmIdentifier;
+ }
+
+ public InputStream getInputStream(InputStream input)
+ {
+ return new CipherInputStream(input, engine);
+ }
+
+ public GenericKey getKey()
+ {
+ return new GenericKey(PKCS12ParametersGenerator.PKCS12PasswordToBytes(password));
+ }
+ };
+ }
+ };
+
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12PBEOutputEncryptorBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12PBEOutputEncryptorBuilder.java
new file mode 100644
index 000000000..d8af97c39
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/BcPKCS12PBEOutputEncryptorBuilder.java
@@ -0,0 +1,77 @@
+package org.spongycastle.pkcs.bc;
+
+import java.io.OutputStream;
+import java.security.SecureRandom;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.BufferedBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.ExtendedDigest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.generators.PKCS12ParametersGenerator;
+import org.spongycastle.crypto.io.CipherOutputStream;
+import org.spongycastle.crypto.paddings.PKCS7Padding;
+import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OutputEncryptor;
+
+public class BcPKCS12PBEOutputEncryptorBuilder
+{
+ private ExtendedDigest digest;
+
+ private BufferedBlockCipher engine;
+ private ASN1ObjectIdentifier algorithm;
+ private SecureRandom random;
+
+ public BcPKCS12PBEOutputEncryptorBuilder(ASN1ObjectIdentifier algorithm, BlockCipher engine)
+ {
+ this(algorithm, engine, new SHA1Digest());
+ }
+
+ public BcPKCS12PBEOutputEncryptorBuilder(ASN1ObjectIdentifier algorithm, BlockCipher engine, ExtendedDigest pbeDigest)
+ {
+ this.algorithm = algorithm;
+ this.engine = new PaddedBufferedBlockCipher(engine, new PKCS7Padding());
+ this.digest = pbeDigest;
+ }
+
+ public OutputEncryptor build(final char[] password)
+ {
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ final byte[] salt = new byte[20];
+ final int iterationCount = 1024;
+
+ random.nextBytes(salt);
+
+ final PKCS12PBEParams pbeParams = new PKCS12PBEParams(salt, iterationCount);
+
+ CipherParameters params = PKCS12PBEUtils.createCipherParameters(algorithm, digest, engine.getBlockSize(), pbeParams, password);
+
+ engine.init(true, params);
+
+ return new OutputEncryptor()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return new AlgorithmIdentifier(algorithm, pbeParams);
+ }
+
+ public OutputStream getOutputStream(OutputStream out)
+ {
+ return new CipherOutputStream(out, engine);
+ }
+
+ public GenericKey getKey()
+ {
+ return new GenericKey(new AlgorithmIdentifier(algorithm, pbeParams), PKCS12ParametersGenerator.PKCS12PasswordToBytes(password));
+ }
+ };
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/PKCS12PBEUtils.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/PKCS12PBEUtils.java
new file mode 100644
index 000000000..52f07a549
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/bc/PKCS12PBEUtils.java
@@ -0,0 +1,153 @@
+package org.spongycastle.pkcs.bc;
+
+import java.io.OutputStream;
+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.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.ExtendedDigest;
+import org.spongycastle.crypto.engines.DESedeEngine;
+import org.spongycastle.crypto.engines.RC2Engine;
+import org.spongycastle.crypto.generators.PKCS12ParametersGenerator;
+import org.spongycastle.crypto.io.MacOutputStream;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.crypto.paddings.PKCS7Padding;
+import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.spongycastle.crypto.params.DESedeParameters;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithIV;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.MacCalculator;
+import org.spongycastle.util.Integers;
+
+class PKCS12PBEUtils
+{
+ private static Map keySizes = new HashMap();
+ private static Set noIvAlgs = new HashSet();
+ private static Set desAlgs = new HashSet();
+
+ static
+ {
+ keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, Integers.valueOf(128));
+ keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4, Integers.valueOf(40));
+ keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, Integers.valueOf(192));
+ keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC, Integers.valueOf(128));
+ keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC, Integers.valueOf(128));
+ keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, Integers.valueOf(40));
+
+ noIvAlgs.add(PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4);
+ noIvAlgs.add(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4);
+
+ desAlgs.add(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC);
+ desAlgs.add(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC);
+ }
+
+ static int getKeySize(ASN1ObjectIdentifier algorithm)
+ {
+ return ((Integer)keySizes.get(algorithm)).intValue();
+ }
+
+ static boolean hasNoIv(ASN1ObjectIdentifier algorithm)
+ {
+ return noIvAlgs.contains(algorithm);
+ }
+
+ static boolean isDesAlg(ASN1ObjectIdentifier algorithm)
+ {
+ return desAlgs.contains(algorithm);
+ }
+
+ static PaddedBufferedBlockCipher getEngine(ASN1ObjectIdentifier algorithm)
+ {
+ BlockCipher engine;
+
+ if (algorithm.equals(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC)
+ || algorithm.equals(PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC))
+ {
+ engine = new DESedeEngine();
+ }
+ else if (algorithm.equals(PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC)
+ || algorithm.equals(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC))
+ {
+ engine = new RC2Engine();
+ }
+ else
+ {
+ throw new IllegalStateException("unknown algorithm");
+ }
+
+ return new PaddedBufferedBlockCipher(new CBCBlockCipher(engine), new PKCS7Padding());
+ }
+
+ static MacCalculator createMacCalculator(final ASN1ObjectIdentifier digestAlgorithm, ExtendedDigest digest, final PKCS12PBEParams pbeParams, final char[] password)
+ {
+ PKCS12ParametersGenerator pGen = new PKCS12ParametersGenerator(digest);
+
+ pGen.init(PKCS12ParametersGenerator.PKCS12PasswordToBytes(password), pbeParams.getIV(), pbeParams.getIterations().intValue());
+
+ final KeyParameter keyParam = (KeyParameter)pGen.generateDerivedMacParameters(digest.getDigestSize() * 8);
+
+ final HMac hMac = new HMac(digest);
+
+ hMac.init(keyParam);
+
+ return new MacCalculator()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return new AlgorithmIdentifier(digestAlgorithm, pbeParams);
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return new MacOutputStream(hMac);
+ }
+
+ public byte[] getMac()
+ {
+ byte[] res = new byte[hMac.getMacSize()];
+
+ hMac.doFinal(res, 0);
+
+ return res;
+ }
+
+ public GenericKey getKey()
+ {
+ return new GenericKey(getAlgorithmIdentifier(), PKCS12ParametersGenerator.PKCS12PasswordToBytes(password));
+ }
+ };
+ }
+
+ static CipherParameters createCipherParameters(ASN1ObjectIdentifier algorithm, ExtendedDigest digest, int blockSize, PKCS12PBEParams pbeParams, char[] password)
+ {
+ PKCS12ParametersGenerator pGen = new PKCS12ParametersGenerator(digest);
+
+ pGen.init(PKCS12ParametersGenerator.PKCS12PasswordToBytes(password), pbeParams.getIV(), pbeParams.getIterations().intValue());
+
+ CipherParameters params;
+
+ if (PKCS12PBEUtils.hasNoIv(algorithm))
+ {
+ params = pGen.generateDerivedParameters(PKCS12PBEUtils.getKeySize(algorithm));
+ }
+ else
+ {
+ params = pGen.generateDerivedParameters(PKCS12PBEUtils.getKeySize(algorithm), blockSize * 8);
+
+ if (PKCS12PBEUtils.isDesAlg(algorithm))
+ {
+ DESedeParameters.setOddParity(((KeyParameter)((ParametersWithIV)params).getParameters()).getKey());
+ }
+ }
+ return params;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS10CertificationRequest.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS10CertificationRequest.java
new file mode 100644
index 000000000..3e4e6dc0e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS10CertificationRequest.java
@@ -0,0 +1,115 @@
+package org.spongycastle.pkcs.jcajce;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Hashtable;
+
+import org.spongycastle.asn1.pkcs.CertificationRequest;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.JcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.pkcs.PKCS10CertificationRequest;
+
+public class JcaPKCS10CertificationRequest
+ extends PKCS10CertificationRequest
+{
+ private static Hashtable keyAlgorithms = new Hashtable();
+
+ static
+ {
+ //
+ // key types
+ //
+ keyAlgorithms.put(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ keyAlgorithms.put(X9ObjectIdentifiers.id_dsa, "DSA");
+ }
+
+ private JcaJceHelper helper = new DefaultJcaJceHelper();
+
+ public JcaPKCS10CertificationRequest(CertificationRequest certificationRequest)
+ {
+ super(certificationRequest);
+ }
+
+ public JcaPKCS10CertificationRequest(byte[] encoding)
+ throws IOException
+ {
+ super(encoding);
+ }
+
+ public JcaPKCS10CertificationRequest(PKCS10CertificationRequest requestHolder)
+ {
+ super(requestHolder.toASN1Structure());
+ }
+
+ public JcaPKCS10CertificationRequest setProvider(String providerName)
+ {
+ helper = new NamedJcaJceHelper(providerName);
+
+ return this;
+ }
+
+ public JcaPKCS10CertificationRequest setProvider(Provider provider)
+ {
+ helper = new ProviderJcaJceHelper(provider);
+
+ return this;
+ }
+
+ public PublicKey getPublicKey()
+ throws InvalidKeyException, NoSuchAlgorithmException
+ {
+ try
+ {
+ SubjectPublicKeyInfo keyInfo = this.getSubjectPublicKeyInfo();
+ X509EncodedKeySpec xspec = new X509EncodedKeySpec(keyInfo.getEncoded());
+ KeyFactory kFact;
+
+ try
+ {
+ kFact = helper.createKeyFactory(keyInfo.getAlgorithm().getAlgorithm().getId());
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ //
+ // try an alternate
+ //
+ if (keyAlgorithms.get(keyInfo.getAlgorithm().getAlgorithm()) != null)
+ {
+ String keyAlgorithm = (String)keyAlgorithms.get(keyInfo.getAlgorithm().getAlgorithm());
+
+ kFact = helper.createKeyFactory(keyAlgorithm);
+ }
+ else
+ {
+ throw e;
+ }
+ }
+
+ return kFact.generatePublic(xspec);
+ }
+ catch (InvalidKeySpecException e)
+ {
+ throw new InvalidKeyException("error decoding public key");
+ }
+ catch (IOException e)
+ {
+ throw new InvalidKeyException("error extracting key encoding");
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new NoSuchAlgorithmException("cannot find provider: " + e.getMessage());
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS10CertificationRequestBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS10CertificationRequestBuilder.java
new file mode 100644
index 000000000..0efa5fa20
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS10CertificationRequestBuilder.java
@@ -0,0 +1,38 @@
+package org.spongycastle.pkcs.jcajce;
+
+import java.security.PublicKey;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.pkcs.PKCS10CertificationRequestBuilder;
+
+/**
+ * Extension of the PKCS#10 builder to support PublicKey and X500Principal objects.
+ */
+public class JcaPKCS10CertificationRequestBuilder
+ extends PKCS10CertificationRequestBuilder
+{
+ /**
+ * Create a PKCS#10 builder for the passed in subject and JCA public key.
+ *
+ * @param subject an X500Name containing the subject associated with the request we are building.
+ * @param publicKey a JCA public key that is to be associated with the request we are building.
+ */
+ public JcaPKCS10CertificationRequestBuilder(X500Name subject, PublicKey publicKey)
+ {
+ super(subject, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));
+ }
+
+ /**
+ * Create a PKCS#10 builder for the passed in subject and JCA public key.
+ *
+ * @param subject an X500Principal containing the subject associated with the request we are building.
+ * @param publicKey a JCA public key that is to be associated with the request we are building.
+ */
+ public JcaPKCS10CertificationRequestBuilder(X500Principal subject, PublicKey publicKey)
+ {
+ super(X500Name.getInstance(subject.getEncoded()), SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS12SafeBagBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS12SafeBagBuilder.java
new file mode 100644
index 000000000..f8c06f7ca
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS12SafeBagBuilder.java
@@ -0,0 +1,45 @@
+package org.spongycastle.pkcs.jcajce;
+
+import java.io.IOException;
+import java.security.PrivateKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.operator.OutputEncryptor;
+import org.spongycastle.pkcs.PKCS12SafeBagBuilder;
+import org.spongycastle.pkcs.PKCSIOException;
+
+public class JcaPKCS12SafeBagBuilder
+ extends PKCS12SafeBagBuilder
+{
+ public JcaPKCS12SafeBagBuilder(X509Certificate certificate)
+ throws IOException
+ {
+ super(convertCert(certificate));
+ }
+
+ private static Certificate convertCert(X509Certificate certificate)
+ throws IOException
+ {
+ try
+ {
+ return Certificate.getInstance(certificate.getEncoded());
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new PKCSIOException("cannot encode certificate: " + e.getMessage(), e);
+ }
+ }
+
+ public JcaPKCS12SafeBagBuilder(PrivateKey privateKey, OutputEncryptor encryptor)
+ {
+ super(PrivateKeyInfo.getInstance(privateKey.getEncoded()), encryptor);
+ }
+
+ public JcaPKCS12SafeBagBuilder(PrivateKey privateKey)
+ {
+ super(PrivateKeyInfo.getInstance(privateKey.getEncoded()));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS8EncryptedPrivateKeyInfoBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS8EncryptedPrivateKeyInfoBuilder.java
new file mode 100644
index 000000000..f8a5856c8
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcaPKCS8EncryptedPrivateKeyInfoBuilder.java
@@ -0,0 +1,15 @@
+package org.spongycastle.pkcs.jcajce;
+
+import java.security.PrivateKey;
+
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.pkcs.PKCS8EncryptedPrivateKeyInfoBuilder;
+
+public class JcaPKCS8EncryptedPrivateKeyInfoBuilder
+ extends PKCS8EncryptedPrivateKeyInfoBuilder
+{
+ public JcaPKCS8EncryptedPrivateKeyInfoBuilder(PrivateKey privateKey)
+ {
+ super(PrivateKeyInfo.getInstance(privateKey.getEncoded()));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilder.java
new file mode 100644
index 000000000..4e6b39f0f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilder.java
@@ -0,0 +1,122 @@
+package org.spongycastle.pkcs.jcajce;
+
+import java.io.OutputStream;
+import java.security.Provider;
+import java.security.SecureRandom;
+
+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.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.ExtendedDigest;
+import org.spongycastle.crypto.generators.PKCS12ParametersGenerator;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.JcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.jcajce.io.MacOutputStream;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.MacCalculator;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.pkcs.PKCS12MacCalculatorBuilder;
+
+public class JcePKCS12MacCalculatorBuilder
+ implements PKCS12MacCalculatorBuilder
+{
+ private JcaJceHelper helper = new DefaultJcaJceHelper();
+ private ExtendedDigest digest;
+ private ASN1ObjectIdentifier algorithm;
+
+ private SecureRandom random;
+ private int saltLength;
+ private int iterationCount = 1024;
+
+ public JcePKCS12MacCalculatorBuilder()
+ {
+ this(OIWObjectIdentifiers.idSHA1);
+ }
+
+ public JcePKCS12MacCalculatorBuilder(ASN1ObjectIdentifier hashAlgorithm)
+ {
+ this.algorithm = hashAlgorithm;
+ }
+
+ public JcePKCS12MacCalculatorBuilder setProvider(Provider provider)
+ {
+ this.helper = new ProviderJcaJceHelper(provider);
+
+ return this;
+ }
+
+ public JcePKCS12MacCalculatorBuilder setProvider(String providerName)
+ {
+ this.helper = new NamedJcaJceHelper(providerName);
+
+ return this;
+ }
+
+ public AlgorithmIdentifier getDigestAlgorithmIdentifier()
+ {
+ return new AlgorithmIdentifier(algorithm, DERNull.INSTANCE);
+ }
+
+ public MacCalculator build(final char[] password)
+ throws OperatorCreationException
+ {
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ try
+ {
+ final Mac mac = helper.createMac(algorithm.getId());
+
+ saltLength = mac.getMacLength();
+ final byte[] salt = new byte[saltLength];
+
+ random.nextBytes(salt);
+
+ SecretKeyFactory keyFact = helper.createSecretKeyFactory(algorithm.getId());
+ PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount);
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ SecretKey key = keyFact.generateSecret(pbeSpec);
+
+ mac.init(key, defParams);
+
+ return new MacCalculator()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return new AlgorithmIdentifier(algorithm, new PKCS12PBEParams(salt, iterationCount));
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return new MacOutputStream(mac);
+ }
+
+ public byte[] getMac()
+ {
+ return mac.doFinal();
+ }
+
+ public GenericKey getKey()
+ {
+ return new GenericKey(getAlgorithmIdentifier(), PKCS12ParametersGenerator.PKCS12PasswordToBytes(password));
+ }
+ };
+ }
+ catch (Exception e)
+ {
+ throw new OperatorCreationException("unable to create MAC calculator: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilderProvider.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilderProvider.java
new file mode 100644
index 000000000..413afeec8
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCS12MacCalculatorBuilderProvider.java
@@ -0,0 +1,108 @@
+package org.spongycastle.pkcs.jcajce;
+
+import java.io.OutputStream;
+import java.security.Provider;
+
+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.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.generators.PKCS12ParametersGenerator;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.JcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.jcajce.io.MacOutputStream;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.MacCalculator;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.pkcs.PKCS12MacCalculatorBuilder;
+import org.spongycastle.pkcs.PKCS12MacCalculatorBuilderProvider;
+
+public class JcePKCS12MacCalculatorBuilderProvider
+ implements PKCS12MacCalculatorBuilderProvider
+{
+ private JcaJceHelper helper = new DefaultJcaJceHelper();
+
+ public JcePKCS12MacCalculatorBuilderProvider()
+ {
+ }
+
+ public JcePKCS12MacCalculatorBuilderProvider setProvider(Provider provider)
+ {
+ this.helper = new ProviderJcaJceHelper(provider);
+
+ return this;
+ }
+
+ public JcePKCS12MacCalculatorBuilderProvider setProvider(String providerName)
+ {
+ this.helper = new NamedJcaJceHelper(providerName);
+
+ return this;
+ }
+
+ public PKCS12MacCalculatorBuilder get(final AlgorithmIdentifier algorithmIdentifier)
+ {
+ return new PKCS12MacCalculatorBuilder()
+ {
+ public MacCalculator build(final char[] password)
+ throws OperatorCreationException
+ {
+ final PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algorithmIdentifier.getParameters());
+
+ try
+ {
+ final ASN1ObjectIdentifier algorithm = algorithmIdentifier.getAlgorithm();
+
+ final Mac mac = helper.createMac(algorithm.getId());
+
+ SecretKeyFactory keyFact = helper.createSecretKeyFactory(algorithm.getId());
+ PBEParameterSpec defParams = new PBEParameterSpec(pbeParams.getIV(), pbeParams.getIterations().intValue());
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ SecretKey key = keyFact.generateSecret(pbeSpec);
+
+ mac.init(key, defParams);
+
+ return new MacCalculator()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return new AlgorithmIdentifier(algorithm, pbeParams);
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return new MacOutputStream(mac);
+ }
+
+ public byte[] getMac()
+ {
+ return mac.doFinal();
+ }
+
+ public GenericKey getKey()
+ {
+ return new GenericKey(getAlgorithmIdentifier(), PKCS12ParametersGenerator.PKCS12PasswordToBytes(password));
+ }
+ };
+ }
+ catch (Exception e)
+ {
+ throw new OperatorCreationException("unable to create MAC calculator: " + e.getMessage(), e);
+ }
+ }
+
+ public AlgorithmIdentifier getDigestAlgorithmIdentifier()
+ {
+ return new AlgorithmIdentifier(algorithmIdentifier.getAlgorithm(), DERNull.INSTANCE);
+ }
+ };
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCSPBEInputDecryptorProviderBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCSPBEInputDecryptorProviderBuilder.java
new file mode 100644
index 000000000..846417382
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCSPBEInputDecryptorProviderBuilder.java
@@ -0,0 +1,177 @@
+package org.spongycastle.pkcs.jcajce;
+
+import java.io.InputStream;
+import java.security.Provider;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+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.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.cryptopro.GOST28147Parameters;
+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.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.JcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.spongycastle.jcajce.spec.GOST28147ParameterSpec;
+import org.spongycastle.jcajce.spec.PBKDF2KeySpec;
+import org.spongycastle.operator.DefaultSecretKeySizeProvider;
+import org.spongycastle.operator.InputDecryptor;
+import org.spongycastle.operator.InputDecryptorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.SecretKeySizeProvider;
+
+public class JcePKCSPBEInputDecryptorProviderBuilder
+{
+ private JcaJceHelper helper = new DefaultJcaJceHelper();
+ private boolean wrongPKCS12Zero = false;
+ private SecretKeySizeProvider keySizeProvider = DefaultSecretKeySizeProvider.INSTANCE;
+
+ public JcePKCSPBEInputDecryptorProviderBuilder()
+ {
+ }
+
+ public JcePKCSPBEInputDecryptorProviderBuilder setProvider(Provider provider)
+ {
+ this.helper = new ProviderJcaJceHelper(provider);
+
+ return this;
+ }
+
+ public JcePKCSPBEInputDecryptorProviderBuilder setProvider(String providerName)
+ {
+ this.helper = new NamedJcaJceHelper(providerName);
+
+ return this;
+ }
+
+ public JcePKCSPBEInputDecryptorProviderBuilder setTryWrongPKCS12Zero(boolean tryWrong)
+ {
+ this.wrongPKCS12Zero = tryWrong;
+
+ return this;
+ }
+
+ /**
+ * Set the lookup provider of AlgorithmIdentifier returning key_size_in_bits used to
+ * handle PKCS5 decryption.
+ *
+ * @param keySizeProvider a provider of integer secret key sizes.
+ *
+ * @return the current builder.
+ */
+ public JcePKCSPBEInputDecryptorProviderBuilder setKeySizeProvider(SecretKeySizeProvider keySizeProvider)
+ {
+ this.keySizeProvider = keySizeProvider;
+
+ return this;
+ }
+
+ public InputDecryptorProvider build(final char[] password)
+ {
+ return new InputDecryptorProvider()
+ {
+ private Cipher cipher;
+ private SecretKey key;
+ private AlgorithmIdentifier encryptionAlg;
+
+ public InputDecryptor get(final AlgorithmIdentifier algorithmIdentifier)
+ throws OperatorCreationException
+ {
+ ASN1ObjectIdentifier algorithm = algorithmIdentifier.getAlgorithm();
+
+ try
+ {
+ if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds))
+ {
+ PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algorithmIdentifier.getParameters());
+
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+
+ SecretKeyFactory keyFact = helper.createSecretKeyFactory(algorithm.getId());
+
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+
+ key = keyFact.generateSecret(pbeSpec);
+
+ if (key instanceof BCPBEKey)
+ {
+ ((BCPBEKey)key).setTryWrongPKCS12Zero(wrongPKCS12Zero);
+ }
+
+ cipher = helper.createCipher(algorithm.getId());
+
+ cipher.init(Cipher.DECRYPT_MODE, key, defParams);
+
+ encryptionAlg = algorithmIdentifier;
+ }
+ else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2))
+ {
+ PBES2Parameters alg = PBES2Parameters.getInstance(algorithmIdentifier.getParameters());
+ PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters());
+ AlgorithmIdentifier encScheme = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme());
+
+ SecretKeyFactory keyFact = helper.createSecretKeyFactory(alg.getKeyDerivationFunc().getAlgorithm().getId());
+
+ 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 = helper.createCipher(alg.getEncryptionScheme().getAlgorithm().getId());
+
+ encryptionAlg = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme());
+
+ ASN1Encodable encParams = alg.getEncryptionScheme().getParameters();
+ if (encParams instanceof ASN1OctetString)
+ {
+ cipher.init(Cipher.DECRYPT_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(Cipher.DECRYPT_MODE, key, new GOST28147ParameterSpec(gParams.getEncryptionParamSet(), gParams.getIV()));
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ throw new OperatorCreationException("unable to create InputDecryptor: " + e.getMessage(), e);
+ }
+
+ return new InputDecryptor()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return encryptionAlg;
+ }
+
+ public InputStream getInputStream(InputStream input)
+ {
+ return new CipherInputStream(input, cipher);
+ }
+ };
+ }
+ };
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCSPBEOutputEncryptorBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCSPBEOutputEncryptorBuilder.java
new file mode 100644
index 000000000..ebf49c5e3
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/jcajce/JcePKCSPBEOutputEncryptorBuilder.java
@@ -0,0 +1,179 @@
+package org.spongycastle.pkcs.jcajce;
+
+import java.io.OutputStream;
+import java.security.Provider;
+import java.security.SecureRandom;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.bc.BCObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.EncryptionScheme;
+import org.spongycastle.asn1.pkcs.KeyDerivationFunc;
+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.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.PBEParametersGenerator;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.JcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.DefaultSecretKeySizeProvider;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.OutputEncryptor;
+import org.spongycastle.operator.SecretKeySizeProvider;
+
+public class JcePKCSPBEOutputEncryptorBuilder
+{
+ private JcaJceHelper helper = new DefaultJcaJceHelper();
+ private ASN1ObjectIdentifier algorithm;
+ private ASN1ObjectIdentifier keyEncAlgorithm;
+ private SecureRandom random;
+ private SecretKeySizeProvider keySizeProvider = DefaultSecretKeySizeProvider.INSTANCE;
+
+ public JcePKCSPBEOutputEncryptorBuilder(ASN1ObjectIdentifier algorithm)
+ {
+ if (isPKCS12(algorithm))
+ {
+ this.algorithm = algorithm;
+ this.keyEncAlgorithm = algorithm;
+ }
+ else
+ {
+ this.algorithm = PKCSObjectIdentifiers.id_PBES2;
+ this.keyEncAlgorithm = algorithm;
+ }
+ }
+
+ public JcePKCSPBEOutputEncryptorBuilder setProvider(Provider provider)
+ {
+ this.helper = new ProviderJcaJceHelper(provider);
+
+ return this;
+ }
+
+ public JcePKCSPBEOutputEncryptorBuilder setProvider(String providerName)
+ {
+ this.helper = new NamedJcaJceHelper(providerName);
+
+ return this;
+ }
+
+ /**
+ * Set the lookup provider of AlgorithmIdentifier returning key_size_in_bits used to
+ * handle PKCS5 decryption.
+ *
+ * @param keySizeProvider a provider of integer secret key sizes.
+ *
+ * @return the current builder.
+ */
+ public JcePKCSPBEOutputEncryptorBuilder setKeySizeProvider(SecretKeySizeProvider keySizeProvider)
+ {
+ this.keySizeProvider = keySizeProvider;
+
+ return this;
+ }
+
+ public OutputEncryptor build(final char[] password)
+ throws OperatorCreationException
+ {
+ final Cipher cipher;
+ SecretKey key;
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ final AlgorithmIdentifier encryptionAlg;
+ final byte[] salt = new byte[20];
+ final int iterationCount = 1024;
+
+ random.nextBytes(salt);
+
+ try
+ {
+ if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds))
+ {
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+
+ SecretKeyFactory keyFact = helper.createSecretKeyFactory(algorithm.getId());
+
+ PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount);
+
+ key = keyFact.generateSecret(pbeSpec);
+
+ cipher = helper.createCipher(algorithm.getId());
+
+ cipher.init(Cipher.ENCRYPT_MODE, key, defParams);
+
+ encryptionAlg = new AlgorithmIdentifier(algorithm, new PKCS12PBEParams(salt, iterationCount));
+ }
+ else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2))
+ {
+ SecretKeyFactory keyFact = helper.createSecretKeyFactory(PKCSObjectIdentifiers.id_PBKDF2.getId());
+
+ key = keyFact.generateSecret(new PBEKeySpec(password, salt, iterationCount, keySizeProvider.getKeySize(new AlgorithmIdentifier(keyEncAlgorithm))));
+
+ cipher = helper.createCipher(keyEncAlgorithm.getId());
+
+ cipher.init(Cipher.ENCRYPT_MODE, key, random);
+
+ PBES2Parameters algParams = new PBES2Parameters(
+ new KeyDerivationFunc(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, iterationCount)),
+ new EncryptionScheme(keyEncAlgorithm, ASN1Primitive.fromByteArray(cipher.getParameters().getEncoded())));
+
+ encryptionAlg = new AlgorithmIdentifier(algorithm, algParams);
+ }
+ else
+ {
+ throw new OperatorCreationException("unrecognised algorithm");
+ }
+
+ return new OutputEncryptor()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return encryptionAlg;
+ }
+
+ public OutputStream getOutputStream(OutputStream out)
+ {
+ return new CipherOutputStream(out, cipher);
+ }
+
+ public GenericKey getKey()
+ {
+ if (isPKCS12(encryptionAlg.getAlgorithm()))
+ {
+ return new GenericKey(encryptionAlg, PBEParametersGenerator.PKCS5PasswordToBytes(password));
+ }
+ else
+ {
+ return new GenericKey(encryptionAlg, PBEParametersGenerator.PKCS12PasswordToBytes(password));
+ }
+ }
+ };
+ }
+ catch (Exception e)
+ {
+ throw new OperatorCreationException("unable to create OutputEncryptor: " + e.getMessage(), e);
+ }
+ }
+
+ private boolean isPKCS12(ASN1ObjectIdentifier algorithm)
+ {
+ return algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds)
+ || algorithm.on(BCObjectIdentifiers.bc_pbe_sha1_pkcs12)
+ || algorithm.on(BCObjectIdentifiers.bc_pbe_sha256_pkcs12);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/GenTimeAccuracy.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/GenTimeAccuracy.java
new file mode 100644
index 000000000..0932f3eec
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/GenTimeAccuracy.java
@@ -0,0 +1,60 @@
+package org.spongycastle.tsp;
+
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.tsp.Accuracy;
+
+public class GenTimeAccuracy
+{
+ private Accuracy accuracy;
+
+ public GenTimeAccuracy(Accuracy accuracy)
+ {
+ this.accuracy = accuracy;
+ }
+
+ public int getSeconds()
+ {
+ return getTimeComponent(accuracy.getSeconds());
+ }
+
+ public int getMillis()
+ {
+ return getTimeComponent(accuracy.getMillis());
+ }
+
+ public int getMicros()
+ {
+ return getTimeComponent(accuracy.getMicros());
+ }
+
+ private int getTimeComponent(
+ DERInteger time)
+ {
+ if (time != null)
+ {
+ return time.getValue().intValue();
+ }
+
+ return 0;
+ }
+
+ public String toString()
+ { // digits
+ return getSeconds() + "." + format(getMillis()) + format(getMicros());
+ }
+
+ private String format(int v)
+ {
+ if (v < 10)
+ {
+ return "00" + v;
+ }
+
+ if (v < 100)
+ {
+ return "0" + v;
+ }
+
+ return Integer.toString(v);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPAlgorithms.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPAlgorithms.java
new file mode 100644
index 000000000..fa5c6f064
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPAlgorithms.java
@@ -0,0 +1,35 @@
+package org.spongycastle.tsp;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+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.teletrust.TeleTrusTObjectIdentifiers;
+
+/**
+ * Recognised hash algorithms for the time stamp protocol.
+ */
+public interface TSPAlgorithms
+{
+ public static final ASN1ObjectIdentifier MD5 = PKCSObjectIdentifiers.md5;
+
+ public static final ASN1ObjectIdentifier SHA1 = OIWObjectIdentifiers.idSHA1;
+
+ public static final ASN1ObjectIdentifier SHA224 = NISTObjectIdentifiers.id_sha224;
+ public static final ASN1ObjectIdentifier SHA256 = NISTObjectIdentifiers.id_sha256;
+ public static final ASN1ObjectIdentifier SHA384 = NISTObjectIdentifiers.id_sha384;
+ public static final ASN1ObjectIdentifier SHA512 = NISTObjectIdentifiers.id_sha512;
+
+ public static final ASN1ObjectIdentifier RIPEMD128 = TeleTrusTObjectIdentifiers.ripemd128;
+ public static final ASN1ObjectIdentifier RIPEMD160 = TeleTrusTObjectIdentifiers.ripemd160;
+ public static final ASN1ObjectIdentifier RIPEMD256 = TeleTrusTObjectIdentifiers.ripemd256;
+
+ public static final ASN1ObjectIdentifier GOST3411 = CryptoProObjectIdentifiers.gostR3411;
+
+ public static final Set ALLOWED = new HashSet(Arrays.asList(new ASN1ObjectIdentifier[] { GOST3411, MD5, SHA1, SHA224, SHA256, SHA384, SHA512, RIPEMD128, RIPEMD160, RIPEMD256 }));
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPException.java
new file mode 100644
index 000000000..6125ceff3
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPException.java
@@ -0,0 +1,28 @@
+package org.spongycastle.tsp;
+
+public class TSPException
+ extends Exception
+{
+ Throwable underlyingException;
+
+ public TSPException(String message)
+ {
+ super(message);
+ }
+
+ public TSPException(String message, Throwable e)
+ {
+ super(message);
+ underlyingException = e;
+ }
+
+ public Exception getUnderlyingException()
+ {
+ return (Exception)underlyingException;
+ }
+
+ public Throwable getCause()
+ {
+ return underlyingException;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPIOException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPIOException.java
new file mode 100644
index 000000000..418ff1b2c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPIOException.java
@@ -0,0 +1,30 @@
+package org.spongycastle.tsp;
+
+import java.io.IOException;
+
+public class TSPIOException
+ extends IOException
+{
+ Throwable underlyingException;
+
+ public TSPIOException(String message)
+ {
+ super(message);
+ }
+
+ public TSPIOException(String message, Throwable e)
+ {
+ super(message);
+ underlyingException = e;
+ }
+
+ public Exception getUnderlyingException()
+ {
+ return (Exception)underlyingException;
+ }
+
+ public Throwable getCause()
+ {
+ return underlyingException;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPUtil.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPUtil.java
new file mode 100644
index 000000000..23a0454c6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPUtil.java
@@ -0,0 +1,209 @@
+package org.spongycastle.tsp;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.cms.Attribute;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.ContentInfo;
+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.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.ExtendedKeyUsage;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.ExtensionsGenerator;
+import org.spongycastle.asn1.x509.KeyPurposeId;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cms.SignerInformation;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Integers;
+
+public class TSPUtil
+{
+ private static List EMPTY_LIST = Collections.unmodifiableList(new ArrayList());
+
+ private static final Map digestLengths = new HashMap();
+ private static final Map digestNames = new HashMap();
+
+ static
+ {
+ digestLengths.put(PKCSObjectIdentifiers.md5.getId(), Integers.valueOf(16));
+ digestLengths.put(OIWObjectIdentifiers.idSHA1.getId(), Integers.valueOf(20));
+ digestLengths.put(NISTObjectIdentifiers.id_sha224.getId(), Integers.valueOf(28));
+ digestLengths.put(NISTObjectIdentifiers.id_sha256.getId(), Integers.valueOf(32));
+ digestLengths.put(NISTObjectIdentifiers.id_sha384.getId(), Integers.valueOf(48));
+ digestLengths.put(NISTObjectIdentifiers.id_sha512.getId(), Integers.valueOf(64));
+ digestLengths.put(TeleTrusTObjectIdentifiers.ripemd128.getId(), Integers.valueOf(16));
+ digestLengths.put(TeleTrusTObjectIdentifiers.ripemd160.getId(), Integers.valueOf(20));
+ digestLengths.put(TeleTrusTObjectIdentifiers.ripemd256.getId(), Integers.valueOf(32));
+ digestLengths.put(CryptoProObjectIdentifiers.gostR3411.getId(), Integers.valueOf(32));
+
+ digestNames.put(PKCSObjectIdentifiers.md5.getId(), "MD5");
+ digestNames.put(OIWObjectIdentifiers.idSHA1.getId(), "SHA1");
+ digestNames.put(NISTObjectIdentifiers.id_sha224.getId(), "SHA224");
+ digestNames.put(NISTObjectIdentifiers.id_sha256.getId(), "SHA256");
+ digestNames.put(NISTObjectIdentifiers.id_sha384.getId(), "SHA384");
+ digestNames.put(NISTObjectIdentifiers.id_sha512.getId(), "SHA512");
+ digestNames.put(PKCSObjectIdentifiers.sha1WithRSAEncryption.getId(), "SHA1");
+ digestNames.put(PKCSObjectIdentifiers.sha224WithRSAEncryption.getId(), "SHA224");
+ digestNames.put(PKCSObjectIdentifiers.sha256WithRSAEncryption.getId(), "SHA256");
+ digestNames.put(PKCSObjectIdentifiers.sha384WithRSAEncryption.getId(), "SHA384");
+ digestNames.put(PKCSObjectIdentifiers.sha512WithRSAEncryption.getId(), "SHA512");
+ digestNames.put(TeleTrusTObjectIdentifiers.ripemd128.getId(), "RIPEMD128");
+ digestNames.put(TeleTrusTObjectIdentifiers.ripemd160.getId(), "RIPEMD160");
+ digestNames.put(TeleTrusTObjectIdentifiers.ripemd256.getId(), "RIPEMD256");
+ digestNames.put(CryptoProObjectIdentifiers.gostR3411.getId(), "GOST3411");
+ }
+
+ /**
+ * Fetches the signature time-stamp attributes from a SignerInformation object.
+ * Checks that the MessageImprint for each time-stamp matches the signature field.
+ * (see RFC 3161 Appendix A).
+ *
+ * @param signerInfo a SignerInformation to search for time-stamps
+ * @param digCalcProvider provider for digest calculators
+ * @return a collection of TimeStampToken objects
+ * @throws TSPValidationException
+ */
+ public static Collection getSignatureTimestamps(SignerInformation signerInfo, DigestCalculatorProvider digCalcProvider)
+ throws TSPValidationException
+ {
+ List timestamps = new ArrayList();
+
+ AttributeTable unsignedAttrs = signerInfo.getUnsignedAttributes();
+ if (unsignedAttrs != null)
+ {
+ ASN1EncodableVector allTSAttrs = unsignedAttrs.getAll(
+ PKCSObjectIdentifiers.id_aa_signatureTimeStampToken);
+ for (int i = 0; i < allTSAttrs.size(); ++i)
+ {
+ Attribute tsAttr = (Attribute)allTSAttrs.get(i);
+ ASN1Set tsAttrValues = tsAttr.getAttrValues();
+ for (int j = 0; j < tsAttrValues.size(); ++j)
+ {
+ try
+ {
+ ContentInfo contentInfo = ContentInfo.getInstance(tsAttrValues.getObjectAt(j));
+ TimeStampToken timeStampToken = new TimeStampToken(contentInfo);
+ TimeStampTokenInfo tstInfo = timeStampToken.getTimeStampInfo();
+
+ DigestCalculator digCalc = digCalcProvider.get(tstInfo.getHashAlgorithm());
+
+ OutputStream dOut = digCalc.getOutputStream();
+
+ dOut.write(signerInfo.getSignature());
+ dOut.close();
+
+ byte[] expectedDigest = digCalc.getDigest();
+
+ if (!Arrays.constantTimeAreEqual(expectedDigest, tstInfo.getMessageImprintDigest()))
+ {
+ throw new TSPValidationException("Incorrect digest in message imprint");
+ }
+
+ timestamps.add(timeStampToken);
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new TSPValidationException("Unknown hash algorithm specified in timestamp");
+ }
+ catch (Exception e)
+ {
+ throw new TSPValidationException("Timestamp could not be parsed");
+ }
+ }
+ }
+ }
+
+ return timestamps;
+ }
+
+ /**
+ * Validate the passed in certificate as being of the correct type to be used
+ * for time stamping. To be valid it must have an ExtendedKeyUsage extension
+ * which has a key purpose identifier of id-kp-timeStamping.
+ *
+ * @param cert the certificate of interest.
+ * @throws TSPValidationException if the certificate fails on one of the check points.
+ */
+ public static void validateCertificate(
+ X509CertificateHolder cert)
+ throws TSPValidationException
+ {
+ if (cert.toASN1Structure().getVersionNumber() != 3)
+ {
+ throw new IllegalArgumentException("Certificate must have an ExtendedKeyUsage extension.");
+ }
+
+ Extension ext = cert.getExtension(Extension.extendedKeyUsage);
+ if (ext == null)
+ {
+ throw new TSPValidationException("Certificate must have an ExtendedKeyUsage extension.");
+ }
+
+ if (!ext.isCritical())
+ {
+ throw new TSPValidationException("Certificate must have an ExtendedKeyUsage extension marked as critical.");
+ }
+
+ ExtendedKeyUsage extKey = ExtendedKeyUsage.getInstance(ext.getParsedValue());
+
+ if (!extKey.hasKeyPurposeId(KeyPurposeId.id_kp_timeStamping) || extKey.size() != 1)
+ {
+ throw new TSPValidationException("ExtendedKeyUsage not solely time stamping.");
+ }
+ }
+
+ static int getDigestLength(
+ String digestAlgOID)
+ throws TSPException
+ {
+ Integer length = (Integer)digestLengths.get(digestAlgOID);
+
+ if (length != null)
+ {
+ return length.intValue();
+ }
+
+ throw new TSPException("digest algorithm cannot be found.");
+ }
+
+ static List getExtensionOIDs(Extensions extensions)
+ {
+ if (extensions == null)
+ {
+ return EMPTY_LIST;
+ }
+
+ return Collections.unmodifiableList(java.util.Arrays.asList(extensions.getExtensionOIDs()));
+ }
+
+ static void addExtension(ExtensionsGenerator extGenerator, ASN1ObjectIdentifier oid, boolean isCritical, ASN1Encodable value)
+ throws TSPIOException
+ {
+ try
+ {
+ extGenerator.addExtension(oid, isCritical, value);
+ }
+ catch (IOException e)
+ {
+ throw new TSPIOException("cannot encode extension: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPValidationException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPValidationException.java
new file mode 100644
index 000000000..f89ac6c15
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TSPValidationException.java
@@ -0,0 +1,34 @@
+package org.spongycastle.tsp;
+
+/**
+ * Exception thrown if a TSP request or response fails to validate.
+ * <p>
+ * If a failure code is associated with the exception it can be retrieved using
+ * the getFailureCode() method.
+ */
+public class TSPValidationException
+ extends TSPException
+{
+ private int failureCode = -1;
+
+ public TSPValidationException(String message)
+ {
+ super(message);
+ }
+
+ public TSPValidationException(String message, int failureCode)
+ {
+ super(message);
+ this.failureCode = failureCode;
+ }
+
+ /**
+ * Return the failure code associated with this exception - if one is set.
+ *
+ * @return the failure code if set, -1 otherwise.
+ */
+ public int getFailureCode()
+ {
+ return failureCode;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampRequest.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampRequest.java
new file mode 100644
index 000000000..55349960e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampRequest.java
@@ -0,0 +1,268 @@
+package org.spongycastle.tsp;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.cmp.PKIFailureInfo;
+import org.spongycastle.asn1.tsp.TimeStampReq;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+
+/**
+ * Base class for an RFC 3161 Time Stamp Request.
+ */
+public class TimeStampRequest
+{
+ private static Set EMPTY_SET = Collections.unmodifiableSet(new HashSet());
+
+ private TimeStampReq req;
+ private Extensions extensions;
+
+ public TimeStampRequest(TimeStampReq req)
+ {
+ this.req = req;
+ this.extensions = req.getExtensions();
+ }
+
+ /**
+ * Create a TimeStampRequest from the past in byte array.
+ *
+ * @param req byte array containing the request.
+ * @throws IOException if the request is malformed.
+ */
+ public TimeStampRequest(byte[] req)
+ throws IOException
+ {
+ this(new ByteArrayInputStream(req));
+ }
+
+ /**
+ * Create a TimeStampRequest from the past in input stream.
+ *
+ * @param in input stream containing the request.
+ * @throws IOException if the request is malformed.
+ */
+ public TimeStampRequest(InputStream in)
+ throws IOException
+ {
+ this(loadRequest(in));
+ }
+
+ private static TimeStampReq loadRequest(InputStream in)
+ throws IOException
+ {
+ try
+ {
+ return TimeStampReq.getInstance(new ASN1InputStream(in).readObject());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("malformed request: " + e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new IOException("malformed request: " + e);
+ }
+ }
+
+ public int getVersion()
+ {
+ return req.getVersion().getValue().intValue();
+ }
+
+ public ASN1ObjectIdentifier getMessageImprintAlgOID()
+ {
+ return req.getMessageImprint().getHashAlgorithm().getAlgorithm();
+ }
+
+ public byte[] getMessageImprintDigest()
+ {
+ return req.getMessageImprint().getHashedMessage();
+ }
+
+ public ASN1ObjectIdentifier getReqPolicy()
+ {
+ if (req.getReqPolicy() != null)
+ {
+ return req.getReqPolicy();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public BigInteger getNonce()
+ {
+ if (req.getNonce() != null)
+ {
+ return req.getNonce().getValue();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public boolean getCertReq()
+ {
+ if (req.getCertReq() != null)
+ {
+ return req.getCertReq().isTrue();
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Validate the timestamp request, checking the digest to see if it is of an
+ * accepted type and whether it is of the correct length for the algorithm specified.
+ *
+ * @param algorithms a set of OIDs giving accepted algorithms.
+ * @param policies if non-null a set of policies OIDs we are willing to sign under.
+ * @param extensions if non-null a set of extensions OIDs we are willing to accept.
+ * @throws TSPException if the request is invalid, or processing fails.
+ */
+ public void validate(
+ Set algorithms,
+ Set policies,
+ Set extensions)
+ throws TSPException
+ {
+ algorithms = convert(algorithms);
+ policies = convert(policies);
+ extensions = convert(extensions);
+
+ if (!algorithms.contains(this.getMessageImprintAlgOID()))
+ {
+ throw new TSPValidationException("request contains unknown algorithm.", PKIFailureInfo.badAlg);
+ }
+
+ if (policies != null && this.getReqPolicy() != null && !policies.contains(this.getReqPolicy()))
+ {
+ throw new TSPValidationException("request contains unknown policy.", PKIFailureInfo.unacceptedPolicy);
+ }
+
+ if (this.getExtensions() != null && extensions != null)
+ {
+ Enumeration en = this.getExtensions().oids();
+ while(en.hasMoreElements())
+ {
+ String oid = ((DERObjectIdentifier)en.nextElement()).getId();
+ if (!extensions.contains(oid))
+ {
+ throw new TSPValidationException("request contains unknown extension.", PKIFailureInfo.unacceptedExtension);
+ }
+ }
+ }
+
+ int digestLength = TSPUtil.getDigestLength(this.getMessageImprintAlgOID().getId());
+
+ if (digestLength != this.getMessageImprintDigest().length)
+ {
+ throw new TSPValidationException("imprint digest the wrong length.", PKIFailureInfo.badDataFormat);
+ }
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ * @return the default ASN,1 byte encoding for the object.
+ */
+ public byte[] getEncoded() throws IOException
+ {
+ return req.getEncoded();
+ }
+
+ Extensions getExtensions()
+ {
+ return extensions;
+ }
+
+ public boolean hasExtensions()
+ {
+ return extensions != null;
+ }
+
+ public Extension getExtension(ASN1ObjectIdentifier oid)
+ {
+ if (extensions != null)
+ {
+ return extensions.getExtension(oid);
+ }
+
+ return null;
+ }
+
+ public List getExtensionOIDs()
+ {
+ return TSPUtil.getExtensionOIDs(extensions);
+ }
+
+ /**
+ * Returns a set of ASN1ObjectIdentifiers giving the non-critical extensions.
+ * @return a set of ASN1ObjectIdentifiers.
+ */
+ public Set getNonCriticalExtensionOIDs()
+ {
+ if (extensions == null)
+ {
+ return EMPTY_SET;
+ }
+
+ return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getNonCriticalExtensionOIDs())));
+ }
+
+ /**
+ * Returns a set of ASN1ObjectIdentifiers giving the critical extensions.
+ * @return a set of ASN1ObjectIdentifiers.
+ */
+ public Set getCriticalExtensionOIDs()
+ {
+ if (extensions == null)
+ {
+ return EMPTY_SET;
+ }
+
+ return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getCriticalExtensionOIDs())));
+ }
+
+ private Set convert(Set orig)
+ {
+ if (orig == null)
+ {
+ return orig;
+ }
+
+ Set con = new HashSet(orig.size());
+
+ for (Iterator it = orig.iterator(); it.hasNext();)
+ {
+ Object o = it.next();
+
+ if (o instanceof String)
+ {
+ con.add(new ASN1ObjectIdentifier((String)o));
+ }
+ else
+ {
+ con.add(o);
+ }
+ }
+
+ return con;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampRequestGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampRequestGenerator.java
new file mode 100644
index 000000000..382b366a8
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampRequestGenerator.java
@@ -0,0 +1,163 @@
+package org.spongycastle.tsp;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.ASN1Boolean;
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.tsp.MessageImprint;
+import org.spongycastle.asn1.tsp.TimeStampReq;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.ExtensionsGenerator;
+
+/**
+ * Generator for RFC 3161 Time Stamp Request objects.
+ */
+public class TimeStampRequestGenerator
+{
+ private ASN1ObjectIdentifier reqPolicy;
+
+ private ASN1Boolean certReq;
+ private ExtensionsGenerator extGenerator = new ExtensionsGenerator();
+
+ public TimeStampRequestGenerator()
+ {
+ }
+
+ /**
+ * @deprecated use method taking ASN1ObjectIdentifier
+ * @param reqPolicy
+ */
+ public void setReqPolicy(
+ String reqPolicy)
+ {
+ this.reqPolicy= new ASN1ObjectIdentifier(reqPolicy);
+ }
+
+ public void setReqPolicy(
+ ASN1ObjectIdentifier reqPolicy)
+ {
+ this.reqPolicy= reqPolicy;
+ }
+
+ public void setCertReq(
+ boolean certReq)
+ {
+ this.certReq = ASN1Boolean.getInstance(certReq);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * @throws IOException
+ * @deprecated use method taking ASN1ObjectIdentifier
+ */
+ 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
+ * The value parameter becomes the contents of the octet string associated
+ * with the extension.
+ * @deprecated use method taking ASN1ObjectIdentifier
+ */
+ public void addExtension(
+ String OID,
+ boolean critical,
+ byte[] value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(OID), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * @throws TSPIOException
+ */
+ public void addExtension(
+ ASN1ObjectIdentifier oid,
+ boolean isCritical,
+ ASN1Encodable value)
+ throws TSPIOException
+ {
+ TSPUtil.addExtension(extGenerator, oid, isCritical, 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(
+ ASN1ObjectIdentifier oid,
+ boolean isCritical,
+ byte[] value)
+ {
+ extGenerator.addExtension(oid, isCritical, value);
+ }
+
+ /**
+ * @deprecated use method taking ANS1ObjectIdentifier
+ */
+ public TimeStampRequest generate(
+ String digestAlgorithm,
+ byte[] digest)
+ {
+ return this.generate(digestAlgorithm, digest, null);
+ }
+
+ /**
+ * @deprecated use method taking ANS1ObjectIdentifier
+ */
+ public TimeStampRequest generate(
+ String digestAlgorithmOID,
+ byte[] digest,
+ BigInteger nonce)
+ {
+ if (digestAlgorithmOID == null)
+ {
+ throw new IllegalArgumentException("No digest algorithm specified");
+ }
+
+ ASN1ObjectIdentifier digestAlgOID = new ASN1ObjectIdentifier(digestAlgorithmOID);
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOID, DERNull.INSTANCE);
+ MessageImprint messageImprint = new MessageImprint(algID, digest);
+
+ Extensions ext = null;
+
+ if (!extGenerator.isEmpty())
+ {
+ ext = extGenerator.generate();
+ }
+
+ if (nonce != null)
+ {
+ return new TimeStampRequest(new TimeStampReq(messageImprint,
+ reqPolicy, new ASN1Integer(nonce), certReq, ext));
+ }
+ else
+ {
+ return new TimeStampRequest(new TimeStampReq(messageImprint,
+ reqPolicy, null, certReq, ext));
+ }
+ }
+
+ public TimeStampRequest generate(ASN1ObjectIdentifier digestAlgorithm, byte[] digest)
+ {
+ return generate(digestAlgorithm.getId(), digest);
+ }
+
+ public TimeStampRequest generate(ASN1ObjectIdentifier digestAlgorithm, byte[] digest, BigInteger nonce)
+ {
+ return generate(digestAlgorithm.getId(), digest, nonce);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampResponse.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampResponse.java
new file mode 100644
index 000000000..cc327f45a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampResponse.java
@@ -0,0 +1,189 @@
+package org.spongycastle.tsp;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.cmp.PKIFailureInfo;
+import org.spongycastle.asn1.cmp.PKIFreeText;
+import org.spongycastle.asn1.cmp.PKIStatus;
+import org.spongycastle.asn1.cms.Attribute;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.tsp.TimeStampResp;
+import org.spongycastle.util.Arrays;
+
+/**
+ * Base class for an RFC 3161 Time Stamp Response object.
+ */
+public class TimeStampResponse
+{
+ TimeStampResp resp;
+ TimeStampToken timeStampToken;
+
+ public TimeStampResponse(TimeStampResp resp)
+ throws TSPException, IOException
+ {
+ this.resp = resp;
+
+ if (resp.getTimeStampToken() != null)
+ {
+ timeStampToken = new TimeStampToken(resp.getTimeStampToken());
+ }
+ }
+
+ /**
+ * Create a TimeStampResponse from a byte array containing an ASN.1 encoding.
+ *
+ * @param resp the byte array containing the encoded response.
+ * @throws TSPException if the response is malformed.
+ * @throws IOException if the byte array doesn't represent an ASN.1 encoding.
+ */
+ public TimeStampResponse(byte[] resp)
+ throws TSPException, IOException
+ {
+ this(new ByteArrayInputStream(resp));
+ }
+
+ /**
+ * Create a TimeStampResponse from an input stream containing an ASN.1 encoding.
+ *
+ * @param in the input stream containing the encoded response.
+ * @throws TSPException if the response is malformed.
+ * @throws IOException if the stream doesn't represent an ASN.1 encoding.
+ */
+ public TimeStampResponse(InputStream in)
+ throws TSPException, IOException
+ {
+ this(readTimeStampResp(in));
+ }
+
+ private static TimeStampResp readTimeStampResp(
+ InputStream in)
+ throws IOException, TSPException
+ {
+ try
+ {
+ return TimeStampResp.getInstance(new ASN1InputStream(in).readObject());
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new TSPException("malformed timestamp response: " + e, e);
+ }
+ catch (ClassCastException e)
+ {
+ throw new TSPException("malformed timestamp response: " + e, e);
+ }
+ }
+
+ public int getStatus()
+ {
+ return resp.getStatus().getStatus().intValue();
+ }
+
+ public String getStatusString()
+ {
+ if (resp.getStatus().getStatusString() != null)
+ {
+ StringBuffer statusStringBuf = new StringBuffer();
+ PKIFreeText text = resp.getStatus().getStatusString();
+ for (int i = 0; i != text.size(); i++)
+ {
+ statusStringBuf.append(text.getStringAt(i).getString());
+ }
+ return statusStringBuf.toString();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public PKIFailureInfo getFailInfo()
+ {
+ if (resp.getStatus().getFailInfo() != null)
+ {
+ return new PKIFailureInfo(resp.getStatus().getFailInfo());
+ }
+
+ return null;
+ }
+
+ public TimeStampToken getTimeStampToken()
+ {
+ return timeStampToken;
+ }
+
+ /**
+ * Check this response against to see if it a well formed response for
+ * the passed in request. Validation will include checking the time stamp
+ * token if the response status is GRANTED or GRANTED_WITH_MODS.
+ *
+ * @param request the request to be checked against
+ * @throws TSPException if the request can not match this response.
+ */
+ public void validate(
+ TimeStampRequest request)
+ throws TSPException
+ {
+ TimeStampToken tok = this.getTimeStampToken();
+
+ if (tok != null)
+ {
+ TimeStampTokenInfo tstInfo = tok.getTimeStampInfo();
+
+ if (request.getNonce() != null && !request.getNonce().equals(tstInfo.getNonce()))
+ {
+ throw new TSPValidationException("response contains wrong nonce value.");
+ }
+
+ if (this.getStatus() != PKIStatus.GRANTED && this.getStatus() != PKIStatus.GRANTED_WITH_MODS)
+ {
+ throw new TSPValidationException("time stamp token found in failed request.");
+ }
+
+ if (!Arrays.constantTimeAreEqual(request.getMessageImprintDigest(), tstInfo.getMessageImprintDigest()))
+ {
+ throw new TSPValidationException("response for different message imprint digest.");
+ }
+
+ if (!tstInfo.getMessageImprintAlgOID().equals(request.getMessageImprintAlgOID()))
+ {
+ throw new TSPValidationException("response for different message imprint algorithm.");
+ }
+
+ Attribute scV1 = tok.getSignedAttributes().get(PKCSObjectIdentifiers.id_aa_signingCertificate);
+ Attribute scV2 = tok.getSignedAttributes().get(PKCSObjectIdentifiers.id_aa_signingCertificateV2);
+
+ if (scV1 == null && scV2 == null)
+ {
+ throw new TSPValidationException("no signing certificate attribute present.");
+ }
+
+ if (scV1 != null && scV2 != null)
+ {
+ /*
+ * RFC 5035 5.4. If both attributes exist in a single message,
+ * they are independently evaluated.
+ */
+ }
+
+ if (request.getReqPolicy() != null && !request.getReqPolicy().equals(tstInfo.getPolicy()))
+ {
+ throw new TSPValidationException("TSA policy wrong for request.");
+ }
+ }
+ else if (this.getStatus() == PKIStatus.GRANTED || this.getStatus() == PKIStatus.GRANTED_WITH_MODS)
+ {
+ throw new TSPValidationException("no time stamp token found and one expected.");
+ }
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] getEncoded() throws IOException
+ {
+ return resp.getEncoded();
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampResponseGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampResponseGenerator.java
new file mode 100644
index 000000000..efe08a50a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampResponseGenerator.java
@@ -0,0 +1,353 @@
+package org.spongycastle.tsp;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERUTF8String;
+import org.spongycastle.asn1.cmp.PKIFailureInfo;
+import org.spongycastle.asn1.cmp.PKIFreeText;
+import org.spongycastle.asn1.cmp.PKIStatus;
+import org.spongycastle.asn1.cmp.PKIStatusInfo;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.tsp.TimeStampResp;
+
+/**
+ * Generator for RFC 3161 Time Stamp Responses.
+ * <p>
+ * New generate methods have been introduced to give people more control over what ends up in the message.
+ * Unfortunately it turns out that in some cases fields like statusString must be left out otherwise a an
+ * otherwise valid timestamp will be rejected.
+ * </p>
+ * If you're after the most control with generating a response use:
+ * <pre>
+ * TimeStampResponse tsResp;
+ *
+ * try
+ * {
+ * tsResp = tsRespGen.generateGrantedResponse(request, new BigInteger("23"), new Date());
+ * }
+ * catch (Exception e)
+ * {
+ * tsResp = tsRespGen.generateRejectedResponse(e);
+ * }
+ * </pre>
+ * The generate method does this, but provides a status string of "Operation Okay".
+ * <p>
+ * It should be pointed out that generateRejectedResponse() may also, on very rare occasions throw a TSPException.
+ * In the event that happens, there's a serious internal problem with your responder.
+ * </p>
+ */
+public class TimeStampResponseGenerator
+{
+ int status;
+
+ ASN1EncodableVector statusStrings;
+
+ int failInfo;
+ private TimeStampTokenGenerator tokenGenerator;
+ private Set acceptedAlgorithms;
+ private Set acceptedPolicies;
+ private Set acceptedExtensions;
+
+ /**
+ *
+ * @param tokenGenerator
+ * @param acceptedAlgorithms a set of OIDs giving accepted algorithms.
+ */
+ public TimeStampResponseGenerator(
+ TimeStampTokenGenerator tokenGenerator,
+ Set acceptedAlgorithms)
+ {
+ this(tokenGenerator, acceptedAlgorithms, null, null);
+ }
+
+ /**
+ *
+ * @param tokenGenerator
+ * @param acceptedAlgorithms a set of OIDs giving accepted algorithms.
+ * @param acceptedPolicies if non-null a set of policies OIDs we are willing to sign under.
+ */
+ public TimeStampResponseGenerator(
+ TimeStampTokenGenerator tokenGenerator,
+ Set acceptedAlgorithms,
+ Set acceptedPolicies)
+ {
+ this(tokenGenerator, acceptedAlgorithms, acceptedPolicies, null);
+ }
+
+ /**
+ *
+ * @param tokenGenerator
+ * @param acceptedAlgorithms a set of OIDs giving accepted algorithms.
+ * @param acceptedPolicies if non-null a set of policies OIDs we are willing to sign under.
+ * @param acceptedExtensions if non-null a set of extensions OIDs we are willing to accept.
+ */
+ public TimeStampResponseGenerator(
+ TimeStampTokenGenerator tokenGenerator,
+ Set acceptedAlgorithms,
+ Set acceptedPolicies,
+ Set acceptedExtensions)
+ {
+ this.tokenGenerator = tokenGenerator;
+ this.acceptedAlgorithms = convert(acceptedAlgorithms);
+ this.acceptedPolicies = convert(acceptedPolicies);
+ this.acceptedExtensions = convert(acceptedExtensions);
+
+ statusStrings = new ASN1EncodableVector();
+ }
+
+ private void addStatusString(String statusString)
+ {
+ statusStrings.add(new DERUTF8String(statusString));
+ }
+
+ private void setFailInfoField(int field)
+ {
+ failInfo = failInfo | field;
+ }
+
+ private PKIStatusInfo getPKIStatusInfo()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new DERInteger(status));
+
+ if (statusStrings.size() > 0)
+ {
+ v.add(PKIFreeText.getInstance(new DERSequence(statusStrings)));
+ }
+
+ if (failInfo != 0)
+ {
+ DERBitString failInfoBitString = new FailInfo(failInfo);
+ v.add(failInfoBitString);
+ }
+
+ return PKIStatusInfo.getInstance(new DERSequence(v));
+ }
+
+ /**
+ * Return an appropriate TimeStampResponse.
+ * <p>
+ * If genTime is null a timeNotAvailable error response will be returned. Calling generate() is the
+ * equivalent of:
+ * <pre>
+ * TimeStampResponse tsResp;
+ *
+ * try
+ * {
+ * tsResp = tsRespGen.generateGrantedResponse(request, serialNumber, genTime, "Operation Okay");
+ * }
+ * catch (Exception e)
+ * {
+ * tsResp = tsRespGen.generateRejectedResponse(e);
+ * }
+ * </pre>
+ * @param request the request this response is for.
+ * @param serialNumber serial number for the response token.
+ * @param genTime generation time for the response token.
+ * @return a TimeStampResponse.
+ * @throws TSPException
+ */
+ public TimeStampResponse generate(
+ TimeStampRequest request,
+ BigInteger serialNumber,
+ Date genTime)
+ throws TSPException
+ {
+ try
+ {
+ return this.generateGrantedResponse(request, serialNumber, genTime, "Operation Okay");
+ }
+ catch (Exception e)
+ {
+ return this.generateRejectedResponse(e);
+ }
+ }
+
+ /**
+ * Return a granted response, if the passed in request passes validation.
+ * <p>
+ * If genTime is null a timeNotAvailable or a validation exception occurs a TSPValidationException will
+ * be thrown. The parent TSPException will only occur on some sort of system failure.
+ * </p>
+ * @param request the request this response is for.
+ * @param serialNumber serial number for the response token.
+ * @param genTime generation time for the response token.
+ * @return the TimeStampResponse with a status of PKIStatus.GRANTED
+ * @throws TSPException on validation exception or internal error.
+ */
+ public TimeStampResponse generateGrantedResponse(
+ TimeStampRequest request,
+ BigInteger serialNumber,
+ Date genTime)
+ throws TSPException
+ {
+ return generateGrantedResponse(request, serialNumber, genTime, null);
+ }
+
+ /**
+ * Return a granted response, if the passed in request passes validation with the passed in status string.
+ * <p>
+ * If genTime is null a timeNotAvailable or a validation exception occurs a TSPValidationException will
+ * be thrown. The parent TSPException will only occur on some sort of system failure.
+ * </p>
+ * @param request the request this response is for.
+ * @param serialNumber serial number for the response token.
+ * @param genTime generation time for the response token.
+ * @return the TimeStampResponse with a status of PKIStatus.GRANTED
+ * @throws TSPException on validation exception or internal error.
+ */
+ public TimeStampResponse generateGrantedResponse(
+ TimeStampRequest request,
+ BigInteger serialNumber,
+ Date genTime,
+ String statusString)
+ throws TSPException
+ {
+ if (genTime == null)
+ {
+ throw new TSPValidationException("The time source is not available.", PKIFailureInfo.timeNotAvailable);
+ }
+
+ request.validate(acceptedAlgorithms, acceptedPolicies, acceptedExtensions);
+
+ status = PKIStatus.GRANTED;
+ statusStrings = new ASN1EncodableVector();
+
+ if (statusString != null)
+ {
+ this.addStatusString(statusString);
+ }
+
+ PKIStatusInfo pkiStatusInfo = getPKIStatusInfo();
+
+ ContentInfo tstTokenContentInfo;
+ try
+ {
+ tstTokenContentInfo = tokenGenerator.generate(request, serialNumber, genTime).toCMSSignedData().toASN1Structure();
+ }
+ catch (TSPException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new TSPException(
+ "Timestamp token received cannot be converted to ContentInfo", e);
+ }
+
+ TimeStampResp resp = new TimeStampResp(pkiStatusInfo, tstTokenContentInfo);
+
+ try
+ {
+ return new TimeStampResponse(resp);
+ }
+ catch (IOException e)
+ {
+ throw new TSPException("created badly formatted response!");
+ }
+ }
+
+ /**
+ * Generate a generic rejection response based on a TSPValidationException or
+ * an Exception. Exceptions which are not an instance of TSPValidationException
+ * will be treated as systemFailure. The return value of exception.getMessage() will
+ * be used as the status string for the response.
+ *
+ * @param exception the exception thrown on validating the request.
+ * @return a TimeStampResponse.
+ * @throws TSPException if a failure response cannot be generated.
+ */
+ public TimeStampResponse generateRejectedResponse(Exception exception)
+ throws TSPException
+ {
+ if (exception instanceof TSPValidationException)
+ {
+ return generateFailResponse(PKIStatus.REJECTION, ((TSPValidationException)exception).getFailureCode(), exception.getMessage());
+ }
+ else
+ {
+ return generateFailResponse(PKIStatus.REJECTION, PKIFailureInfo.systemFailure, exception.getMessage());
+ }
+ }
+
+ /**
+ * Generate a non-granted TimeStampResponse with chosen status and FailInfoField.
+ *
+ * @param status the PKIStatus to set.
+ * @param failInfoField the FailInfoField to set.
+ * @param statusString an optional string describing the failure.
+ * @return a TimeStampResponse with a failInfoField and optional statusString
+ * @throws TSPException in case the response could not be created
+ */
+ public TimeStampResponse generateFailResponse(int status, int failInfoField, String statusString)
+ throws TSPException
+ {
+ this.status = status;
+ this.statusStrings = new ASN1EncodableVector();
+
+ this.setFailInfoField(failInfoField);
+
+ if (statusString != null)
+ {
+ this.addStatusString(statusString);
+ }
+
+ PKIStatusInfo pkiStatusInfo = getPKIStatusInfo();
+
+ TimeStampResp resp = new TimeStampResp(pkiStatusInfo, null);
+
+ try
+ {
+ return new TimeStampResponse(resp);
+ }
+ catch (IOException e)
+ {
+ throw new TSPException("created badly formatted response!");
+ }
+ }
+
+ private Set convert(Set orig)
+ {
+ if (orig == null)
+ {
+ return orig;
+ }
+
+ Set con = new HashSet(orig.size());
+
+ for (Iterator it = orig.iterator(); it.hasNext();)
+ {
+ Object o = it.next();
+
+ if (o instanceof String)
+ {
+ con.add(new ASN1ObjectIdentifier((String)o));
+ }
+ else
+ {
+ con.add(o);
+ }
+ }
+
+ return con;
+ }
+
+ class FailInfo extends DERBitString
+ {
+ FailInfo(int failInfoValue)
+ {
+ super(getBytes(failInfoValue), getPadBits(failInfoValue));
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampToken.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampToken.java
new file mode 100644
index 000000000..00d2a903b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampToken.java
@@ -0,0 +1,393 @@
+package org.spongycastle.tsp;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.Date;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.cms.Attribute;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.IssuerAndSerialNumber;
+import org.spongycastle.asn1.ess.ESSCertID;
+import org.spongycastle.asn1.ess.ESSCertIDv2;
+import org.spongycastle.asn1.ess.SigningCertificate;
+import org.spongycastle.asn1.ess.SigningCertificateV2;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.tsp.TSTInfo;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.IssuerSerial;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.CMSProcessable;
+import org.spongycastle.cms.CMSSignedData;
+import org.spongycastle.cms.SignerId;
+import org.spongycastle.cms.SignerInformation;
+import org.spongycastle.cms.SignerInformationVerifier;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Store;
+
+/**
+ * Carrier class for a TimeStampToken.
+ */
+public class TimeStampToken
+{
+ CMSSignedData tsToken;
+
+ SignerInformation tsaSignerInfo;
+
+ Date genTime;
+
+ TimeStampTokenInfo tstInfo;
+
+ CertID certID;
+
+ public TimeStampToken(ContentInfo contentInfo)
+ throws TSPException, IOException
+ {
+ this(getSignedData(contentInfo));
+ }
+
+ private static CMSSignedData getSignedData(ContentInfo contentInfo)
+ throws TSPException
+ {
+ try
+ {
+ return new CMSSignedData(contentInfo);
+ }
+ catch (CMSException e)
+ {
+ throw new TSPException("TSP parsing error: " + e.getMessage(), e.getCause());
+ }
+ }
+
+ public TimeStampToken(CMSSignedData signedData)
+ throws TSPException, IOException
+ {
+ this.tsToken = signedData;
+
+ if (!this.tsToken.getSignedContentTypeOID().equals(PKCSObjectIdentifiers.id_ct_TSTInfo.getId()))
+ {
+ throw new TSPValidationException("ContentInfo object not for a time stamp.");
+ }
+
+ Collection signers = tsToken.getSignerInfos().getSigners();
+
+ if (signers.size() != 1)
+ {
+ throw new IllegalArgumentException("Time-stamp token signed by "
+ + signers.size()
+ + " signers, but it must contain just the TSA signature.");
+ }
+
+ tsaSignerInfo = (SignerInformation)signers.iterator().next();
+
+ try
+ {
+ CMSProcessable content = tsToken.getSignedContent();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ content.write(bOut);
+
+ ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(bOut.toByteArray()));
+
+ this.tstInfo = new TimeStampTokenInfo(TSTInfo.getInstance(aIn.readObject()));
+
+ Attribute attr = tsaSignerInfo.getSignedAttributes().get(PKCSObjectIdentifiers.id_aa_signingCertificate);
+
+ if (attr != null)
+ {
+ SigningCertificate signCert = SigningCertificate.getInstance(attr.getAttrValues().getObjectAt(0));
+
+ this.certID = new CertID(ESSCertID.getInstance(signCert.getCerts()[0]));
+ }
+ else
+ {
+ attr = tsaSignerInfo.getSignedAttributes().get(PKCSObjectIdentifiers.id_aa_signingCertificateV2);
+
+ if (attr == null)
+ {
+ throw new TSPValidationException("no signing certificate attribute found, time stamp invalid.");
+ }
+
+ SigningCertificateV2 signCertV2 = SigningCertificateV2.getInstance(attr.getAttrValues().getObjectAt(0));
+
+ this.certID = new CertID(ESSCertIDv2.getInstance(signCertV2.getCerts()[0]));
+ }
+ }
+ catch (CMSException e)
+ {
+ throw new TSPException(e.getMessage(), e.getUnderlyingException());
+ }
+ }
+
+ public TimeStampTokenInfo getTimeStampInfo()
+ {
+ return tstInfo;
+ }
+
+ public SignerId getSID()
+ {
+ return tsaSignerInfo.getSID();
+ }
+
+ public AttributeTable getSignedAttributes()
+ {
+ return tsaSignerInfo.getSignedAttributes();
+ }
+
+ public AttributeTable getUnsignedAttributes()
+ {
+ return tsaSignerInfo.getUnsignedAttributes();
+ }
+
+ public Store getCertificates()
+ {
+ return tsToken.getCertificates();
+ }
+
+ public Store getCRLs()
+ {
+ return tsToken.getCRLs();
+ }
+
+ public Store getAttributeCertificates()
+ {
+ return tsToken.getAttributeCertificates();
+ }
+
+ /**
+ * Validate the time stamp token.
+ * <p>
+ * To be valid the token must be signed by the passed in certificate and
+ * the certificate must be the one referred to by the SigningCertificate
+ * attribute included in the hashed attributes of the token. The
+ * certificate must also have the ExtendedKeyUsageExtension with only
+ * KeyPurposeId.id_kp_timeStamping and have been valid at the time the
+ * timestamp was created.
+ * </p>
+ * <p>
+ * A successful call to validate means all the above are true.
+ * </p>
+ *
+ * @param sigVerifier the content verifier create the objects required to verify the CMS object in the timestamp.
+ * @throws TSPException if an exception occurs in processing the token.
+ * @throws TSPValidationException if the certificate or signature fail to be valid.
+ * @throws IllegalArgumentException if the sigVerifierProvider has no associated certificate.
+ */
+ public void validate(
+ SignerInformationVerifier sigVerifier)
+ throws TSPException, TSPValidationException
+ {
+ if (!sigVerifier.hasAssociatedCertificate())
+ {
+ throw new IllegalArgumentException("verifier provider needs an associated certificate");
+ }
+
+ try
+ {
+ X509CertificateHolder certHolder = sigVerifier.getAssociatedCertificate();
+ DigestCalculator calc = sigVerifier.getDigestCalculator(certID.getHashAlgorithm());
+
+ OutputStream cOut = calc.getOutputStream();
+
+ cOut.write(certHolder.getEncoded());
+ cOut.close();
+
+ if (!Arrays.constantTimeAreEqual(certID.getCertHash(), calc.getDigest()))
+ {
+ throw new TSPValidationException("certificate hash does not match certID hash.");
+ }
+
+ if (certID.getIssuerSerial() != null)
+ {
+ IssuerAndSerialNumber issuerSerial = new IssuerAndSerialNumber(certHolder.toASN1Structure());
+
+ if (!certID.getIssuerSerial().getSerial().equals(issuerSerial.getSerialNumber()))
+ {
+ throw new TSPValidationException("certificate serial number does not match certID for signature.");
+ }
+
+ GeneralName[] names = certID.getIssuerSerial().getIssuer().getNames();
+ boolean found = false;
+
+ for (int i = 0; i != names.length; i++)
+ {
+ if (names[i].getTagNo() == 4 && X500Name.getInstance(names[i].getName()).equals(X500Name.getInstance(issuerSerial.getName())))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ throw new TSPValidationException("certificate name does not match certID for signature. ");
+ }
+ }
+
+ TSPUtil.validateCertificate(certHolder);
+
+ if (!certHolder.isValidOn(tstInfo.getGenTime()))
+ {
+ throw new TSPValidationException("certificate not valid when time stamp created.");
+ }
+
+ if (!tsaSignerInfo.verify(sigVerifier))
+ {
+ throw new TSPValidationException("signature not created by certificate.");
+ }
+ }
+ catch (CMSException e)
+ {
+ if (e.getUnderlyingException() != null)
+ {
+ throw new TSPException(e.getMessage(), e.getUnderlyingException());
+ }
+ else
+ {
+ throw new TSPException("CMS exception: " + e, e);
+ }
+ }
+ catch (IOException e)
+ {
+ throw new TSPException("problem processing certificate: " + e, e);
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new TSPException("unable to create digest: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Return true if the signature on time stamp token is valid.
+ * <p>
+ * Note: this is a much weaker proof of correctness than calling validate().
+ * </p>
+ *
+ * @param sigVerifier the content verifier create the objects required to verify the CMS object in the timestamp.
+ * @return true if the signature matches, false otherwise.
+ * @throws TSPException if the signature cannot be processed or the provider cannot match the algorithm.
+ */
+ public boolean isSignatureValid(
+ SignerInformationVerifier sigVerifier)
+ throws TSPException
+ {
+ try
+ {
+ return tsaSignerInfo.verify(sigVerifier);
+ }
+ catch (CMSException e)
+ {
+ if (e.getUnderlyingException() != null)
+ {
+ throw new TSPException(e.getMessage(), e.getUnderlyingException());
+ }
+ else
+ {
+ throw new TSPException("CMS exception: " + e, e);
+ }
+ }
+ }
+
+ /**
+ * Return the underlying CMSSignedData object.
+ *
+ * @return the underlying CMS structure.
+ */
+ public CMSSignedData toCMSSignedData()
+ {
+ return tsToken;
+ }
+
+ /**
+ * Return a ASN.1 encoded byte stream representing the encoded object.
+ *
+ * @throws IOException if encoding fails.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return tsToken.getEncoded();
+ }
+
+ // perhaps this should be done using an interface on the ASN.1 classes...
+ private class CertID
+ {
+ private ESSCertID certID;
+ private ESSCertIDv2 certIDv2;
+
+ CertID(ESSCertID certID)
+ {
+ this.certID = certID;
+ this.certIDv2 = null;
+ }
+
+ CertID(ESSCertIDv2 certID)
+ {
+ this.certIDv2 = certID;
+ this.certID = null;
+ }
+
+ public String getHashAlgorithmName()
+ {
+ if (certID != null)
+ {
+ return "SHA-1";
+ }
+ else
+ {
+ if (NISTObjectIdentifiers.id_sha256.equals(certIDv2.getHashAlgorithm().getAlgorithm()))
+ {
+ return "SHA-256";
+ }
+ return certIDv2.getHashAlgorithm().getAlgorithm().getId();
+ }
+ }
+
+ public AlgorithmIdentifier getHashAlgorithm()
+ {
+ if (certID != null)
+ {
+ return new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1);
+ }
+ else
+ {
+ return certIDv2.getHashAlgorithm();
+ }
+ }
+
+ public byte[] getCertHash()
+ {
+ if (certID != null)
+ {
+ return certID.getCertHash();
+ }
+ else
+ {
+ return certIDv2.getCertHash();
+ }
+ }
+
+ public IssuerSerial getIssuerSerial()
+ {
+ if (certID != null)
+ {
+ return certID.getIssuerSerial();
+ }
+ else
+ {
+ return certIDv2.getIssuerSerial();
+ }
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampTokenGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampTokenGenerator.java
new file mode 100644
index 000000000..71b1cda91
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampTokenGenerator.java
@@ -0,0 +1,356 @@
+package org.spongycastle.tsp;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1Boolean;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.ess.ESSCertID;
+import org.spongycastle.asn1.ess.ESSCertIDv2;
+import org.spongycastle.asn1.ess.SigningCertificate;
+import org.spongycastle.asn1.ess.SigningCertificateV2;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.tsp.Accuracy;
+import org.spongycastle.asn1.tsp.MessageImprint;
+import org.spongycastle.asn1.tsp.TSTInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.IssuerSerial;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cms.CMSAttributeTableGenerationException;
+import org.spongycastle.cms.CMSAttributeTableGenerator;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.CMSSignedData;
+import org.spongycastle.cms.CMSSignedDataGenerator;
+import org.spongycastle.cms.SignerInfoGenerator;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.util.CollectionStore;
+import org.spongycastle.util.Store;
+
+/**
+ * Currently the class supports ESSCertID by if a digest calculator based on SHA1 is passed in, otherwise it uses
+ * ESSCertIDv2. In the event you need to pass both types, you will need to override the SignedAttributeGenerator
+ * for the SignerInfoGeneratorBuilder you are using. For the default for ESSCertIDv2 the code will look something
+ * like the following:
+ * <pre>
+ * final ESSCertID essCertid = new ESSCertID(certHashSha1, issuerSerial);
+ * final ESSCertIDv2 essCertidV2 = new ESSCertIDv2(certHashSha256, issuerSerial);
+ *
+ * signerInfoGenBuilder.setSignedAttributeGenerator(new CMSAttributeTableGenerator()
+ * {
+ * public AttributeTable getAttributes(Map parameters)
+ * throws CMSAttributeTableGenerationException
+ * {
+ * CMSAttributeTableGenerator attrGen = new DefaultSignedAttributeTableGenerator();
+ *
+ * AttributeTable table = attrGen.getAttributes(parameters);
+ *
+ * table = table.add(PKCSObjectIdentifiers.id_aa_signingCertificate, new SigningCertificate(essCertid));
+ * table = table.add(PKCSObjectIdentifiers.id_aa_signingCertificateV2, new SigningCertificateV2(essCertidV2));
+ *
+ * return table;
+ * }
+ * });
+ * </pre>
+ */
+public class TimeStampTokenGenerator
+{
+ int accuracySeconds = -1;
+
+ int accuracyMillis = -1;
+
+ int accuracyMicros = -1;
+
+ boolean ordering = false;
+
+ GeneralName tsa = null;
+
+ private ASN1ObjectIdentifier tsaPolicyOID;
+
+ private List certs = new ArrayList();
+ private List crls = new ArrayList();
+ private List attrCerts = new ArrayList();
+ private SignerInfoGenerator signerInfoGen;
+
+ /**
+ * Basic Constructor - set up a calculator based on signerInfoGen with a ESSCertID calculated from
+ * the signer's associated certificate using the sha1DigestCalculator. If alternate values are required
+ * for id-aa-signingCertificate they should be added to the signerInfoGen object before it is passed in,
+ * otherwise a standard digest based value will be added.
+ *
+ * @param signerInfoGen the generator for the signer we are using.
+ * @param digestCalculator calculator for to use for digest of certificate.
+ * @param tsaPolicy tasPolicy to send.
+ * @throws IllegalArgumentException if calculator is not SHA-1 or there is no associated certificate for the signer,
+ * @throws TSPException if the signer certificate cannot be processed.
+ */
+ public TimeStampTokenGenerator(
+ final SignerInfoGenerator signerInfoGen,
+ DigestCalculator digestCalculator,
+ ASN1ObjectIdentifier tsaPolicy)
+ throws IllegalArgumentException, TSPException
+ {
+ this(signerInfoGen, digestCalculator, tsaPolicy, false);
+ }
+
+ /**
+ * Basic Constructor - set up a calculator based on signerInfoGen with a ESSCertID calculated from
+ * the signer's associated certificate using the sha1DigestCalculator. If alternate values are required
+ * for id-aa-signingCertificate they should be added to the signerInfoGen object before it is passed in,
+ * otherwise a standard digest based value will be added.
+ *
+ * @param signerInfoGen the generator for the signer we are using.
+ * @param digestCalculator calculator for to use for digest of certificate.
+ * @param tsaPolicy tasPolicy to send.
+ * @param isIssuerSerialIncluded should issuerSerial be included in the ESSCertIDs, true if yes, by default false.
+ * @throws IllegalArgumentException if calculator is not SHA-1 or there is no associated certificate for the signer,
+ * @throws TSPException if the signer certificate cannot be processed.
+ */
+ public TimeStampTokenGenerator(
+ final SignerInfoGenerator signerInfoGen,
+ DigestCalculator digestCalculator,
+ ASN1ObjectIdentifier tsaPolicy,
+ boolean isIssuerSerialIncluded)
+ throws IllegalArgumentException, TSPException
+ {
+ this.signerInfoGen = signerInfoGen;
+ this.tsaPolicyOID = tsaPolicy;
+
+ if (!signerInfoGen.hasAssociatedCertificate())
+ {
+ throw new IllegalArgumentException("SignerInfoGenerator must have an associated certificate");
+ }
+
+ X509CertificateHolder assocCert = signerInfoGen.getAssociatedCertificate();
+ TSPUtil.validateCertificate(assocCert);
+
+ try
+ {
+ OutputStream dOut = digestCalculator.getOutputStream();
+
+ dOut.write(assocCert.getEncoded());
+
+ dOut.close();
+
+ if (digestCalculator.getAlgorithmIdentifier().getAlgorithm().equals(OIWObjectIdentifiers.idSHA1))
+ {
+ final ESSCertID essCertid = new ESSCertID(digestCalculator.getDigest(),
+ isIssuerSerialIncluded ? new IssuerSerial(new GeneralNames(new GeneralName(assocCert.getIssuer())), assocCert.getSerialNumber())
+ : null);
+
+ this.signerInfoGen = new SignerInfoGenerator(signerInfoGen, new CMSAttributeTableGenerator()
+ {
+ public AttributeTable getAttributes(Map parameters)
+ throws CMSAttributeTableGenerationException
+ {
+ AttributeTable table = signerInfoGen.getSignedAttributeTableGenerator().getAttributes(parameters);
+
+ if (table.get(PKCSObjectIdentifiers.id_aa_signingCertificate) == null)
+ {
+ return table.add(PKCSObjectIdentifiers.id_aa_signingCertificate, new SigningCertificate(essCertid));
+ }
+
+ return table;
+ }
+ }, signerInfoGen.getUnsignedAttributeTableGenerator());
+ }
+ else
+ {
+ AlgorithmIdentifier digAlgID = new AlgorithmIdentifier(digestCalculator.getAlgorithmIdentifier().getAlgorithm());
+ final ESSCertIDv2 essCertid = new ESSCertIDv2(digAlgID, digestCalculator.getDigest(),
+ isIssuerSerialIncluded ? new IssuerSerial(new GeneralNames(new GeneralName(assocCert.getIssuer())), new ASN1Integer(assocCert.getSerialNumber()))
+ : null);
+
+ this.signerInfoGen = new SignerInfoGenerator(signerInfoGen, new CMSAttributeTableGenerator()
+ {
+ public AttributeTable getAttributes(Map parameters)
+ throws CMSAttributeTableGenerationException
+ {
+ AttributeTable table = signerInfoGen.getSignedAttributeTableGenerator().getAttributes(parameters);
+
+ if (table.get(PKCSObjectIdentifiers.id_aa_signingCertificateV2) == null)
+ {
+ return table.add(PKCSObjectIdentifiers.id_aa_signingCertificateV2, new SigningCertificateV2(essCertid));
+ }
+
+ return table;
+ }
+ }, signerInfoGen.getUnsignedAttributeTableGenerator());
+ }
+ }
+ catch (IOException e)
+ {
+ throw new TSPException("Exception processing certificate.", e);
+ }
+ }
+
+ /**
+ * Add the store of X509 Certificates to the generator.
+ *
+ * @param certStore a Store containing X509CertificateHolder objects
+ */
+ public void addCertificates(
+ Store certStore)
+ {
+ certs.addAll(certStore.getMatches(null));
+ }
+
+ /**
+ *
+ * @param crlStore a Store containing X509CRLHolder objects.
+ */
+ public void addCRLs(
+ Store crlStore)
+ {
+ crls.addAll(crlStore.getMatches(null));
+ }
+
+ /**
+ *
+ * @param attrStore a Store containing X509AttributeCertificate objects.
+ */
+ public void addAttributeCertificates(
+ Store attrStore)
+ {
+ attrCerts.addAll(attrStore.getMatches(null));
+ }
+
+ public void setAccuracySeconds(int accuracySeconds)
+ {
+ this.accuracySeconds = accuracySeconds;
+ }
+
+ public void setAccuracyMillis(int accuracyMillis)
+ {
+ this.accuracyMillis = accuracyMillis;
+ }
+
+ public void setAccuracyMicros(int accuracyMicros)
+ {
+ this.accuracyMicros = accuracyMicros;
+ }
+
+ public void setOrdering(boolean ordering)
+ {
+ this.ordering = ordering;
+ }
+
+ public void setTSA(GeneralName tsa)
+ {
+ this.tsa = tsa;
+ }
+
+ /**
+ * Generate a TimeStampToken for the passed in request and serialNumber marking it with the passed in genTime.
+ *
+ * @param request the originating request.
+ * @param serialNumber serial number for the TimeStampToken
+ * @param genTime token generation time.
+ * @return a TimeStampToken
+ * @throws TSPException
+ */
+ public TimeStampToken generate(
+ TimeStampRequest request,
+ BigInteger serialNumber,
+ Date genTime)
+ throws TSPException
+ {
+ ASN1ObjectIdentifier digestAlgOID = request.getMessageImprintAlgOID();
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOID, DERNull.INSTANCE);
+ MessageImprint messageImprint = new MessageImprint(algID, request.getMessageImprintDigest());
+
+ Accuracy accuracy = null;
+ if (accuracySeconds > 0 || accuracyMillis > 0 || accuracyMicros > 0)
+ {
+ ASN1Integer seconds = null;
+ if (accuracySeconds > 0)
+ {
+ seconds = new ASN1Integer(accuracySeconds);
+ }
+
+ ASN1Integer millis = null;
+ if (accuracyMillis > 0)
+ {
+ millis = new ASN1Integer(accuracyMillis);
+ }
+
+ ASN1Integer micros = null;
+ if (accuracyMicros > 0)
+ {
+ micros = new ASN1Integer(accuracyMicros);
+ }
+
+ accuracy = new Accuracy(seconds, millis, micros);
+ }
+
+ ASN1Boolean derOrdering = null;
+ if (ordering)
+ {
+ derOrdering = new ASN1Boolean(ordering);
+ }
+
+ ASN1Integer nonce = null;
+ if (request.getNonce() != null)
+ {
+ nonce = new ASN1Integer(request.getNonce());
+ }
+
+ ASN1ObjectIdentifier tsaPolicy = tsaPolicyOID;
+ if (request.getReqPolicy() != null)
+ {
+ tsaPolicy = request.getReqPolicy();
+ }
+
+ TSTInfo tstInfo = new TSTInfo(tsaPolicy,
+ messageImprint, new ASN1Integer(serialNumber),
+ new ASN1GeneralizedTime(genTime), accuracy, derOrdering,
+ nonce, tsa, request.getExtensions());
+
+ try
+ {
+ CMSSignedDataGenerator signedDataGenerator = new CMSSignedDataGenerator();
+
+ if (request.getCertReq())
+ {
+ // TODO: do we need to check certs non-empty?
+ signedDataGenerator.addCertificates(new CollectionStore(certs));
+ signedDataGenerator.addCRLs(new CollectionStore(crls));
+ signedDataGenerator.addAttributeCertificates(new CollectionStore(attrCerts));
+ }
+ else
+ {
+ signedDataGenerator.addCRLs(new CollectionStore(crls));
+ }
+
+ signedDataGenerator.addSignerInfoGenerator(signerInfoGen);
+
+ byte[] derEncodedTSTInfo = tstInfo.getEncoded(ASN1Encoding.DER);
+
+ CMSSignedData signedData = signedDataGenerator.generate(new CMSProcessableByteArray(PKCSObjectIdentifiers.id_ct_TSTInfo, derEncodedTSTInfo), true);
+
+ return new TimeStampToken(signedData);
+ }
+ catch (CMSException cmsEx)
+ {
+ throw new TSPException("Error generating time-stamp token", cmsEx);
+ }
+ catch (IOException e)
+ {
+ throw new TSPException("Exception encoding info", e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampTokenInfo.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampTokenInfo.java
new file mode 100644
index 000000000..e9f706507
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/TimeStampTokenInfo.java
@@ -0,0 +1,121 @@
+package org.spongycastle.tsp;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.text.ParseException;
+import java.util.Date;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.tsp.Accuracy;
+import org.spongycastle.asn1.tsp.TSTInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.GeneralName;
+
+public class TimeStampTokenInfo
+{
+ TSTInfo tstInfo;
+ Date genTime;
+
+ TimeStampTokenInfo(TSTInfo tstInfo)
+ throws TSPException, IOException
+ {
+ this.tstInfo = tstInfo;
+
+ try
+ {
+ this.genTime = tstInfo.getGenTime().getDate();
+ }
+ catch (ParseException e)
+ {
+ throw new TSPException("unable to parse genTime field");
+ }
+ }
+
+ public boolean isOrdered()
+ {
+ return tstInfo.getOrdering().isTrue();
+ }
+
+ public Accuracy getAccuracy()
+ {
+ return tstInfo.getAccuracy();
+ }
+
+ public Date getGenTime()
+ {
+ return genTime;
+ }
+
+ public GenTimeAccuracy getGenTimeAccuracy()
+ {
+ if (this.getAccuracy() != null)
+ {
+ return new GenTimeAccuracy(this.getAccuracy());
+ }
+
+ return null;
+ }
+
+ public ASN1ObjectIdentifier getPolicy()
+ {
+ return tstInfo.getPolicy();
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return tstInfo.getSerialNumber().getValue();
+ }
+
+ public GeneralName getTsa()
+ {
+ return tstInfo.getTsa();
+ }
+
+ /**
+ * @return the nonce value, null if there isn't one.
+ */
+ public BigInteger getNonce()
+ {
+ if (tstInfo.getNonce() != null)
+ {
+ return tstInfo.getNonce().getValue();
+ }
+
+ return null;
+ }
+
+ public AlgorithmIdentifier getHashAlgorithm()
+ {
+ return tstInfo.getMessageImprint().getHashAlgorithm();
+ }
+
+ public ASN1ObjectIdentifier getMessageImprintAlgOID()
+ {
+ return tstInfo.getMessageImprint().getHashAlgorithm().getAlgorithm();
+ }
+
+ public byte[] getMessageImprintDigest()
+ {
+ return tstInfo.getMessageImprint().getHashedMessage();
+ }
+
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return tstInfo.getEncoded();
+ }
+
+ /**
+ * @deprecated use toASN1Structure
+ * @return
+ */
+ public TSTInfo toTSTInfo()
+ {
+ return tstInfo;
+ }
+
+ public TSTInfo toASN1Structure()
+ {
+ return tstInfo;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedData.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedData.java
new file mode 100644
index 000000000..844f123a1
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedData.java
@@ -0,0 +1,204 @@
+package org.spongycastle.tsp.cms;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.Evidence;
+import org.spongycastle.asn1.cms.TimeStampAndCRL;
+import org.spongycastle.asn1.cms.TimeStampTokenEvidence;
+import org.spongycastle.asn1.cms.TimeStampedData;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.tsp.TimeStampToken;
+
+public class CMSTimeStampedData
+{
+ private TimeStampedData timeStampedData;
+ private ContentInfo contentInfo;
+ private TimeStampDataUtil util;
+
+ public CMSTimeStampedData(ContentInfo contentInfo)
+ {
+ this.initialize(contentInfo);
+ }
+
+ public CMSTimeStampedData(InputStream in)
+ throws IOException
+ {
+ try
+ {
+ initialize(ContentInfo.getInstance(new ASN1InputStream(in).readObject()));
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Malformed content: " + e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new IOException("Malformed content: " + e);
+ }
+ }
+
+ public CMSTimeStampedData(byte[] baseData)
+ throws IOException
+ {
+ this(new ByteArrayInputStream(baseData));
+ }
+
+ private void initialize(ContentInfo contentInfo)
+ {
+ this.contentInfo = contentInfo;
+
+ if (CMSObjectIdentifiers.timestampedData.equals(contentInfo.getContentType()))
+ {
+ this.timeStampedData = TimeStampedData.getInstance(contentInfo.getContent());
+ }
+ else
+ {
+ throw new IllegalArgumentException("Malformed content - type must be " + CMSObjectIdentifiers.timestampedData.getId());
+ }
+
+ util = new TimeStampDataUtil(this.timeStampedData);
+ }
+
+ public byte[] calculateNextHash(DigestCalculator calculator)
+ throws CMSException
+ {
+ return util.calculateNextHash(calculator);
+ }
+
+ /**
+ * Return a new timeStampedData object with the additional token attached.
+ *
+ * @throws CMSException
+ */
+ public CMSTimeStampedData addTimeStamp(TimeStampToken token)
+ throws CMSException
+ {
+ TimeStampAndCRL[] timeStamps = util.getTimeStamps();
+ TimeStampAndCRL[] newTimeStamps = new TimeStampAndCRL[timeStamps.length + 1];
+
+ System.arraycopy(timeStamps, 0, newTimeStamps, 0, timeStamps.length);
+
+ newTimeStamps[timeStamps.length] = new TimeStampAndCRL(token.toCMSSignedData().toASN1Structure());
+
+ return new CMSTimeStampedData(new ContentInfo(CMSObjectIdentifiers.timestampedData, new TimeStampedData(timeStampedData.getDataUri(), timeStampedData.getMetaData(), timeStampedData.getContent(), new Evidence(new TimeStampTokenEvidence(newTimeStamps)))));
+ }
+
+ public byte[] getContent()
+ {
+ if (timeStampedData.getContent() != null)
+ {
+ return timeStampedData.getContent().getOctets();
+ }
+
+ return null;
+ }
+
+ public URI getDataUri()
+ throws URISyntaxException
+ {
+ DERIA5String dataURI = this.timeStampedData.getDataUri();
+
+ if (dataURI != null)
+ {
+ return new URI(dataURI.getString());
+ }
+
+ return null;
+ }
+
+ public String getFileName()
+ {
+ return util.getFileName();
+ }
+
+ public String getMediaType()
+ {
+ return util.getMediaType();
+ }
+
+ public AttributeTable getOtherMetaData()
+ {
+ return util.getOtherMetaData();
+ }
+
+ public TimeStampToken[] getTimeStampTokens()
+ throws CMSException
+ {
+ return util.getTimeStampTokens();
+ }
+
+ /**
+ * Initialise the passed in calculator with the MetaData for this message, if it is
+ * required as part of the initial message imprint calculation.
+ *
+ * @param calculator the digest calculator to be initialised.
+ * @throws CMSException if the MetaData is required and cannot be processed
+ */
+ public void initialiseMessageImprintDigestCalculator(DigestCalculator calculator)
+ throws CMSException
+ {
+ util.initialiseMessageImprintDigestCalculator(calculator);
+ }
+
+ /**
+ * Returns an appropriately initialised digest calculator based on the message imprint algorithm
+ * described in the first time stamp in the TemporalData for this message. If the metadata is required
+ * to be included in the digest calculation, the returned calculator will be pre-initialised.
+ *
+ * @param calculatorProvider a provider of DigestCalculator objects.
+ * @return an initialised digest calculator.
+ * @throws OperatorCreationException if the provider is unable to create the calculator.
+ */
+ public DigestCalculator getMessageImprintDigestCalculator(DigestCalculatorProvider calculatorProvider)
+ throws OperatorCreationException
+ {
+ return util.getMessageImprintDigestCalculator(calculatorProvider);
+ }
+
+ /**
+ * Validate the digests present in the TimeStampTokens contained in the CMSTimeStampedData.
+ *
+ * @param calculatorProvider provider for digest calculators
+ * @param dataDigest the calculated data digest for the message
+ * @throws ImprintDigestInvalidException if an imprint digest fails to compare
+ * @throws CMSException if an exception occurs processing the message.
+ */
+ public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest)
+ throws ImprintDigestInvalidException, CMSException
+ {
+ util.validate(calculatorProvider, dataDigest);
+ }
+
+ /**
+ * Validate the passed in timestamp token against the tokens and data present in the message.
+ *
+ * @param calculatorProvider provider for digest calculators
+ * @param dataDigest the calculated data digest for the message.
+ * @param timeStampToken the timestamp token of interest.
+ * @throws ImprintDigestInvalidException if the token is not present in the message, or an imprint digest fails to compare.
+ * @throws CMSException if an exception occurs processing the message.
+ */
+ public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest, TimeStampToken timeStampToken)
+ throws ImprintDigestInvalidException, CMSException
+ {
+ util.validate(calculatorProvider, dataDigest, timeStampToken);
+ }
+
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return contentInfo.getEncoded();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedDataGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedDataGenerator.java
new file mode 100644
index 000000000..a1ad0c0ff
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedDataGenerator.java
@@ -0,0 +1,70 @@
+package org.spongycastle.tsp.cms;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.BEROctetString;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.Evidence;
+import org.spongycastle.asn1.cms.TimeStampAndCRL;
+import org.spongycastle.asn1.cms.TimeStampTokenEvidence;
+import org.spongycastle.asn1.cms.TimeStampedData;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.tsp.TimeStampToken;
+import org.spongycastle.util.io.Streams;
+
+public class CMSTimeStampedDataGenerator
+ extends CMSTimeStampedGenerator
+{
+ public CMSTimeStampedData generate(TimeStampToken timeStamp) throws CMSException
+ {
+ return generate(timeStamp, (InputStream)null);
+ }
+
+ public CMSTimeStampedData generate(TimeStampToken timeStamp, byte[] content) throws CMSException
+ {
+ return generate(timeStamp, new ByteArrayInputStream(content));
+ }
+
+ public CMSTimeStampedData generate(TimeStampToken timeStamp, InputStream content)
+ throws CMSException
+ {
+ ByteArrayOutputStream contentOut = new ByteArrayOutputStream();
+
+ if (content != null)
+ {
+ try
+ {
+ Streams.pipeAll(content, contentOut);
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("exception encapsulating content: " + e.getMessage(), e);
+ }
+ }
+
+ ASN1OctetString encContent = null;
+
+ if (contentOut.size() != 0)
+ {
+ encContent = new BEROctetString(contentOut.toByteArray());
+ }
+
+ TimeStampAndCRL stamp = new TimeStampAndCRL(timeStamp.toCMSSignedData().toASN1Structure());
+
+ DERIA5String asn1DataUri = null;
+
+ if (dataUri != null)
+ {
+ asn1DataUri = new DERIA5String(dataUri.toString());
+ }
+
+ return new CMSTimeStampedData(new ContentInfo(CMSObjectIdentifiers.timestampedData, new TimeStampedData(asn1DataUri, metaData, encContent, new Evidence(new TimeStampTokenEvidence(stamp)))));
+ }
+}
+
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedDataParser.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedDataParser.java
new file mode 100644
index 000000000..c3518b778
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedDataParser.java
@@ -0,0 +1,207 @@
+package org.spongycastle.tsp.cms;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.spongycastle.asn1.BERTags;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.ContentInfoParser;
+import org.spongycastle.asn1.cms.TimeStampedDataParser;
+import org.spongycastle.cms.CMSContentInfoParser;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.tsp.TimeStampToken;
+import org.spongycastle.util.io.Streams;
+
+public class CMSTimeStampedDataParser
+ extends CMSContentInfoParser
+{
+ private TimeStampedDataParser timeStampedData;
+ private TimeStampDataUtil util;
+
+ public CMSTimeStampedDataParser(InputStream in)
+ throws CMSException
+ {
+ super(in);
+
+ initialize(_contentInfo);
+ }
+
+ public CMSTimeStampedDataParser(byte[] baseData)
+ throws CMSException
+ {
+ this(new ByteArrayInputStream(baseData));
+ }
+
+ private void initialize(ContentInfoParser contentInfo)
+ throws CMSException
+ {
+ try
+ {
+ if (CMSObjectIdentifiers.timestampedData.equals(contentInfo.getContentType()))
+ {
+ this.timeStampedData = TimeStampedDataParser.getInstance(contentInfo.getContent(BERTags.SEQUENCE));
+ }
+ else
+ {
+ throw new IllegalArgumentException("Malformed content - type must be " + CMSObjectIdentifiers.timestampedData.getId());
+ }
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("parsing exception: " + e.getMessage(), e);
+ }
+ }
+
+ public byte[] calculateNextHash(DigestCalculator calculator)
+ throws CMSException
+ {
+ return util.calculateNextHash(calculator);
+ }
+
+ public InputStream getContent()
+ {
+ if (timeStampedData.getContent() != null)
+ {
+ return timeStampedData.getContent().getOctetStream();
+ }
+
+ return null;
+ }
+
+ public URI getDataUri()
+ throws URISyntaxException
+ {
+ DERIA5String dataURI = this.timeStampedData.getDataUri();
+
+ if (dataURI != null)
+ {
+ return new URI(dataURI.getString());
+ }
+
+ return null;
+ }
+
+ public String getFileName()
+ {
+ return util.getFileName();
+ }
+
+ public String getMediaType()
+ {
+ return util.getMediaType();
+ }
+
+ public AttributeTable getOtherMetaData()
+ {
+ return util.getOtherMetaData();
+ }
+
+ /**
+ * Initialise the passed in calculator with the MetaData for this message, if it is
+ * required as part of the initial message imprint calculation.
+ *
+ * @param calculator the digest calculator to be initialised.
+ * @throws CMSException if the MetaData is required and cannot be processed
+ */
+ public void initialiseMessageImprintDigestCalculator(DigestCalculator calculator)
+ throws CMSException
+ {
+ util.initialiseMessageImprintDigestCalculator(calculator);
+ }
+
+ /**
+ * Returns an appropriately initialised digest calculator based on the message imprint algorithm
+ * described in the first time stamp in the TemporalData for this message. If the metadata is required
+ * to be included in the digest calculation, the returned calculator will be pre-initialised.
+ *
+ * @param calculatorProvider a provider of DigestCalculator objects.
+ * @return an initialised digest calculator.
+ * @throws OperatorCreationException if the provider is unable to create the calculator.
+ */
+ public DigestCalculator getMessageImprintDigestCalculator(DigestCalculatorProvider calculatorProvider)
+ throws OperatorCreationException
+ {
+ try
+ {
+ parseTimeStamps();
+ }
+ catch (CMSException e)
+ {
+ throw new OperatorCreationException("unable to extract algorithm ID: " + e.getMessage(), e);
+ }
+
+ return util.getMessageImprintDigestCalculator(calculatorProvider);
+ }
+
+ public TimeStampToken[] getTimeStampTokens()
+ throws CMSException
+ {
+ parseTimeStamps();
+
+ return util.getTimeStampTokens();
+ }
+
+ /**
+ * Validate the digests present in the TimeStampTokens contained in the CMSTimeStampedData.
+ *
+ * @param calculatorProvider provider for digest calculators
+ * @param dataDigest the calculated data digest for the message
+ * @throws ImprintDigestInvalidException if an imprint digest fails to compare
+ * @throws CMSException if an exception occurs processing the message.
+ */
+ public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest)
+ throws ImprintDigestInvalidException, CMSException
+ {
+ parseTimeStamps();
+
+ util.validate(calculatorProvider, dataDigest);
+ }
+
+ /**
+ * Validate the passed in timestamp token against the tokens and data present in the message.
+ *
+ * @param calculatorProvider provider for digest calculators
+ * @param dataDigest the calculated data digest for the message.
+ * @param timeStampToken the timestamp token of interest.
+ * @throws ImprintDigestInvalidException if the token is not present in the message, or an imprint digest fails to compare.
+ * @throws CMSException if an exception occurs processing the message.
+ */
+ public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest, TimeStampToken timeStampToken)
+ throws ImprintDigestInvalidException, CMSException
+ {
+ parseTimeStamps();
+
+ util.validate(calculatorProvider, dataDigest, timeStampToken);
+ }
+
+ private void parseTimeStamps()
+ throws CMSException
+ {
+ try
+ {
+ if (util == null)
+ {
+ InputStream cont = this.getContent();
+
+ if (cont != null)
+ {
+ Streams.drain(cont);
+ }
+
+ util = new TimeStampDataUtil(timeStampedData);
+ }
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("unable to parse evidence block: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedGenerator.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedGenerator.java
new file mode 100644
index 000000000..9dbeb97fa
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/CMSTimeStampedGenerator.java
@@ -0,0 +1,88 @@
+package org.spongycastle.tsp.cms;
+
+import java.net.URI;
+
+import org.spongycastle.asn1.ASN1Boolean;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DERUTF8String;
+import org.spongycastle.asn1.cms.Attributes;
+import org.spongycastle.asn1.cms.MetaData;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.operator.DigestCalculator;
+
+public class CMSTimeStampedGenerator
+{
+ protected MetaData metaData;
+ protected URI dataUri;
+
+ /**
+ * Set the dataURI to be included in message.
+ *
+ * @param dataUri URI for the data the initial message imprint digest is based on.
+ */
+ public void setDataUri(URI dataUri)
+ {
+ this.dataUri = dataUri;
+ }
+
+ /**
+ * Set the MetaData for the generated message.
+ *
+ * @param hashProtected true if the MetaData should be included in first imprint calculation, false otherwise.
+ * @param fileName optional file name, may be null.
+ * @param mediaType optional media type, may be null.
+ */
+ public void setMetaData(boolean hashProtected, String fileName, String mediaType)
+ {
+ setMetaData(hashProtected, fileName, mediaType, null);
+ }
+
+ /**
+ * Set the MetaData for the generated message.
+ *
+ * @param hashProtected true if the MetaData should be included in first imprint calculation, false otherwise.
+ * @param fileName optional file name, may be null.
+ * @param mediaType optional media type, may be null.
+ * @param attributes optional attributes, may be null.
+ */
+ public void setMetaData(boolean hashProtected, String fileName, String mediaType, Attributes attributes)
+ {
+ DERUTF8String asn1FileName = null;
+
+ if (fileName != null)
+ {
+ asn1FileName = new DERUTF8String(fileName);
+ }
+
+ DERIA5String asn1MediaType = null;
+
+ if (mediaType != null)
+ {
+ asn1MediaType = new DERIA5String(mediaType);
+ }
+
+ setMetaData(hashProtected, asn1FileName, asn1MediaType, attributes);
+ }
+
+ private void setMetaData(boolean hashProtected, DERUTF8String fileName, DERIA5String mediaType, Attributes attributes)
+ {
+ this.metaData = new MetaData(ASN1Boolean.getInstance(hashProtected), fileName, mediaType, attributes);
+ }
+
+ /**
+ * Initialise the passed in calculator with the MetaData for this message, if it is
+ * required as part of the initial message imprint calculation. After initialisation the
+ * calculator can then be used to calculate the initial message imprint digest for the first
+ * timestamp.
+ *
+ * @param calculator the digest calculator to be initialised.
+ * @throws CMSException if the MetaData is required and cannot be processed
+ */
+ public void initialiseMessageImprintDigestCalculator(DigestCalculator calculator)
+ throws CMSException
+ {
+ MetaDataUtil util = new MetaDataUtil(metaData);
+
+ util.initialiseMessageImprintDigestCalculator(calculator);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/ImprintDigestInvalidException.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/ImprintDigestInvalidException.java
new file mode 100644
index 000000000..1dfc2bb36
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/ImprintDigestInvalidException.java
@@ -0,0 +1,21 @@
+package org.spongycastle.tsp.cms;
+
+import org.spongycastle.tsp.TimeStampToken;
+
+public class ImprintDigestInvalidException
+ extends Exception
+{
+ private TimeStampToken token;
+
+ public ImprintDigestInvalidException(String message, TimeStampToken token)
+ {
+ super(message);
+
+ this.token = token;
+ }
+
+ public TimeStampToken getTimeStampToken()
+ {
+ return token;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/MetaDataUtil.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/MetaDataUtil.java
new file mode 100644
index 000000000..f4ad579ad
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/MetaDataUtil.java
@@ -0,0 +1,76 @@
+package org.spongycastle.tsp.cms;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1String;
+import org.spongycastle.asn1.cms.Attributes;
+import org.spongycastle.asn1.cms.MetaData;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.operator.DigestCalculator;
+
+class MetaDataUtil
+{
+ private final MetaData metaData;
+
+ MetaDataUtil(MetaData metaData)
+ {
+ this.metaData = metaData;
+ }
+
+ void initialiseMessageImprintDigestCalculator(DigestCalculator calculator)
+ throws CMSException
+ {
+ if (metaData != null && metaData.isHashProtected())
+ {
+ try
+ {
+ calculator.getOutputStream().write(metaData.getEncoded(ASN1Encoding.DER));
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("unable to initialise calculator from metaData: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ String getFileName()
+ {
+ if (metaData != null)
+ {
+ return convertString(metaData.getFileName());
+ }
+
+ return null;
+ }
+
+ String getMediaType()
+ {
+ if (metaData != null)
+ {
+ return convertString(metaData.getMediaType());
+ }
+
+ return null;
+ }
+
+ Attributes getOtherMetaData()
+ {
+ if (metaData != null)
+ {
+ return metaData.getOtherMetaData();
+ }
+
+ return null;
+ }
+
+ private String convertString(ASN1String s)
+ {
+ if (s != null)
+ {
+ return s.toString();
+ }
+
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/TimeStampDataUtil.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/TimeStampDataUtil.java
new file mode 100644
index 000000000..fd1bcc8dc
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/tsp/cms/TimeStampDataUtil.java
@@ -0,0 +1,256 @@
+package org.spongycastle.tsp.cms;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.Evidence;
+import org.spongycastle.asn1.cms.TimeStampAndCRL;
+import org.spongycastle.asn1.cms.TimeStampedData;
+import org.spongycastle.asn1.cms.TimeStampedDataParser;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.tsp.TSPException;
+import org.spongycastle.tsp.TimeStampToken;
+import org.spongycastle.tsp.TimeStampTokenInfo;
+import org.spongycastle.util.Arrays;
+
+class TimeStampDataUtil
+{
+ private final TimeStampAndCRL[] timeStamps;
+
+ private final MetaDataUtil metaDataUtil;
+
+ TimeStampDataUtil(TimeStampedData timeStampedData)
+ {
+ this.metaDataUtil = new MetaDataUtil(timeStampedData.getMetaData());
+
+ Evidence evidence = timeStampedData.getTemporalEvidence();
+ this.timeStamps = evidence.getTstEvidence().toTimeStampAndCRLArray();
+ }
+
+ TimeStampDataUtil(TimeStampedDataParser timeStampedData)
+ throws IOException
+ {
+ this.metaDataUtil = new MetaDataUtil(timeStampedData.getMetaData());
+
+ Evidence evidence = timeStampedData.getTemporalEvidence();
+ this.timeStamps = evidence.getTstEvidence().toTimeStampAndCRLArray();
+ }
+
+ TimeStampToken getTimeStampToken(TimeStampAndCRL timeStampAndCRL)
+ throws CMSException
+ {
+ ContentInfo timeStampToken = timeStampAndCRL.getTimeStampToken();
+
+ try
+ {
+ TimeStampToken token = new TimeStampToken(timeStampToken);
+ return token;
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("unable to parse token data: " + e.getMessage(), e);
+ }
+ catch (TSPException e)
+ {
+ if (e.getCause() instanceof CMSException)
+ {
+ throw (CMSException)e.getCause();
+ }
+
+ throw new CMSException("token data invalid: " + e.getMessage(), e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CMSException("token data invalid: " + e.getMessage(), e);
+ }
+ }
+
+ void initialiseMessageImprintDigestCalculator(DigestCalculator calculator)
+ throws CMSException
+ {
+ metaDataUtil.initialiseMessageImprintDigestCalculator(calculator);
+ }
+
+ DigestCalculator getMessageImprintDigestCalculator(DigestCalculatorProvider calculatorProvider)
+ throws OperatorCreationException
+ {
+ TimeStampToken token;
+
+ try
+ {
+ token = this.getTimeStampToken(timeStamps[0]);
+
+ TimeStampTokenInfo info = token.getTimeStampInfo();
+ ASN1ObjectIdentifier algOID = info.getMessageImprintAlgOID();
+
+ DigestCalculator calc = calculatorProvider.get(new AlgorithmIdentifier(algOID));
+
+ initialiseMessageImprintDigestCalculator(calc);
+
+ return calc;
+ }
+ catch (CMSException e)
+ {
+ throw new OperatorCreationException("unable to extract algorithm ID: " + e.getMessage(), e);
+ }
+ }
+
+ TimeStampToken[] getTimeStampTokens()
+ throws CMSException
+ {
+ TimeStampToken[] tokens = new TimeStampToken[timeStamps.length];
+ for (int i = 0; i < timeStamps.length; i++)
+ {
+ tokens[i] = this.getTimeStampToken(timeStamps[i]);
+ }
+
+ return tokens;
+ }
+
+ TimeStampAndCRL[] getTimeStamps()
+ {
+ return timeStamps;
+ }
+
+ byte[] calculateNextHash(DigestCalculator calculator)
+ throws CMSException
+ {
+ TimeStampAndCRL tspToken = timeStamps[timeStamps.length - 1];
+
+ OutputStream out = calculator.getOutputStream();
+
+ try
+ {
+ out.write(tspToken.getEncoded(ASN1Encoding.DER));
+
+ out.close();
+
+ return calculator.getDigest();
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("exception calculating hash: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Validate the digests present in the TimeStampTokens contained in the CMSTimeStampedData.
+ */
+ void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest)
+ throws ImprintDigestInvalidException, CMSException
+ {
+ byte[] currentDigest = dataDigest;
+
+ for (int i = 0; i < timeStamps.length; i++)
+ {
+ try
+ {
+ TimeStampToken token = this.getTimeStampToken(timeStamps[i]);
+ if (i > 0)
+ {
+ TimeStampTokenInfo info = token.getTimeStampInfo();
+ DigestCalculator calculator = calculatorProvider.get(info.getHashAlgorithm());
+
+ calculator.getOutputStream().write(timeStamps[i - 1].getEncoded(ASN1Encoding.DER));
+
+ currentDigest = calculator.getDigest();
+ }
+
+ this.compareDigest(token, currentDigest);
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("exception calculating hash: " + e.getMessage(), e);
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new CMSException("cannot create digest: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest, TimeStampToken timeStampToken)
+ throws ImprintDigestInvalidException, CMSException
+ {
+ byte[] currentDigest = dataDigest;
+ byte[] encToken;
+
+ try
+ {
+ encToken = timeStampToken.getEncoded();
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("exception encoding timeStampToken: " + e.getMessage(), e);
+ }
+
+ for (int i = 0; i < timeStamps.length; i++)
+ {
+ try
+ {
+ TimeStampToken token = this.getTimeStampToken(timeStamps[i]);
+ if (i > 0)
+ {
+ TimeStampTokenInfo info = token.getTimeStampInfo();
+ DigestCalculator calculator = calculatorProvider.get(info.getHashAlgorithm());
+
+ calculator.getOutputStream().write(timeStamps[i - 1].getEncoded(ASN1Encoding.DER));
+
+ currentDigest = calculator.getDigest();
+ }
+
+ this.compareDigest(token, currentDigest);
+
+ if (Arrays.areEqual(token.getEncoded(), encToken))
+ {
+ return;
+ }
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("exception calculating hash: " + e.getMessage(), e);
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new CMSException("cannot create digest: " + e.getMessage(), e);
+ }
+ }
+
+ throw new ImprintDigestInvalidException("passed in token not associated with timestamps present", timeStampToken);
+ }
+
+ private void compareDigest(TimeStampToken timeStampToken, byte[] digest)
+ throws ImprintDigestInvalidException
+ {
+ TimeStampTokenInfo info = timeStampToken.getTimeStampInfo();
+ byte[] tsrMessageDigest = info.getMessageImprintDigest();
+
+ if (!Arrays.areEqual(digest, tsrMessageDigest))
+ {
+ throw new ImprintDigestInvalidException("hash calculated is different from MessageImprintDigest found in TimeStampToken", timeStampToken);
+ }
+ }
+
+ String getFileName()
+ {
+ return metaDataUtil.getFileName();
+ }
+
+ String getMediaType()
+ {
+ return metaDataUtil.getMediaType();
+ }
+
+ AttributeTable getOtherMetaData()
+ {
+ return new AttributeTable(metaDataUtil.getOtherMetaData());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/voms/VOMSAttribute.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/voms/VOMSAttribute.java
new file mode 100644
index 000000000..4e7aac737
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/voms/VOMSAttribute.java
@@ -0,0 +1,242 @@
+package org.spongycastle.voms;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.x509.IetfAttrSyntax;
+import org.spongycastle.x509.X509Attribute;
+import org.spongycastle.x509.X509AttributeCertificate;
+
+
+/**
+ * Representation of the authorization information (VO, server address
+ * and list of Fully Qualified Attribute Names, or FQANs) contained in
+ * a VOMS attribute certificate.
+ */
+public class VOMSAttribute
+{
+
+ /**
+ * The ASN.1 object identifier for VOMS attributes
+ */
+ public static final String VOMS_ATTR_OID = "1.3.6.1.4.1.8005.100.100.4";
+ private X509AttributeCertificate myAC;
+ private String myHostPort;
+ private String myVo;
+ private List myStringList = new ArrayList();
+ private List myFQANs = new ArrayList();
+
+ /**
+ * Parses the contents of an attribute certificate.<br>
+ * <b>NOTE:</b> Cryptographic signatures, time stamps etc. will <b>not</b> be checked.
+ *
+ * @param ac the attribute certificate to parse for VOMS attributes
+ */
+ public VOMSAttribute(X509AttributeCertificate ac)
+ {
+ if (ac == null)
+ {
+ throw new IllegalArgumentException("VOMSAttribute: AttributeCertificate is NULL");
+ }
+
+ myAC = ac;
+
+ X509Attribute[] l = ac.getAttributes(VOMS_ATTR_OID);
+
+ if (l == null)
+ {
+ return;
+ }
+
+ try
+ {
+ for (int i = 0; i != l.length; i++)
+ {
+ IetfAttrSyntax attr = IetfAttrSyntax.getInstance(l[i].getValues()[0]);
+
+ // policyAuthority is on the format <vo>/<host>:<port>
+ String url = ((DERIA5String)attr.getPolicyAuthority().getNames()[0].getName()).getString();
+ int idx = url.indexOf("://");
+
+ if ((idx < 0) || (idx == (url.length() - 1)))
+ {
+ throw new IllegalArgumentException("Bad encoding of VOMS policyAuthority : [" + url + "]");
+ }
+
+ myVo = url.substring(0, idx);
+ myHostPort = url.substring(idx + 3);
+
+ if (attr.getValueType() != IetfAttrSyntax.VALUE_OCTETS)
+ {
+ throw new IllegalArgumentException(
+ "VOMS attribute values are not encoded as octet strings, policyAuthority = " + url);
+ }
+
+ ASN1OctetString[] values = (ASN1OctetString[])attr.getValues();
+ for (int j = 0; j != values.length; j++)
+ {
+ String fqan = new String(values[j].getOctets());
+ FQAN f = new FQAN(fqan);
+
+ if (!myStringList.contains(fqan) && fqan.startsWith("/" + myVo + "/"))
+ {
+ myStringList.add(fqan);
+ myFQANs.add(f);
+ }
+ }
+ }
+ }
+ catch (IllegalArgumentException ie)
+ {
+ throw ie;
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Badly encoded VOMS extension in AC issued by " +
+ ac.getIssuer());
+ }
+ }
+
+ /**
+ * @return The AttributeCertificate containing the VOMS information
+ */
+ public X509AttributeCertificate getAC()
+ {
+ return myAC;
+ }
+
+ /**
+ * @return List of String of the VOMS fully qualified
+ * attributes names (FQANs):<br>
+ * <code>/vo[/group[/group2...]][/Role=[role]][/Capability=capability]</code>
+ */
+ public List getFullyQualifiedAttributes()
+ {
+ return myStringList;
+ }
+
+ /**
+ * @return List of FQAN of the VOMS fully qualified
+ * attributes names (FQANs)
+ */
+ public List getListOfFQAN()
+ {
+ return myFQANs;
+ }
+
+ /**
+ * Returns the address of the issuing VOMS server, on the form <code>&lt;host&gt;:&lt;port&gt;</code>
+ * @return String
+ */
+ public String getHostPort()
+ {
+ return myHostPort;
+ }
+
+ /**
+ * Returns the VO name
+ * @return
+ */
+ public String getVO()
+ {
+ return myVo;
+ }
+
+ public String toString()
+ {
+ return "VO :" + myVo + "\n" + "HostPort:" + myHostPort + "\n" + "FQANs :" + myFQANs;
+ }
+
+ /**
+ * Inner class providing a container of the group,role,capability
+ * information triplet in an FQAN.
+ */
+ public class FQAN
+ {
+ String fqan;
+ String group;
+ String role;
+ String capability;
+
+ public FQAN(String fqan)
+ {
+ this.fqan = fqan;
+ }
+
+ public FQAN(String group, String role, String capability)
+ {
+ this.group = group;
+ this.role = role;
+ this.capability = capability;
+ }
+
+ public String getFQAN()
+ {
+ if (fqan != null)
+ {
+ return fqan;
+ }
+
+ fqan = group + "/Role=" + ((role != null) ? role : "") +
+ ((capability != null) ? ("/Capability=" + capability) : "");
+
+ return fqan;
+ }
+
+ protected void split()
+ {
+ int len = fqan.length();
+ int i = fqan.indexOf("/Role=");
+
+ if (i < 0)
+ {
+ return;
+ }
+
+ group = fqan.substring(0, i);
+
+ int j = fqan.indexOf("/Capability=", i + 6);
+ String s = (j < 0) ? fqan.substring(i + 6) : fqan.substring(i + 6, j);
+ role = (s.length() == 0) ? null : s;
+ s = (j < 0) ? null : fqan.substring(j + 12);
+ capability = ((s == null) || (s.length() == 0)) ? null : s;
+ }
+
+ public String getGroup()
+ {
+ if ((group == null) && (fqan != null))
+ {
+ split();
+ }
+
+ return group;
+ }
+
+ public String getRole()
+ {
+ if ((group == null) && (fqan != null))
+ {
+ split();
+ }
+
+ return role;
+ }
+
+ public String getCapability()
+ {
+ if ((group == null) && (fqan != null))
+ {
+ split();
+ }
+
+ return capability;
+ }
+
+ public String toString()
+ {
+ return getFQAN();
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/cmp/package.html b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/cmp/package.html
new file mode 100644
index 000000000..a58af189b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/cmp/package.html
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<body bgcolor="#ffffff">
+Basic support package for handling and creating CMP (RFC 4210) certificate management messages.
+</body>
+</html> \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/crmf/jcajce/package.html b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/crmf/jcajce/package.html
new file mode 100644
index 000000000..e9bc53fd7
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/crmf/jcajce/package.html
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<body bgcolor="#ffffff">
+JCA extensions to the CRMF online certificate request package.
+</body>
+</html> \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/crmf/package.html b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/crmf/package.html
new file mode 100644
index 000000000..521fc4406
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/crmf/package.html
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<body bgcolor="#ffffff">
+Basic support package for handling and creating CRMF (RFC 4211) certificate request messages.
+</body>
+</html> \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/jcajce/package.html b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/jcajce/package.html
new file mode 100644
index 000000000..cc15e01ab
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/jcajce/package.html
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<body bgcolor="#ffffff">
+JCA extensions to the certificate building and processing package.
+</body>
+</html> \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/ocsp/jcajce/package.html b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/ocsp/jcajce/package.html
new file mode 100644
index 000000000..cfe87f22a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/ocsp/jcajce/package.html
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<body bgcolor="#ffffff">
+JCA extensions to the OCSP online certificate status package.
+</body>
+</html> \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/ocsp/package.html b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/ocsp/package.html
new file mode 100644
index 000000000..234cb327e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/ocsp/package.html
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<body bgcolor="#ffffff">
+Basic support package for handling and creating OCSP (RFC 2560) online certificate status requests.
+</body>
+</html> \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/package.html b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/package.html
new file mode 100644
index 000000000..1b2a30530
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/package.html
@@ -0,0 +1,5 @@
+<html>
+<body bgcolor="#ffffff">
+Basic support package for handling and creating X.509 certificates, CRLs, and attribute certificates.
+</body>
+</html>
diff --git a/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/selector/package.html b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/selector/package.html
new file mode 100644
index 000000000..c5c421106
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cert/selector/package.html
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<body bgcolor="#ffffff">
+Specialised Selector classes for certificates, CRLs, and attribute certificates.
+</body>
+</html> \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cms/package.html b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cms/package.html
new file mode 100644
index 000000000..644e8620a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/cms/package.html
@@ -0,0 +1,5 @@
+<html>
+<body bgcolor="#ffffff">
+A package for processing RFC 3852 Cryptographic Message Syntax (CMS) objects - also referred to as PKCS#7 (formerly RFC 2630, 3369).
+</body>
+</html>
diff --git a/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/dvcs/package.html b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/dvcs/package.html
new file mode 100644
index 000000000..aecbd708f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/dvcs/package.html
@@ -0,0 +1,5 @@
+<html>
+<body bgcolor="#ffffff">
+Classes for dealing "Internet X.509 Public Key Infrastructure Data Validation and Certification Server Protocols" - RFC 3029.
+</body>
+</html>
diff --git a/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/eac/package.html b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/eac/package.html
new file mode 100644
index 000000000..97c41fa9a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/eac/package.html
@@ -0,0 +1,5 @@
+<html>
+<body bgcolor="#ffffff">
+Base classes Extended Access Control (EAC) Certificates as described in "Technical Guideline, Advanced Security Mechanisms for Machine Readable Travel Documents, Extended Access Control (EAC), Version 1.0.1, BSI 2006".
+</body>
+</html>
diff --git a/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/mozilla/package.html b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/mozilla/package.html
new file mode 100644
index 000000000..dd2203e40
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/mozilla/package.html
@@ -0,0 +1,5 @@
+<html>
+<body bgcolor="#ffffff">
+Support class for mozilla signed public key and challenge.
+</body>
+</html>
diff --git a/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/openssl/package.html b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/openssl/package.html
new file mode 100644
index 000000000..7e60a79ea
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/openssl/package.html
@@ -0,0 +1,5 @@
+<html>
+<body bgcolor="#ffffff">
+Classes for dealing with OpenSSL PEM files.
+</body>
+</html>
diff --git a/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/operator/package.html b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/operator/package.html
new file mode 100644
index 000000000..b64343adc
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/operator/package.html
@@ -0,0 +1,5 @@
+<html>
+<body bgcolor="#ffffff">
+Basic operators for doing encryption, signing, and digest operations.
+</body>
+</html>
diff --git a/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/pkcs/jcajce/package.html b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/pkcs/jcajce/package.html
new file mode 100644
index 000000000..9b10dc42f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/pkcs/jcajce/package.html
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<body bgcolor="#ffffff">
+JCA extensions to the PKCS#10 certification request package.
+</body>
+</html> \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/pkcs/package.html b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/pkcs/package.html
new file mode 100644
index 000000000..c83de7cfd
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/pkcs/package.html
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<body bgcolor="#ffffff">
+Basic support package for handling and creating PKCS#10 certification requests, PKCS#8 encrypted keys and PKCS#12 keys stores.
+</body>
+</html> \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/tsp/cms/package.html b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/tsp/cms/package.html
new file mode 100644
index 000000000..2cf1bacee
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/tsp/cms/package.html
@@ -0,0 +1,5 @@
+<html>
+<body bgcolor="#ffffff">
+Classes for dealing Syntax for Binding Documents with Time-Stamps - RFC 5544.
+</body>
+</html>
diff --git a/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/tsp/package.html b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/tsp/package.html
new file mode 100644
index 000000000..45d0c3c3f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/javadoc/org/spongycastle/tsp/package.html
@@ -0,0 +1,5 @@
+<html>
+<body bgcolor="#ffffff">
+Classes for dealing Time Stamp Protocol (TSP) - RFC 3161.
+</body>
+</html>
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/cmp/GeneralPKIMessage.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/cmp/GeneralPKIMessage.java
new file mode 100644
index 000000000..2f74fe551
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/cmp/GeneralPKIMessage.java
@@ -0,0 +1,82 @@
+package org.spongycastle.cert.cmp;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.cmp.PKIBody;
+import org.spongycastle.asn1.cmp.PKIHeader;
+import org.spongycastle.asn1.cmp.PKIMessage;
+import org.spongycastle.cert.CertIOException;
+
+/**
+ * General wrapper for a generic PKIMessage
+ */
+public class GeneralPKIMessage
+{
+ private PKIMessage pkiMessage;
+
+ private static PKIMessage parseBytes(byte[] encoding)
+ throws IOException
+ {
+ try
+ {
+ return PKIMessage.getInstance(ASN1Primitive.fromByteArray(encoding));
+ }
+ catch (ClassCastException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Create a PKIMessage from the passed in bytes.
+ *
+ * @param encoding BER/DER encoding of the PKIMessage
+ * @throws IOException in the event of corrupted data, or an incorrect structure.
+ */
+ public GeneralPKIMessage(byte[] encoding)
+ throws IOException
+ {
+ this(parseBytes(encoding));
+ }
+
+ /**
+ * Wrap a PKIMessage ASN.1 structure.
+ *
+ * @param pkiMessage base PKI message.
+ */
+ public GeneralPKIMessage(PKIMessage pkiMessage)
+ {
+ this.pkiMessage = pkiMessage;
+ }
+
+ public PKIHeader getHeader()
+ {
+ return pkiMessage.getHeader();
+ }
+
+ public PKIBody getBody()
+ {
+ return pkiMessage.getBody();
+ }
+
+ /**
+ * Return true if this message has protection bits on it. A return value of true
+ * indicates the message can be used to construct a ProtectedPKIMessage.
+ *
+ * @return true if message has protection, false otherwise.
+ */
+ public boolean hasProtection()
+ {
+ return pkiMessage.getHeader().getProtectionAlg() != null;
+ }
+
+ public PKIMessage toASN1Structure()
+ {
+ return pkiMessage;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/CertificateRequestMessage.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/CertificateRequestMessage.java
new file mode 100644
index 000000000..6f582812b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/CertificateRequestMessage.java
@@ -0,0 +1,309 @@
+package org.spongycastle.cert.crmf;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERUTF8String;
+import org.spongycastle.asn1.crmf.AttributeTypeAndValue;
+import org.spongycastle.asn1.crmf.CRMFObjectIdentifiers;
+import org.spongycastle.asn1.crmf.CertReqMsg;
+import org.spongycastle.asn1.crmf.CertTemplate;
+import org.spongycastle.asn1.crmf.Controls;
+import org.spongycastle.asn1.crmf.PKIArchiveOptions;
+import org.spongycastle.asn1.crmf.PKMACValue;
+import org.spongycastle.asn1.crmf.POPOSigningKey;
+import org.spongycastle.asn1.crmf.ProofOfPossession;
+import org.spongycastle.cert.CertIOException;
+import org.spongycastle.operator.ContentVerifier;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.OperatorCreationException;
+
+/**
+ * Carrier for a CRMF CertReqMsg.
+ */
+public class CertificateRequestMessage
+{
+ public static final int popRaVerified = ProofOfPossession.TYPE_RA_VERIFIED;
+ public static final int popSigningKey = ProofOfPossession.TYPE_SIGNING_KEY;
+ public static final int popKeyEncipherment = ProofOfPossession.TYPE_KEY_ENCIPHERMENT;
+ public static final int popKeyAgreement = ProofOfPossession.TYPE_KEY_AGREEMENT;
+
+ private CertReqMsg certReqMsg;
+ private Controls controls;
+
+ private static CertReqMsg parseBytes(byte[] encoding)
+ throws IOException
+ {
+ try
+ {
+ return CertReqMsg.getInstance(ASN1Primitive.fromByteArray(encoding));
+ }
+ catch (ClassCastException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new CertIOException("malformed data: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Create a CertificateRequestMessage from the passed in bytes.
+ *
+ * @param certReqMsg BER/DER encoding of the CertReqMsg structure.
+ * @throws IOException in the event of corrupted data, or an incorrect structure.
+ */
+ public CertificateRequestMessage(byte[] certReqMsg)
+ throws IOException
+ {
+ this(parseBytes(certReqMsg));
+ }
+
+ public CertificateRequestMessage(CertReqMsg certReqMsg)
+ {
+ this.certReqMsg = certReqMsg;
+ this.controls = certReqMsg.getCertReq().getControls();
+ }
+
+ /**
+ * Return the underlying ASN.1 object defining this CertificateRequestMessage object.
+ *
+ * @return a CertReqMsg.
+ */
+ public CertReqMsg toASN1Structure()
+ {
+ return certReqMsg;
+ }
+
+ /**
+ * Return the certificate template contained in this message.
+ *
+ * @return a CertTemplate structure.
+ */
+ public CertTemplate getCertTemplate()
+ {
+ return this.certReqMsg.getCertReq().getCertTemplate();
+ }
+
+ /**
+ * Return whether or not this request has control values associated with it.
+ *
+ * @return true if there are control values present, false otherwise.
+ */
+ public boolean hasControls()
+ {
+ return controls != null;
+ }
+
+ /**
+ * Return whether or not this request has a specific type of control value.
+ *
+ * @param type the type OID for the control value we are checking for.
+ * @return true if a control value of type is present, false otherwise.
+ */
+ public boolean hasControl(ASN1ObjectIdentifier type)
+ {
+ return findControl(type) != null;
+ }
+
+ /**
+ * Return a control value of the specified type.
+ *
+ * @param type the type OID for the control value we are checking for.
+ * @return the control value if present, null otherwise.
+ */
+ public Control getControl(ASN1ObjectIdentifier type)
+ {
+ AttributeTypeAndValue found = findControl(type);
+
+ if (found != null)
+ {
+ if (found.getType().equals(CRMFObjectIdentifiers.id_regCtrl_pkiArchiveOptions))
+ {
+ return new PKIArchiveControl(PKIArchiveOptions.getInstance(found.getValue()));
+ }
+ if (found.getType().equals(CRMFObjectIdentifiers.id_regCtrl_regToken))
+ {
+ return new RegTokenControl(DERUTF8String.getInstance(found.getValue()));
+ }
+ if (found.getType().equals(CRMFObjectIdentifiers.id_regCtrl_authenticator))
+ {
+ return new AuthenticatorControl(DERUTF8String.getInstance(found.getValue()));
+ }
+ }
+
+ return null;
+ }
+
+ private AttributeTypeAndValue findControl(ASN1ObjectIdentifier type)
+ {
+ if (controls == null)
+ {
+ return null;
+ }
+
+ AttributeTypeAndValue[] tAndVs = controls.toAttributeTypeAndValueArray();
+ AttributeTypeAndValue found = null;
+
+ for (int i = 0; i != tAndVs.length; i++)
+ {
+ if (tAndVs[i].getType().equals(type))
+ {
+ found = tAndVs[i];
+ break;
+ }
+ }
+
+ return found;
+ }
+
+ /**
+ * Return whether or not this request message has a proof-of-possession field in it.
+ *
+ * @return true if proof-of-possession is present, false otherwise.
+ */
+ public boolean hasProofOfPossession()
+ {
+ return this.certReqMsg.getPopo() != null;
+ }
+
+ /**
+ * Return the type of the proof-of-possession this request message provides.
+ *
+ * @return one of: popRaVerified, popSigningKey, popKeyEncipherment, popKeyAgreement
+ */
+ public int getProofOfPossessionType()
+ {
+ return this.certReqMsg.getPopo().getType();
+ }
+
+ /**
+ * Return whether or not the proof-of-possession (POP) is of the type popSigningKey and
+ * it has a public key MAC associated with it.
+ *
+ * @return true if POP is popSigningKey and a PKMAC is present, false otherwise.
+ */
+ public boolean hasSigningKeyProofOfPossessionWithPKMAC()
+ {
+ ProofOfPossession pop = certReqMsg.getPopo();
+
+ if (pop.getType() == popSigningKey)
+ {
+ POPOSigningKey popoSign = POPOSigningKey.getInstance(pop.getObject());
+
+ return popoSign.getPoposkInput().getPublicKeyMAC() != null;
+ }
+
+ return false;
+ }
+
+ /**
+ * Return whether or not a signing key proof-of-possession (POP) is valid.
+ *
+ * @param verifierProvider a provider that can produce content verifiers for the signature contained in this POP.
+ * @return true if the POP is valid, false otherwise.
+ * @throws CRMFException if there is a problem in verification or content verifier creation.
+ * @throws IllegalStateException if POP not appropriate.
+ */
+ public boolean isValidSigningKeyPOP(ContentVerifierProvider verifierProvider)
+ throws CRMFException, IllegalStateException
+ {
+ ProofOfPossession pop = certReqMsg.getPopo();
+
+ if (pop.getType() == popSigningKey)
+ {
+ POPOSigningKey popoSign = POPOSigningKey.getInstance(pop.getObject());
+
+ if (popoSign.getPoposkInput() != null && popoSign.getPoposkInput().getPublicKeyMAC() != null)
+ {
+ throw new IllegalStateException("verification requires password check");
+ }
+
+ return verifySignature(verifierProvider, popoSign);
+ }
+ else
+ {
+ throw new IllegalStateException("not Signing Key type of proof of possession");
+ }
+ }
+
+ /**
+ * Return whether or not a signing key proof-of-possession (POP), with an associated PKMAC, is valid.
+ *
+ * @param verifierProvider a provider that can produce content verifiers for the signature contained in this POP.
+ * @param macBuilder a suitable PKMACBuilder to create the MAC verifier.
+ * @param password the password used to key the MAC calculation.
+ * @return true if the POP is valid, false otherwise.
+ * @throws CRMFException if there is a problem in verification or content verifier creation.
+ * @throws IllegalStateException if POP not appropriate.
+ */
+ public boolean isValidSigningKeyPOP(ContentVerifierProvider verifierProvider, PKMACBuilder macBuilder, char[] password)
+ throws CRMFException, IllegalStateException
+ {
+ ProofOfPossession pop = certReqMsg.getPopo();
+
+ if (pop.getType() == popSigningKey)
+ {
+ POPOSigningKey popoSign = POPOSigningKey.getInstance(pop.getObject());
+
+ if (popoSign.getPoposkInput() == null || popoSign.getPoposkInput().getSender() != null)
+ {
+ throw new IllegalStateException("no PKMAC present in proof of possession");
+ }
+
+ PKMACValue pkMAC = popoSign.getPoposkInput().getPublicKeyMAC();
+ PKMACValueVerifier macVerifier = new PKMACValueVerifier(macBuilder);
+
+ if (macVerifier.isValid(pkMAC, password, this.getCertTemplate().getPublicKey()))
+ {
+ return verifySignature(verifierProvider, popoSign);
+ }
+
+ return false;
+ }
+ else
+ {
+ throw new IllegalStateException("not Signing Key type of proof of possession");
+ }
+ }
+
+ private boolean verifySignature(ContentVerifierProvider verifierProvider, POPOSigningKey popoSign)
+ throws CRMFException
+ {
+ ContentVerifier verifier;
+
+ try
+ {
+ verifier = verifierProvider.get(popoSign.getAlgorithmIdentifier());
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new CRMFException("unable to create verifier: " + e.getMessage(), e);
+ }
+
+ if (popoSign.getPoposkInput() != null)
+ {
+ CRMFUtil.derEncodeToStream(popoSign.getPoposkInput(), verifier.getOutputStream());
+ }
+ else
+ {
+ CRMFUtil.derEncodeToStream(certReqMsg.getCertReq(), verifier.getOutputStream());
+ }
+
+ return verifier.verify(popoSign.getSignature().getBytes());
+ }
+
+ /**
+ * Return the ASN.1 encoding of the certReqMsg we wrap.
+ *
+ * @return a byte array containing the binary encoding of the certReqMsg.
+ * @throws IOException if there is an exception creating the encoding.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return certReqMsg.getEncoded();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/FixedLengthMGF1Padder.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/FixedLengthMGF1Padder.java
new file mode 100644
index 000000000..cfb33d62e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/FixedLengthMGF1Padder.java
@@ -0,0 +1,120 @@
+package org.spongycastle.cert.crmf;
+
+import java.security.SecureRandom;
+
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.generators.MGF1BytesGenerator;
+import org.spongycastle.crypto.params.MGFParameters;
+
+/**
+ * An encrypted value padder that uses MGF1 as the basis of the padding.
+ */
+public class FixedLengthMGF1Padder
+ implements EncryptedValuePadder
+{
+ private int length;
+ private SecureRandom random;
+ private Digest dig = new SHA1Digest();
+
+ /**
+ * Create a padder to so that padded output will always be at least
+ * length bytes long.
+ *
+ * @param length fixed length for padded output.
+ */
+ public FixedLengthMGF1Padder(int length)
+ {
+ this(length, null);
+ }
+
+ /**
+ * Create a padder to so that padded output will always be at least
+ * length bytes long, using the passed in source of randomness to
+ * provide the random material for the padder.
+ *
+ * @param length fixed length for padded output.
+ * @param random a source of randomness.
+ */
+ public FixedLengthMGF1Padder(int length, SecureRandom random)
+ {
+ this.length = length;
+ this.random = random;
+ }
+
+ public byte[] getPaddedData(byte[] data)
+ {
+ byte[] bytes = new byte[length];
+ byte[] seed = new byte[dig.getDigestSize()];
+ byte[] mask = new byte[length - dig.getDigestSize()];
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(seed);
+
+ MGF1BytesGenerator maskGen = new MGF1BytesGenerator(dig);
+
+ maskGen.init(new MGFParameters(seed));
+
+ maskGen.generateBytes(mask, 0, mask.length);
+
+ System.arraycopy(seed, 0, bytes, 0, seed.length);
+ System.arraycopy(data, 0, bytes, seed.length, data.length);
+
+ for (int i = seed.length + data.length + 1; i != bytes.length; i++)
+ {
+ bytes[i] = (byte)(1 + Math.abs(random.nextInt()) % 254);
+ }
+
+ for (int i = 0; i != mask.length; i++)
+ {
+ bytes[i + seed.length] ^= mask[i];
+ }
+
+ return bytes;
+ }
+
+ public byte[] getUnpaddedData(byte[] paddedData)
+ {
+ byte[] seed = new byte[dig.getDigestSize()];
+ byte[] mask = new byte[length - dig.getDigestSize()];
+
+ System.arraycopy(paddedData, 0, seed, 0, seed.length);
+
+ MGF1BytesGenerator maskGen = new MGF1BytesGenerator(dig);
+
+ maskGen.init(new MGFParameters(seed));
+
+ maskGen.generateBytes(mask, 0, mask.length);
+
+ for (int i = 0; i != mask.length; i++)
+ {
+ paddedData[i + seed.length] ^= mask[i];
+ }
+
+ int end = 0;
+
+ for (int i = paddedData.length - 1; i != seed.length; i--)
+ {
+ if (paddedData[i] == 0)
+ {
+ end = i;
+ break;
+ }
+ }
+
+ if (end == 0)
+ {
+ throw new IllegalStateException("bad padding in encoding");
+ }
+
+ byte[] data = new byte[end - seed.length];
+
+ System.arraycopy(paddedData, seed.length, data, 0, data.length);
+
+ return data;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/jcajce/CRMFHelper.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/jcajce/CRMFHelper.java
new file mode 100644
index 000000000..c11e55f0d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/jcajce/CRMFHelper.java
@@ -0,0 +1,485 @@
+package org.spongycastle.cert.crmf.jcajce;
+
+import java.io.IOException;
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Null;
+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.iana.IANAObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.cert.crmf.CRMFException;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSEnvelopedDataGenerator;
+import org.spongycastle.jcajce.JcaJceHelper;
+
+class CRMFHelper
+{
+ protected static final Map BASE_CIPHER_NAMES = new HashMap();
+ protected static final Map CIPHER_ALG_NAMES = new HashMap();
+ protected static final Map DIGEST_ALG_NAMES = new HashMap();
+ protected static final Map KEY_ALG_NAMES = new HashMap();
+ protected static final Map MAC_ALG_NAMES = new HashMap();
+
+ static
+ {
+ BASE_CIPHER_NAMES.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESEDE");
+ BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes128_CBC, "AES");
+ BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes192_CBC, "AES");
+ BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes256_CBC, "AES");
+
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, "AES/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AES/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AES/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(new ASN1ObjectIdentifier(PKCSObjectIdentifiers.rsaEncryption.getId()), "RSA/ECB/PKCS1Padding");
+
+ DIGEST_ALG_NAMES.put(OIWObjectIdentifiers.idSHA1, "SHA1");
+ DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha224, "SHA224");
+ DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha256, "SHA256");
+ DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha384, "SHA384");
+ DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha512, "SHA512");
+
+ MAC_ALG_NAMES.put(IANAObjectIdentifiers.hmacSHA1, "HMACSHA1");
+ MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA1, "HMACSHA1");
+ MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA224, "HMACSHA224");
+ MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA256, "HMACSHA256");
+ MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA384, "HMACSHA384");
+ MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA512, "HMACSHA512");
+
+ KEY_ALG_NAMES.put(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ KEY_ALG_NAMES.put(X9ObjectIdentifiers.id_dsa, "DSA");
+ }
+
+ private JcaJceHelper helper;
+
+ CRMFHelper(JcaJceHelper helper)
+ {
+ this.helper = helper;
+ }
+
+ PublicKey toPublicKey(SubjectPublicKeyInfo subjectPublicKeyInfo)
+ throws CRMFException
+ {
+
+ try
+ {
+ X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString(subjectPublicKeyInfo).getBytes());
+ AlgorithmIdentifier keyAlg = subjectPublicKeyInfo.getAlgorithmId();
+ return createKeyFactory(keyAlg.getAlgorithm()).generatePublic(xspec);
+ }
+ catch (IOException e)
+ {
+ throw new CRMFException("invalid key: " + e.getMessage(), e);
+ }
+ catch (InvalidKeySpecException e)
+ {
+ throw new CRMFException("invalid key: " + e.getMessage(), e);
+ }
+ }
+
+ Cipher createCipher(ASN1ObjectIdentifier algorithm)
+ throws CRMFException
+ {
+ try
+ {
+ String cipherName = (String)CIPHER_ALG_NAMES.get(algorithm);
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createCipher(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createCipher(algorithm.getId());
+ }
+ catch (NoSuchPaddingException e)
+ {
+ throw new CRMFException("cannot create cipher: " + e.getMessage(), e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new CRMFException("cannot create cipher: " + e.getMessage(), e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new CRMFException("cannot create cipher: " + e.getMessage(), e);
+ }
+ }
+
+ public KeyGenerator createKeyGenerator(ASN1ObjectIdentifier algorithm)
+ throws CRMFException
+ {
+ try
+ {
+ String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createKeyGenerator(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createKeyGenerator(algorithm.getId());
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new CRMFException("cannot create key generator: " + e.getMessage(), e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new CRMFException("cannot create key generator: " + e.getMessage(), e);
+ }
+ }
+
+ Cipher createContentCipher(final Key sKey, final AlgorithmIdentifier encryptionAlgID)
+ throws CRMFException
+ {
+ return (Cipher)execute(new JCECallback()
+ {
+ public Object doInJCE()
+ throws CRMFException, InvalidAlgorithmParameterException,
+ InvalidKeyException, InvalidParameterSpecException, NoSuchAlgorithmException,
+ NoSuchPaddingException, NoSuchProviderException
+ {
+ Cipher cipher = createCipher(encryptionAlgID.getAlgorithm());
+ ASN1Primitive sParams = (ASN1Primitive)encryptionAlgID.getParameters();
+ String encAlg = encryptionAlgID.getAlgorithm().getId();
+
+ if (sParams != null && !(sParams instanceof ASN1Null))
+ {
+ try
+ {
+ AlgorithmParameters params = createAlgorithmParameters(encryptionAlgID.getAlgorithm());
+
+ try
+ {
+ params.init(sParams.getEncoded(), "ASN.1");
+ }
+ catch (IOException e)
+ {
+ throw new CRMFException("error decoding algorithm parameters.", e);
+ }
+
+ cipher.init(Cipher.DECRYPT_MODE, sKey, params);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ if (encAlg.equals(CMSEnvelopedDataGenerator.DES_EDE3_CBC)
+ || encAlg.equals(CMSEnvelopedDataGenerator.IDEA_CBC)
+ || encAlg.equals(CMSEnvelopedDataGenerator.AES128_CBC)
+ || encAlg.equals(CMSEnvelopedDataGenerator.AES192_CBC)
+ || encAlg.equals(CMSEnvelopedDataGenerator.AES256_CBC))
+ {
+ cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec(
+ ASN1OctetString.getInstance(sParams).getOctets()));
+ }
+ else
+ {
+ throw e;
+ }
+ }
+ }
+ else
+ {
+ if (encAlg.equals(CMSEnvelopedDataGenerator.DES_EDE3_CBC)
+ || encAlg.equals(CMSEnvelopedDataGenerator.IDEA_CBC)
+ || encAlg.equals(CMSEnvelopedDataGenerator.CAST5_CBC))
+ {
+ cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec(new byte[8]));
+ }
+ else
+ {
+ cipher.init(Cipher.DECRYPT_MODE, sKey);
+ }
+ }
+
+ return cipher;
+ }
+ });
+ }
+
+ AlgorithmParameters createAlgorithmParameters(ASN1ObjectIdentifier algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (algorithmName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createAlgorithmParameters(algorithmName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createAlgorithmParameters(algorithm.getId());
+ }
+
+ KeyFactory createKeyFactory(ASN1ObjectIdentifier algorithm)
+ throws CRMFException
+ {
+ try
+ {
+ String algName = (String)KEY_ALG_NAMES.get(algorithm);
+
+ if (algName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createKeyFactory(algName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createKeyFactory(algorithm.getId());
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new CRMFException("cannot create cipher: " + e.getMessage(), e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new CRMFException("cannot create cipher: " + e.getMessage(), e);
+ }
+ }
+
+ MessageDigest createDigest(ASN1ObjectIdentifier algorithm)
+ throws CRMFException
+ {
+ try
+ {
+ String digestName = (String)DIGEST_ALG_NAMES.get(algorithm);
+
+ if (digestName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createDigest(digestName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createDigest(algorithm.getId());
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new CRMFException("cannot create cipher: " + e.getMessage(), e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new CRMFException("cannot create cipher: " + e.getMessage(), e);
+ }
+ }
+
+ Mac createMac(ASN1ObjectIdentifier algorithm)
+ throws CRMFException
+ {
+ try
+ {
+ String macName = (String)MAC_ALG_NAMES.get(algorithm);
+
+ if (macName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createMac(macName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createMac(algorithm.getId());
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new CRMFException("cannot create mac: " + e.getMessage(), e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new CRMFException("cannot create mac: " + e.getMessage(), e);
+ }
+ }
+
+ AlgorithmParameterGenerator createAlgorithmParameterGenerator(ASN1ObjectIdentifier algorithm)
+ throws GeneralSecurityException
+ {
+ String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ try
+ {
+ if (algorithmName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createAlgorithmParameterGenerator(algorithmName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createAlgorithmParameterGenerator(algorithm.getId());
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new GeneralSecurityException(e.toString());
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new GeneralSecurityException(e.toString());
+ }
+ }
+
+ AlgorithmParameters generateParameters(ASN1ObjectIdentifier encryptionOID, SecretKey encKey, SecureRandom rand)
+ throws CRMFException
+ {
+ try
+ {
+ AlgorithmParameterGenerator pGen = createAlgorithmParameterGenerator(encryptionOID);
+
+ if (encryptionOID.equals(CMSEnvelopedDataGenerator.RC2_CBC))
+ {
+ byte[] iv = new byte[8];
+
+ rand.nextBytes(iv);
+
+ try
+ {
+ pGen.init(new RC2ParameterSpec(encKey.getEncoded().length * 8, iv), rand);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new CRMFException("parameters generation error: " + e, e);
+ }
+ }
+
+ return pGen.generateParameters();
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CRMFException("exception creating algorithm parameter generator: " + e, e);
+ }
+ }
+
+ AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier encryptionOID, AlgorithmParameters params)
+ throws CRMFException
+ {
+ ASN1Encodable asn1Params;
+ if (params != null)
+ {
+ try
+ {
+ asn1Params = ASN1Primitive.fromByteArray(params.getEncoded("ASN.1"));
+ }
+ catch (IOException e)
+ {
+ throw new CRMFException("cannot encode parameters: " + e.getMessage(), e);
+ }
+ }
+ else
+ {
+ asn1Params = DERNull.INSTANCE;
+ }
+
+ return new AlgorithmIdentifier(
+ encryptionOID,
+ asn1Params);
+ }
+
+ static Object execute(JCECallback callback) throws CRMFException
+ {
+ try
+ {
+ return callback.doInJCE();
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new CRMFException("can't find algorithm.", e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CRMFException("key invalid in message.", e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new CRMFException("can't find provider.", e);
+ }
+ catch (NoSuchPaddingException e)
+ {
+ throw new CRMFException("required padding not supported.", e);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new CRMFException("algorithm parameters invalid.", e);
+ }
+ catch (InvalidParameterSpecException e)
+ {
+ throw new CRMFException("MAC algorithm parameter spec invalid.", e);
+ }
+ }
+
+ static interface JCECallback
+ {
+ Object doInJCE()
+ throws CRMFException, InvalidAlgorithmParameterException, InvalidKeyException, InvalidParameterSpecException,
+ NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/jcajce/JceAsymmetricValueDecryptorGenerator.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/jcajce/JceAsymmetricValueDecryptorGenerator.java
new file mode 100644
index 000000000..e06e249fa
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/jcajce/JceAsymmetricValueDecryptorGenerator.java
@@ -0,0 +1,121 @@
+package org.spongycastle.cert.crmf.jcajce;
+
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.ProviderException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.crmf.CRMFException;
+import org.spongycastle.cert.crmf.ValueDecryptorGenerator;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.InputDecryptor;
+
+public class JceAsymmetricValueDecryptorGenerator
+ implements ValueDecryptorGenerator
+{
+ private PrivateKey recipientKey;
+ private CRMFHelper helper = new CRMFHelper(new DefaultJcaJceHelper());
+
+ public JceAsymmetricValueDecryptorGenerator(PrivateKey recipientKey)
+ {
+ this.recipientKey = recipientKey;
+ }
+
+ public JceAsymmetricValueDecryptorGenerator setProvider(Provider provider)
+ {
+ this.helper = new CRMFHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JceAsymmetricValueDecryptorGenerator setProvider(String providerName)
+ {
+ this.helper = new CRMFHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ private Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey)
+ throws CRMFException
+ {
+ try
+ {
+ Key sKey = null;
+
+ Cipher keyCipher = helper.createCipher(keyEncryptionAlgorithm.getAlgorithm());
+
+ try
+ {
+ keyCipher.init(Cipher.UNWRAP_MODE, recipientKey);
+ sKey = keyCipher.unwrap(encryptedContentEncryptionKey, contentEncryptionAlgorithm.getAlgorithm().getId(), Cipher.SECRET_KEY);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ }
+ catch (IllegalStateException e)
+ {
+ }
+ catch (UnsupportedOperationException e)
+ {
+ }
+ catch (ProviderException e)
+ {
+ }
+
+ // some providers do not support UNWRAP (this appears to be only for asymmetric algorithms)
+ if (sKey == null)
+ {
+ keyCipher.init(Cipher.DECRYPT_MODE, recipientKey);
+ sKey = new SecretKeySpec(keyCipher.doFinal(encryptedContentEncryptionKey), contentEncryptionAlgorithm.getAlgorithm().getId());
+ }
+
+ return sKey;
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CRMFException("key invalid in message.", e);
+ }
+ catch (IllegalBlockSizeException e)
+ {
+ throw new CRMFException("illegal blocksize in message.", e);
+ }
+ catch (BadPaddingException e)
+ {
+ throw new CRMFException("bad padding in message.", e);
+ }
+ }
+
+ public InputDecryptor getValueDecryptor(AlgorithmIdentifier keyEncryptionAlgorithm, final AlgorithmIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey)
+ throws CRMFException
+ {
+ Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentEncryptionAlgorithm, encryptedContentEncryptionKey);
+
+ final Cipher dataCipher = helper.createContentCipher(secretKey, contentEncryptionAlgorithm);
+
+ return new InputDecryptor()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return contentEncryptionAlgorithm;
+ }
+
+ public InputStream getInputStream(InputStream dataIn)
+ {
+ return new CipherInputStream(dataIn, dataCipher);
+ }
+ };
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/jcajce/JceCRMFEncryptorBuilder.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/jcajce/JceCRMFEncryptorBuilder.java
new file mode 100644
index 000000000..6b8e0d2ac
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/jcajce/JceCRMFEncryptorBuilder.java
@@ -0,0 +1,140 @@
+package org.spongycastle.cert.crmf.jcajce;
+
+import java.io.OutputStream;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.InvalidKeyException;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.crmf.CRMFException;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OutputEncryptor;
+
+public class JceCRMFEncryptorBuilder
+{
+ private ASN1ObjectIdentifier encryptionOID;
+ private int keySize;
+
+ private CRMFHelper helper = new CRMFHelper(new DefaultJcaJceHelper());
+ private SecureRandom random;
+
+ public JceCRMFEncryptorBuilder(ASN1ObjectIdentifier encryptionOID)
+ {
+ this(encryptionOID, -1);
+ }
+
+ public JceCRMFEncryptorBuilder(ASN1ObjectIdentifier encryptionOID, int keySize)
+ {
+ this.encryptionOID = encryptionOID;
+ this.keySize = keySize;
+ }
+
+ public JceCRMFEncryptorBuilder setProvider(Provider provider)
+ {
+ this.helper = new CRMFHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JceCRMFEncryptorBuilder setProvider(String providerName)
+ {
+ this.helper = new CRMFHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public JceCRMFEncryptorBuilder setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public OutputEncryptor build()
+ throws CRMFException
+ {
+ return new CRMFOutputEncryptor(encryptionOID, keySize, random);
+ }
+
+ private class CRMFOutputEncryptor
+ implements OutputEncryptor
+ {
+ private SecretKey encKey;
+ private AlgorithmIdentifier algorithmIdentifier;
+ private Cipher cipher;
+
+ CRMFOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, SecureRandom random)
+ throws CRMFException
+ {
+ KeyGenerator keyGen = helper.createKeyGenerator(encryptionOID);
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ if (keySize < 0)
+ {
+ keyGen.init(random);
+ }
+ else
+ {
+ keyGen.init(keySize, random);
+ }
+
+ cipher = helper.createCipher(encryptionOID);
+ encKey = keyGen.generateKey();
+ AlgorithmParameters params = helper.generateParameters(encryptionOID, encKey, random);
+
+ try
+ {
+ cipher.init(Cipher.ENCRYPT_MODE, encKey, params, random);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CRMFException("unable to initialize cipher: " + e.getMessage(), e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CRMFException("unable to initialize cipher: " + e.getMessage(), e);
+ }
+
+ //
+ // If params are null we try and second guess on them as some providers don't provide
+ // algorithm parameter generation explicity but instead generate them under the hood.
+ //
+ if (params == null)
+ {
+ params = cipher.getParameters();
+ }
+
+ algorithmIdentifier = helper.getAlgorithmIdentifier(encryptionOID, params);
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmIdentifier;
+ }
+
+ public OutputStream getOutputStream(OutputStream dOut)
+ {
+ return new CipherOutputStream(dOut, cipher);
+ }
+
+ public GenericKey getKey()
+ {
+ return new GenericKey(encKey);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/jcajce/JcePKMACValuesCalculator.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/jcajce/JcePKMACValuesCalculator.java
new file mode 100644
index 000000000..4aaff8618
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/crmf/jcajce/JcePKMACValuesCalculator.java
@@ -0,0 +1,70 @@
+package org.spongycastle.cert.crmf.jcajce;
+
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.security.Provider;
+import java.security.InvalidKeyException;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.crmf.CRMFException;
+import org.spongycastle.cert.crmf.PKMACValuesCalculator;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+
+public class JcePKMACValuesCalculator
+ implements PKMACValuesCalculator
+{
+ private MessageDigest digest;
+ private Mac mac;
+ private CRMFHelper helper;
+
+ public JcePKMACValuesCalculator()
+ {
+ this.helper = new CRMFHelper(new DefaultJcaJceHelper());
+ }
+
+ public JcePKMACValuesCalculator setProvider(Provider provider)
+ {
+ this.helper = new CRMFHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JcePKMACValuesCalculator setProvider(String providerName)
+ {
+ this.helper = new CRMFHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public void setup(AlgorithmIdentifier digAlg, AlgorithmIdentifier macAlg)
+ throws CRMFException
+ {
+ digest = helper.createDigest(digAlg.getAlgorithm());
+ mac = helper.createMac(macAlg.getAlgorithm());
+ }
+
+ public byte[] calculateDigest(byte[] data)
+ {
+ return digest.digest(data);
+ }
+
+ public byte[] calculateMac(byte[] pwd, byte[] data)
+ throws CRMFException
+ {
+ try
+ {
+ mac.init(new SecretKeySpec(pwd, mac.getAlgorithm()));
+
+ return mac.doFinal(data);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CRMFException("failure in setup: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/jcajce/JcaCertStoreBuilder.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/jcajce/JcaCertStoreBuilder.java
new file mode 100644
index 000000000..63b14ff7b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/jcajce/JcaCertStoreBuilder.java
@@ -0,0 +1,149 @@
+package org.spongycastle.cert.jcajce;
+
+import java.security.GeneralSecurityException;
+import java.security.Provider;
+import java.security.NoSuchProviderException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CRLException;
+import java.security.cert.CertStore;
+import java.security.cert.CertificateException;
+import java.security.cert.CollectionCertStoreParameters;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.cert.X509CRLHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.util.Store;
+
+/**
+ * Builder to create a CertStore from certificate and CRL stores.
+ */
+public class JcaCertStoreBuilder
+{
+ private List certs = new ArrayList();
+ private List crls = new ArrayList();
+ private Object provider;
+ private JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter();
+ private JcaX509CRLConverter crlConverter = new JcaX509CRLConverter();
+
+ /**
+ * Add a store full of X509CertificateHolder objects.
+ *
+ * @param certStore a store of X509CertificateHolder objects.
+ */
+ public JcaCertStoreBuilder addCertificates(Store certStore)
+ {
+ certs.addAll(certStore.getMatches(null));
+
+ return this;
+ }
+
+ /**
+ * Add a single certificate.
+ *
+ * @param cert the X509 certificate holder containing the certificate.
+ */
+ public JcaCertStoreBuilder addCertificate(X509CertificateHolder cert)
+ {
+ certs.add(cert);
+
+ return this;
+ }
+
+ /**
+ * Add a store full of X509CRLHolder objects.
+ * @param crlStore a store of X509CRLHolder objects.
+ */
+ public JcaCertStoreBuilder addCRLs(Store crlStore)
+ {
+ crls.addAll(crlStore.getMatches(null));
+
+ return this;
+ }
+
+ /**
+ * Add a single CRL.
+ *
+ * @param crl the X509 CRL holder containing the CRL.
+ */
+ public JcaCertStoreBuilder addCRL(X509CRLHolder crl)
+ {
+ crls.add(crl);
+
+ return this;
+ }
+
+ public JcaCertStoreBuilder setProvider(String providerName)
+ throws GeneralSecurityException
+ {
+ certificateConverter.setProvider(providerName);
+ crlConverter.setProvider(providerName);
+ this.provider = providerName;
+
+ return this;
+ }
+
+ public JcaCertStoreBuilder setProvider(Provider provider)
+ throws GeneralSecurityException
+ {
+ certificateConverter.setProvider(provider);
+ crlConverter.setProvider(provider);
+ this.provider = provider;
+
+ return this;
+ }
+
+ /**
+ * Build the CertStore from the current inputs.
+ *
+ * @return a CertStore.
+ * @throws GeneralSecurityException
+ */
+ public CertStore build()
+ throws GeneralSecurityException
+ {
+ CollectionCertStoreParameters params = convertHolders(certificateConverter, crlConverter);
+
+ try
+{
+ if (provider instanceof String)
+ {
+ return CertStore.getInstance("Collection", params, (String)provider);
+ }
+
+ if (provider instanceof Provider)
+ {
+ return CertStore.getInstance("Collection", params, (Provider)provider);
+ }
+
+ return CertStore.getInstance("Collection", params);
+}
+catch (NoSuchAlgorithmException e)
+{
+ throw new GeneralSecurityException(e.toString());
+}
+catch (NoSuchProviderException e)
+{
+ throw new GeneralSecurityException(e.toString());
+}
+ }
+
+ private CollectionCertStoreParameters convertHolders(JcaX509CertificateConverter certificateConverter, JcaX509CRLConverter crlConverter)
+ throws CertificateException, CRLException
+ {
+ List jcaObjs = new ArrayList(certs.size() + crls.size());
+
+ for (Iterator it = certs.iterator(); it.hasNext();)
+ {
+ jcaObjs.add(certificateConverter.getCertificate((X509CertificateHolder)it.next()));
+ }
+
+ for (Iterator it = crls.iterator(); it.hasNext();)
+ {
+ jcaObjs.add(crlConverter.getCRL((X509CRLHolder)it.next()));
+ }
+
+ return new CollectionCertStoreParameters(jcaObjs);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/path/CertPathValidationException.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/path/CertPathValidationException.java
new file mode 100644
index 000000000..d0cbf6079
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/path/CertPathValidationException.java
@@ -0,0 +1,24 @@
+package org.spongycastle.cert.path;
+
+public class CertPathValidationException
+ extends Exception
+{
+ private Exception cause;
+
+ public CertPathValidationException(String msg)
+ {
+ this(msg, null);
+ }
+
+ public CertPathValidationException(String msg, Exception cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/selector/jcajce/JcaSelectorConverter.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/selector/jcajce/JcaSelectorConverter.java
new file mode 100644
index 000000000..8bda2e465
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/selector/jcajce/JcaSelectorConverter.java
@@ -0,0 +1,34 @@
+package org.spongycastle.cert.selector.jcajce;
+
+import java.security.cert.X509CertSelector;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cert.selector.X509CertificateHolderSelector;
+
+public class JcaSelectorConverter
+{
+ public JcaSelectorConverter()
+ {
+
+ }
+
+ public X509CertificateHolderSelector getCertificateHolderSelector(X509CertSelector certSelector)
+ {
+try
+{
+ if (certSelector.getSubjectKeyIdentifier() != null)
+ {
+ return new X509CertificateHolderSelector(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber(), ASN1OctetString.getInstance(certSelector.getSubjectKeyIdentifier()).getOctets());
+ }
+ else
+ {
+ return new X509CertificateHolderSelector(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber());
+ }
+}
+catch (Exception e)
+{
+throw new IllegalArgumentException("conversion failed: " + e.toString());
+}
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java
new file mode 100644
index 000000000..6dbcef43f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java
@@ -0,0 +1,57 @@
+package org.spongycastle.cert.selector.jcajce;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.X509CertSelector;
+
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cert.selector.X509CertificateHolderSelector;
+
+public class JcaX509CertSelectorConverter
+{
+ public JcaX509CertSelectorConverter()
+ {
+ }
+
+ protected X509CertSelector doConversion(X500Name issuer, BigInteger serialNumber, byte[] subjectKeyIdentifier)
+ {
+ X509CertSelector selector = new X509CertSelector();
+
+ if (issuer != null)
+ {
+ try
+ {
+ selector.setIssuer(issuer.getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage());
+ }
+ }
+
+ if (serialNumber != null)
+ {
+ selector.setSerialNumber(serialNumber);
+ }
+
+ if (subjectKeyIdentifier != null)
+ {
+ try
+ {
+ selector.setSubjectKeyIdentifier(new DEROctetString(subjectKeyIdentifier).getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage());
+ }
+ }
+
+ return selector;
+ }
+
+ public X509CertSelector getCertSelector(X509CertificateHolderSelector holderSelector)
+ {
+ return doConversion(holderSelector.getIssuer(), holderSelector.getSerialNumber(), holderSelector.getSubjectKeyIdentifier());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/CMSAbsentContent.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/CMSAbsentContent.java
new file mode 100644
index 000000000..e1d7e5867
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/CMSAbsentContent.java
@@ -0,0 +1,49 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+
+/**
+ * a class representing null or absent content.
+ */
+public class CMSAbsentContent
+ implements CMSTypedData, CMSReadable
+{
+ private ASN1ObjectIdentifier type;
+
+ public CMSAbsentContent()
+ {
+ this(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()));
+ }
+
+ public CMSAbsentContent(
+ ASN1ObjectIdentifier type)
+ {
+ this.type = type;
+ }
+
+ public InputStream getInputStream()
+ {
+ return null;
+ }
+
+ public void write(OutputStream zOut)
+ throws IOException, CMSException
+ {
+ // do nothing
+ }
+
+ public Object getContent()
+ {
+ return null;
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return type;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/CMSProcessableByteArray.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/CMSProcessableByteArray.java
new file mode 100644
index 000000000..6ac965c78
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/CMSProcessableByteArray.java
@@ -0,0 +1,55 @@
+package org.spongycastle.cms;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.util.Arrays;
+
+/**
+ * a holding class for a byte array of data to be processed.
+ */
+public class CMSProcessableByteArray
+ implements CMSTypedData, CMSReadable
+{
+ private ASN1ObjectIdentifier type;
+ private byte[] bytes;
+
+ public CMSProcessableByteArray(
+ byte[] bytes)
+ {
+ this(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()), bytes);
+ }
+
+ public CMSProcessableByteArray(
+ ASN1ObjectIdentifier type,
+ byte[] bytes)
+ {
+ this.type = type;
+ this.bytes = bytes;
+ }
+
+ public InputStream getInputStream()
+ {
+ return new ByteArrayInputStream(bytes);
+ }
+
+ public void write(OutputStream zOut)
+ throws IOException, CMSException
+ {
+ zOut.write(bytes);
+ }
+
+ public Object getContent()
+ {
+ return Arrays.clone(bytes);
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return type;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/CMSProcessableFile.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/CMSProcessableFile.java
new file mode 100644
index 000000000..87b7c4e94
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/CMSProcessableFile.java
@@ -0,0 +1,80 @@
+package org.spongycastle.cms;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+
+/**
+ * a holding class for a file of data to be processed.
+ */
+public class CMSProcessableFile
+ implements CMSTypedData, CMSReadable
+{
+ private static final int DEFAULT_BUF_SIZE = 32 * 1024;
+
+ private ASN1ObjectIdentifier type;
+ private File file;
+ private byte[] buf;
+
+ public CMSProcessableFile(
+ File file)
+ {
+ this(file, DEFAULT_BUF_SIZE);
+ }
+
+ public CMSProcessableFile(
+ File file,
+ int bufSize)
+ {
+ this(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()), file, bufSize);
+ }
+
+ public CMSProcessableFile(
+ ASN1ObjectIdentifier type,
+ File file,
+ int bufSize)
+ {
+ this.type = type;
+ this.file = file;
+ buf = new byte[bufSize];
+ }
+
+ public InputStream getInputStream()
+ throws IOException, CMSException
+ {
+ return new BufferedInputStream(new FileInputStream(file), DEFAULT_BUF_SIZE);
+ }
+
+ public void write(OutputStream zOut)
+ throws IOException, CMSException
+ {
+ FileInputStream fIn = new FileInputStream(file);
+ int len;
+
+ while ((len = fIn.read(buf, 0, buf.length)) > 0)
+ {
+ zOut.write(buf, 0, len);
+ }
+
+ fIn.close();
+ }
+
+ /**
+ * Return the file handle.
+ */
+ public Object getContent()
+ {
+ return file;
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return type;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/CMSTypedStream.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/CMSTypedStream.java
new file mode 100644
index 000000000..82466af71
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/CMSTypedStream.java
@@ -0,0 +1,86 @@
+package org.spongycastle.cms;
+
+import java.io.BufferedInputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.util.io.Streams;
+
+public class CMSTypedStream
+{
+ private static final int BUF_SIZ = 32 * 1024;
+
+ private ASN1ObjectIdentifier _oid;
+ private InputStream _in;
+
+ public CMSTypedStream(
+ InputStream in)
+ {
+ this(PKCSObjectIdentifiers.data.getId(), in, BUF_SIZ);
+ }
+
+ public CMSTypedStream(
+ String oid,
+ InputStream in)
+ {
+ this(new ASN1ObjectIdentifier(oid), in, BUF_SIZ);
+ }
+
+ public CMSTypedStream(
+ String oid,
+ InputStream in,
+ int bufSize)
+ {
+ this(new ASN1ObjectIdentifier(oid), in, bufSize);
+ }
+
+ public CMSTypedStream(
+ ASN1ObjectIdentifier oid,
+ InputStream in)
+ {
+ this(oid, in, BUF_SIZ);
+ }
+
+ public CMSTypedStream(
+ ASN1ObjectIdentifier oid,
+ InputStream in,
+ int bufSize)
+ {
+ _oid = oid;
+ _in = new FullReaderStream(new BufferedInputStream(in, bufSize));
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return _oid;
+ }
+
+ public InputStream getContentStream()
+ {
+ return _in;
+ }
+
+ public void drain()
+ throws IOException
+ {
+ Streams.drain(_in);
+ _in.close();
+ }
+
+ private static class FullReaderStream extends FilterInputStream
+ {
+ FullReaderStream(InputStream in)
+ {
+ super(in);
+ }
+
+ public int read(byte[] buf, int off, int len) throws IOException
+ {
+ int totalRead = Streams.readFully(super.in, buf, off, len);
+ return totalRead > 0 ? totalRead : -1;
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/OriginatorInfoGenerator.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/OriginatorInfoGenerator.java
new file mode 100644
index 000000000..b6cfdd0be
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/OriginatorInfoGenerator.java
@@ -0,0 +1,54 @@
+package org.spongycastle.cms;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.spongycastle.asn1.cms.OriginatorInfo;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.util.Store;
+
+public class OriginatorInfoGenerator
+{
+ private List origCerts;
+ private List origCRLs;
+
+ public OriginatorInfoGenerator(X509CertificateHolder origCert)
+ {
+ this.origCerts = new ArrayList(1);
+ this.origCRLs = null;
+ origCerts.add(origCert.toASN1Structure());
+ }
+
+ public OriginatorInfoGenerator(Store origCerts)
+ throws CMSException
+ {
+ this(origCerts, null);
+ }
+
+ public OriginatorInfoGenerator(Store origCerts, Store origCRLs)
+ throws CMSException
+ {
+ this.origCerts = CMSUtils.getCertificatesFromStore(origCerts);
+
+ if (origCRLs != null)
+ {
+ this.origCRLs = CMSUtils.getCRLsFromStore(origCRLs);
+ }
+ else
+ {
+ this.origCRLs = null;
+ }
+ }
+
+ public OriginatorInformation generate()
+ {
+ if (origCRLs != null)
+ {
+ return new OriginatorInformation(new OriginatorInfo(CMSUtils.createDerSetFromList(origCerts), CMSUtils.createDerSetFromList(origCRLs)));
+ }
+ else
+ {
+ return new OriginatorInformation(new OriginatorInfo(CMSUtils.createDerSetFromList(origCerts), null));
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/RecipientId.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/RecipientId.java
new file mode 100644
index 000000000..f2dd5dff2
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/RecipientId.java
@@ -0,0 +1,31 @@
+package org.spongycastle.cms;
+
+import org.spongycastle.util.Selector;
+
+public abstract class RecipientId
+ implements Selector
+{
+ public static final int keyTrans = 0;
+ public static final int kek = 1;
+ public static final int keyAgree = 2;
+ public static final int password = 3;
+
+ private int type;
+
+ protected RecipientId(int type)
+ {
+ this.type = type;
+ }
+
+ /**
+ * Return the type code for this recipient ID.
+ *
+ * @return one of keyTrans, kek, keyAgree, password
+ */
+ public int getType()
+ {
+ return type;
+ }
+
+ public abstract Object clone();
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/SignerInfoGenerator.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/SignerInfoGenerator.java
new file mode 100644
index 000000000..47028b995
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/SignerInfoGenerator.java
@@ -0,0 +1,291 @@
+package org.spongycastle.cms;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.SignerIdentifier;
+import org.spongycastle.asn1.cms.SignerInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.io.TeeOutputStream;
+
+public class SignerInfoGenerator
+{
+ private SignerIdentifier signerIdentifier;
+ private CMSAttributeTableGenerator sAttrGen;
+ private CMSAttributeTableGenerator unsAttrGen;
+ private ContentSigner signer;
+ private DigestCalculator digester;
+ private DigestAlgorithmIdentifierFinder digAlgFinder = new DefaultDigestAlgorithmIdentifierFinder();
+ private CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder;
+
+ private byte[] calculatedDigest = null;
+ private X509CertificateHolder certHolder;
+
+ SignerInfoGenerator(
+ SignerIdentifier signerIdentifier,
+ ContentSigner signer,
+ DigestCalculatorProvider digesterProvider,
+ CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder)
+ throws OperatorCreationException
+ {
+ this(signerIdentifier, signer, digesterProvider, sigEncAlgFinder, false);
+ }
+
+ SignerInfoGenerator(
+ SignerIdentifier signerIdentifier,
+ ContentSigner signer,
+ DigestCalculatorProvider digesterProvider,
+ CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder,
+ boolean isDirectSignature)
+ throws OperatorCreationException
+ {
+ this.signerIdentifier = signerIdentifier;
+ this.signer = signer;
+
+ if (digesterProvider != null)
+ {
+ this.digester = digesterProvider.get(digAlgFinder.find(signer.getAlgorithmIdentifier()));
+ }
+ else
+ {
+ this.digester = null;
+ }
+
+ if (isDirectSignature)
+ {
+ this.sAttrGen = null;
+ this.unsAttrGen = null;
+ }
+ else
+ {
+ this.sAttrGen = new DefaultSignedAttributeTableGenerator();
+ this.unsAttrGen = null;
+ }
+
+ this.sigEncAlgFinder = sigEncAlgFinder;
+ }
+
+ public SignerInfoGenerator(
+ SignerInfoGenerator original,
+ CMSAttributeTableGenerator sAttrGen,
+ CMSAttributeTableGenerator unsAttrGen)
+ {
+ this.signerIdentifier = original.signerIdentifier;
+ this.signer = original.signer;
+ this.digester = original.digester;
+ this.sigEncAlgFinder = original.sigEncAlgFinder;
+ this.sAttrGen = sAttrGen;
+ this.unsAttrGen = unsAttrGen;
+ }
+
+ SignerInfoGenerator(
+ SignerIdentifier signerIdentifier,
+ ContentSigner signer,
+ DigestCalculatorProvider digesterProvider,
+ CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder,
+ CMSAttributeTableGenerator sAttrGen,
+ CMSAttributeTableGenerator unsAttrGen)
+ throws OperatorCreationException
+ {
+ this.signerIdentifier = signerIdentifier;
+ this.signer = signer;
+
+ if (digesterProvider != null)
+ {
+ this.digester = digesterProvider.get(digAlgFinder.find(signer.getAlgorithmIdentifier()));
+ }
+ else
+ {
+ this.digester = null;
+ }
+
+ this.sAttrGen = sAttrGen;
+ this.unsAttrGen = unsAttrGen;
+ this.sigEncAlgFinder = sigEncAlgFinder;
+ }
+
+ public SignerIdentifier getSID()
+ {
+ return signerIdentifier;
+ }
+
+ public int getGeneratedVersion()
+ {
+ return signerIdentifier.isTagged() ? 3 : 1;
+ }
+
+ public boolean hasAssociatedCertificate()
+ {
+ return certHolder != null;
+ }
+
+ public X509CertificateHolder getAssociatedCertificate()
+ {
+ return certHolder;
+ }
+
+ public AlgorithmIdentifier getDigestAlgorithm()
+ {
+ if (digester != null)
+ {
+ return digester.getAlgorithmIdentifier();
+ }
+
+ return digAlgFinder.find(signer.getAlgorithmIdentifier());
+ }
+
+ public OutputStream getCalculatingOutputStream()
+ {
+ if (digester != null)
+ {
+ if (sAttrGen == null)
+ {
+ return new TeeOutputStream(digester.getOutputStream(), signer.getOutputStream());
+ }
+ return digester.getOutputStream();
+ }
+ else
+ {
+ return signer.getOutputStream();
+ }
+ }
+
+ public SignerInfo generate(ASN1ObjectIdentifier contentType)
+ throws CMSException
+ {
+ try
+ {
+ /* RFC 3852 5.4
+ * The result of the message digest calculation process depends on
+ * whether the signedAttrs field is present. When the field is absent,
+ * the result is just the message digest of the content as described
+ *
+ * above. When the field is present, however, the result is the message
+ * digest of the complete DER encoding of the SignedAttrs value
+ * contained in the signedAttrs field.
+ */
+ ASN1Set signedAttr = null;
+
+ AlgorithmIdentifier digestAlg = null;
+
+ if (sAttrGen != null)
+ {
+ digestAlg = digester.getAlgorithmIdentifier();
+ calculatedDigest = digester.getDigest();
+ Map parameters = getBaseParameters(contentType, digester.getAlgorithmIdentifier(), calculatedDigest);
+ AttributeTable signed = sAttrGen.getAttributes(Collections.unmodifiableMap(parameters));
+
+ signedAttr = getAttributeSet(signed);
+
+ // sig must be composed from the DER encoding.
+ OutputStream sOut = signer.getOutputStream();
+
+ sOut.write(signedAttr.getEncoded(ASN1Encoding.DER));
+
+ sOut.close();
+ }
+ else
+ {
+ if (digester != null)
+ {
+ digestAlg = digester.getAlgorithmIdentifier();
+ calculatedDigest = digester.getDigest();
+ }
+ else
+ {
+ digestAlg = digAlgFinder.find(signer.getAlgorithmIdentifier());
+ calculatedDigest = null;
+ }
+ }
+
+ byte[] sigBytes = signer.getSignature();
+
+ ASN1Set unsignedAttr = null;
+ if (unsAttrGen != null)
+ {
+ Map parameters = getBaseParameters(contentType, digestAlg, calculatedDigest);
+ parameters.put(CMSAttributeTableGenerator.SIGNATURE, Arrays.clone(sigBytes));
+
+ AttributeTable unsigned = unsAttrGen.getAttributes(Collections.unmodifiableMap(parameters));
+
+ unsignedAttr = getAttributeSet(unsigned);
+ }
+
+ AlgorithmIdentifier digestEncryptionAlgorithm = sigEncAlgFinder.findEncryptionAlgorithm(signer.getAlgorithmIdentifier());
+
+ return new SignerInfo(signerIdentifier, digestAlg,
+ signedAttr, digestEncryptionAlgorithm, new DEROctetString(sigBytes), unsignedAttr);
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("encoding error.", e);
+ }
+ }
+
+ void setAssociatedCertificate(X509CertificateHolder certHolder)
+ {
+ this.certHolder = certHolder;
+ }
+
+ private ASN1Set getAttributeSet(
+ AttributeTable attr)
+ {
+ if (attr != null)
+ {
+ return new DERSet(attr.toASN1EncodableVector());
+ }
+
+ return null;
+ }
+
+ private Map getBaseParameters(ASN1ObjectIdentifier contentType, AlgorithmIdentifier digAlgId, byte[] hash)
+ {
+ Map param = new HashMap();
+
+ if (contentType != null)
+ {
+ param.put(CMSAttributeTableGenerator.CONTENT_TYPE, contentType);
+ }
+
+ param.put(CMSAttributeTableGenerator.DIGEST_ALGORITHM_IDENTIFIER, digAlgId);
+ param.put(CMSAttributeTableGenerator.DIGEST, Arrays.clone(hash));
+ return param;
+ }
+
+ public byte[] getCalculatedDigest()
+ {
+ if (calculatedDigest != null)
+ {
+ return Arrays.clone(calculatedDigest);
+ }
+
+ return null;
+ }
+
+ public CMSAttributeTableGenerator getSignedAttributeTableGenerator()
+ {
+ return sAttrGen;
+ }
+
+ public CMSAttributeTableGenerator getUnsignedAttributeTableGenerator()
+ {
+ return unsAttrGen;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/EnvelopedDataHelper.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/EnvelopedDataHelper.java
new file mode 100644
index 000000000..56f6f2f25
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/EnvelopedDataHelper.java
@@ -0,0 +1,671 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+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.InvalidParameterSpecException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Null;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+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.RC2CBCParameter;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSEnvelopedDataGenerator;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.operator.DefaultSecretKeySizeProvider;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.SecretKeySizeProvider;
+import org.spongycastle.operator.SymmetricKeyUnwrapper;
+import org.spongycastle.operator.jcajce.JceAsymmetricKeyUnwrapper;
+
+public class EnvelopedDataHelper
+{
+ protected static final SecretKeySizeProvider KEY_SIZE_PROVIDER = DefaultSecretKeySizeProvider.INSTANCE;
+
+ protected static final Map BASE_CIPHER_NAMES = new HashMap();
+ protected static final Map CIPHER_ALG_NAMES = new HashMap();
+ protected static final Map MAC_ALG_NAMES = new HashMap();
+
+ static
+ {
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.DES_CBC, "DES");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.AES128_CBC, "AES");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.AES192_CBC, "AES");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.AES256_CBC, "AES");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.RC2_CBC, "RC2");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.CAST5_CBC, "CAST5");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.CAMELLIA128_CBC, "Camellia");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.CAMELLIA192_CBC, "Camellia");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.CAMELLIA256_CBC, "Camellia");
+ BASE_CIPHER_NAMES.put(CMSAlgorithm.SEED_CBC, "SEED");
+ BASE_CIPHER_NAMES.put(PKCSObjectIdentifiers.rc4, "RC4");
+
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.DES_CBC, "DES/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.RC2_CBC, "RC2/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, "AES/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AES/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AES/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(PKCSObjectIdentifiers.rsaEncryption, "RSA/ECB/PKCS1Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.CAST5_CBC, "CAST5/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA128_CBC, "Camellia/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA192_CBC, "Camellia/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.CAMELLIA256_CBC, "Camellia/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(CMSAlgorithm.SEED_CBC, "SEED/CBC/PKCS5Padding");
+ CIPHER_ALG_NAMES.put(PKCSObjectIdentifiers.rc4, "RC4");
+
+ MAC_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDEMac");
+ MAC_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, "AESMac");
+ MAC_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AESMac");
+ MAC_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AESMac");
+ MAC_ALG_NAMES.put(CMSAlgorithm.RC2_CBC, "RC2Mac");
+ }
+
+ private static final short[] rc2Table = {
+ 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[] rc2Ekb = {
+ 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 JcaJceExtHelper helper;
+
+ EnvelopedDataHelper(JcaJceExtHelper helper)
+ {
+ this.helper = helper;
+ }
+
+ String getBaseCipherName(ASN1ObjectIdentifier algorithm)
+ {
+ String name = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (name == null)
+ {
+ return algorithm.getId();
+ }
+
+ return name;
+ }
+
+ Key getJceKey(GenericKey key)
+ {
+ if (key.getRepresentation() instanceof Key)
+ {
+ return (Key)key.getRepresentation();
+ }
+
+ if (key.getRepresentation() instanceof byte[])
+ {
+ return new SecretKeySpec((byte[])key.getRepresentation(), "ENC");
+ }
+
+ throw new IllegalArgumentException("unknown generic key type");
+ }
+
+ public Key getJceKey(ASN1ObjectIdentifier algorithm, GenericKey key)
+ {
+ if (key.getRepresentation() instanceof Key)
+ {
+ return (Key)key.getRepresentation();
+ }
+
+ if (key.getRepresentation() instanceof byte[])
+ {
+ return new SecretKeySpec((byte[])key.getRepresentation(), getBaseCipherName(algorithm));
+ }
+
+ throw new IllegalArgumentException("unknown generic key type");
+ }
+
+ public void keySizeCheck(AlgorithmIdentifier keyAlgorithm, Key key)
+ throws CMSException
+ {
+ int expectedKeySize = EnvelopedDataHelper.KEY_SIZE_PROVIDER.getKeySize(keyAlgorithm);
+ if (expectedKeySize > 0)
+ {
+ byte[] keyEnc = null;
+
+ try
+ {
+ keyEnc = key.getEncoded();
+ }
+ catch (Exception e)
+ {
+ // ignore - we're using a HSM...
+ }
+
+ if (keyEnc != null)
+ {
+ if (keyEnc.length * 8 != expectedKeySize)
+ {
+ throw new CMSException("Expected key size for algorithm OID not found in recipient.");
+ }
+ }
+ }
+ }
+
+ Cipher createCipher(ASN1ObjectIdentifier algorithm)
+ throws CMSException
+ {
+ try
+ {
+ String cipherName = (String)CIPHER_ALG_NAMES.get(algorithm);
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createCipher(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createCipher(algorithm.getId());
+ }
+ catch (Exception e)
+ {
+ throw new CMSException("cannot create cipher: " + e.getMessage(), e);
+ }
+ }
+
+ Mac createMac(ASN1ObjectIdentifier algorithm)
+ throws CMSException
+ {
+ try
+ {
+ String macName = (String)MAC_ALG_NAMES.get(algorithm);
+
+ if (macName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createMac(macName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createMac(algorithm.getId());
+ }
+ catch (Exception e)
+ {
+ throw new CMSException("cannot create mac: " + e.getMessage(), e);
+ }
+ }
+
+ Cipher createRFC3211Wrapper(ASN1ObjectIdentifier algorithm)
+ throws CMSException
+ {
+ String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (cipherName == null)
+ {
+ throw new CMSException("no name for " + algorithm);
+ }
+
+ cipherName += "RFC3211Wrap";
+
+ try
+ {
+ return helper.createCipher(cipherName);
+ }
+ catch (Exception e)
+ {
+ throw new CMSException("cannot create cipher: " + e.getMessage(), e);
+ }
+ }
+
+ KeyAgreement createKeyAgreement(ASN1ObjectIdentifier algorithm)
+ throws CMSException
+ {
+ try
+ {
+ String agreementName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (agreementName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createKeyAgreement(agreementName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createKeyAgreement(algorithm.getId());
+ }
+ catch (Exception e)
+ {
+ throw new CMSException("cannot create key pair generator: " + e.getMessage(), e);
+ }
+ }
+
+ AlgorithmParameterGenerator createAlgorithmParameterGenerator(ASN1ObjectIdentifier algorithm)
+ throws CMSException
+ {
+ String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ try
+ {
+ if (algorithmName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createAlgorithmParameterGenerator(algorithmName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createAlgorithmParameterGenerator(algorithm.getId());
+ }
+ catch (Exception e)
+ {
+ throw new CMSException("cannot create key pair generator: " + e.getMessage(), e);
+ }
+ }
+
+ public Cipher createContentCipher(final Key sKey, final AlgorithmIdentifier encryptionAlgID)
+ throws CMSException
+ {
+ return (Cipher)execute(new JCECallback()
+ {
+ public Object doInJCE()
+ throws CMSException, InvalidAlgorithmParameterException,
+ InvalidKeyException, InvalidParameterSpecException, NoSuchAlgorithmException,
+ NoSuchPaddingException, NoSuchProviderException
+ {
+ Cipher cipher = createCipher(encryptionAlgID.getAlgorithm());
+ ASN1Encodable sParams = encryptionAlgID.getParameters();
+ String encAlg = encryptionAlgID.getAlgorithm().getId();
+
+ if (sParams != null && !(sParams instanceof ASN1Null))
+ {
+ try
+ {
+ AlgorithmParameters params = createAlgorithmParameters(encryptionAlgID.getAlgorithm());
+
+ CMSUtils.loadParameters(params, sParams);
+
+ cipher.init(Cipher.DECRYPT_MODE, sKey, params);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ if (encAlg.equals(CMSAlgorithm.DES_CBC.getId())
+ || encAlg.equals(CMSEnvelopedDataGenerator.DES_EDE3_CBC)
+ || encAlg.equals(CMSEnvelopedDataGenerator.IDEA_CBC)
+ || encAlg.equals(CMSEnvelopedDataGenerator.AES128_CBC)
+ || encAlg.equals(CMSEnvelopedDataGenerator.AES192_CBC)
+ || encAlg.equals(CMSEnvelopedDataGenerator.AES256_CBC))
+ {
+ cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec(
+ ASN1OctetString.getInstance(sParams).getOctets()));
+ }
+ else
+ {
+ throw e;
+ }
+ }
+ }
+ else
+ {
+ if (encAlg.equals(CMSAlgorithm.DES_CBC.getId())
+ || encAlg.equals(CMSEnvelopedDataGenerator.DES_EDE3_CBC)
+ || encAlg.equals(CMSEnvelopedDataGenerator.IDEA_CBC)
+ || encAlg.equals(CMSEnvelopedDataGenerator.CAST5_CBC))
+ {
+ cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec(new byte[8]));
+ }
+ else
+ {
+ cipher.init(Cipher.DECRYPT_MODE, sKey);
+ }
+ }
+
+ return cipher;
+ }
+ });
+ }
+
+ Mac createContentMac(final Key sKey, final AlgorithmIdentifier macAlgId)
+ throws CMSException
+ {
+ return (Mac)execute(new JCECallback()
+ {
+ public Object doInJCE()
+ throws CMSException, InvalidAlgorithmParameterException,
+ InvalidKeyException, InvalidParameterSpecException, NoSuchAlgorithmException,
+ NoSuchPaddingException, NoSuchProviderException
+ {
+ Mac mac = createMac(macAlgId.getAlgorithm());
+ ASN1Encodable sParams = macAlgId.getParameters();
+ String macAlg = macAlgId.getAlgorithm().getId();
+
+ if (sParams != null && !(sParams instanceof ASN1Null))
+ {
+ try
+ {
+ AlgorithmParameters params = createAlgorithmParameters(macAlgId.getAlgorithm());
+
+ CMSUtils.loadParameters(params, sParams);
+
+ mac.init(sKey, params.getParameterSpec(IvParameterSpec.class));
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw e;
+ }
+ }
+ else
+ {
+ mac.init(sKey);
+ }
+
+ return mac;
+ }
+ });
+ }
+
+ AlgorithmParameters createAlgorithmParameters(ASN1ObjectIdentifier algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (algorithmName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createAlgorithmParameters(algorithmName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createAlgorithmParameters(algorithm.getId());
+ }
+
+
+ KeyPairGenerator createKeyPairGenerator(ASN1ObjectIdentifier algorithm)
+ throws CMSException
+ {
+ try
+ {
+ String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createKeyPairGenerator(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createKeyPairGenerator(algorithm.getId());
+ }
+ catch (Exception e)
+ {
+ throw new CMSException("cannot create key pair generator: " + e.getMessage(), e);
+ }
+ }
+
+ public KeyGenerator createKeyGenerator(ASN1ObjectIdentifier algorithm)
+ throws CMSException
+ {
+ try
+ {
+ String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createKeyGenerator(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createKeyGenerator(algorithm.getId());
+ }
+ catch (Exception e)
+ {
+ throw new CMSException("cannot create key generator: " + e.getMessage(), e);
+ }
+ }
+
+ AlgorithmParameters generateParameters(ASN1ObjectIdentifier encryptionOID, SecretKey encKey, SecureRandom rand)
+ throws CMSException
+ {
+ try
+ {
+ AlgorithmParameterGenerator pGen = createAlgorithmParameterGenerator(encryptionOID);
+
+ if (encryptionOID.equals(CMSAlgorithm.RC2_CBC))
+ {
+ byte[] iv = new byte[8];
+
+ rand.nextBytes(iv);
+
+ try
+ {
+ pGen.init(new RC2ParameterSpec(encKey.getEncoded().length * 8, iv), rand);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new CMSException("parameters generation error: " + e, e);
+ }
+ }
+
+ return pGen.generateParameters();
+ }
+ catch (Exception e)
+ {
+ throw new CMSException("exception creating algorithm parameter generator: " + e, e);
+ }
+ }
+
+ AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier encryptionOID, AlgorithmParameters params)
+ throws CMSException
+ {
+ ASN1Encodable asn1Params;
+ if (params != null)
+ {
+ asn1Params = CMSUtils.extractParameters(params);
+ }
+ else
+ {
+ asn1Params = DERNull.INSTANCE;
+ }
+
+ return new AlgorithmIdentifier(
+ encryptionOID,
+ asn1Params);
+ }
+
+ static Object execute(JCECallback callback) throws CMSException
+ {
+ try
+ {
+ return callback.doInJCE();
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new CMSException("can't find algorithm.", e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CMSException("key invalid in message.", e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new CMSException("can't find provider.", e);
+ }
+ catch (NoSuchPaddingException e)
+ {
+ throw new CMSException("required padding not supported.", e);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new CMSException("algorithm parameters invalid.", e);
+ }
+ catch (InvalidParameterSpecException e)
+ {
+ throw new CMSException("MAC algorithm parameter spec invalid.", e);
+ }
+ }
+
+ public KeyFactory createKeyFactory(ASN1ObjectIdentifier algorithm)
+ throws CMSException
+ {
+ try
+ {
+ String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm);
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createKeyFactory(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createKeyFactory(algorithm.getId());
+ }
+ catch (Exception e)
+ {
+ throw new CMSException("cannot create key factory: " + e.getMessage(), e);
+ }
+ }
+
+ public JceAsymmetricKeyUnwrapper createAsymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, PrivateKey keyEncryptionKey)
+ {
+ return helper.createAsymmetricUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey);
+ }
+
+ public SymmetricKeyUnwrapper createSymmetricUnwrapper(AlgorithmIdentifier keyEncryptionAlgorithm, SecretKey keyEncryptionKey)
+ {
+ return helper.createSymmetricUnwrapper(keyEncryptionAlgorithm, keyEncryptionKey);
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier macOID, AlgorithmParameterSpec paramSpec)
+ {
+ if (paramSpec instanceof IvParameterSpec)
+ {
+ return new AlgorithmIdentifier(macOID, new DEROctetString(((IvParameterSpec)paramSpec).getIV()));
+ }
+
+ if (paramSpec instanceof RC2ParameterSpec)
+ {
+ RC2ParameterSpec rc2Spec = (RC2ParameterSpec)paramSpec;
+
+ int effKeyBits = ((RC2ParameterSpec)paramSpec).getEffectiveKeyBits();
+
+ if (effKeyBits != -1)
+ {
+ int parameterVersion;
+
+ if (effKeyBits < 256)
+ {
+ parameterVersion = rc2Table[effKeyBits];
+ }
+ else
+ {
+ parameterVersion = effKeyBits;
+ }
+
+ return new AlgorithmIdentifier(macOID, new RC2CBCParameter(parameterVersion, rc2Spec.getIV()));
+ }
+
+ return new AlgorithmIdentifier(macOID, new RC2CBCParameter(rc2Spec.getIV()));
+ }
+
+ throw new IllegalStateException("unknown parameter spec: " + paramSpec);
+ }
+
+ static interface JCECallback
+ {
+ Object doInJCE()
+ throws CMSException, InvalidAlgorithmParameterException, InvalidKeyException, InvalidParameterSpecException,
+ NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JcaSelectorConverter.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JcaSelectorConverter.java
new file mode 100644
index 000000000..6f0224679
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JcaSelectorConverter.java
@@ -0,0 +1,54 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.cert.X509CertSelector;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cms.KeyTransRecipientId;
+import org.spongycastle.cms.SignerId;
+
+public class JcaSelectorConverter
+{
+ public JcaSelectorConverter()
+ {
+
+ }
+
+ public SignerId getSignerId(X509CertSelector certSelector)
+ {
+try
+{
+ if (certSelector.getSubjectKeyIdentifier() != null)
+ {
+ return new SignerId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber(), ASN1OctetString.getInstance(certSelector.getSubjectKeyIdentifier()).getOctets());
+ }
+ else
+ {
+ return new SignerId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber());
+ }
+}
+catch (Exception e)
+{
+ throw new IllegalArgumentException("conversion failed: " + e.toString());
+}
+ }
+
+ public KeyTransRecipientId getKeyTransRecipientId(X509CertSelector certSelector)
+ {
+try
+{
+ if (certSelector.getSubjectKeyIdentifier() != null)
+ {
+ return new KeyTransRecipientId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber(), ASN1OctetString.getInstance(certSelector.getSubjectKeyIdentifier()).getOctets());
+ }
+ else
+ {
+ return new KeyTransRecipientId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber());
+ }
+}
+catch (Exception e)
+{
+ throw new IllegalArgumentException("conversion failed: " + e.toString());
+}
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JcaX509CertSelectorConverter.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JcaX509CertSelectorConverter.java
new file mode 100644
index 000000000..ceb138ed6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JcaX509CertSelectorConverter.java
@@ -0,0 +1,24 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.cert.X509CertSelector;
+
+import org.spongycastle.cms.KeyTransRecipientId;
+import org.spongycastle.cms.SignerId;
+
+public class JcaX509CertSelectorConverter
+ extends org.spongycastle.cert.selector.jcajce.JcaX509CertSelectorConverter
+{
+ public JcaX509CertSelectorConverter()
+ {
+ }
+
+ public X509CertSelector getCertSelector(KeyTransRecipientId recipientId)
+ {
+ return doConversion(recipientId.getIssuer(), recipientId.getSerialNumber(), recipientId.getSubjectKeyIdentifier());
+ }
+
+ public X509CertSelector getCertSelector(SignerId signerId)
+ {
+ return doConversion(signerId.getIssuer(), signerId.getSerialNumber(), signerId.getSubjectKeyIdentifier());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java
new file mode 100644
index 000000000..b4bdd4ad7
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java
@@ -0,0 +1,166 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.OutputStream;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OutputEncryptor;
+import org.spongycastle.util.Integers;
+
+public class JceCMSContentEncryptorBuilder
+{
+ private static Map keySizes = new HashMap();
+
+ static
+ {
+ keySizes.put(CMSAlgorithm.AES128_CBC, Integers.valueOf(128));
+ keySizes.put(CMSAlgorithm.AES192_CBC, Integers.valueOf(192));
+ keySizes.put(CMSAlgorithm.AES256_CBC, Integers.valueOf(256));
+
+ keySizes.put(CMSAlgorithm.CAMELLIA128_CBC, Integers.valueOf(128));
+ keySizes.put(CMSAlgorithm.CAMELLIA192_CBC, Integers.valueOf(192));
+ keySizes.put(CMSAlgorithm.CAMELLIA256_CBC, Integers.valueOf(256));
+ }
+
+ private static int getKeySize(ASN1ObjectIdentifier oid)
+ {
+ Integer size = (Integer)keySizes.get(oid);
+
+ if (size != null)
+ {
+ return size.intValue();
+ }
+
+ return -1;
+ }
+
+ private ASN1ObjectIdentifier encryptionOID;
+ private int keySize;
+
+ private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+ private SecureRandom random;
+
+ public JceCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID)
+ {
+ this(encryptionOID, getKeySize(encryptionOID));
+ }
+
+ public JceCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID, int keySize)
+ {
+ this.encryptionOID = encryptionOID;
+ this.keySize = keySize;
+ }
+
+ public JceCMSContentEncryptorBuilder setProvider(Provider provider)
+ {
+ this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
+
+ return this;
+ }
+
+ public JceCMSContentEncryptorBuilder setProvider(String providerName)
+ {
+ this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
+
+ return this;
+ }
+
+ public JceCMSContentEncryptorBuilder setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public OutputEncryptor build()
+ throws CMSException
+ {
+ return new CMSOutputEncryptor(encryptionOID, keySize, random);
+ }
+
+ private class CMSOutputEncryptor
+ implements OutputEncryptor
+ {
+ private SecretKey encKey;
+ private AlgorithmIdentifier algorithmIdentifier;
+ private Cipher cipher;
+
+ CMSOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, SecureRandom random)
+ throws CMSException
+ {
+ KeyGenerator keyGen = helper.createKeyGenerator(encryptionOID);
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ if (keySize < 0)
+ {
+ keyGen.init(random);
+ }
+ else
+ {
+ keyGen.init(keySize, random);
+ }
+
+ cipher = helper.createCipher(encryptionOID);
+ encKey = keyGen.generateKey();
+ AlgorithmParameters params = helper.generateParameters(encryptionOID, encKey, random);
+
+ try
+ {
+ cipher.init(Cipher.ENCRYPT_MODE, encKey, params, random);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CMSException("unable to initialize cipher: " + e.getMessage(), e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("unable to initialize cipher: " + e.getMessage(), e);
+ }
+
+ //
+ // If params are null we try and second guess on them as some providers don't provide
+ // algorithm parameter generation explicity but instead generate them under the hood.
+ //
+ if (params == null)
+ {
+ params = cipher.getParameters();
+ }
+
+ algorithmIdentifier = helper.getAlgorithmIdentifier(encryptionOID, params);
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmIdentifier;
+ }
+
+ public OutputStream getOutputStream(OutputStream dOut)
+ {
+ return new CipherOutputStream(dOut, cipher);
+ }
+
+ public GenericKey getKey()
+ {
+ return new GenericKey(encKey);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JceKeyAgreeRecipient.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JceKeyAgreeRecipient.java
new file mode 100644
index 000000000..93c11b215
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JceKeyAgreeRecipient.java
@@ -0,0 +1,184 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.cms.ecc.MQVuserKeyingMaterial;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cms.CMSEnvelopedGenerator;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.KeyAgreeRecipient;
+import org.spongycastle.jce.spec.MQVPrivateKeySpec;
+import org.spongycastle.jce.spec.MQVPublicKeySpec;
+
+public abstract class JceKeyAgreeRecipient
+ implements KeyAgreeRecipient
+{
+ private PrivateKey recipientKey;
+ protected EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+ protected EnvelopedDataHelper contentHelper = helper;
+
+ public JceKeyAgreeRecipient(PrivateKey recipientKey)
+ {
+ this.recipientKey = recipientKey;
+ }
+
+ /**
+ * Set the provider to use for key recovery and content processing.
+ *
+ * @param provider provider to use.
+ * @return this recipient.
+ */
+ public JceKeyAgreeRecipient setProvider(Provider provider)
+ {
+ this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
+ this.contentHelper = helper;
+
+ return this;
+ }
+
+ /**
+ * Set the provider to use for key recovery and content processing.
+ *
+ * @param providerName the name of the provider to use.
+ * @return this recipient.
+ */
+ public JceKeyAgreeRecipient setProvider(String providerName)
+ {
+ this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
+ this.contentHelper = helper;
+
+ return this;
+ }
+
+ /**
+ * Set the provider to use for content processing. If providerName is null a "no provider" search will be
+ * used to satisfy getInstance calls.
+ *
+ * @param provider the provider to use.
+ * @return this recipient.
+ */
+ public JceKeyAgreeRecipient setContentProvider(Provider provider)
+ {
+ this.contentHelper = CMSUtils.createContentHelper(provider);
+
+ return this;
+ }
+
+ /**
+ * Set the provider to use for content processing. If providerName is null a "no provider" search will be
+ * used to satisfy getInstance calls.
+ *
+ * @param providerName the name of the provider to use.
+ * @return this recipient.
+ */
+ public JceKeyAgreeRecipient setContentProvider(String providerName)
+ {
+ this.contentHelper = CMSUtils.createContentHelper(providerName);
+
+ return this;
+ }
+
+ private SecretKey calculateAgreedWrapKey(AlgorithmIdentifier keyEncAlg, ASN1ObjectIdentifier wrapAlg,
+ PublicKey senderPublicKey, ASN1OctetString userKeyingMaterial, PrivateKey receiverPrivateKey)
+ throws CMSException, GeneralSecurityException, IOException, InvalidKeyException, NoSuchAlgorithmException
+ {
+ String agreeAlg = keyEncAlg.getAlgorithm().getId();
+
+ if (agreeAlg.equals(CMSEnvelopedGenerator.ECMQV_SHA1KDF))
+ {
+ byte[] ukmEncoding = userKeyingMaterial.getOctets();
+ MQVuserKeyingMaterial ukm = MQVuserKeyingMaterial.getInstance(
+ ASN1Primitive.fromByteArray(ukmEncoding));
+
+ SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(
+ getPrivateKeyAlgorithmIdentifier(),
+ ukm.getEphemeralPublicKey().getPublicKey().getBytes());
+
+ X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubInfo.getEncoded());
+ KeyFactory fact = helper.createKeyFactory(keyEncAlg.getAlgorithm());
+ PublicKey ephemeralKey = fact.generatePublic(pubSpec);
+
+ senderPublicKey = new MQVPublicKeySpec(senderPublicKey, ephemeralKey);
+ receiverPrivateKey = new MQVPrivateKeySpec(receiverPrivateKey, receiverPrivateKey);
+ }
+
+ KeyAgreement agreement = helper.createKeyAgreement(keyEncAlg.getAlgorithm());
+
+ agreement.init(receiverPrivateKey);
+ agreement.doPhase(senderPublicKey, true);
+
+ return agreement.generateSecret(wrapAlg.getId());
+ }
+
+ private Key unwrapSessionKey(ASN1ObjectIdentifier wrapAlg, SecretKey agreedKey, ASN1ObjectIdentifier contentEncryptionAlgorithm, byte[] encryptedContentEncryptionKey)
+ throws CMSException, InvalidKeyException, NoSuchAlgorithmException
+ {
+ Cipher keyCipher = helper.createCipher(wrapAlg);
+ keyCipher.init(Cipher.UNWRAP_MODE, agreedKey);
+ return keyCipher.unwrap(encryptedContentEncryptionKey, helper.getBaseCipherName(contentEncryptionAlgorithm), Cipher.SECRET_KEY);
+ }
+
+ protected Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, SubjectPublicKeyInfo senderKey, ASN1OctetString userKeyingMaterial, byte[] encryptedContentEncryptionKey)
+ throws CMSException
+ {
+ try
+ {
+ ASN1ObjectIdentifier wrapAlg =
+ AlgorithmIdentifier.getInstance(keyEncryptionAlgorithm.getParameters()).getAlgorithm();
+
+ X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(senderKey.getEncoded());
+ KeyFactory fact = helper.createKeyFactory(keyEncryptionAlgorithm.getAlgorithm());
+ PublicKey senderPublicKey = fact.generatePublic(pubSpec);
+
+ SecretKey agreedWrapKey = calculateAgreedWrapKey(keyEncryptionAlgorithm, wrapAlg,
+ senderPublicKey, userKeyingMaterial, recipientKey);
+
+ return unwrapSessionKey(wrapAlg, agreedWrapKey, contentEncryptionAlgorithm.getAlgorithm(), encryptedContentEncryptionKey);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new CMSException("can't find algorithm.", e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CMSException("key invalid in message.", e);
+ }
+ catch (InvalidKeySpecException e)
+ {
+ throw new CMSException("originator key spec invalid.", e);
+ }
+ catch (NoSuchPaddingException e)
+ {
+ throw new CMSException("required padding not supported.", e);
+ }
+ catch (Exception e)
+ {
+ throw new CMSException("originator key invalid.", e);
+ }
+ }
+
+ public AlgorithmIdentifier getPrivateKeyAlgorithmIdentifier()
+ {
+ return PrivateKeyInfo.getInstance(recipientKey.getEncoded()).getAlgorithmId();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java
new file mode 100644
index 000000000..b37828840
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java
@@ -0,0 +1,212 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.cms.KeyAgreeRecipientIdentifier;
+import org.spongycastle.asn1.cms.RecipientEncryptedKey;
+import org.spongycastle.asn1.cms.RecipientKeyIdentifier;
+import org.spongycastle.asn1.cms.ecc.MQVuserKeyingMaterial;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSEnvelopedGenerator;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.KeyAgreeRecipientInfoGenerator;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.MQVPrivateKeySpec;
+import org.spongycastle.jce.spec.MQVPublicKeySpec;
+import org.spongycastle.operator.GenericKey;
+
+public class JceKeyAgreeRecipientInfoGenerator
+ extends KeyAgreeRecipientInfoGenerator
+{
+ private List recipientIDs = new ArrayList();
+ private List recipientKeys = new ArrayList();
+ private PublicKey senderPublicKey;
+ private PrivateKey senderPrivateKey;
+
+ private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+ private SecureRandom random;
+ private KeyPair ephemeralKP;
+
+ public JceKeyAgreeRecipientInfoGenerator(ASN1ObjectIdentifier keyAgreementOID, PrivateKey senderPrivateKey, PublicKey senderPublicKey, ASN1ObjectIdentifier keyEncryptionOID)
+ {
+ super(keyAgreementOID, SubjectPublicKeyInfo.getInstance(senderPublicKey.getEncoded()), keyEncryptionOID);
+
+ this.senderPublicKey = senderPublicKey;
+ this.senderPrivateKey = senderPrivateKey;
+ }
+
+ public JceKeyAgreeRecipientInfoGenerator setProvider(Provider provider)
+ {
+ this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
+
+ return this;
+ }
+
+ public JceKeyAgreeRecipientInfoGenerator setProvider(String providerName)
+ {
+ this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
+
+ return this;
+ }
+
+ public JceKeyAgreeRecipientInfoGenerator setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ /**
+ * Add a recipient based on the passed in certificate's public key and its issuer and serial number.
+ *
+ * @param recipientCert recipient's certificate
+ * @return the current instance.
+ * @throws CertificateEncodingException if the necessary data cannot be extracted from the certificate.
+ */
+ public JceKeyAgreeRecipientInfoGenerator addRecipient(X509Certificate recipientCert)
+ throws CertificateEncodingException
+ {
+ recipientIDs.add(new KeyAgreeRecipientIdentifier(CMSUtils.getIssuerAndSerialNumber(recipientCert)));
+ recipientKeys.add(recipientCert.getPublicKey());
+
+ return this;
+ }
+
+ /**
+ * Add a recipient identified by the passed in subjectKeyID and the for the passed in public key.
+ *
+ * @param subjectKeyID identifier actual recipient will use to match the private key.
+ * @param publicKey the public key for encrypting the secret key.
+ * @return the current instance.
+ * @throws CertificateEncodingException
+ */
+ public JceKeyAgreeRecipientInfoGenerator addRecipient(byte[] subjectKeyID, PublicKey publicKey)
+ throws CertificateEncodingException
+ {
+ recipientIDs.add(new KeyAgreeRecipientIdentifier(new RecipientKeyIdentifier(subjectKeyID)));
+ recipientKeys.add(publicKey);
+
+ return this;
+ }
+
+ public ASN1Sequence generateRecipientEncryptedKeys(AlgorithmIdentifier keyAgreeAlgorithm, AlgorithmIdentifier keyEncryptionAlgorithm, GenericKey contentEncryptionKey)
+ throws CMSException
+ {
+ init(keyAgreeAlgorithm.getAlgorithm());
+
+ PrivateKey senderPrivateKey = this.senderPrivateKey;
+
+ ASN1ObjectIdentifier keyAgreementOID = keyAgreeAlgorithm.getAlgorithm();
+
+ if (keyAgreementOID.getId().equals(CMSEnvelopedGenerator.ECMQV_SHA1KDF))
+ {
+ senderPrivateKey = new MQVPrivateKeySpec(
+ senderPrivateKey, ephemeralKP.getPrivate(), ephemeralKP.getPublic());
+ }
+
+ ASN1EncodableVector recipientEncryptedKeys = new ASN1EncodableVector();
+ for (int i = 0; i != recipientIDs.size(); i++)
+ {
+ PublicKey recipientPublicKey = (PublicKey)recipientKeys.get(i);
+ KeyAgreeRecipientIdentifier karId = (KeyAgreeRecipientIdentifier)recipientIDs.get(i);
+
+ if (keyAgreementOID.getId().equals(CMSEnvelopedGenerator.ECMQV_SHA1KDF))
+ {
+ recipientPublicKey = new MQVPublicKeySpec(recipientPublicKey, recipientPublicKey);
+ }
+
+ try
+ {
+ // Use key agreement to choose a wrap key for this recipient
+ KeyAgreement keyAgreement = helper.createKeyAgreement(keyAgreementOID);
+ keyAgreement.init(senderPrivateKey, random);
+ keyAgreement.doPhase(recipientPublicKey, true);
+ SecretKey keyEncryptionKey = keyAgreement.generateSecret(keyEncryptionAlgorithm.getAlgorithm().getId());
+
+ // Wrap the content encryption key with the agreement key
+ Cipher keyEncryptionCipher = helper.createCipher(keyEncryptionAlgorithm.getAlgorithm());
+
+ keyEncryptionCipher.init(Cipher.WRAP_MODE, keyEncryptionKey, random);
+
+ byte[] encryptedKeyBytes = keyEncryptionCipher.wrap(helper.getJceKey(contentEncryptionKey));
+
+ ASN1OctetString encryptedKey = new DEROctetString(encryptedKeyBytes);
+
+ recipientEncryptedKeys.add(new RecipientEncryptedKey(karId, encryptedKey));
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new CMSException("cannot perform agreement step: " + e.getMessage(), e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CMSException("cannot perform agreement step: " + e.getMessage(), e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("cannot perform agreement step: " + e.getMessage(), e);
+ }
+ }
+
+ return new DERSequence(recipientEncryptedKeys);
+ }
+
+ protected ASN1Encodable getUserKeyingMaterial(AlgorithmIdentifier keyAgreeAlg)
+ throws CMSException
+ {
+ init(keyAgreeAlg.getAlgorithm());
+
+ if (ephemeralKP != null)
+ {
+ return new MQVuserKeyingMaterial(
+ createOriginatorPublicKey(SubjectPublicKeyInfo.getInstance(ephemeralKP.getPublic().getEncoded())), null);
+ }
+
+ return null;
+ }
+
+ private void init(ASN1ObjectIdentifier keyAgreementOID)
+ throws CMSException
+ {
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ if (keyAgreementOID.equals(CMSAlgorithm.ECMQV_SHA1KDF))
+ {
+ if (ephemeralKP == null)
+ {
+ throw new CMSException(
+ "cannot determine MQV ephemeral key pair parameters from public key");
+ }
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JcePasswordRecipient.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JcePasswordRecipient.java
new file mode 100644
index 000000000..0572364bf
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JcePasswordRecipient.java
@@ -0,0 +1,92 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.Provider;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.PasswordRecipient;
+
+/**
+ * the RecipientInfo class for a recipient who has been sent a message
+ * encrypted using a password.
+ */
+public abstract class JcePasswordRecipient
+ implements PasswordRecipient
+{
+ private int schemeID = PasswordRecipient.PKCS5_SCHEME2_UTF8;
+ protected EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+ private char[] password;
+
+ JcePasswordRecipient(
+ char[] password)
+ {
+ this.password = password;
+ }
+
+ public JcePasswordRecipient setPasswordConversionScheme(int schemeID)
+ {
+ this.schemeID = schemeID;
+
+ return this;
+ }
+
+ public JcePasswordRecipient setProvider(Provider provider)
+ {
+ this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
+
+ return this;
+ }
+
+ public JcePasswordRecipient setProvider(String providerName)
+ {
+ this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
+
+ return this;
+ }
+
+ protected Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] derivedKey, byte[] encryptedContentEncryptionKey)
+ throws CMSException
+ {
+ Cipher keyEncryptionCipher = helper.createRFC3211Wrapper(keyEncryptionAlgorithm.getAlgorithm());
+
+ try
+ {
+ IvParameterSpec ivSpec = new IvParameterSpec(ASN1OctetString.getInstance(keyEncryptionAlgorithm.getParameters()).getOctets());
+
+ keyEncryptionCipher.init(Cipher.UNWRAP_MODE, new SecretKeySpec(derivedKey, keyEncryptionCipher.getAlgorithm()), ivSpec);
+
+ return keyEncryptionCipher.unwrap(encryptedContentEncryptionKey, contentEncryptionAlgorithm.getAlgorithm().getId(), Cipher.SECRET_KEY);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new CMSException("cannot process content encryption key: " + e.getMessage(), e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CMSException("cannot process content encryption key: " + e.getMessage(), e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("cannot process content encryption key: " + e.getMessage(), e);
+ }
+ }
+
+ public int getPasswordConversionScheme()
+ {
+ return schemeID;
+ }
+
+ public char[] getPassword()
+ {
+ return password;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JcePasswordRecipientInfoGenerator.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JcePasswordRecipientInfoGenerator.java
new file mode 100644
index 000000000..e1306fd9e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/JcePasswordRecipientInfoGenerator.java
@@ -0,0 +1,66 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.Provider;
+import java.security.InvalidKeyException;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.PasswordRecipientInfoGenerator;
+import org.spongycastle.operator.GenericKey;
+
+public class JcePasswordRecipientInfoGenerator
+ extends PasswordRecipientInfoGenerator
+{
+ private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+
+ public JcePasswordRecipientInfoGenerator(ASN1ObjectIdentifier kekAlgorithm, char[] password)
+ {
+ super(kekAlgorithm, password);
+ }
+
+ public JcePasswordRecipientInfoGenerator setProvider(Provider provider)
+ {
+ this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
+
+ return this;
+ }
+
+ public JcePasswordRecipientInfoGenerator setProvider(String providerName)
+ {
+ this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
+
+ return this;
+ }
+
+ public byte[] generateEncryptedBytes(AlgorithmIdentifier keyEncryptionAlgorithm, byte[] derivedKey, GenericKey contentEncryptionKey)
+ throws CMSException
+ {
+ Key contentEncryptionKeySpec = helper.getJceKey(contentEncryptionKey);
+ Cipher keyEncryptionCipher = helper.createRFC3211Wrapper(keyEncryptionAlgorithm.getAlgorithm());
+
+ try
+ {
+ IvParameterSpec ivSpec = new IvParameterSpec(ASN1OctetString.getInstance(keyEncryptionAlgorithm.getParameters()).getOctets());
+
+ keyEncryptionCipher.init(Cipher.WRAP_MODE, new SecretKeySpec(derivedKey, keyEncryptionCipher.getAlgorithm()), ivSpec);
+
+ return keyEncryptionCipher.wrap(contentEncryptionKeySpec);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CMSException("cannot process content encryption key: " + e.getMessage(), e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("cannot process content encryption key: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/ZlibExpanderProvider.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/ZlibExpanderProvider.java
new file mode 100644
index 000000000..880dc2cea
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/cms/jcajce/ZlibExpanderProvider.java
@@ -0,0 +1,113 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.InflaterInputStream;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.InputExpander;
+import org.spongycastle.operator.InputExpanderProvider;
+import org.spongycastle.util.io.StreamOverflowException;
+
+public class ZlibExpanderProvider
+ implements InputExpanderProvider
+{
+ private long limit;
+
+ public ZlibExpanderProvider()
+ {
+ this.limit = -1;
+ }
+
+ /**
+ * Create a provider which caps the number of expanded bytes that can be produced when the
+ * compressed stream is parsed.
+ *
+ * @param limit max number of bytes allowed in an expanded stream.
+ */
+ public ZlibExpanderProvider(long limit)
+ {
+ this.limit = limit;
+ }
+
+ public InputExpander get(final AlgorithmIdentifier algorithm)
+ {
+ return new InputExpander()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithm;
+ }
+
+ public InputStream getInputStream(InputStream comIn)
+ {
+ InputStream s = new InflaterInputStream(comIn);
+ if (limit >= 0)
+ {
+ s = new LimitedInputStream(s, limit);
+ }
+ return s;
+ }
+ };
+ }
+
+ private static class LimitedInputStream
+ extends FilterInputStream
+ {
+ private long remaining;
+
+ public LimitedInputStream(InputStream input, long limit)
+ {
+ super(input);
+
+ this.remaining = limit;
+ }
+
+ public int read()
+ throws IOException
+ {
+ // Only a single 'extra' byte will ever be read
+ if (remaining >= 0)
+ {
+ int b = super.in.read();
+ if (b < 0 || --remaining >= 0)
+ {
+ return b;
+ }
+ }
+
+ throw new StreamOverflowException("expanded byte limit exceeded");
+ }
+
+ public int read(byte[] buf, int off, int len)
+ throws IOException
+ {
+ if (len < 1)
+ {
+ // This will give correct exceptions/returns for strange lengths
+ return super.read(buf, off, len);
+ }
+
+ if (remaining < 1)
+ {
+ // Will either return EOF or throw exception
+ read();
+ return -1;
+ }
+
+ /*
+ * Limit the underlying request to 'remaining' bytes. This ensures the
+ * caller will see the full 'limit' bytes before getting an exception.
+ * Also, only one extra byte will ever be read.
+ */
+ int actualLen = (remaining > len ? len : (int)remaining);
+ int numRead = super.in.read(buf, off, actualLen);
+ if (numRead > 0)
+ {
+ remaining -= numRead;
+ }
+ return numRead;
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8DecryptorProviderBuilder.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8DecryptorProviderBuilder.java
new file mode 100644
index 000000000..22c8c3de3
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8DecryptorProviderBuilder.java
@@ -0,0 +1,156 @@
+package org.spongycastle.openssl.jcajce;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.InvalidKeyException;
+import java.security.Provider;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.spongycastle.asn1.pkcs.KeyDerivationFunc;
+import org.spongycastle.asn1.pkcs.EncryptionScheme;
+import org.spongycastle.asn1.pkcs.PBEParameter;
+import org.spongycastle.asn1.pkcs.PBES2Parameters;
+import org.spongycastle.asn1.pkcs.PBKDF2Params;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.JcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.openssl.PEMException;
+import org.spongycastle.operator.InputDecryptor;
+import org.spongycastle.operator.InputDecryptorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+
+public class JceOpenSSLPKCS8DecryptorProviderBuilder
+{
+ private JcaJceHelper helper = new DefaultJcaJceHelper();
+
+ public JceOpenSSLPKCS8DecryptorProviderBuilder()
+ {
+ helper = new DefaultJcaJceHelper();
+ }
+
+ public JceOpenSSLPKCS8DecryptorProviderBuilder setProvider(String providerName)
+ {
+ helper = new NamedJcaJceHelper(providerName);
+
+ return this;
+ }
+
+ public JceOpenSSLPKCS8DecryptorProviderBuilder setProvider(Provider provider)
+ {
+ helper = new ProviderJcaJceHelper(provider);
+
+ return this;
+ }
+
+ public InputDecryptorProvider build(final char[] password)
+ throws OperatorCreationException
+ {
+ return new InputDecryptorProvider()
+ {
+ public InputDecryptor get(final AlgorithmIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ final Cipher cipher;
+
+ try
+ {
+ if (PEMUtilities.isPKCS5Scheme2(algorithm.getAlgorithm()))
+ {
+ PBES2Parameters params = PBES2Parameters.getInstance(algorithm.getParameters());
+ KeyDerivationFunc func = params.getKeyDerivationFunc();
+ EncryptionScheme scheme = params.getEncryptionScheme();
+ PBKDF2Params defParams = (PBKDF2Params)func.getParameters();
+
+ int iterationCount = defParams.getIterationCount().intValue();
+ byte[] salt = defParams.getSalt();
+
+ String oid = scheme.getAlgorithm().getId();
+
+ SecretKey key = PEMUtilities.generateSecretKeyForPKCS5Scheme2(oid, password, salt, iterationCount);
+
+ cipher = helper.createCipher(oid);
+ AlgorithmParameters algParams = helper.createAlgorithmParameters(oid);
+
+ algParams.init(scheme.getParameters().toASN1Primitive().getEncoded());
+
+ cipher.init(Cipher.DECRYPT_MODE, key, algParams);
+ }
+ else if (PEMUtilities.isPKCS12(algorithm.getAlgorithm()))
+ {
+ PKCS12PBEParams params = PKCS12PBEParams.getInstance(algorithm.getParameters());
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+
+ SecretKeyFactory secKeyFact = helper.createSecretKeyFactory(algorithm.getAlgorithm().getId());
+ PBEParameterSpec defParams = new PBEParameterSpec(params.getIV(), params.getIterations().intValue());
+
+ cipher = helper.createCipher(algorithm.getAlgorithm().getId());
+
+ cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams);
+ }
+ else if (PEMUtilities.isPKCS5Scheme1(algorithm.getAlgorithm()))
+ {
+ PBEParameter params = PBEParameter.getInstance(algorithm.getParameters());
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+
+ SecretKeyFactory secKeyFact = helper.createSecretKeyFactory(algorithm.getAlgorithm().getId());
+ PBEParameterSpec defParams = new PBEParameterSpec(params.getSalt(), params.getIterationCount().intValue());
+
+ cipher = helper.createCipher(algorithm.getAlgorithm().getId());
+
+ cipher.init(Cipher.DECRYPT_MODE, secKeyFact.generateSecret(pbeSpec), defParams);
+ }
+ else
+ {
+ throw new PEMException("Unknown algorithm: " + algorithm.getAlgorithm());
+ }
+
+ return new InputDecryptor()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithm;
+ }
+
+ public InputStream getInputStream(InputStream encIn)
+ {
+ return new CipherInputStream(encIn, cipher);
+ }
+ };
+ }
+ catch (IOException e)
+ {
+ throw new OperatorCreationException(algorithm.getAlgorithm() + " not available: " + e.getMessage(), e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new OperatorCreationException(algorithm.getAlgorithm() + " not available: " + e.getMessage(), e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new OperatorCreationException(algorithm.getAlgorithm() + " not available: " + e.getMessage(), e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new OperatorCreationException(algorithm.getAlgorithm() + " not available: " + e.getMessage(), e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException(algorithm.getAlgorithm() + " not available: " + e.getMessage(), e);
+ }
+ };
+ };
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java
new file mode 100644
index 000000000..60b715d45
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java
@@ -0,0 +1,240 @@
+package org.spongycastle.openssl.jcajce;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.InvalidKeyException;
+import java.security.Provider;
+import java.security.SecureRandom;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.KeyDerivationFunc;
+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.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.JcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.OutputEncryptor;
+import org.spongycastle.operator.jcajce.JceGenericKey;
+
+public class JceOpenSSLPKCS8EncryptorBuilder
+{
+ public static final String AES_128_CBC = NISTObjectIdentifiers.id_aes128_CBC.getId();
+ public static final String AES_192_CBC = NISTObjectIdentifiers.id_aes192_CBC.getId();
+ public static final String AES_256_CBC = NISTObjectIdentifiers.id_aes256_CBC.getId();
+
+ public static final String DES3_CBC = PKCSObjectIdentifiers.des_EDE3_CBC.getId();
+
+ public static final String PBE_SHA1_RC4_128 = PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4.getId();
+ public static final String PBE_SHA1_RC4_40 = PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4.getId();
+ public static final String PBE_SHA1_3DES = PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC.getId();
+ public static final String PBE_SHA1_2DES = PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC.getId();
+ public static final String PBE_SHA1_RC2_128 = PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC.getId();
+ public static final String PBE_SHA1_RC2_40 = PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC.getId();
+
+ private JcaJceHelper helper = new DefaultJcaJceHelper();
+
+ private AlgorithmParameters params;
+ private ASN1ObjectIdentifier algOID;
+ byte[] salt;
+ int iterationCount;
+ private Cipher cipher;
+ private SecureRandom random;
+ private AlgorithmParameterGenerator paramGen;
+ private SecretKeyFactory secKeyFact;
+ private char[] password;
+
+ private SecretKey key;
+
+ public JceOpenSSLPKCS8EncryptorBuilder(ASN1ObjectIdentifier algorithm)
+ {
+ algOID = algorithm;
+
+ this.iterationCount = 2048;
+ }
+
+ public JceOpenSSLPKCS8EncryptorBuilder setRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public JceOpenSSLPKCS8EncryptorBuilder setPasssword(char[] password)
+ {
+ this.password = password;
+
+ return this;
+ }
+
+ public JceOpenSSLPKCS8EncryptorBuilder setIterationCount(int iterationCount)
+ {
+ this.iterationCount = iterationCount;
+
+ return this;
+ }
+
+ public JceOpenSSLPKCS8EncryptorBuilder setProvider(String providerName)
+ {
+ helper = new NamedJcaJceHelper(providerName);
+
+ return this;
+ }
+
+ public JceOpenSSLPKCS8EncryptorBuilder setProvider(Provider provider)
+ {
+ helper = new ProviderJcaJceHelper(provider);
+
+ return this;
+ }
+
+ public OutputEncryptor build()
+ throws OperatorCreationException
+ {
+ final AlgorithmIdentifier algID;
+
+ salt = new byte[20];
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(salt);
+
+ try
+ {
+ this.cipher = helper.createCipher(algOID.getId());
+
+ if (PEMUtilities.isPKCS5Scheme2(algOID))
+ {
+ this.paramGen = helper.createAlgorithmParameterGenerator(algOID.getId());
+ }
+ else
+ {
+ this.secKeyFact = helper.createSecretKeyFactory(algOID.getId());
+ }
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new OperatorCreationException(algOID + " not available: " + e.getMessage(), e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new OperatorCreationException(algOID + " not available: " + e.getMessage(), e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException(algOID + " not available: " + e.getMessage(), e);
+ }
+
+ if (PEMUtilities.isPKCS5Scheme2(algOID))
+ {
+ params = paramGen.generateParameters();
+
+ try
+ {
+ KeyDerivationFunc scheme = new KeyDerivationFunc(algOID, ASN1Primitive.fromByteArray(params.getEncoded()));
+ KeyDerivationFunc func = new KeyDerivationFunc(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, iterationCount));
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(func);
+ v.add(scheme);
+
+ algID = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, PBES2Parameters.getInstance(new DERSequence(v)));
+ }
+ catch (IOException e)
+ {
+ throw new OperatorCreationException(e.getMessage(), e);
+ }
+
+ key = PEMUtilities.generateSecretKeyForPKCS5Scheme2(algOID.getId(), password, salt, iterationCount);
+
+ try
+ {
+ cipher.init(Cipher.ENCRYPT_MODE, key, params);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new OperatorCreationException(e.getMessage(), e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException(e.getMessage(), e);
+ }
+ }
+ else if (PEMUtilities.isPKCS12(algOID))
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new DEROctetString(salt));
+ v.add(new ASN1Integer(iterationCount));
+
+ algID = new AlgorithmIdentifier(algOID, PKCS12PBEParams.getInstance(new DERSequence(v)));
+
+ try
+ {
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount);
+
+ key = secKeyFact.generateSecret(pbeSpec);
+
+ cipher.init(Cipher.ENCRYPT_MODE, key, defParams);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new OperatorCreationException(e.getMessage(), e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException(e.getMessage(), e);
+ }
+ }
+ else
+ {
+ throw new OperatorCreationException("unknown algorithm: " + algOID, null);
+ }
+
+ return new OutputEncryptor()
+ {
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algID;
+ }
+
+ public OutputStream getOutputStream(OutputStream encOut)
+ {
+ return new CipherOutputStream(encOut, cipher);
+ }
+
+ public GenericKey getKey()
+ {
+ return new JceGenericKey(algID, key);
+ }
+ };
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/JcaContentSignerBuilder.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/JcaContentSignerBuilder.java
new file mode 100644
index 000000000..f677e3f93
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/JcaContentSignerBuilder.java
@@ -0,0 +1,166 @@
+package org.spongycastle.operator.jcajce;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.JcaJceHelper;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.OperatorStreamException;
+import org.spongycastle.operator.RuntimeOperatorException;
+
+public class JcaContentSignerBuilder
+{
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+ private SecureRandom random;
+ private String signatureAlgorithm;
+ private AlgorithmIdentifier sigAlgId;
+
+ public JcaContentSignerBuilder(String signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+ this.sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find(signatureAlgorithm);
+ }
+
+ public JcaContentSignerBuilder setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JcaContentSignerBuilder setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public JcaContentSignerBuilder setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public ContentSigner build(PrivateKey privateKey)
+ throws OperatorCreationException
+ {
+ try
+ {
+ final Signature sig = helper.createSignature(sigAlgId);
+
+ if (random != null)
+ {
+ sig.initSign(privateKey);
+ }
+ else
+ {
+ sig.initSign(privateKey);
+ }
+
+ return new ContentSigner()
+ {
+ private SignatureOutputStream stream = new SignatureOutputStream(sig);
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return sigAlgId;
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return stream;
+ }
+
+ public byte[] getSignature()
+ {
+ try
+ {
+ return stream.getSignature();
+ }
+ catch (SignatureException e)
+ {
+ throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e);
+ }
+ }
+ };
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new OperatorCreationException("cannot create signer: " + e.getMessage(), e);
+ }
+ catch (Exception e)
+ {
+ throw new OperatorCreationException("cannot create signer: " + e.getMessage(), e);
+ }
+ }
+
+ private class SignatureOutputStream
+ extends OutputStream
+ {
+ private Signature sig;
+
+ SignatureOutputStream(Signature sig)
+ {
+ this.sig = sig;
+ }
+
+ public void write(byte[] bytes, int off, int len)
+ throws IOException
+ {
+ try
+ {
+ sig.update(bytes, off, len);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ public void write(byte[] bytes)
+ throws IOException
+ {
+ try
+ {
+ sig.update(bytes);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ try
+ {
+ sig.update((byte)b);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ byte[] getSignature()
+ throws SignatureException
+ {
+ return sig.sign();
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java
new file mode 100644
index 000000000..fe44d94e3
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java
@@ -0,0 +1,312 @@
+package org.spongycastle.operator.jcajce;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.GeneralSecurityException;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.ContentVerifier;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.OperatorStreamException;
+import org.spongycastle.operator.RawContentVerifier;
+import org.spongycastle.operator.RuntimeOperatorException;
+
+public class JcaContentVerifierProviderBuilder
+{
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+
+ public JcaContentVerifierProviderBuilder()
+ {
+ }
+
+ public JcaContentVerifierProviderBuilder setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JcaContentVerifierProviderBuilder setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public ContentVerifierProvider build(X509CertificateHolder certHolder)
+ throws OperatorCreationException, CertificateException
+ {
+ return build(helper.convertCertificate(certHolder));
+ }
+
+ public ContentVerifierProvider build(final X509Certificate certificate)
+ throws OperatorCreationException
+ {
+ final X509CertificateHolder certHolder;
+
+ try
+ {
+ certHolder = new JcaX509CertificateHolder(certificate);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new OperatorCreationException("cannot process certificate: " + e.getMessage(), e);
+ }
+
+ return new ContentVerifierProvider()
+ {
+ private SignatureOutputStream stream;
+
+ public boolean hasAssociatedCertificate()
+ {
+ return true;
+ }
+
+ public X509CertificateHolder getAssociatedCertificate()
+ {
+ return certHolder;
+ }
+
+ public ContentVerifier get(AlgorithmIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ try
+ {
+ Signature sig = helper.createSignature(algorithm);
+
+ sig.initVerify(certificate.getPublicKey());
+
+ stream = new SignatureOutputStream(sig);
+ }
+ catch (Exception e)
+ {
+ throw new OperatorCreationException("exception on setup: " + e, e);
+ }
+
+ Signature rawSig = createRawSig(algorithm, certificate.getPublicKey());
+
+ if (rawSig != null)
+ {
+ return new RawSigVerifier(algorithm, stream, rawSig);
+ }
+ else
+ {
+ return new SigVerifier(algorithm, stream);
+ }
+ }
+ };
+ }
+
+ public ContentVerifierProvider build(final PublicKey publicKey)
+ throws OperatorCreationException
+ {
+ return new ContentVerifierProvider()
+ {
+ public boolean hasAssociatedCertificate()
+ {
+ return false;
+ }
+
+ public X509CertificateHolder getAssociatedCertificate()
+ {
+ return null;
+ }
+
+ public ContentVerifier get(AlgorithmIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ SignatureOutputStream stream = createSignatureStream(algorithm, publicKey);
+
+ Signature rawSig = createRawSig(algorithm, publicKey);
+
+ if (rawSig != null)
+ {
+ return new RawSigVerifier(algorithm, stream, rawSig);
+ }
+ else
+ {
+ return new SigVerifier(algorithm, stream);
+ }
+ }
+ };
+ }
+
+ public ContentVerifierProvider build(SubjectPublicKeyInfo publicKey)
+ throws OperatorCreationException
+ {
+ return this.build(helper.convertPublicKey(publicKey));
+ }
+
+ private SignatureOutputStream createSignatureStream(AlgorithmIdentifier algorithm, PublicKey publicKey)
+ throws OperatorCreationException
+ {
+ try
+ {
+ Signature sig = helper.createSignature(algorithm);
+
+ sig.initVerify(publicKey);
+
+ return new SignatureOutputStream(sig);
+ }
+ catch (Exception e)
+ {
+ throw new OperatorCreationException("exception on setup: " + e, e);
+ }
+ }
+
+ private Signature createRawSig(AlgorithmIdentifier algorithm, PublicKey publicKey)
+ {
+ Signature rawSig;
+ try
+ {
+ rawSig = helper.createRawSignature(algorithm);
+
+ if (rawSig != null)
+ {
+ rawSig.initVerify(publicKey);
+ }
+ }
+ catch (Exception e)
+ {
+ rawSig = null;
+ }
+ return rawSig;
+ }
+
+ private class SigVerifier
+ implements ContentVerifier
+ {
+ private SignatureOutputStream stream;
+ private AlgorithmIdentifier algorithm;
+
+ SigVerifier(AlgorithmIdentifier algorithm, SignatureOutputStream stream)
+ {
+ this.algorithm = algorithm;
+ this.stream = stream;
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithm;
+ }
+
+ public OutputStream getOutputStream()
+ {
+ if (stream == null)
+ {
+ throw new IllegalStateException("verifier not initialised");
+ }
+
+ return stream;
+ }
+
+ public boolean verify(byte[] expected)
+ {
+ try
+ {
+ return stream.verify(expected);
+ }
+ catch (SignatureException e)
+ {
+ throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ private class RawSigVerifier
+ extends SigVerifier
+ implements RawContentVerifier
+ {
+ private Signature rawSignature;
+
+ RawSigVerifier(AlgorithmIdentifier algorithm, SignatureOutputStream stream, Signature rawSignature)
+ {
+ super(algorithm, stream);
+ this.rawSignature = rawSignature;
+ }
+
+ public boolean verify(byte[] digest, byte[] expected)
+ {
+ try
+ {
+ rawSignature.update(digest);
+
+ return rawSignature.verify(expected);
+ }
+ catch (SignatureException e)
+ {
+ throw new RuntimeOperatorException("exception obtaining raw signature: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ private class SignatureOutputStream
+ extends OutputStream
+ {
+ private Signature sig;
+
+ SignatureOutputStream(Signature sig)
+ {
+ this.sig = sig;
+ }
+
+ public void write(byte[] bytes, int off, int len)
+ throws IOException
+ {
+ try
+ {
+ sig.update(bytes, off, len);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ public void write(byte[] bytes)
+ throws IOException
+ {
+ try
+ {
+ sig.update(bytes);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ try
+ {
+ sig.update((byte)b);
+ }
+ catch (SignatureException e)
+ {
+ throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
+ }
+ }
+
+ boolean verify(byte[] expected)
+ throws SignatureException
+ {
+ return sig.verify(expected);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java
new file mode 100644
index 000000000..3cf379a2b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java
@@ -0,0 +1,128 @@
+package org.spongycastle.operator.jcajce;
+
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.ProviderException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.AsymmetricKeyUnwrapper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+
+public class JceAsymmetricKeyUnwrapper
+ extends AsymmetricKeyUnwrapper
+{
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+ private Map extraMappings = new HashMap();
+ private PrivateKey privKey;
+
+ public JceAsymmetricKeyUnwrapper(AlgorithmIdentifier algorithmIdentifier, PrivateKey privKey)
+ {
+ super(algorithmIdentifier);
+
+ this.privKey = privKey;
+ }
+
+ public JceAsymmetricKeyUnwrapper setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JceAsymmetricKeyUnwrapper setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ /**
+ * Internally algorithm ids are converted into cipher names using a lookup table. For some providers
+ * the standard lookup table won't work. Use this method to establish a specific mapping from an
+ * algorithm identifier to a specific algorithm.
+ * <p>
+ * For example:
+ * <pre>
+ * unwrapper.setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ * </pre>
+ * </p>
+ * @param algorithm OID of algorithm in recipient.
+ * @param algorithmName JCE algorithm name to use.
+ * @return the current Unwrapper.
+ */
+ public JceAsymmetricKeyUnwrapper setAlgorithmMapping(ASN1ObjectIdentifier algorithm, String algorithmName)
+ {
+ extraMappings.put(algorithm, algorithmName);
+
+ return this;
+ }
+
+ public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm, byte[] encryptedKey)
+ throws OperatorException
+ {
+ try
+ {
+ Key sKey = null;
+
+ Cipher keyCipher = helper.createAsymmetricWrapper(this.getAlgorithmIdentifier().getAlgorithm(), extraMappings);
+
+ try
+ {
+ keyCipher.init(Cipher.UNWRAP_MODE, privKey);
+ sKey = keyCipher.unwrap(encryptedKey, helper.getKeyAlgorithmName(encryptedKeyAlgorithm.getAlgorithm()), Cipher.SECRET_KEY);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ }
+ catch (InvalidKeyException e)
+ {
+ }
+ catch (IllegalStateException e)
+ {
+ }
+ catch (UnsupportedOperationException e)
+ {
+ }
+ catch (ProviderException e)
+ {
+ }
+
+ // some providers do not support UNWRAP (this appears to be only for asymmetric algorithms)
+ if (sKey == null)
+ {
+ keyCipher.init(Cipher.DECRYPT_MODE, privKey);
+ sKey = new SecretKeySpec(keyCipher.doFinal(encryptedKey), encryptedKeyAlgorithm.getAlgorithm().getId());
+ }
+
+ return new GenericKey(sKey);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new OperatorException("key invalid: " + e.getMessage(), e);
+ }
+ catch (IllegalBlockSizeException e)
+ {
+ throw new OperatorException("illegal blocksize: " + e.getMessage(), e);
+ }
+ catch (BadPaddingException e)
+ {
+ throw new OperatorException("bad padding: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/JceSymmetricKeyWrapper.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/JceSymmetricKeyWrapper.java
new file mode 100644
index 000000000..4f5818246
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/JceSymmetricKeyWrapper.java
@@ -0,0 +1,159 @@
+package org.spongycastle.operator.jcajce;
+
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.InvalidKeyException;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.kisa.KISAObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.ntt.NTTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OperatorException;
+import org.spongycastle.operator.SymmetricKeyWrapper;
+
+public class JceSymmetricKeyWrapper
+ extends SymmetricKeyWrapper
+{
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+ private SecureRandom random;
+ private SecretKey wrappingKey;
+
+ public JceSymmetricKeyWrapper(SecretKey wrappingKey)
+ {
+ super(determineKeyEncAlg(wrappingKey));
+
+ this.wrappingKey = wrappingKey;
+ }
+
+ public JceSymmetricKeyWrapper setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JceSymmetricKeyWrapper setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public JceSymmetricKeyWrapper setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public byte[] generateWrappedKey(GenericKey encryptionKey)
+ throws OperatorException
+ {
+ Key contentEncryptionKeySpec = OperatorUtils.getJceKey(encryptionKey);
+
+ Cipher keyEncryptionCipher = helper.createSymmetricWrapper(this.getAlgorithmIdentifier().getAlgorithm());
+
+ try
+ {
+ keyEncryptionCipher.init(Cipher.WRAP_MODE, wrappingKey, random);
+
+ return keyEncryptionCipher.wrap(contentEncryptionKeySpec);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new OperatorException("cannot wrap key: " + e.getMessage(), e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorException("cannot wrap key: " + e.getMessage(), e);
+ }
+ }
+
+ private static AlgorithmIdentifier determineKeyEncAlg(SecretKey key)
+ {
+ String algorithm = key.getAlgorithm();
+
+ if (algorithm.startsWith("DES"))
+ {
+ return new AlgorithmIdentifier(new DERObjectIdentifier(
+ "1.2.840.113549.1.9.16.3.6"), new DERNull());
+ }
+ else if (algorithm.startsWith("RC2"))
+ {
+ return new AlgorithmIdentifier(new DERObjectIdentifier(
+ "1.2.840.113549.1.9.16.3.7"), new DERInteger(58));
+ }
+ else if (algorithm.startsWith("AES"))
+ {
+ int length = key.getEncoded().length * 8;
+ DERObjectIdentifier wrapOid;
+
+ if (length == 128)
+ {
+ wrapOid = NISTObjectIdentifiers.id_aes128_wrap;
+ }
+ else if (length == 192)
+ {
+ wrapOid = NISTObjectIdentifiers.id_aes192_wrap;
+ }
+ else if (length == 256)
+ {
+ wrapOid = NISTObjectIdentifiers.id_aes256_wrap;
+ }
+ else
+ {
+ throw new IllegalArgumentException("illegal keysize in AES");
+ }
+
+ return new AlgorithmIdentifier(wrapOid); // parameters absent
+ }
+ else if (algorithm.startsWith("SEED"))
+ {
+ // parameters absent
+ return new AlgorithmIdentifier(
+ KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap);
+ }
+ else if (algorithm.startsWith("Camellia"))
+ {
+ int length = key.getEncoded().length * 8;
+ DERObjectIdentifier wrapOid;
+
+ if (length == 128)
+ {
+ wrapOid = NTTObjectIdentifiers.id_camellia128_wrap;
+ }
+ else if (length == 192)
+ {
+ wrapOid = NTTObjectIdentifiers.id_camellia192_wrap;
+ }
+ else if (length == 256)
+ {
+ wrapOid = NTTObjectIdentifiers.id_camellia256_wrap;
+ }
+ else
+ {
+ throw new IllegalArgumentException(
+ "illegal keysize in Camellia");
+ }
+
+ return new AlgorithmIdentifier(wrapOid); // parameters must be
+ // absent
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown algorithm");
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/OperatorHelper.java b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/OperatorHelper.java
new file mode 100644
index 000000000..25aaefd38
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.1/org/spongycastle/operator/jcajce/OperatorHelper.java
@@ -0,0 +1,478 @@
+package org.spongycastle.operator.jcajce;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.MessageDigest;
+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.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+//import java.security.spec.PSSParameterSpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.kisa.KISAObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.ntt.NTTObjectIdentifiers;
+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.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.jcajce.JcaJceHelper;
+import org.spongycastle.jcajce.JcaJceUtils;
+import org.spongycastle.operator.OperatorCreationException;
+
+class OperatorHelper
+{
+ private static final Map oids = new HashMap();
+ private static final Map asymmetricWrapperAlgNames = new HashMap();
+ private static final Map symmetricWrapperAlgNames = new HashMap();
+ private static final Map symmetricKeyAlgNames = new HashMap();
+
+ static
+ {
+ //
+ // reverse mappings
+ //
+ oids.put(new ASN1ObjectIdentifier("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 ASN1ObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
+ oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA");
+ oids.put(new ASN1ObjectIdentifier("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");
+
+ oids.put(OIWObjectIdentifiers.idSHA1, "SHA-1");
+ oids.put(NISTObjectIdentifiers.id_sha224, "SHA-224");
+ oids.put(NISTObjectIdentifiers.id_sha256, "SHA-256");
+ oids.put(NISTObjectIdentifiers.id_sha384, "SHA-384");
+ oids.put(NISTObjectIdentifiers.id_sha512, "SHA-512");
+ oids.put(TeleTrusTObjectIdentifiers.ripemd128, "RIPEMD-128");
+ oids.put(TeleTrusTObjectIdentifiers.ripemd160, "RIPEMD-160");
+ oids.put(TeleTrusTObjectIdentifiers.ripemd256, "RIPEMD-256");
+
+ asymmetricWrapperAlgNames.put(PKCSObjectIdentifiers.rsaEncryption, "RSA/ECB/PKCS1Padding");
+
+ symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "DESEDEWrap");
+ symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.id_alg_CMSRC2wrap, "RC2Wrap");
+ symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes128_wrap, "AESWrap");
+ symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes192_wrap, "AESWrap");
+ symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes256_wrap, "AESWrap");
+ symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia128_wrap, "CamelliaWrap");
+ symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia192_wrap, "CamelliaWrap");
+ symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia256_wrap, "CamelliaWrap");
+ symmetricWrapperAlgNames.put(KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap, "SEEDWrap");
+ symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESede");
+
+ symmetricKeyAlgNames.put(NISTObjectIdentifiers.aes, "AES");
+ symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes128_CBC, "AES");
+ symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes192_CBC, "AES");
+ symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes256_CBC, "AES");
+ symmetricKeyAlgNames.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESede");
+ symmetricKeyAlgNames.put(PKCSObjectIdentifiers.RC2_CBC, "RC2");
+ }
+
+ private JcaJceHelper helper;
+
+ OperatorHelper(JcaJceHelper helper)
+ {
+ this.helper = helper;
+ }
+
+ Cipher createAsymmetricWrapper(ASN1ObjectIdentifier algorithm, Map extraAlgNames)
+ throws OperatorCreationException
+ {
+ try
+ {
+ String cipherName = null;
+
+ if (!extraAlgNames.isEmpty())
+ {
+ cipherName = (String)extraAlgNames.get(algorithm);
+ }
+
+ if (cipherName == null)
+ {
+ cipherName = (String)asymmetricWrapperAlgNames.get(algorithm);
+ }
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createCipher(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // try alternate for RSA
+ if (cipherName.equals("RSA/ECB/PKCS1Padding"))
+ {
+ try
+ {
+ return helper.createCipher("RSA/NONE/PKCS1Padding");
+ }
+ catch (NoSuchAlgorithmException ex)
+ {
+ // Ignore
+ }
+ }
+ // Ignore
+ }
+ }
+
+ return helper.createCipher(algorithm.getId());
+ }
+ catch (Exception e)
+ {
+ throw new OperatorCreationException("cannot create cipher: " + e.getMessage(), e);
+ }
+ }
+
+ Cipher createSymmetricWrapper(ASN1ObjectIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ try
+ {
+ String cipherName = (String)symmetricWrapperAlgNames.get(algorithm);
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createCipher(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createCipher(algorithm.getId());
+ }
+ catch (Exception e)
+ {
+ throw new OperatorCreationException("cannot create cipher: " + e.getMessage(), e);
+ }
+ }
+
+ AlgorithmParameters createAlgorithmParameters(AlgorithmIdentifier cipherAlgId)
+ throws OperatorCreationException
+ {
+ AlgorithmParameters parameters;
+
+ if (cipherAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption))
+ {
+ return null;
+ }
+
+ try
+ {
+ parameters = helper.createAlgorithmParameters(cipherAlgId.getAlgorithm().getId());
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ return null; // There's a good chance there aren't any!
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new OperatorCreationException("cannot create algorithm parameters: " + e.getMessage(), e);
+ }
+
+ try
+ {
+ parameters.init(cipherAlgId.getParameters().toASN1Primitive().getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new OperatorCreationException("cannot initialise algorithm parameters: " + e.getMessage(), e);
+ }
+
+ return parameters;
+ }
+
+ MessageDigest createDigest(AlgorithmIdentifier digAlgId)
+ throws GeneralSecurityException
+ {
+ MessageDigest dig;
+
+ try
+ {
+ try
+ {
+ dig = helper.createDigest(getDigestAlgName(digAlgId.getAlgorithm()));
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ //
+ // try an alternate
+ //
+ if (oids.get(digAlgId.getAlgorithm()) != null)
+ {
+ String digestAlgorithm = (String)oids.get(digAlgId.getAlgorithm());
+
+ dig = helper.createDigest(digestAlgorithm);
+ }
+ else
+ {
+ throw e;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new GeneralSecurityException(ex.toString());
+ }
+
+ return dig;
+ }
+
+ Signature createSignature(AlgorithmIdentifier sigAlgId)
+ throws Exception
+ {
+ Signature sig;
+
+ try
+ {
+ sig = helper.createSignature(getSignatureName(sigAlgId));
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ //
+ // try an alternate
+ //
+ if (oids.get(sigAlgId.getAlgorithm()) != null)
+ {
+ String signatureAlgorithm = (String)oids.get(sigAlgId.getAlgorithm());
+
+ sig = helper.createSignature(signatureAlgorithm);
+ }
+ else
+ {
+ throw e;
+ }
+ }
+
+ return sig;
+ }
+
+ public Signature createRawSignature(AlgorithmIdentifier algorithm)
+ {
+ Signature sig;
+
+ try
+ {
+ String algName = getSignatureName(algorithm);
+
+ algName = "NONE" + algName.substring(algName.indexOf("WITH"));
+
+ sig = helper.createSignature(algName);
+
+ // RFC 4056
+ // When the id-RSASSA-PSS algorithm identifier is used for a signature,
+ // the AlgorithmIdentifier parameters field MUST contain RSASSA-PSS-params.
+/*
+ if (algorithm.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ AlgorithmParameters params = helper.createAlgorithmParameters(algName);
+
+ JcaJceUtils.loadParameters(params, algorithm.getParameters());
+
+ PSSParameterSpec spec = (PSSParameterSpec)params.getParameterSpec(PSSParameterSpec.class);
+ sig.setParameter(spec);
+ }
+*/
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+
+ return sig;
+ }
+
+ private static String getSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ ASN1Encodable params = sigAlgId.getParameters();
+
+ if (params != null && !DERNull.INSTANCE.equals(params))
+ {
+ if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+ return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "WITHRSAANDMGF1";
+ }
+ }
+
+ if (oids.containsKey(sigAlgId.getAlgorithm()))
+ {
+ return (String)oids.get(sigAlgId.getAlgorithm());
+ }
+
+ return sigAlgId.getAlgorithm().getId();
+ }
+
+ 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();
+ }
+ }
+
+ public X509Certificate convertCertificate(X509CertificateHolder certHolder)
+ throws CertificateException
+ {
+
+ try
+ {
+ CertificateFactory certFact = helper.createCertificateFactory("X.509");
+
+ return (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(certHolder.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new OpCertificateException("cannot get encoded form of certificate: " + e.getMessage(), e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new OpCertificateException("cannot create certificate factory: " + e.getMessage(), e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new OpCertificateException("cannot find factory provider: " + e.getMessage(), e);
+ }
+ }
+
+ public PublicKey convertPublicKey(SubjectPublicKeyInfo publicKeyInfo)
+ throws OperatorCreationException
+ {
+ try
+ {
+ KeyFactory keyFact = helper.createKeyFactory(publicKeyInfo.getAlgorithm().getAlgorithm().getId());
+
+ return keyFact.generatePublic(new X509EncodedKeySpec(publicKeyInfo.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new OperatorCreationException("cannot get encoded form of key: " + e.getMessage(), e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new OperatorCreationException("cannot create key factory: " + e.getMessage(), e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new OperatorCreationException("cannot find factory provider: " + e.getMessage(), e);
+ }
+ catch (InvalidKeySpecException e)
+ {
+ throw new OperatorCreationException("cannot create key factory: " + e.getMessage(), e);
+ }
+ }
+
+ // TODO: put somewhere public so cause easily accessed
+ private static class OpCertificateException
+ extends CertificateException
+ {
+ private Throwable cause;
+
+ public OpCertificateException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+
+ String getKeyAlgorithmName(ASN1ObjectIdentifier oid)
+ {
+
+ String name = (String)symmetricKeyAlgNames.get(oid);
+
+ if (name != null)
+ {
+ return name;
+ }
+
+ return oid.getId();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cert/crmf/jcajce/JceCRMFEncryptorBuilder.java b/libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cert/crmf/jcajce/JceCRMFEncryptorBuilder.java
new file mode 100644
index 000000000..1a1114561
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cert/crmf/jcajce/JceCRMFEncryptorBuilder.java
@@ -0,0 +1,135 @@
+package org.spongycastle.cert.crmf.jcajce;
+
+import java.io.OutputStream;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.Provider;
+import java.security.SecureRandom;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.crmf.CRMFException;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OutputEncryptor;
+
+public class JceCRMFEncryptorBuilder
+{
+ private ASN1ObjectIdentifier encryptionOID;
+ private int keySize;
+
+ private CRMFHelper helper = new CRMFHelper(new DefaultJcaJceHelper());
+ private SecureRandom random;
+
+ public JceCRMFEncryptorBuilder(ASN1ObjectIdentifier encryptionOID)
+ {
+ this(encryptionOID, -1);
+ }
+
+ public JceCRMFEncryptorBuilder(ASN1ObjectIdentifier encryptionOID, int keySize)
+ {
+ this.encryptionOID = encryptionOID;
+ this.keySize = keySize;
+ }
+
+ public JceCRMFEncryptorBuilder setProvider(Provider provider)
+ {
+ this.helper = new CRMFHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JceCRMFEncryptorBuilder setProvider(String providerName)
+ {
+ this.helper = new CRMFHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public JceCRMFEncryptorBuilder setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public OutputEncryptor build()
+ throws CRMFException
+ {
+ return new CRMFOutputEncryptor(encryptionOID, keySize, random);
+ }
+
+ private class CRMFOutputEncryptor
+ implements OutputEncryptor
+ {
+ private SecretKey encKey;
+ private AlgorithmIdentifier algorithmIdentifier;
+ private Cipher cipher;
+
+ CRMFOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, SecureRandom random)
+ throws CRMFException
+ {
+ KeyGenerator keyGen = helper.createKeyGenerator(encryptionOID);
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ if (keySize < 0)
+ {
+ keyGen.init(random);
+ }
+ else
+ {
+ keyGen.init(keySize, random);
+ }
+
+ cipher = helper.createCipher(encryptionOID);
+ encKey = keyGen.generateKey();
+ AlgorithmParameters params = helper.generateParameters(encryptionOID, encKey, random);
+
+ try
+ {
+ cipher.init(Cipher.ENCRYPT_MODE, encKey, params, random);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CRMFException("unable to initialize cipher: " + e.getMessage(), e);
+ }
+
+ //
+ // If params are null we try and second guess on them as some providers don't provide
+ // algorithm parameter generation explicity but instead generate them under the hood.
+ //
+ if (params == null)
+ {
+ params = cipher.getParameters();
+ }
+
+ algorithmIdentifier = helper.getAlgorithmIdentifier(encryptionOID, params);
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmIdentifier;
+ }
+
+ public OutputStream getOutputStream(OutputStream dOut)
+ {
+ return new CipherOutputStream(dOut, cipher);
+ }
+
+ public GenericKey getKey()
+ {
+ return new GenericKey(encKey);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cert/jcajce/JcaAttrCertStore.java b/libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cert/jcajce/JcaAttrCertStore.java
new file mode 100644
index 000000000..3135567b5
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cert/jcajce/JcaAttrCertStore.java
@@ -0,0 +1,72 @@
+package org.spongycastle.cert.jcajce;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.util.CollectionStore;
+import org.spongycastle.x509.X509AttributeCertificate;
+
+/**
+ * Class for storing Attribute Certificates for later lookup.
+ * <p>
+ * The class will convert X509AttributeCertificate objects into X509AttributeCertificateHolder objects.
+ * </p>
+ */
+public class JcaAttrCertStore
+ extends CollectionStore
+{
+ /**
+ * Basic constructor.
+ *
+ * @param collection - initial contents for the store, this is copied.
+ */
+ public JcaAttrCertStore(Collection collection)
+ throws IOException
+ {
+ super(convertCerts(collection));
+ }
+
+ public JcaAttrCertStore(X509AttributeCertificate attrCert)
+ throws IOException
+ {
+ this(convertCert(attrCert));
+ }
+
+ private static Collection convertCert(X509AttributeCertificate attrCert)
+ throws IOException
+ {
+ List tmp = new ArrayList();
+
+ tmp.add(attrCert);
+
+ return convertCerts(tmp);
+ }
+
+ private static Collection convertCerts(Collection collection)
+ throws IOException
+ {
+ List list = new ArrayList(collection.size());
+
+ for (Iterator it = collection.iterator(); it.hasNext();)
+ {
+ Object o = it.next();
+
+ if (o instanceof X509AttributeCertificate)
+ {
+ X509AttributeCertificate cert = (X509AttributeCertificate)o;
+
+ list.add(new JcaX509AttributeCertificateHolder(cert));
+ }
+ else
+ {
+ list.add(o);
+ }
+ }
+
+ return list;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cms/bc/BcCMSContentEncryptorBuilder.java b/libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cms/bc/BcCMSContentEncryptorBuilder.java
new file mode 100644
index 000000000..0e0c1f9fe
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cms/bc/BcCMSContentEncryptorBuilder.java
@@ -0,0 +1,124 @@
+package org.spongycastle.cms.bc;
+
+import java.io.OutputStream;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.crypto.BufferedBlockCipher;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.StreamCipher;
+import org.spongycastle.crypto.io.CipherOutputStream;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OutputEncryptor;
+import org.spongycastle.util.Integers;
+
+public class BcCMSContentEncryptorBuilder
+{
+ private static Map keySizes = new HashMap();
+
+ static
+ {
+ keySizes.put(CMSAlgorithm.AES128_CBC, Integers.valueOf(128));
+ keySizes.put(CMSAlgorithm.AES192_CBC, Integers.valueOf(192));
+ keySizes.put(CMSAlgorithm.AES256_CBC, Integers.valueOf(256));
+
+ keySizes.put(CMSAlgorithm.CAMELLIA128_CBC, Integers.valueOf(128));
+ keySizes.put(CMSAlgorithm.CAMELLIA192_CBC, Integers.valueOf(192));
+ keySizes.put(CMSAlgorithm.CAMELLIA256_CBC, Integers.valueOf(256));
+ }
+
+ private static int getKeySize(ASN1ObjectIdentifier oid)
+ {
+ Integer size = (Integer)keySizes.get(oid);
+
+ if (size != null)
+ {
+ return size.intValue();
+ }
+
+ return -1;
+ }
+
+ private ASN1ObjectIdentifier encryptionOID;
+ private int keySize;
+
+ private EnvelopedDataHelper helper = new EnvelopedDataHelper();
+ private SecureRandom random;
+
+ public BcCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID)
+ {
+ this(encryptionOID, getKeySize(encryptionOID));
+ }
+
+ public BcCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID, int keySize)
+ {
+ this.encryptionOID = encryptionOID;
+ this.keySize = keySize;
+ }
+
+ public BcCMSContentEncryptorBuilder setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public OutputEncryptor build()
+ throws CMSException
+ {
+ return new CMSOutputEncryptor(encryptionOID, keySize, random);
+ }
+
+ private class CMSOutputEncryptor
+ implements OutputEncryptor
+ {
+ private KeyParameter encKey;
+ private AlgorithmIdentifier algorithmIdentifier;
+ private Object cipher;
+
+ CMSOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, SecureRandom random)
+ throws CMSException
+ {
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ CipherKeyGenerator keyGen = helper.createKeyGenerator(encryptionOID, random);
+
+ encKey = new KeyParameter(keyGen.generateKey());
+
+ algorithmIdentifier = helper.generateAlgorithmIdentifier(encryptionOID, encKey, random);
+
+ cipher = helper.createContentCipher(true, encKey, algorithmIdentifier);
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmIdentifier;
+ }
+
+ public OutputStream getOutputStream(OutputStream dOut)
+ {
+ if (cipher instanceof BufferedBlockCipher)
+ {
+ return new CipherOutputStream(dOut, (BufferedBlockCipher)cipher);
+ }
+ else
+ {
+ return new CipherOutputStream(dOut, (StreamCipher)cipher);
+ }
+ }
+
+ public GenericKey getKey()
+ {
+ return new GenericKey(algorithmIdentifier, encKey.getKey());
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java b/libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java
new file mode 100644
index 000000000..60bd74a75
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java
@@ -0,0 +1,161 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.OutputStream;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.OutputEncryptor;
+import org.spongycastle.util.Integers;
+
+public class JceCMSContentEncryptorBuilder
+{
+ private static Map keySizes = new HashMap();
+
+ static
+ {
+ keySizes.put(CMSAlgorithm.AES128_CBC, Integers.valueOf(128));
+ keySizes.put(CMSAlgorithm.AES192_CBC, Integers.valueOf(192));
+ keySizes.put(CMSAlgorithm.AES256_CBC, Integers.valueOf(256));
+
+ keySizes.put(CMSAlgorithm.CAMELLIA128_CBC, Integers.valueOf(128));
+ keySizes.put(CMSAlgorithm.CAMELLIA192_CBC, Integers.valueOf(192));
+ keySizes.put(CMSAlgorithm.CAMELLIA256_CBC, Integers.valueOf(256));
+ }
+
+ private static int getKeySize(ASN1ObjectIdentifier oid)
+ {
+ Integer size = (Integer)keySizes.get(oid);
+
+ if (size != null)
+ {
+ return size.intValue();
+ }
+
+ return -1;
+ }
+
+ private ASN1ObjectIdentifier encryptionOID;
+ private int keySize;
+
+ private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+ private SecureRandom random;
+
+ public JceCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID)
+ {
+ this(encryptionOID, getKeySize(encryptionOID));
+ }
+
+ public JceCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID, int keySize)
+ {
+ this.encryptionOID = encryptionOID;
+ this.keySize = keySize;
+ }
+
+ public JceCMSContentEncryptorBuilder setProvider(Provider provider)
+ {
+ this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
+
+ return this;
+ }
+
+ public JceCMSContentEncryptorBuilder setProvider(String providerName)
+ {
+ this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
+
+ return this;
+ }
+
+ public JceCMSContentEncryptorBuilder setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public OutputEncryptor build()
+ throws CMSException
+ {
+ return new CMSOutputEncryptor(encryptionOID, keySize, random);
+ }
+
+ private class CMSOutputEncryptor
+ implements OutputEncryptor
+ {
+ private SecretKey encKey;
+ private AlgorithmIdentifier algorithmIdentifier;
+ private Cipher cipher;
+
+ CMSOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, SecureRandom random)
+ throws CMSException
+ {
+ KeyGenerator keyGen = helper.createKeyGenerator(encryptionOID);
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ if (keySize < 0)
+ {
+ keyGen.init(random);
+ }
+ else
+ {
+ keyGen.init(keySize, random);
+ }
+
+ cipher = helper.createCipher(encryptionOID);
+ encKey = keyGen.generateKey();
+ AlgorithmParameters params = helper.generateParameters(encryptionOID, encKey, random);
+
+ try
+ {
+ cipher.init(Cipher.ENCRYPT_MODE, encKey, params, random);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("unable to initialize cipher: " + e.getMessage(), e);
+ }
+
+ //
+ // If params are null we try and second guess on them as some providers don't provide
+ // algorithm parameter generation explicity but instead generate them under the hood.
+ //
+ if (params == null)
+ {
+ params = cipher.getParameters();
+ }
+
+ algorithmIdentifier = helper.getAlgorithmIdentifier(encryptionOID, params);
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmIdentifier;
+ }
+
+ public OutputStream getOutputStream(OutputStream dOut)
+ {
+ return new CipherOutputStream(dOut, cipher);
+ }
+
+ public GenericKey getKey()
+ {
+ return new GenericKey(encKey);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java b/libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java
new file mode 100644
index 000000000..ab168ffb8
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.2/org/spongycastle/cms/jcajce/JceCMSMacCalculatorBuilder.java
@@ -0,0 +1,155 @@
+package org.spongycastle.cms.jcajce;
+
+import java.io.OutputStream;
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.jcajce.io.MacOutputStream;
+import org.spongycastle.operator.GenericKey;
+import org.spongycastle.operator.MacCalculator;
+
+public class JceCMSMacCalculatorBuilder
+{
+ private ASN1ObjectIdentifier macOID;
+ private int keySize;
+
+ private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+ private SecureRandom random;
+ private MacOutputStream macOutputStream;
+
+ public JceCMSMacCalculatorBuilder(ASN1ObjectIdentifier macOID)
+ {
+ this(macOID, -1);
+ }
+
+ public JceCMSMacCalculatorBuilder(ASN1ObjectIdentifier macOID, int keySize)
+ {
+ this.macOID = macOID;
+ this.keySize = keySize;
+ }
+
+ public JceCMSMacCalculatorBuilder setProvider(Provider provider)
+ {
+ this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
+
+ return this;
+ }
+
+ public JceCMSMacCalculatorBuilder setProvider(String providerName)
+ {
+ this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
+
+ return this;
+ }
+
+ public JceCMSMacCalculatorBuilder setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ public MacCalculator build()
+ throws CMSException
+ {
+ return new CMSOutputEncryptor(macOID, keySize, random);
+ }
+
+ private class CMSOutputEncryptor
+ implements MacCalculator
+ {
+ private SecretKey encKey;
+ private AlgorithmIdentifier algorithmIdentifier;
+ private Mac mac;
+ private SecureRandom random;
+
+ CMSOutputEncryptor(ASN1ObjectIdentifier macOID, int keySize, SecureRandom random)
+ throws CMSException
+ {
+ KeyGenerator keyGen = helper.createKeyGenerator(macOID);
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ this.random = random;
+
+ if (keySize < 0)
+ {
+ keyGen.init(random);
+ }
+ else
+ {
+ keyGen.init(keySize, random);
+ }
+
+ encKey = keyGen.generateKey();
+
+ AlgorithmParameterSpec paramSpec = generateParameterSpec(macOID, encKey);
+
+ algorithmIdentifier = helper.getAlgorithmIdentifier(macOID, paramSpec);
+ mac = helper.createContentMac(encKey, algorithmIdentifier);
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return algorithmIdentifier;
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return new MacOutputStream(mac);
+ }
+
+ public byte[] getMac()
+ {
+ return mac.doFinal();
+ }
+
+ public GenericKey getKey()
+ {
+ return new GenericKey(encKey);
+ }
+
+ protected AlgorithmParameterSpec generateParameterSpec(ASN1ObjectIdentifier macOID, SecretKey encKey)
+ throws CMSException
+ {
+ try
+ {
+ if (macOID.equals(PKCSObjectIdentifiers.RC2_CBC))
+ {
+ byte[] iv = new byte[8];
+
+ random.nextBytes(iv);
+
+ return new RC2ParameterSpec(encKey.getEncoded().length * 8, iv);
+ }
+
+ AlgorithmParameterGenerator pGen = helper.createAlgorithmParameterGenerator(macOID);
+
+ AlgorithmParameters p = pGen.generateParameters();
+
+ return p.getParameterSpec(IvParameterSpec.class);
+ }
+ catch (GeneralSecurityException e)
+ {
+ return null;
+ }
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessage.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessage.java
new file mode 100644
index 000000000..abbf964ad
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessage.java
@@ -0,0 +1,55 @@
+package org.spongycastle.cert.crmf.jcajce;
+
+import java.security.Provider;
+import java.security.PublicKey;
+
+import org.spongycastle.asn1.crmf.CertReqMsg;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.crmf.CRMFException;
+import org.spongycastle.cert.crmf.CertificateRequestMessage;
+import org.spongycastle.jcajce.DefaultJcaJceHelper;
+import org.spongycastle.jcajce.NamedJcaJceHelper;
+import org.spongycastle.jcajce.ProviderJcaJceHelper;
+
+public class JcaCertificateRequestMessage
+ extends CertificateRequestMessage
+{
+ private CRMFHelper helper = new CRMFHelper(new DefaultJcaJceHelper());
+
+ public JcaCertificateRequestMessage(CertificateRequestMessage certReqMsg)
+ {
+ this(certReqMsg.toASN1Structure());
+ }
+
+ public JcaCertificateRequestMessage(CertReqMsg certReqMsg)
+ {
+ super(certReqMsg);
+ }
+
+ public JcaCertificateRequestMessage setProvider(String providerName)
+ {
+ this.helper = new CRMFHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ public JcaCertificateRequestMessage setProvider(Provider provider)
+ {
+ this.helper = new CRMFHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public PublicKey getPublicKey()
+ throws CRMFException
+ {
+ SubjectPublicKeyInfo subjectPublicKeyInfo = getCertTemplate().getPublicKey();
+
+ if (subjectPublicKeyInfo != null)
+ {
+ return helper.toPublicKey(subjectPublicKeyInfo);
+ }
+
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessageBuilder.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessageBuilder.java
new file mode 100644
index 000000000..6b2f85217
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/crmf/jcajce/JcaCertificateRequestMessageBuilder.java
@@ -0,0 +1,25 @@
+package org.spongycastle.cert.crmf.jcajce;
+
+import java.math.BigInteger;
+import java.security.PublicKey;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.crmf.CertificateRequestMessageBuilder;
+
+public class JcaCertificateRequestMessageBuilder
+ extends CertificateRequestMessageBuilder
+{
+ public JcaCertificateRequestMessageBuilder(BigInteger certReqId)
+ {
+ super(certReqId);
+ }
+
+ public JcaCertificateRequestMessageBuilder setPublicKey(PublicKey publicKey)
+ {
+ setPublicKey(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));
+
+ return this;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/crmf/jcajce/JcaPKIArchiveControlBuilder.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/crmf/jcajce/JcaPKIArchiveControlBuilder.java
new file mode 100644
index 000000000..9e2963c8f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/crmf/jcajce/JcaPKIArchiveControlBuilder.java
@@ -0,0 +1,22 @@
+package org.spongycastle.cert.crmf.jcajce;
+
+import java.security.PrivateKey;
+
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.cert.crmf.PKIArchiveControlBuilder;
+
+public class JcaPKIArchiveControlBuilder
+ extends PKIArchiveControlBuilder
+{
+ public JcaPKIArchiveControlBuilder(PrivateKey privateKey, X500Name name)
+ {
+ this(privateKey, new GeneralName(name));
+ }
+
+ public JcaPKIArchiveControlBuilder(PrivateKey privateKey, GeneralName generalName)
+ {
+ super(PrivateKeyInfo.getInstance(privateKey.getEncoded()), generalName);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaCertStoreBuilder.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaCertStoreBuilder.java
new file mode 100644
index 000000000..37a1723cb
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaCertStoreBuilder.java
@@ -0,0 +1,151 @@
+package org.spongycastle.cert.jcajce;
+
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.cert.CRLException;
+import org.spongycastle.jce.cert.CertStore;
+import java.security.cert.CertificateException;
+import org.spongycastle.jce.cert.CollectionCertStoreParameters;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.cert.X509CRLHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.util.Store;
+
+/**
+ * Builder to create a CertStore from certificate and CRL stores.
+ */
+public class JcaCertStoreBuilder
+{
+ private List certs = new ArrayList();
+ private List crls = new ArrayList();
+ private Object provider;
+ private JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter();
+ private JcaX509CRLConverter crlConverter = new JcaX509CRLConverter();
+ private String type = "Collection";
+
+ /**
+ * Add a store full of X509CertificateHolder objects.
+ *
+ * @param certStore a store of X509CertificateHolder objects.
+ */
+ public JcaCertStoreBuilder addCertificates(Store certStore)
+ {
+ certs.addAll(certStore.getMatches(null));
+
+ return this;
+ }
+
+ /**
+ * Add a single certificate.
+ *
+ * @param cert the X509 certificate holder containing the certificate.
+ */
+ public JcaCertStoreBuilder addCertificate(X509CertificateHolder cert)
+ {
+ certs.add(cert);
+
+ return this;
+ }
+
+ /**
+ * Add a store full of X509CRLHolder objects.
+ * @param crlStore a store of X509CRLHolder objects.
+ */
+ public JcaCertStoreBuilder addCRLs(Store crlStore)
+ {
+ crls.addAll(crlStore.getMatches(null));
+
+ return this;
+ }
+
+ /**
+ * Add a single CRL.
+ *
+ * @param crl the X509 CRL holder containing the CRL.
+ */
+ public JcaCertStoreBuilder addCRL(X509CRLHolder crl)
+ {
+ crls.add(crl);
+
+ return this;
+ }
+
+ public JcaCertStoreBuilder setProvider(String providerName)
+ {
+ certificateConverter.setProvider(providerName);
+ crlConverter.setProvider(providerName);
+ this.provider = providerName;
+
+ return this;
+ }
+
+ public JcaCertStoreBuilder setProvider(Provider provider)
+ {
+ certificateConverter.setProvider(provider);
+ crlConverter.setProvider(provider);
+ this.provider = provider;
+
+ return this;
+ }
+
+ /**
+ * Set the type of the CertStore generated. By default it is "Collection".
+ *
+ * @param type type of CertStore passed to CertStore.getInstance().
+ * @return the current builder.
+ */
+ public JcaCertStoreBuilder setType(String type)
+ {
+ this.type = type;
+
+ return this;
+ }
+
+ /**
+ * Build the CertStore from the current inputs.
+ *
+ * @return a CertStore.
+ * @throws GeneralSecurityException
+ */
+ public CertStore build()
+ throws GeneralSecurityException
+ {
+ CollectionCertStoreParameters params = convertHolders(certificateConverter, crlConverter);
+
+ if (provider instanceof String)
+ {
+ return CertStore.getInstance(type, params, (String)provider);
+ }
+
+ if (provider instanceof Provider)
+ {
+ return CertStore.getInstance(type, params, (Provider)provider);
+ }
+
+ return CertStore.getInstance(type, params);
+ }
+
+ private CollectionCertStoreParameters convertHolders(JcaX509CertificateConverter certificateConverter, JcaX509CRLConverter crlConverter)
+ throws CertificateException, CRLException
+ {
+ List jcaObjs = new ArrayList(certs.size() + crls.size());
+
+ for (Iterator it = certs.iterator(); it.hasNext();)
+ {
+ jcaObjs.add(certificateConverter.getCertificate((X509CertificateHolder)it.next()));
+ }
+
+ for (Iterator it = crls.iterator(); it.hasNext();)
+ {
+ jcaObjs.add(crlConverter.getCRL((X509CRLHolder)it.next()));
+ }
+
+ return new CollectionCertStoreParameters(jcaObjs);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaX500NameUtil.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaX500NameUtil.java
new file mode 100644
index 000000000..840dde552
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaX500NameUtil.java
@@ -0,0 +1,58 @@
+package org.spongycastle.cert.jcajce;
+
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.X500NameStyle;
+import org.spongycastle.jce.PrincipalUtil;
+
+public class JcaX500NameUtil
+{
+ public static X500Name getIssuer(X509Certificate certificate)
+ {
+try
+{
+ return X500Name.getInstance(PrincipalUtil.getIssuerX509Principal(certificate).getEncoded());
+}
+catch (Exception e)
+{
+ throw new IllegalStateException(e.toString());
+}
+ }
+
+ public static X500Name getSubject(X509Certificate certificate)
+ {
+try
+{
+ return X500Name.getInstance(PrincipalUtil.getSubjectX509Principal(certificate).getEncoded());
+}
+catch (Exception e)
+{
+ throw new IllegalStateException(e.toString());
+}
+ }
+
+ public static X500Name getIssuer(X500NameStyle style, X509Certificate certificate)
+ {
+try
+{
+ return X500Name.getInstance(style, PrincipalUtil.getIssuerX509Principal(certificate).getEncoded());
+}
+catch (Exception e)
+{
+ throw new IllegalStateException(e.toString());
+}
+ }
+
+ public static X500Name getSubject(X500NameStyle style, X509Certificate certificate)
+ {
+try
+{
+ return X500Name.getInstance(style, PrincipalUtil.getSubjectX509Principal(certificate).getEncoded());
+}
+catch (Exception e)
+{
+ throw new IllegalStateException(e.toString());
+}
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaX509v1CertificateBuilder.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaX509v1CertificateBuilder.java
new file mode 100644
index 000000000..b67959bc8
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaX509v1CertificateBuilder.java
@@ -0,0 +1,31 @@
+package org.spongycastle.cert.jcajce;
+
+import java.math.BigInteger;
+import java.security.PublicKey;
+import java.util.Date;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.X509v1CertificateBuilder;
+
+/**
+ * JCA helper class to allow JCA objects to be used in the construction of a Version 1 certificate.
+ */
+public class JcaX509v1CertificateBuilder
+ extends X509v1CertificateBuilder
+{
+ /**
+ * Initialise the builder using a PublicKey.
+ *
+ * @param issuer X500Name representing the issuer of this certificate.
+ * @param serial the serial number for the certificate.
+ * @param notBefore date before which the certificate is not valid.
+ * @param notAfter date after which the certificate is not valid.
+ * @param subject X500Name representing the subject of this certificate.
+ * @param publicKey the public key to be associated with the certificate.
+ */
+ public JcaX509v1CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, PublicKey publicKey)
+ {
+ super(issuer, serial, notBefore, notAfter, subject, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaX509v2CRLBuilder.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaX509v2CRLBuilder.java
new file mode 100644
index 000000000..4b1f4907b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaX509v2CRLBuilder.java
@@ -0,0 +1,15 @@
+package org.spongycastle.cert.jcajce;
+
+import java.util.Date;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cert.X509v2CRLBuilder;
+
+public class JcaX509v2CRLBuilder
+ extends X509v2CRLBuilder
+{
+ public JcaX509v2CRLBuilder(X500Name issuer, Date now)
+ {
+ super(issuer, now);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaX509v3CertificateBuilder.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaX509v3CertificateBuilder.java
new file mode 100644
index 000000000..4f7a4a1e5
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/JcaX509v3CertificateBuilder.java
@@ -0,0 +1,54 @@
+package org.spongycastle.cert.jcajce;
+
+import java.math.BigInteger;
+import java.security.PublicKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.X509v3CertificateBuilder;
+
+/**
+ * JCA helper class to allow JCA objects to be used in the construction of a Version 3 certificate.
+ */
+public class JcaX509v3CertificateBuilder
+ extends X509v3CertificateBuilder
+{
+ /**
+ * Initialise the builder using a PublicKey.
+ *
+ * @param issuer X500Name representing the issuer of this certificate.
+ * @param serial the serial number for the certificate.
+ * @param notBefore date before which the certificate is not valid.
+ * @param notAfter date after which the certificate is not valid.
+ * @param subject X500Name representing the subject of this certificate.
+ * @param publicKey the public key to be associated with the certificate.
+ */
+ public JcaX509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, PublicKey publicKey)
+ {
+ super(issuer, serial, notBefore, notAfter, subject, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));
+ }
+
+ /**
+ * Add a given extension field for the standard extensions tag (tag 3)
+ * copying the extension value from another certificate.
+ *
+ * @param oid the type of the extension to be copied.
+ * @param critical true if the extension is to be marked critical, false otherwise.
+ * @param certificate the source of the extension to be copied.
+ * @return the builder instance.
+ */
+ public JcaX509v3CertificateBuilder copyAndAddExtension(
+ ASN1ObjectIdentifier oid,
+ boolean critical,
+ X509Certificate certificate)
+ throws CertificateEncodingException
+ {
+ this.copyAndAddExtension(oid, critical, new JcaX509CertificateHolder(certificate));
+
+ return this;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/ProviderCertHelper.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/ProviderCertHelper.java
new file mode 100644
index 000000000..a28a7c562
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/jcajce/ProviderCertHelper.java
@@ -0,0 +1,30 @@
+package org.spongycastle.cert.jcajce;
+
+import java.security.Provider;
+import java.security.NoSuchProviderException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+class ProviderCertHelper
+ extends CertHelper
+{
+ private final Provider provider;
+
+ ProviderCertHelper(Provider provider)
+ {
+ this.provider = provider;
+ }
+
+ protected CertificateFactory createCertificateFactory(String type)
+ throws CertificateException
+ {
+ try
+ {
+ return CertificateFactory.getInstance(type, provider.getName());
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new CertificateException(e.toString());
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/ocsp/jcajce/JcaRespID.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/ocsp/jcajce/JcaRespID.java
new file mode 100644
index 000000000..41d9072c2
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/ocsp/jcajce/JcaRespID.java
@@ -0,0 +1,19 @@
+package org.spongycastle.cert.ocsp.jcajce;
+
+import java.security.PublicKey;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.ocsp.OCSPException;
+import org.spongycastle.cert.ocsp.RespID;
+import org.spongycastle.operator.DigestCalculator;
+
+public class JcaRespID
+ extends RespID
+{
+ public JcaRespID(PublicKey pubKey, DigestCalculator digCalc)
+ throws OCSPException
+ {
+ super(SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()), digCalc);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/selector/jcajce/JcaSelectorConverter.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/selector/jcajce/JcaSelectorConverter.java
new file mode 100644
index 000000000..cede4acc8
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/selector/jcajce/JcaSelectorConverter.java
@@ -0,0 +1,34 @@
+package org.spongycastle.cert.selector.jcajce;
+
+import org.spongycastle.jce.cert.X509CertSelector;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cert.selector.X509CertificateHolderSelector;
+
+public class JcaSelectorConverter
+{
+ public JcaSelectorConverter()
+ {
+
+ }
+
+ public X509CertificateHolderSelector getCertificateHolderSelector(X509CertSelector certSelector)
+ {
+try
+{
+ if (certSelector.getSubjectKeyIdentifier() != null)
+ {
+ return new X509CertificateHolderSelector(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber(), ASN1OctetString.getInstance(certSelector.getSubjectKeyIdentifier()).getOctets());
+ }
+ else
+ {
+ return new X509CertificateHolderSelector(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber());
+ }
+}
+catch (Exception e)
+{
+throw new IllegalArgumentException("conversion failed: " + e.toString());
+}
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java
new file mode 100644
index 000000000..b2dbb563e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java
@@ -0,0 +1,57 @@
+package org.spongycastle.cert.selector.jcajce;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import org.spongycastle.jce.cert.X509CertSelector;
+
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cert.selector.X509CertificateHolderSelector;
+
+public class JcaX509CertSelectorConverter
+{
+ public JcaX509CertSelectorConverter()
+ {
+ }
+
+ protected X509CertSelector doConversion(X500Name issuer, BigInteger serialNumber, byte[] subjectKeyIdentifier)
+ {
+ X509CertSelector selector = new X509CertSelector();
+
+ if (issuer != null)
+ {
+ try
+ {
+ selector.setIssuer(issuer.getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage());
+ }
+ }
+
+ if (serialNumber != null)
+ {
+ selector.setSerialNumber(serialNumber);
+ }
+
+ if (subjectKeyIdentifier != null)
+ {
+ try
+ {
+ selector.setSubjectKeyIdentifier(new DEROctetString(subjectKeyIdentifier).getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage());
+ }
+ }
+
+ return selector;
+ }
+
+ public X509CertSelector getCertSelector(X509CertificateHolderSelector holderSelector)
+ {
+ return doConversion(holderSelector.getIssuer(), holderSelector.getSerialNumber(), holderSelector.getSubjectKeyIdentifier());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/selector/jcajce/JcaX509CertificateHolderSelector.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/selector/jcajce/JcaX509CertificateHolderSelector.java
new file mode 100644
index 000000000..3280af2a0
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cert/selector/jcajce/JcaX509CertificateHolderSelector.java
@@ -0,0 +1,57 @@
+package org.spongycastle.cert.selector.jcajce;
+
+import java.math.BigInteger;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.PrincipalUtil;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.cert.selector.X509CertificateHolderSelector;
+
+public class JcaX509CertificateHolderSelector
+ extends X509CertificateHolderSelector
+{
+ /**
+ * Construct a signer identifier based on the issuer, serial number and subject key identifier (if present) of the passed in
+ * certificate.
+ *
+ * @param certificate certificate providing the issue and serial number and subject key identifier.
+ */
+ public JcaX509CertificateHolderSelector(X509Certificate certificate)
+ {
+ super(convertPrincipal(certificate), certificate.getSerialNumber(), getSubjectKeyId(certificate));
+ }
+
+ private static X500Name convertPrincipal(X509Certificate issuer)
+ {
+ if (issuer == null)
+ {
+ return null;
+ }
+try
+{
+ return X500Name.getInstance(PrincipalUtil.getIssuerX509Principal(issuer).toASN1Primitive());
+}
+catch (Exception e)
+{
+ throw new IllegalArgumentException("conversion failed: " + e.toString());
+}
+ }
+
+ private static byte[] getSubjectKeyId(X509Certificate cert)
+ {
+ byte[] ext = cert.getExtensionValue(X509Extension.subjectKeyIdentifier.getId());
+
+ if (ext != null)
+ {
+ return ASN1OctetString.getInstance(ASN1OctetString.getInstance(ext).getOctets()).getOctets();
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JcaSelectorConverter.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JcaSelectorConverter.java
new file mode 100644
index 000000000..c6d0cebe6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JcaSelectorConverter.java
@@ -0,0 +1,54 @@
+package org.spongycastle.cms.jcajce;
+
+import org.spongycastle.jce.cert.X509CertSelector;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cms.KeyTransRecipientId;
+import org.spongycastle.cms.SignerId;
+
+public class JcaSelectorConverter
+{
+ public JcaSelectorConverter()
+ {
+
+ }
+
+ public SignerId getSignerId(X509CertSelector certSelector)
+ {
+try
+{
+ if (certSelector.getSubjectKeyIdentifier() != null)
+ {
+ return new SignerId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber(), ASN1OctetString.getInstance(certSelector.getSubjectKeyIdentifier()).getOctets());
+ }
+ else
+ {
+ return new SignerId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber());
+ }
+}
+catch (Exception e)
+{
+ throw new IllegalArgumentException("conversion failed: " + e.toString());
+}
+ }
+
+ public KeyTransRecipientId getKeyTransRecipientId(X509CertSelector certSelector)
+ {
+try
+{
+ if (certSelector.getSubjectKeyIdentifier() != null)
+ {
+ return new KeyTransRecipientId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber(), ASN1OctetString.getInstance(certSelector.getSubjectKeyIdentifier()).getOctets());
+ }
+ else
+ {
+ return new KeyTransRecipientId(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber());
+ }
+}
+catch (Exception e)
+{
+ throw new IllegalArgumentException("conversion failed: " + e.toString());
+}
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JcaSignerId.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JcaSignerId.java
new file mode 100644
index 000000000..99650cfb1
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JcaSignerId.java
@@ -0,0 +1,36 @@
+package org.spongycastle.cms.jcajce;
+
+import java.math.BigInteger;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cms.SignerId;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.jce.X509Principal;
+
+public class JcaSignerId
+ extends SignerId
+{
+ private static X509Principal getPrincipal(X509Certificate cert)
+ {
+ try
+ {
+ return PrincipalUtil.getIssuerX509Principal(cert);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("unable to extract principle");
+ }
+ }
+
+ /**
+ * Construct a signer identifier based on the issuer, serial number and subject key identifier (if present) of the passed in
+ * certificate.
+ *
+ * @param certificate certificate providing the issue and serial number and subject key identifier.
+ */
+ public JcaSignerId(X509Certificate certificate)
+ {
+ super(X500Name.getInstance(getPrincipal(certificate).getEncoded()), certificate.getSerialNumber(), CMSUtils.getSubjectKeyId(certificate));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JcaX509CertSelectorConverter.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JcaX509CertSelectorConverter.java
new file mode 100644
index 000000000..594ed1d55
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JcaX509CertSelectorConverter.java
@@ -0,0 +1,24 @@
+package org.spongycastle.cms.jcajce;
+
+import org.spongycastle.jce.cert.X509CertSelector;
+
+import org.spongycastle.cms.KeyTransRecipientId;
+import org.spongycastle.cms.SignerId;
+
+public class JcaX509CertSelectorConverter
+ extends org.spongycastle.cert.selector.jcajce.JcaX509CertSelectorConverter
+{
+ public JcaX509CertSelectorConverter()
+ {
+ }
+
+ public X509CertSelector getCertSelector(KeyTransRecipientId recipientId)
+ {
+ return doConversion(recipientId.getIssuer(), recipientId.getSerialNumber(), recipientId.getSubjectKeyIdentifier());
+ }
+
+ public X509CertSelector getCertSelector(SignerId signerId)
+ {
+ return doConversion(signerId.getIssuer(), signerId.getSerialNumber(), signerId.getSubjectKeyIdentifier());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientId.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientId.java
new file mode 100644
index 000000000..91875037e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientId.java
@@ -0,0 +1,32 @@
+package org.spongycastle.cms.jcajce;
+
+import java.math.BigInteger;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.jce.X509Principal;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cms.KeyAgreeRecipientId;
+
+public class JceKeyAgreeRecipientId
+ extends KeyAgreeRecipientId
+{
+ public JceKeyAgreeRecipientId(X509Certificate certificate)
+ {
+ super(X500Name.getInstance(extractIssuer(certificate)), certificate.getSerialNumber());
+ }
+
+ private static X509Principal extractIssuer(X509Certificate certificate)
+ {
+ try
+ {
+ return PrincipalUtil.getIssuerX509Principal(certificate);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IllegalStateException("can't extract issuer");
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JceKeyTransRecipientId.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JceKeyTransRecipientId.java
new file mode 100644
index 000000000..5bac48b57
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/cms/jcajce/JceKeyTransRecipientId.java
@@ -0,0 +1,30 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cms.KeyTransRecipientId;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.jce.X509Principal;
+
+public class JceKeyTransRecipientId
+ extends KeyTransRecipientId
+{
+ public JceKeyTransRecipientId(X509Certificate certificate)
+ {
+ super(X500Name.getInstance(extractIssuer(certificate)), certificate.getSerialNumber(), CMSUtils.getSubjectKeyId(certificate));
+ }
+
+ private static X509Principal extractIssuer(X509Certificate certificate)
+ {
+ try
+ {
+ return PrincipalUtil.getIssuerX509Principal(certificate);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IllegalStateException("can't extract issuer");
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/eac/jcajce/ProviderEACHelper.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/eac/jcajce/ProviderEACHelper.java
new file mode 100644
index 000000000..4bc4dfa32
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/eac/jcajce/ProviderEACHelper.java
@@ -0,0 +1,23 @@
+package org.spongycastle.eac.jcajce;
+
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+
+class ProviderEACHelper
+ implements EACHelper
+{
+ private final Provider provider;
+
+ ProviderEACHelper(Provider provider)
+ {
+ this.provider = provider;
+ }
+
+ public KeyFactory createKeyFactory(String type)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return KeyFactory.getInstance(type, provider.getName());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/eac/operator/jcajce/ProviderEACHelper.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/eac/operator/jcajce/ProviderEACHelper.java
new file mode 100644
index 000000000..dcdd1e1c0
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/eac/operator/jcajce/ProviderEACHelper.java
@@ -0,0 +1,23 @@
+package org.spongycastle.eac.operator.jcajce;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Signature;
+
+class ProviderEACHelper
+ extends EACHelper
+{
+ private final Provider provider;
+
+ ProviderEACHelper(Provider provider)
+ {
+ this.provider = provider;
+ }
+
+ protected Signature createSignature(String type)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return Signature.getInstance(type, provider.getName());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/operator/jcajce/JcaAlgorithmParametersConverter.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/operator/jcajce/JcaAlgorithmParametersConverter.java
new file mode 100644
index 000000000..a4de4911a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/operator/jcajce/JcaAlgorithmParametersConverter.java
@@ -0,0 +1,44 @@
+package org.spongycastle.operator.jcajce;
+
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSAESOAEPparams;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+
+public class JcaAlgorithmParametersConverter
+{
+ public JcaAlgorithmParametersConverter()
+ {
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier algId, AlgorithmParameters parameters)
+ throws InvalidAlgorithmParameterException
+ {
+ try
+ {
+ ASN1Encodable params = ASN1Primitive.fromByteArray(parameters.getEncoded());
+
+ return new AlgorithmIdentifier(algId, params);
+ }
+ catch (IOException e)
+ {
+ throw new InvalidAlgorithmParameterException("unable to encode parameters object: " + e.getMessage());
+ }
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier algorithm, AlgorithmParameterSpec algorithmSpec)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("unknown parameter spec passed.");
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/operator/jcajce/OperatorHelper.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/operator/jcajce/OperatorHelper.java
new file mode 100644
index 000000000..135e59655
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/operator/jcajce/OperatorHelper.java
@@ -0,0 +1,471 @@
+package org.spongycastle.operator.jcajce;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.MessageDigest;
+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.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+//import java.security.spec.PSSParameterSpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.Cipher;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.kisa.KISAObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.ntt.NTTObjectIdentifiers;
+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.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.jcajce.JcaJceHelper;
+import org.spongycastle.jcajce.JcaJceUtils;
+import org.spongycastle.operator.OperatorCreationException;
+
+class OperatorHelper
+{
+ private static final Map oids = new HashMap();
+ private static final Map asymmetricWrapperAlgNames = new HashMap();
+ private static final Map symmetricWrapperAlgNames = new HashMap();
+ private static final Map symmetricKeyAlgNames = new HashMap();
+
+ static
+ {
+ //
+ // reverse mappings
+ //
+ oids.put(new ASN1ObjectIdentifier("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 ASN1ObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
+ oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA");
+ oids.put(new ASN1ObjectIdentifier("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");
+
+ oids.put(OIWObjectIdentifiers.idSHA1, "SHA-1");
+ oids.put(NISTObjectIdentifiers.id_sha224, "SHA-224");
+ oids.put(NISTObjectIdentifiers.id_sha256, "SHA-256");
+ oids.put(NISTObjectIdentifiers.id_sha384, "SHA-384");
+ oids.put(NISTObjectIdentifiers.id_sha512, "SHA-512");
+ oids.put(TeleTrusTObjectIdentifiers.ripemd128, "RIPEMD-128");
+ oids.put(TeleTrusTObjectIdentifiers.ripemd160, "RIPEMD-160");
+ oids.put(TeleTrusTObjectIdentifiers.ripemd256, "RIPEMD-256");
+
+ asymmetricWrapperAlgNames.put(PKCSObjectIdentifiers.rsaEncryption, "RSA/ECB/PKCS1Padding");
+
+ symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "DESEDEWrap");
+ symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.id_alg_CMSRC2wrap, "RC2Wrap");
+ symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes128_wrap, "AESWrap");
+ symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes192_wrap, "AESWrap");
+ symmetricWrapperAlgNames.put(NISTObjectIdentifiers.id_aes256_wrap, "AESWrap");
+ symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia128_wrap, "CamelliaWrap");
+ symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia192_wrap, "CamelliaWrap");
+ symmetricWrapperAlgNames.put(NTTObjectIdentifiers.id_camellia256_wrap, "CamelliaWrap");
+ symmetricWrapperAlgNames.put(KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap, "SEEDWrap");
+ symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESede");
+
+ symmetricKeyAlgNames.put(NISTObjectIdentifiers.aes, "AES");
+ symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes128_CBC, "AES");
+ symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes192_CBC, "AES");
+ symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes256_CBC, "AES");
+ symmetricKeyAlgNames.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESede");
+ symmetricKeyAlgNames.put(PKCSObjectIdentifiers.RC2_CBC, "RC2");
+ }
+
+ private JcaJceHelper helper;
+
+ OperatorHelper(JcaJceHelper helper)
+ {
+ this.helper = helper;
+ }
+
+ Cipher createAsymmetricWrapper(ASN1ObjectIdentifier algorithm, Map extraAlgNames)
+ throws OperatorCreationException
+ {
+ try
+ {
+ String cipherName = null;
+
+ if (!extraAlgNames.isEmpty())
+ {
+ cipherName = (String)extraAlgNames.get(algorithm);
+ }
+
+ if (cipherName == null)
+ {
+ cipherName = (String)asymmetricWrapperAlgNames.get(algorithm);
+ }
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createCipher(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // try alternate for RSA
+ if (cipherName.equals("RSA/ECB/PKCS1Padding"))
+ {
+ try
+ {
+ return helper.createCipher("RSA/NONE/PKCS1Padding");
+ }
+ catch (NoSuchAlgorithmException ex)
+ {
+ // Ignore
+ }
+ }
+ // Ignore
+ }
+ }
+
+ return helper.createCipher(algorithm.getId());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException("cannot create cipher: " + e.getMessage(), e);
+ }
+ }
+
+ Cipher createSymmetricWrapper(ASN1ObjectIdentifier algorithm)
+ throws OperatorCreationException
+ {
+ try
+ {
+ String cipherName = (String)symmetricWrapperAlgNames.get(algorithm);
+
+ if (cipherName != null)
+ {
+ try
+ {
+ // this is reversed as the Sun policy files now allow unlimited strength RSA
+ return helper.createCipher(cipherName);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+ return helper.createCipher(algorithm.getId());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OperatorCreationException("cannot create cipher: " + e.getMessage(), e);
+ }
+ }
+
+ AlgorithmParameters createAlgorithmParameters(AlgorithmIdentifier cipherAlgId)
+ throws OperatorCreationException
+ {
+ AlgorithmParameters parameters;
+
+ if (cipherAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption))
+ {
+ return null;
+ }
+
+ try
+ {
+ parameters = helper.createAlgorithmParameters(cipherAlgId.getAlgorithm().getId());
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ return null; // There's a good chance there aren't any!
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new OperatorCreationException("cannot create algorithm parameters: " + e.getMessage(), e);
+ }
+
+ try
+ {
+ parameters.init(cipherAlgId.getParameters().toASN1Primitive().getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new OperatorCreationException("cannot initialise algorithm parameters: " + e.getMessage(), e);
+ }
+
+ return parameters;
+ }
+
+ MessageDigest createDigest(AlgorithmIdentifier digAlgId)
+ throws GeneralSecurityException
+ {
+ MessageDigest dig;
+
+ try
+ {
+ dig = helper.createDigest(getDigestAlgName(digAlgId.getAlgorithm()));
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ //
+ // try an alternate
+ //
+ if (oids.get(digAlgId.getAlgorithm()) != null)
+ {
+ String digestAlgorithm = (String)oids.get(digAlgId.getAlgorithm());
+
+ dig = helper.createDigest(digestAlgorithm);
+ }
+ else
+ {
+ throw e;
+ }
+ }
+
+ return dig;
+ }
+
+ Signature createSignature(AlgorithmIdentifier sigAlgId)
+ throws GeneralSecurityException
+ {
+ Signature sig;
+
+ try
+ {
+ sig = helper.createSignature(getSignatureName(sigAlgId));
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ //
+ // try an alternate
+ //
+ if (oids.get(sigAlgId.getAlgorithm()) != null)
+ {
+ String signatureAlgorithm = (String)oids.get(sigAlgId.getAlgorithm());
+
+ sig = helper.createSignature(signatureAlgorithm);
+ }
+ else
+ {
+ throw e;
+ }
+ }
+
+ return sig;
+ }
+
+ public Signature createRawSignature(AlgorithmIdentifier algorithm)
+ {
+ Signature sig;
+
+ try
+ {
+ String algName = getSignatureName(algorithm);
+
+ algName = "NONE" + algName.substring(algName.indexOf("WITH"));
+
+ sig = helper.createSignature(algName);
+
+ // RFC 4056
+ // When the id-RSASSA-PSS algorithm identifier is used for a signature,
+ // the AlgorithmIdentifier parameters field MUST contain RSASSA-PSS-params.
+/*
+ if (algorithm.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ AlgorithmParameters params = helper.createAlgorithmParameters(algName);
+
+ JcaJceUtils.loadParameters(params, algorithm.getParameters());
+
+ PSSParameterSpec spec = (PSSParameterSpec)params.getParameterSpec(PSSParameterSpec.class);
+ sig.setParameter(spec);
+ }
+*/
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+
+ return sig;
+ }
+
+ private static String getSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ ASN1Encodable params = sigAlgId.getParameters();
+
+ if (params != null && !DERNull.INSTANCE.equals(params))
+ {
+ if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+ return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "WITHRSAANDMGF1";
+ }
+ }
+
+ if (oids.containsKey(sigAlgId.getAlgorithm()))
+ {
+ return (String)oids.get(sigAlgId.getAlgorithm());
+ }
+
+ return sigAlgId.getAlgorithm().getId();
+ }
+
+ 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();
+ }
+ }
+
+ public X509Certificate convertCertificate(X509CertificateHolder certHolder)
+ throws CertificateException
+ {
+
+ try
+ {
+ CertificateFactory certFact = helper.createCertificateFactory("X.509");
+
+ return (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(certHolder.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new OpCertificateException("cannot get encoded form of certificate: " + e.getMessage(), e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new OpCertificateException("cannot create certificate factory: " + e.getMessage(), e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new OpCertificateException("cannot find factory provider: " + e.getMessage(), e);
+ }
+ }
+
+ public PublicKey convertPublicKey(SubjectPublicKeyInfo publicKeyInfo)
+ throws OperatorCreationException
+ {
+ try
+ {
+ KeyFactory keyFact = helper.createKeyFactory(publicKeyInfo.getAlgorithm().getAlgorithm().getId());
+
+ return keyFact.generatePublic(new X509EncodedKeySpec(publicKeyInfo.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new OperatorCreationException("cannot get encoded form of key: " + e.getMessage(), e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new OperatorCreationException("cannot create key factory: " + e.getMessage(), e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new OperatorCreationException("cannot find factory provider: " + e.getMessage(), e);
+ }
+ catch (InvalidKeySpecException e)
+ {
+ throw new OperatorCreationException("cannot create key factory: " + e.getMessage(), e);
+ }
+ }
+
+ // TODO: put somewhere public so cause easily accessed
+ private static class OpCertificateException
+ extends CertificateException
+ {
+ private Throwable cause;
+
+ public OpCertificateException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+
+ String getKeyAlgorithmName(ASN1ObjectIdentifier oid)
+ {
+
+ String name = (String)symmetricKeyAlgNames.get(oid);
+
+ if (name != null)
+ {
+ return name;
+ }
+
+ return oid.getId();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/pkcs/jcajce/JcaPKCS10CertificationRequestBuilder.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/pkcs/jcajce/JcaPKCS10CertificationRequestBuilder.java
new file mode 100644
index 000000000..2e0000e08
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/pkcs/jcajce/JcaPKCS10CertificationRequestBuilder.java
@@ -0,0 +1,25 @@
+package org.spongycastle.pkcs.jcajce;
+
+import java.security.PublicKey;
+
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.pkcs.PKCS10CertificationRequestBuilder;
+
+/**
+ * Extension of the PKCS#10 builder to support PublicKey and X500Principal objects.
+ */
+public class JcaPKCS10CertificationRequestBuilder
+ extends PKCS10CertificationRequestBuilder
+{
+ /**
+ * Create a PKCS#10 builder for the passed in subject and JCA public key.
+ *
+ * @param subject an X500Name containing the subject associated with the request we are building.
+ * @param publicKey a JCA public key that is to be associated with the request we are building.
+ */
+ public JcaPKCS10CertificationRequestBuilder(X500Name subject, PublicKey publicKey)
+ {
+ super(subject, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/tsp/cms/CMSTimeStampedData.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/tsp/cms/CMSTimeStampedData.java
new file mode 100644
index 000000000..0b5cb6fda
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/tsp/cms/CMSTimeStampedData.java
@@ -0,0 +1,204 @@
+package org.spongycastle.tsp.cms;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.MalformedURLException;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.Evidence;
+import org.spongycastle.asn1.cms.TimeStampAndCRL;
+import org.spongycastle.asn1.cms.TimeStampTokenEvidence;
+import org.spongycastle.asn1.cms.TimeStampedData;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.tsp.TimeStampToken;
+
+public class CMSTimeStampedData
+{
+ private TimeStampedData timeStampedData;
+ private ContentInfo contentInfo;
+ private TimeStampDataUtil util;
+
+ public CMSTimeStampedData(ContentInfo contentInfo)
+ {
+ this.initialize(contentInfo);
+ }
+
+ public CMSTimeStampedData(InputStream in)
+ throws IOException
+ {
+ try
+ {
+ initialize(ContentInfo.getInstance(new ASN1InputStream(in).readObject()));
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Malformed content: " + e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new IOException("Malformed content: " + e);
+ }
+ }
+
+ public CMSTimeStampedData(byte[] baseData)
+ throws IOException
+ {
+ this(new ByteArrayInputStream(baseData));
+ }
+
+ private void initialize(ContentInfo contentInfo)
+ {
+ this.contentInfo = contentInfo;
+
+ if (CMSObjectIdentifiers.timestampedData.equals(contentInfo.getContentType()))
+ {
+ this.timeStampedData = TimeStampedData.getInstance(contentInfo.getContent());
+ }
+ else
+ {
+ throw new IllegalArgumentException("Malformed content - type must be " + CMSObjectIdentifiers.timestampedData.getId());
+ }
+
+ util = new TimeStampDataUtil(this.timeStampedData);
+ }
+
+ public byte[] calculateNextHash(DigestCalculator calculator)
+ throws CMSException
+ {
+ return util.calculateNextHash(calculator);
+ }
+
+ /**
+ * Return a new timeStampedData object with the additional token attached.
+ *
+ * @throws CMSException
+ */
+ public CMSTimeStampedData addTimeStamp(TimeStampToken token)
+ throws CMSException
+ {
+ TimeStampAndCRL[] timeStamps = util.getTimeStamps();
+ TimeStampAndCRL[] newTimeStamps = new TimeStampAndCRL[timeStamps.length + 1];
+
+ System.arraycopy(timeStamps, 0, newTimeStamps, 0, timeStamps.length);
+
+ newTimeStamps[timeStamps.length] = new TimeStampAndCRL(token.toCMSSignedData().toASN1Structure());
+
+ return new CMSTimeStampedData(new ContentInfo(CMSObjectIdentifiers.timestampedData, new TimeStampedData(timeStampedData.getDataUri(), timeStampedData.getMetaData(), timeStampedData.getContent(), new Evidence(new TimeStampTokenEvidence(newTimeStamps)))));
+ }
+
+ public byte[] getContent()
+ {
+ if (timeStampedData.getContent() != null)
+ {
+ return timeStampedData.getContent().getOctets();
+ }
+
+ return null;
+ }
+
+ public URL getDataUri()
+ throws MalformedURLException
+ {
+ DERIA5String dataURI = this.timeStampedData.getDataUri();
+
+ if (dataURI != null)
+ {
+ return new URL(dataURI.getString());
+ }
+
+ return null;
+ }
+
+ public String getFileName()
+ {
+ return util.getFileName();
+ }
+
+ public String getMediaType()
+ {
+ return util.getMediaType();
+ }
+
+ public AttributeTable getOtherMetaData()
+ {
+ return util.getOtherMetaData();
+ }
+
+ public TimeStampToken[] getTimeStampTokens()
+ throws CMSException
+ {
+ return util.getTimeStampTokens();
+ }
+
+ /**
+ * Initialise the passed in calculator with the MetaData for this message, if it is
+ * required as part of the initial message imprint calculation.
+ *
+ * @param calculator the digest calculator to be initialised.
+ * @throws CMSException if the MetaData is required and cannot be processed
+ */
+ public void initialiseMessageImprintDigestCalculator(DigestCalculator calculator)
+ throws CMSException
+ {
+ util.initialiseMessageImprintDigestCalculator(calculator);
+ }
+
+ /**
+ * Returns an appropriately initialised digest calculator based on the message imprint algorithm
+ * described in the first time stamp in the TemporalData for this message. If the metadata is required
+ * to be included in the digest calculation, the returned calculator will be pre-initialised.
+ *
+ * @param calculatorProvider a provider of DigestCalculator objects.
+ * @return an initialised digest calculator.
+ * @throws OperatorCreationException if the provider is unable to create the calculator.
+ */
+ public DigestCalculator getMessageImprintDigestCalculator(DigestCalculatorProvider calculatorProvider)
+ throws OperatorCreationException
+ {
+ return util.getMessageImprintDigestCalculator(calculatorProvider);
+ }
+
+ /**
+ * Validate the digests present in the TimeStampTokens contained in the CMSTimeStampedData.
+ *
+ * @param calculatorProvider provider for digest calculators
+ * @param dataDigest the calculated data digest for the message
+ * @throws ImprintDigestInvalidException if an imprint digest fails to compare
+ * @throws CMSException if an exception occurs processing the message.
+ */
+ public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest)
+ throws ImprintDigestInvalidException, CMSException
+ {
+ util.validate(calculatorProvider, dataDigest);
+ }
+
+ /**
+ * Validate the passed in timestamp token against the tokens and data present in the message.
+ *
+ * @param calculatorProvider provider for digest calculators
+ * @param dataDigest the calculated data digest for the message.
+ * @param timeStampToken the timestamp token of interest.
+ * @throws ImprintDigestInvalidException if the token is not present in the message, or an imprint digest fails to compare.
+ * @throws CMSException if an exception occurs processing the message.
+ */
+ public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest, TimeStampToken timeStampToken)
+ throws ImprintDigestInvalidException, CMSException
+ {
+ util.validate(calculatorProvider, dataDigest, timeStampToken);
+ }
+
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return contentInfo.getEncoded();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/tsp/cms/CMSTimeStampedDataParser.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/tsp/cms/CMSTimeStampedDataParser.java
new file mode 100644
index 000000000..2b1a695fa
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/tsp/cms/CMSTimeStampedDataParser.java
@@ -0,0 +1,207 @@
+package org.spongycastle.tsp.cms;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.spongycastle.asn1.BERTags;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.ContentInfoParser;
+import org.spongycastle.asn1.cms.TimeStampedDataParser;
+import org.spongycastle.cms.CMSContentInfoParser;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.tsp.TimeStampToken;
+import org.spongycastle.util.io.Streams;
+
+public class CMSTimeStampedDataParser
+ extends CMSContentInfoParser
+{
+ private TimeStampedDataParser timeStampedData;
+ private TimeStampDataUtil util;
+
+ public CMSTimeStampedDataParser(InputStream in)
+ throws CMSException
+ {
+ super(in);
+
+ initialize(_contentInfo);
+ }
+
+ public CMSTimeStampedDataParser(byte[] baseData)
+ throws CMSException
+ {
+ this(new ByteArrayInputStream(baseData));
+ }
+
+ private void initialize(ContentInfoParser contentInfo)
+ throws CMSException
+ {
+ try
+ {
+ if (CMSObjectIdentifiers.timestampedData.equals(contentInfo.getContentType()))
+ {
+ this.timeStampedData = TimeStampedDataParser.getInstance(contentInfo.getContent(BERTags.SEQUENCE));
+ }
+ else
+ {
+ throw new IllegalArgumentException("Malformed content - type must be " + CMSObjectIdentifiers.timestampedData.getId());
+ }
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("parsing exception: " + e.getMessage(), e);
+ }
+ }
+
+ public byte[] calculateNextHash(DigestCalculator calculator)
+ throws CMSException
+ {
+ return util.calculateNextHash(calculator);
+ }
+
+ public InputStream getContent()
+ {
+ if (timeStampedData.getContent() != null)
+ {
+ return timeStampedData.getContent().getOctetStream();
+ }
+
+ return null;
+ }
+
+ public URL getDataUri()
+ throws MalformedURLException
+ {
+ DERIA5String dataURI = this.timeStampedData.getDataUri();
+
+ if (dataURI != null)
+ {
+ return new URL(dataURI.getString());
+ }
+
+ return null;
+ }
+
+ /**
+ * Initialise the passed in calculator with the MetaData for this message, if it is
+ * required as part of the initial message imprint calculation.
+ *
+ * @param calculator the digest calculator to be initialised.
+ * @throws CMSException if the MetaData is required and cannot be processed
+ */
+ public void initialiseMessageImprintDigestCalculator(DigestCalculator calculator)
+ throws CMSException
+ {
+ util.initialiseMessageImprintDigestCalculator(calculator);
+ }
+
+ /**
+ * Returns an appropriately initialised digest calculator based on the message imprint algorithm
+ * described in the first time stamp in the TemporalData for this message. If the metadata is required
+ * to be included in the digest calculation, the returned calculator will be pre-initialised.
+ *
+ * @param calculatorProvider a provider of DigestCalculator objects.
+ * @return an initialised digest calculator.
+ * @throws OperatorCreationException if the provider is unable to create the calculator.
+ */
+ public DigestCalculator getMessageImprintDigestCalculator(DigestCalculatorProvider calculatorProvider)
+ throws OperatorCreationException
+ {
+ try
+ {
+ parseTimeStamps();
+ }
+ catch (CMSException e)
+ {
+ throw new OperatorCreationException("unable to extract algorithm ID: " + e.getMessage(), e);
+ }
+
+ return util.getMessageImprintDigestCalculator(calculatorProvider);
+ }
+
+ public String getFileName()
+ {
+ return util.getFileName();
+ }
+
+ public String getMediaType()
+ {
+ return util.getMediaType();
+ }
+
+ public AttributeTable getOtherMetaData()
+ {
+ return util.getOtherMetaData();
+ }
+
+ public TimeStampToken[] getTimeStampTokens()
+ throws CMSException
+ {
+ parseTimeStamps();
+
+ return util.getTimeStampTokens();
+ }
+
+ /**
+ * Validate the digests present in the TimeStampTokens contained in the CMSTimeStampedData.
+ *
+ * @param calculatorProvider provider for digest calculators
+ * @param dataDigest the calculated data digest for the message
+ * @throws ImprintDigestInvalidException if an imprint digest fails to compare
+ * @throws CMSException if an exception occurs processing the message.
+ */
+ public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest)
+ throws ImprintDigestInvalidException, CMSException
+ {
+ parseTimeStamps();
+
+ util.validate(calculatorProvider, dataDigest);
+ }
+
+ /**
+ * Validate the passed in timestamp token against the tokens and data present in the message.
+ *
+ * @param calculatorProvider provider for digest calculators
+ * @param dataDigest the calculated data digest for the message.
+ * @param timeStampToken the timestamp token of interest.
+ * @throws ImprintDigestInvalidException if the token is not present in the message, or an imprint digest fails to compare.
+ * @throws CMSException if an exception occurs processing the message.
+ */
+ public void validate(DigestCalculatorProvider calculatorProvider, byte[] dataDigest, TimeStampToken timeStampToken)
+ throws ImprintDigestInvalidException, CMSException
+ {
+ parseTimeStamps();
+
+ util.validate(calculatorProvider, dataDigest, timeStampToken);
+ }
+
+ private void parseTimeStamps()
+ throws CMSException
+ {
+ try
+ {
+ if (util == null)
+ {
+ InputStream cont = this.getContent();
+
+ if (cont != null)
+ {
+ Streams.drain(cont);
+ }
+
+ util = new TimeStampDataUtil(timeStampedData);
+ }
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("unable to parse evidence block: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/tsp/cms/CMSTimeStampedGenerator.java b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/tsp/cms/CMSTimeStampedGenerator.java
new file mode 100644
index 000000000..614a744b4
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.3/org/spongycastle/tsp/cms/CMSTimeStampedGenerator.java
@@ -0,0 +1,90 @@
+package org.spongycastle.tsp.cms;
+
+import java.net.URL;
+
+import org.spongycastle.asn1.ASN1Boolean;
+import org.spongycastle.asn1.DERBoolean;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DERUTF8String;
+import org.spongycastle.asn1.cms.Attributes;
+import org.spongycastle.asn1.cms.MetaData;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.util.Integers;
+
+public class CMSTimeStampedGenerator
+{
+ protected MetaData metaData;
+ protected URL dataUri;
+
+ /**
+ * Set the dataURL to be included in message.
+ *
+ * @param dataUri URL for the data the initial message imprint digest is based on.
+ */
+ public void setDataUri(URL dataUri)
+ {
+ this.dataUri = dataUri;
+ }
+
+ /**
+ * Set the MetaData for the generated message.
+ *
+ * @param hashProtected true if the MetaData should be included in first imprint calculation, false otherwise.
+ * @param fileName optional file name, may be null.
+ * @param mediaType optional media type, may be null.
+ */
+ public void setMetaData(boolean hashProtected, String fileName, String mediaType)
+ {
+ setMetaData(hashProtected, fileName, mediaType, null);
+ }
+
+ /**
+ * Set the MetaData for the generated message.
+ *
+ * @param hashProtected true if the MetaData should be included in first imprint calculation, false otherwise.
+ * @param fileName optional file name, may be null.
+ * @param mediaType optional media type, may be null.
+ * @param attributes optional attributes, may be null.
+ */
+ public void setMetaData(boolean hashProtected, String fileName, String mediaType, Attributes attributes)
+ {
+ DERUTF8String asn1FileName = null;
+
+ if (fileName != null)
+ {
+ asn1FileName = new DERUTF8String(fileName);
+ }
+
+ DERIA5String asn1MediaType = null;
+
+ if (mediaType != null)
+ {
+ asn1MediaType = new DERIA5String(mediaType);
+ }
+
+ setMetaData(hashProtected, asn1FileName, asn1MediaType, attributes);
+ }
+
+ private void setMetaData(boolean hashProtected, DERUTF8String fileName, DERIA5String mediaType, Attributes attributes)
+ {
+ this.metaData = new MetaData(ASN1Boolean.getInstance(hashProtected), fileName, mediaType, attributes);
+ }
+
+ /**
+ * Initialise the passed in calculator with the MetaData for this message, if it is
+ * required as part of the initial message imprint calculation. After initialisation the
+ * calculator can then be used to calculate the initial message imprint digest for the first
+ * timestamp.
+ *
+ * @param calculator the digest calculator to be initialised.
+ * @throws CMSException if the MetaData is required and cannot be processed
+ */
+ public void initialiseMessageImprintDigestCalculator(DigestCalculator calculator)
+ throws CMSException
+ {
+ MetaDataUtil util = new MetaDataUtil(metaData);
+
+ util.initialiseMessageImprintDigestCalculator(calculator);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.4/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java b/libraries/spongycastle/pkix/src/main/jdk1.4/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java
new file mode 100644
index 000000000..d808d5075
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.4/org/spongycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java
@@ -0,0 +1,215 @@
+package org.spongycastle.cms.jcajce;
+
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.cms.KeyAgreeRecipientIdentifier;
+import org.spongycastle.asn1.cms.RecipientEncryptedKey;
+import org.spongycastle.asn1.cms.RecipientKeyIdentifier;
+import org.spongycastle.asn1.cms.ecc.MQVuserKeyingMaterial;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSEnvelopedGenerator;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.KeyAgreeRecipientInfoGenerator;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.MQVPrivateKeySpec;
+import org.spongycastle.jce.spec.MQVPublicKeySpec;
+import org.spongycastle.operator.GenericKey;
+
+public class JceKeyAgreeRecipientInfoGenerator
+ extends KeyAgreeRecipientInfoGenerator
+{
+ private List recipientIDs = new ArrayList();
+ private List recipientKeys = new ArrayList();
+ private PublicKey senderPublicKey;
+ private PrivateKey senderPrivateKey;
+
+ private EnvelopedDataHelper helper = new EnvelopedDataHelper(new DefaultJcaJceExtHelper());
+ private SecureRandom random;
+ private KeyPair ephemeralKP;
+
+ public JceKeyAgreeRecipientInfoGenerator(ASN1ObjectIdentifier keyAgreementOID, PrivateKey senderPrivateKey, PublicKey senderPublicKey, ASN1ObjectIdentifier keyEncryptionOID)
+ {
+ super(keyAgreementOID, SubjectPublicKeyInfo.getInstance(senderPublicKey.getEncoded()), keyEncryptionOID);
+
+ this.senderPublicKey = senderPublicKey;
+ this.senderPrivateKey = senderPrivateKey;
+ }
+
+ public JceKeyAgreeRecipientInfoGenerator setProvider(Provider provider)
+ {
+ this.helper = new EnvelopedDataHelper(new ProviderJcaJceExtHelper(provider));
+
+ return this;
+ }
+
+ public JceKeyAgreeRecipientInfoGenerator setProvider(String providerName)
+ {
+ this.helper = new EnvelopedDataHelper(new NamedJcaJceExtHelper(providerName));
+
+ return this;
+ }
+
+ public JceKeyAgreeRecipientInfoGenerator setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ /**
+ * Add a recipient based on the passed in certificate's public key and its issuer and serial number.
+ *
+ * @param recipientCert recipient's certificate
+ * @return the current instance.
+ * @throws CertificateEncodingException if the necessary data cannot be extracted from the certificate.
+ */
+ public JceKeyAgreeRecipientInfoGenerator addRecipient(X509Certificate recipientCert)
+ throws CertificateEncodingException
+ {
+ recipientIDs.add(new KeyAgreeRecipientIdentifier(CMSUtils.getIssuerAndSerialNumber(recipientCert)));
+ recipientKeys.add(recipientCert.getPublicKey());
+
+ return this;
+ }
+
+ /**
+ * Add a recipient identified by the passed in subjectKeyID and the for the passed in public key.
+ *
+ * @param subjectKeyID identifier actual recipient will use to match the private key.
+ * @param publicKey the public key for encrypting the secret key.
+ * @return the current instance.
+ * @throws CertificateEncodingException
+ */
+ public JceKeyAgreeRecipientInfoGenerator addRecipient(byte[] subjectKeyID, PublicKey publicKey)
+ throws CertificateEncodingException
+ {
+ recipientIDs.add(new KeyAgreeRecipientIdentifier(new RecipientKeyIdentifier(subjectKeyID)));
+ recipientKeys.add(publicKey);
+
+ return this;
+ }
+
+ public ASN1Sequence generateRecipientEncryptedKeys(AlgorithmIdentifier keyAgreeAlgorithm, AlgorithmIdentifier keyEncryptionAlgorithm, GenericKey contentEncryptionKey)
+ throws CMSException
+ {
+ init(keyAgreeAlgorithm.getAlgorithm());
+
+ PrivateKey senderPrivateKey = this.senderPrivateKey;
+
+ ASN1ObjectIdentifier keyAgreementOID = keyAgreeAlgorithm.getAlgorithm();
+
+ if (keyAgreementOID.getId().equals(CMSEnvelopedGenerator.ECMQV_SHA1KDF))
+ {
+ senderPrivateKey = new MQVPrivateKeySpec(
+ senderPrivateKey, ephemeralKP.getPrivate(), ephemeralKP.getPublic());
+ }
+
+ ASN1EncodableVector recipientEncryptedKeys = new ASN1EncodableVector();
+ for (int i = 0; i != recipientIDs.size(); i++)
+ {
+ PublicKey recipientPublicKey = (PublicKey)recipientKeys.get(i);
+ KeyAgreeRecipientIdentifier karId = (KeyAgreeRecipientIdentifier)recipientIDs.get(i);
+
+ if (keyAgreementOID.getId().equals(CMSEnvelopedGenerator.ECMQV_SHA1KDF))
+ {
+ recipientPublicKey = new MQVPublicKeySpec(recipientPublicKey, recipientPublicKey);
+ }
+
+ try
+ {
+ // Use key agreement to choose a wrap key for this recipient
+ KeyAgreement keyAgreement = helper.createKeyAgreement(keyAgreementOID);
+ keyAgreement.init(senderPrivateKey, random);
+ keyAgreement.doPhase(recipientPublicKey, true);
+ SecretKey keyEncryptionKey = keyAgreement.generateSecret(keyEncryptionAlgorithm.getAlgorithm().getId());
+
+ // Wrap the content encryption key with the agreement key
+ Cipher keyEncryptionCipher = helper.createCipher(keyEncryptionAlgorithm.getAlgorithm());
+
+ keyEncryptionCipher.init(Cipher.WRAP_MODE, keyEncryptionKey, random);
+
+ byte[] encryptedKeyBytes = keyEncryptionCipher.wrap(helper.getJceKey(contentEncryptionKey));
+
+ ASN1OctetString encryptedKey = new DEROctetString(encryptedKeyBytes);
+
+ recipientEncryptedKeys.add(new RecipientEncryptedKey(karId, encryptedKey));
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("cannot perform agreement step: " + e.getMessage(), e);
+ }
+ }
+
+ return new DERSequence(recipientEncryptedKeys);
+ }
+
+ protected ASN1Encodable getUserKeyingMaterial(AlgorithmIdentifier keyAgreeAlg)
+ throws CMSException
+ {
+ init(keyAgreeAlg.getAlgorithm());
+
+ if (ephemeralKP != null)
+ {
+ return new MQVuserKeyingMaterial(
+ createOriginatorPublicKey(SubjectPublicKeyInfo.getInstance(ephemeralKP.getPublic().getEncoded())), null);
+ }
+
+ return null;
+ }
+
+ private void init(ASN1ObjectIdentifier keyAgreementOID)
+ throws CMSException
+ {
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ if (keyAgreementOID.equals(CMSAlgorithm.ECMQV_SHA1KDF))
+ {
+ if (ephemeralKP == null)
+ {
+ try
+ {
+ ECParameterSpec ecParamSpec = ((ECPublicKey)senderPublicKey).getParams();
+
+ KeyPairGenerator ephemKPG = helper.createKeyPairGenerator(keyAgreementOID);
+
+ ephemKPG.initialize(ecParamSpec, random);
+
+ ephemeralKP = ephemKPG.generateKeyPair();
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new CMSException(
+ "cannot determine MQV ephemeral key pair parameters from public key: " + e);
+ }
+ }
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.4/org/spongycastle/eac/jcajce/JcaPublicKeyConverter.java b/libraries/spongycastle/pkix/src/main/jdk1.4/org/spongycastle/eac/jcajce/JcaPublicKeyConverter.java
new file mode 100644
index 000000000..9c1801ec8
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.4/org/spongycastle/eac/jcajce/JcaPublicKeyConverter.java
@@ -0,0 +1,141 @@
+package org.spongycastle.eac.jcajce;
+
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPublicKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.eac.EACObjectIdentifiers;
+import org.spongycastle.asn1.eac.ECDSAPublicKey;
+import org.spongycastle.asn1.eac.PublicKeyDataObject;
+import org.spongycastle.asn1.eac.RSAPublicKey;
+import org.spongycastle.eac.EACException;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPublicKeySpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.math.ec.ECFieldElement;
+import org.spongycastle.math.ec.ECPoint;
+
+public class JcaPublicKeyConverter
+{
+ private EACHelper helper = new DefaultEACHelper();
+
+ public JcaPublicKeyConverter setProvider(String providerName)
+ {
+ this.helper = new NamedEACHelper(providerName);
+
+ return this;
+ }
+
+ public JcaPublicKeyConverter setProvider(Provider provider)
+ {
+ this.helper = new ProviderEACHelper(provider);
+
+ return this;
+ }
+
+ public PublicKey getKey(PublicKeyDataObject publicKeyDataObject)
+ throws EACException, InvalidKeySpecException
+ {
+ if (publicKeyDataObject.getUsage().on(EACObjectIdentifiers.id_TA_ECDSA))
+ {
+ return getECPublicKeyPublicKey((ECDSAPublicKey)publicKeyDataObject);
+ }
+ else
+ {
+ RSAPublicKey pubKey = (RSAPublicKey)publicKeyDataObject;
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(pubKey.getModulus(), pubKey.getPublicExponent());
+
+ try
+ {
+ KeyFactory factk = helper.createKeyFactory("RSA");
+
+ return factk.generatePublic(pubKeySpec);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new EACException("cannot find provider: " + e.getMessage(), e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new EACException("cannot find algorithm ECDSA: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ private PublicKey getECPublicKeyPublicKey(ECDSAPublicKey key)
+ throws EACException, InvalidKeySpecException
+ {
+ ECParameterSpec spec = getParams(key);
+ ECCurve curve = spec.getCurve();
+
+ ECPoint point = curve.decodePoint(key.getPublicPointY());
+ ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, spec);
+
+ KeyFactory factk;
+ try
+ {
+ factk = helper.createKeyFactory("ECDSA");
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new EACException("cannot find provider: " + e.getMessage(), e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new EACException("cannot find algorithm ECDSA: " + e.getMessage(), e);
+ }
+
+ return factk.generatePublic(pubKeySpec);
+ }
+
+ private ECParameterSpec getParams(ECDSAPublicKey key)
+ {
+ if (!key.hasParameters())
+ {
+ throw new IllegalArgumentException("Public key does not contains EC Params");
+ }
+
+ BigInteger p = key.getPrimeModulusP();
+ ECCurve.Fp curve = new ECCurve.Fp(p, key.getFirstCoefA(), key.getSecondCoefB());
+
+ ECPoint G = curve.decodePoint(key.getBasePointG());
+
+ BigInteger order = key.getOrderOfBasePointR();
+ BigInteger coFactor = key.getCofactorF();
+
+ ECParameterSpec ecspec = new ECParameterSpec(curve, G, order, coFactor);
+
+ return ecspec;
+ }
+
+ public PublicKeyDataObject getPublicKeyDataObject(ASN1ObjectIdentifier usage, PublicKey publicKey)
+ {
+ if (publicKey instanceof java.security.interfaces.RSAPublicKey)
+ {
+ java.security.interfaces.RSAPublicKey pubKey = (java.security.interfaces.RSAPublicKey)publicKey;
+
+ return new RSAPublicKey(usage, pubKey.getModulus(), pubKey.getPublicExponent());
+ }
+ else
+ {
+ ECPublicKey pubKey = (ECPublicKey)publicKey;
+ ECParameterSpec params = pubKey.getParameters();
+
+ return new ECDSAPublicKey(
+ usage,
+ ((ECCurve.Fp)params.getCurve()).getQ(),
+ ((ECFieldElement.Fp)params.getCurve().getA()).toBigInteger(), ((ECFieldElement.Fp)params.getCurve().getB()).toBigInteger(),
+ params.getG().getEncoded(),
+ params.getN(),
+ pubKey.getQ().getEncoded(),
+ params.getH().intValue());
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/main/jdk1.4/org/spongycastle/operator/jcajce/JcaAlgorithmParametersConverter.java b/libraries/spongycastle/pkix/src/main/jdk1.4/org/spongycastle/operator/jcajce/JcaAlgorithmParametersConverter.java
new file mode 100644
index 000000000..a4de4911a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/jdk1.4/org/spongycastle/operator/jcajce/JcaAlgorithmParametersConverter.java
@@ -0,0 +1,44 @@
+package org.spongycastle.operator.jcajce;
+
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSAESOAEPparams;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+
+public class JcaAlgorithmParametersConverter
+{
+ public JcaAlgorithmParametersConverter()
+ {
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier algId, AlgorithmParameters parameters)
+ throws InvalidAlgorithmParameterException
+ {
+ try
+ {
+ ASN1Encodable params = ASN1Primitive.fromByteArray(parameters.getEncoded());
+
+ return new AlgorithmIdentifier(algId, params);
+ }
+ catch (IOException e)
+ {
+ throw new InvalidAlgorithmParameterException("unable to encode parameters object: " + e.getMessage());
+ }
+ }
+
+ public AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier algorithm, AlgorithmParameterSpec algorithmSpec)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("unknown parameter spec passed.");
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/data/org/spongycastle/tsp/test/FileDaFirmare.data b/libraries/spongycastle/pkix/src/test/data/org/spongycastle/tsp/test/FileDaFirmare.data
new file mode 100644
index 000000000..836a9fcc1
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/data/org/spongycastle/tsp/test/FileDaFirmare.data
@@ -0,0 +1,3 @@
+INIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINI
+dati da firmaredati da firmaredati da firmaredati da firmaredati da firmare
+FINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFIN \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/test/data/org/spongycastle/tsp/test/FileDaFirmare.txt.tsd.der b/libraries/spongycastle/pkix/src/test/data/org/spongycastle/tsp/test/FileDaFirmare.txt.tsd.der
new file mode 100644
index 000000000..1686986ef
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/data/org/spongycastle/tsp/test/FileDaFirmare.txt.tsd.der
Binary files differ
diff --git a/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/AttrCertSelectorTest.java b/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/AttrCertSelectorTest.java
new file mode 100644
index 000000000..c64598e94
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/AttrCertSelectorTest.java
@@ -0,0 +1,217 @@
+package org.spongycastle.cert.test;
+
+import java.math.BigInteger;
+import java.util.Date;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.Target;
+import org.spongycastle.asn1.x509.TargetInformation;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.cert.AttributeCertificateHolder;
+import org.spongycastle.cert.AttributeCertificateIssuer;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509v2AttributeCertificateBuilder;
+import org.spongycastle.cert.selector.X509AttributeCertificateHolderSelectorBuilder;
+import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.bc.BcRSAContentSignerBuilder;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.test.SimpleTest;
+import org.spongycastle.util.test.Test;
+import org.spongycastle.util.test.TestResult;
+
+public class AttrCertSelectorTest
+ extends SimpleTest
+{
+ private static final RSAPrivateCrtKeyParameters RSA_PRIVATE_KEY = new RSAPrivateCrtKeyParameters(
+ 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));
+
+ static final byte[] holderCert = Base64
+ .decode("MIIGjTCCBXWgAwIBAgICAPswDQYJKoZIhvcNAQEEBQAwaTEdMBsGCSqGSIb3DQEJ"
+ + "ARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZpcmdpbmlhIFRlY2ggQ2VydGlm"
+ + "aWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0MQswCQYDVQQGEwJVUzAeFw0w"
+ + "MzAxMzExMzUyMTRaFw0wNDAxMzExMzUyMTRaMIGDMRswGQYJKoZIhvcNAQkBFgxz"
+ + "c2hhaEB2dC5lZHUxGzAZBgNVBAMTElN1bWl0IFNoYWggKHNzaGFoKTEbMBkGA1UE"
+ + "CxMSVmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAxMQswCQYDVQQK"
+ + "EwJ2dDELMAkGA1UEBhMCVVMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPDc"
+ + "scgSKmsEp0VegFkuitD5j5PUkDuzLjlfaYONt2SN8WeqU4j2qtlCnsipa128cyKS"
+ + "JzYe9duUdNxquh5BPIkMkHBw4jHoQA33tk0J/sydWdN74/AHPpPieK5GHwhU7GTG"
+ + "rCCS1PJRxjXqse79ExAlul+gjQwHeldAC+d4A6oZAgMBAAGjggOmMIIDojAMBgNV"
+ + "HRMBAf8EAjAAMBEGCWCGSAGG+EIBAQQEAwIFoDAOBgNVHQ8BAf8EBAMCA/gwHQYD"
+ + "VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMB0GA1UdDgQWBBRUIoWAzlXbzBYE"
+ + "yVTjQFWyMMKo1jCBkwYDVR0jBIGLMIGIgBTgc3Fm+TGqKDhen+oKfbl+xVbj2KFt"
+ + "pGswaTEdMBsGCSqGSIb3DQEJARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZp"
+ + "cmdpbmlhIFRlY2ggQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0"
+ + "MQswCQYDVQQGEwJVU4IBADCBiwYJYIZIAYb4QgENBH4WfFZpcmdpbmlhIFRlY2gg"
+ + "Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgZGlnaXRhbCBjZXJ0aWZpY2F0ZXMgYXJl"
+ + "IHN1YmplY3QgdG8gcG9saWNpZXMgbG9jYXRlZCBhdCBodHRwOi8vd3d3LnBraS52"
+ + "dC5lZHUvY2EvY3BzLy4wFwYDVR0RBBAwDoEMc3NoYWhAdnQuZWR1MBkGA1UdEgQS"
+ + "MBCBDmlybWhlbHBAdnQuZWR1MEMGCCsGAQUFBwEBBDcwNTAzBggrBgEFBQcwAoYn"
+ + "aHR0cDovL2JveDE3Ny5jYy52dC5lZHUvY2EvaXNzdWVycy5odG1sMEQGA1UdHwQ9"
+ + "MDswOaA3oDWGM2h0dHA6Ly9ib3gxNzcuY2MudnQuZWR1L2h0ZG9jcy1wdWJsaWMv"
+ + "Y3JsL2NhY3JsLmNybDBUBgNVHSAETTBLMA0GCysGAQQBtGgFAQEBMDoGCysGAQQB"
+ + "tGgFAQEBMCswKQYIKwYBBQUHAgEWHWh0dHA6Ly93d3cucGtpLnZ0LmVkdS9jYS9j"
+ + "cHMvMD8GCWCGSAGG+EIBBAQyFjBodHRwOi8vYm94MTc3LmNjLnZ0LmVkdS9jZ2kt"
+ + "cHVibGljL2NoZWNrX3Jldl9jYT8wPAYJYIZIAYb4QgEDBC8WLWh0dHA6Ly9ib3gx"
+ + "NzcuY2MudnQuZWR1L2NnaS1wdWJsaWMvY2hlY2tfcmV2PzBLBglghkgBhvhCAQcE"
+ + "PhY8aHR0cHM6Ly9ib3gxNzcuY2MudnQuZWR1L35PcGVuQ0E4LjAxMDYzMC9jZ2kt"
+ + "cHVibGljL3JlbmV3YWw/MCwGCWCGSAGG+EIBCAQfFh1odHRwOi8vd3d3LnBraS52"
+ + "dC5lZHUvY2EvY3BzLzANBgkqhkiG9w0BAQQFAAOCAQEAHJ2ls9yjpZVcu5DqiE67"
+ + "r7BfkdMnm7IOj2v8cd4EAlPp6OPBmjwDMwvKRBb/P733kLBqFNWXWKTpT008R0KB"
+ + "8kehbx4h0UPz9vp31zhGv169+5iReQUUQSIwTGNWGLzrT8kPdvxiSAvdAJxcbRBm"
+ + "KzDic5I8PoGe48kSCkPpT1oNmnivmcu5j1SMvlx0IS2BkFMksr0OHiAW1elSnE/N"
+ + "RuX2k73b3FucwVxB3NRo3vgoHPCTnh9r4qItAHdxFlF+pPtbw2oHESKRfMRfOIHz"
+ + "CLQWSIa6Tvg4NIV3RRJ0sbCObesyg08lymalQMdkXwtRn5eGE00SHWwEUjSXP2gR"
+ + "3g==");
+
+ public String getName()
+ {
+ return "AttrCertSelector";
+ }
+
+ private X509AttributeCertificateHolder createAttrCert() throws Exception
+ {
+ X509CertificateHolder iCertHolder = new X509CertificateHolder(holderCert);
+ //
+ // a sample key pair.
+ //
+ // RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ // new BigInteger(
+ // "b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7",
+ // 16), new BigInteger("11", 16));
+
+ //
+ // set up the keys
+ //
+ X509v2AttributeCertificateBuilder gen = new X509v2AttributeCertificateBuilder(
+ new AttributeCertificateHolder(iCertHolder.getSubject()),
+ new AttributeCertificateIssuer(new X500Name("cn=test")),
+ BigInteger.valueOf(1),
+ new Date(System.currentTimeMillis() - 50000),
+ new Date(System.currentTimeMillis() + 50000));
+
+ // the actual attributes
+ GeneralName roleName = new GeneralName(GeneralName.rfc822Name,
+ "DAU123456789@test.com");
+ ASN1EncodableVector roleSyntax = new ASN1EncodableVector();
+ roleSyntax.add(roleName);
+
+ // roleSyntax OID: 2.5.24.72
+ gen.addAttribute(new ASN1ObjectIdentifier("2.5.24.72"), new DERSequence(roleSyntax));
+
+ AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1WithRSAEncryption");
+ AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
+
+ ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(RSA_PRIVATE_KEY);
+
+ Target targetName = new Target(Target.targetName, new GeneralName(GeneralName.dNSName,
+ "www.test.com"));
+
+ Target targetGroup = new Target(Target.targetGroup, new GeneralName(
+ GeneralName.directoryName, "o=Test, ou=Test"));
+ Target[] targets = new Target[2];
+ targets[0] = targetName;
+ targets[1] = targetGroup;
+ TargetInformation targetInformation = new TargetInformation(targets);
+
+ gen.addExtension(X509Extension.targetInformation, true, targetInformation);
+
+ return gen.build(sigGen);
+ }
+
+ public void testSelector() throws Exception
+ {
+ X509AttributeCertificateHolder aCert = createAttrCert();
+ X509AttributeCertificateHolderSelectorBuilder sel = new X509AttributeCertificateHolderSelectorBuilder();
+ sel.setAttributeCert(aCert);
+ boolean match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate.");
+ }
+ sel.setAttributeCert(null);
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate.");
+ }
+ sel.setHolder(aCert.getHolder());
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate holder.");
+ }
+ sel.setHolder(null);
+ sel.setIssuer(aCert.getIssuer());
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate issuer.");
+ }
+ sel.setIssuer(null);
+
+ X509CertificateHolder iCert = new X509CertificateHolder(holderCert);
+ match = aCert.getHolder().match(iCert);
+ if (!match)
+ {
+ fail("Issuer holder does not match signing certificate of attribute certificate.");
+ }
+
+ sel.setSerialNumber(aCert.getSerialNumber());
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate serial number.");
+ }
+
+ sel.setAttributeCertificateValid(new Date());
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate time.");
+ }
+
+ sel.addTargetName(new GeneralName(2, "www.test.com"));
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate target name.");
+ }
+ sel.setTargetNames(null);
+ sel.addTargetGroup(new GeneralName(4, "o=Test, ou=Test"));
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate target group.");
+ }
+ sel.setTargetGroups(null);
+ }
+
+ public void performTest() throws Exception
+ {
+ testSelector();
+ }
+
+ public static void main(String[] args)
+ {
+ Test test = new AttrCertSelectorTest();
+ TestResult result = test.perform();
+ System.out.println(result);
+ }
+}
+
diff --git a/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/AttrCertTest.java b/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/AttrCertTest.java
new file mode 100644
index 000000000..a072d9639
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/AttrCertTest.java
@@ -0,0 +1,639 @@
+package org.spongycastle.cert.test;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+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.x500.style.BCStrictStyle;
+import org.spongycastle.asn1.x500.style.RFC4519Style;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.Attribute;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.cert.AttributeCertificateHolder;
+import org.spongycastle.cert.AttributeCertificateIssuer;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509v2AttributeCertificateBuilder;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.bc.BcRSAContentSignerBuilder;
+import org.spongycastle.operator.bc.BcRSAContentVerifierProviderBuilder;
+import org.spongycastle.util.CollectionStore;
+import org.spongycastle.util.Store;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.test.SimpleTest;
+
+public class AttrCertTest
+ extends SimpleTest
+{
+ private static final RSAPrivateCrtKeyParameters RSA_PRIVATE_KEY = new RSAPrivateCrtKeyParameters(
+ 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));
+
+ public static byte[] attrCert = Base64.decode(
+ "MIIHQDCCBqkCAQEwgZChgY2kgYowgYcxHDAaBgkqhkiG9w0BCQEWDW1sb3JjaEB2"
+ + "dC5lZHUxHjAcBgNVBAMTFU1hcmt1cyBMb3JjaCAobWxvcmNoKTEbMBkGA1UECxMS"
+ + "VmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAyMQswCQYDVQQKEwJ2"
+ + "dDELMAkGA1UEBhMCVVMwgYmkgYYwgYMxGzAZBgkqhkiG9w0BCQEWDHNzaGFoQHZ0"
+ + "LmVkdTEbMBkGA1UEAxMSU3VtaXQgU2hhaCAoc3NoYWgpMRswGQYDVQQLExJWaXJn"
+ + "aW5pYSBUZWNoIFVzZXIxEDAOBgNVBAsTB0NsYXNzIDExCzAJBgNVBAoTAnZ0MQsw"
+ + "CQYDVQQGEwJVUzANBgkqhkiG9w0BAQQFAAIBBTAiGA8yMDAzMDcxODE2MDgwMloY"
+ + "DzIwMDMwNzI1MTYwODAyWjCCBU0wggVJBgorBgEEAbRoCAEBMYIFORaCBTU8UnVs"
+ + "ZSBSdWxlSWQ9IkZpbGUtUHJpdmlsZWdlLVJ1bGUiIEVmZmVjdD0iUGVybWl0Ij4K"
+ + "IDxUYXJnZXQ+CiAgPFN1YmplY3RzPgogICA8U3ViamVjdD4KICAgIDxTdWJqZWN0"
+ + "TWF0Y2ggTWF0Y2hJZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5j"
+ + "dGlvbjpzdHJpbmctZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlw"
+ + "ZT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjc3RyaW5nIj4KICAg"
+ + "ICAgIENOPU1hcmt1cyBMb3JjaDwvQXR0cmlidXRlVmFsdWU+CiAgICAgPFN1Ympl"
+ + "Y3RBdHRyaWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFt"
+ + "ZXM6dGM6eGFjbWw6MS4wOnN1YmplY3Q6c3ViamVjdC1pZCIgRGF0YVR5cGU9Imh0"
+ + "dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hI3N0cmluZyIgLz4gCiAgICA8"
+ + "L1N1YmplY3RNYXRjaD4KICAgPC9TdWJqZWN0PgogIDwvU3ViamVjdHM+CiAgPFJl"
+ + "c291cmNlcz4KICAgPFJlc291cmNlPgogICAgPFJlc291cmNlTWF0Y2ggTWF0Y2hJ"
+ + "ZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5jdGlvbjpzdHJpbmct"
+ + "ZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlwZT0iaHR0cDovL3d3"
+ + "dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIj4KICAgICAgaHR0cDovL3p1"
+ + "bmkuY3MudnQuZWR1PC9BdHRyaWJ1dGVWYWx1ZT4KICAgICA8UmVzb3VyY2VBdHRy"
+ + "aWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6"
+ + "eGFjbWw6MS4wOnJlc291cmNlOnJlc291cmNlLWlkIiBEYXRhVHlwZT0iaHR0cDov"
+ + "L3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIiAvPiAKICAgIDwvUmVz"
+ + "b3VyY2VNYXRjaD4KICAgPC9SZXNvdXJjZT4KICA8L1Jlc291cmNlcz4KICA8QWN0"
+ + "aW9ucz4KICAgPEFjdGlvbj4KICAgIDxBY3Rpb25NYXRjaCBNYXRjaElkPSJ1cm46"
+ + "b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmZ1bmN0aW9uOnN0cmluZy1lcXVhbCI+"
+ + "CiAgICAgPEF0dHJpYnV0ZVZhbHVlIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9y"
+ + "Zy8yMDAxL1hNTFNjaGVtYSNzdHJpbmciPgpEZWxlZ2F0ZSBBY2Nlc3MgICAgIDwv"
+ + "QXR0cmlidXRlVmFsdWU+CgkgIDxBY3Rpb25BdHRyaWJ1dGVEZXNpZ25hdG9yIEF0"
+ + "dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmFjdGlvbjph"
+ + "Y3Rpb24taWQiIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNj"
+ + "aGVtYSNzdHJpbmciIC8+IAogICAgPC9BY3Rpb25NYXRjaD4KICAgPC9BY3Rpb24+"
+ + "CiAgPC9BY3Rpb25zPgogPC9UYXJnZXQ+CjwvUnVsZT4KMA0GCSqGSIb3DQEBBAUA"
+ + "A4GBAGiJSM48XsY90HlYxGmGVSmNR6ZW2As+bot3KAfiCIkUIOAqhcphBS23egTr"
+ + "6asYwy151HshbPNYz+Cgeqs45KkVzh7bL/0e1r8sDVIaaGIkjHK3CqBABnfSayr3"
+ + "Rd1yBoDdEv8Qb+3eEPH6ab9021AsLEnJ6LWTmybbOpMNZ3tv");
+
+ byte[] signCert = Base64.decode(
+ "MIIGjTCCBXWgAwIBAgICAPswDQYJKoZIhvcNAQEEBQAwaTEdMBsGCSqGSIb3DQEJ"
+ + "ARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZpcmdpbmlhIFRlY2ggQ2VydGlm"
+ + "aWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0MQswCQYDVQQGEwJVUzAeFw0w"
+ + "MzAxMzExMzUyMTRaFw0wNDAxMzExMzUyMTRaMIGDMRswGQYJKoZIhvcNAQkBFgxz"
+ + "c2hhaEB2dC5lZHUxGzAZBgNVBAMTElN1bWl0IFNoYWggKHNzaGFoKTEbMBkGA1UE"
+ + "CxMSVmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAxMQswCQYDVQQK"
+ + "EwJ2dDELMAkGA1UEBhMCVVMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPDc"
+ + "scgSKmsEp0VegFkuitD5j5PUkDuzLjlfaYONt2SN8WeqU4j2qtlCnsipa128cyKS"
+ + "JzYe9duUdNxquh5BPIkMkHBw4jHoQA33tk0J/sydWdN74/AHPpPieK5GHwhU7GTG"
+ + "rCCS1PJRxjXqse79ExAlul+gjQwHeldAC+d4A6oZAgMBAAGjggOmMIIDojAMBgNV"
+ + "HRMBAf8EAjAAMBEGCWCGSAGG+EIBAQQEAwIFoDAOBgNVHQ8BAf8EBAMCA/gwHQYD"
+ + "VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMB0GA1UdDgQWBBRUIoWAzlXbzBYE"
+ + "yVTjQFWyMMKo1jCBkwYDVR0jBIGLMIGIgBTgc3Fm+TGqKDhen+oKfbl+xVbj2KFt"
+ + "pGswaTEdMBsGCSqGSIb3DQEJARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZp"
+ + "cmdpbmlhIFRlY2ggQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0"
+ + "MQswCQYDVQQGEwJVU4IBADCBiwYJYIZIAYb4QgENBH4WfFZpcmdpbmlhIFRlY2gg"
+ + "Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgZGlnaXRhbCBjZXJ0aWZpY2F0ZXMgYXJl"
+ + "IHN1YmplY3QgdG8gcG9saWNpZXMgbG9jYXRlZCBhdCBodHRwOi8vd3d3LnBraS52"
+ + "dC5lZHUvY2EvY3BzLy4wFwYDVR0RBBAwDoEMc3NoYWhAdnQuZWR1MBkGA1UdEgQS"
+ + "MBCBDmlybWhlbHBAdnQuZWR1MEMGCCsGAQUFBwEBBDcwNTAzBggrBgEFBQcwAoYn"
+ + "aHR0cDovL2JveDE3Ny5jYy52dC5lZHUvY2EvaXNzdWVycy5odG1sMEQGA1UdHwQ9"
+ + "MDswOaA3oDWGM2h0dHA6Ly9ib3gxNzcuY2MudnQuZWR1L2h0ZG9jcy1wdWJsaWMv"
+ + "Y3JsL2NhY3JsLmNybDBUBgNVHSAETTBLMA0GCysGAQQBtGgFAQEBMDoGCysGAQQB"
+ + "tGgFAQEBMCswKQYIKwYBBQUHAgEWHWh0dHA6Ly93d3cucGtpLnZ0LmVkdS9jYS9j"
+ + "cHMvMD8GCWCGSAGG+EIBBAQyFjBodHRwOi8vYm94MTc3LmNjLnZ0LmVkdS9jZ2kt"
+ + "cHVibGljL2NoZWNrX3Jldl9jYT8wPAYJYIZIAYb4QgEDBC8WLWh0dHA6Ly9ib3gx"
+ + "NzcuY2MudnQuZWR1L2NnaS1wdWJsaWMvY2hlY2tfcmV2PzBLBglghkgBhvhCAQcE"
+ + "PhY8aHR0cHM6Ly9ib3gxNzcuY2MudnQuZWR1L35PcGVuQ0E4LjAxMDYzMC9jZ2kt"
+ + "cHVibGljL3JlbmV3YWw/MCwGCWCGSAGG+EIBCAQfFh1odHRwOi8vd3d3LnBraS52"
+ + "dC5lZHUvY2EvY3BzLzANBgkqhkiG9w0BAQQFAAOCAQEAHJ2ls9yjpZVcu5DqiE67"
+ + "r7BfkdMnm7IOj2v8cd4EAlPp6OPBmjwDMwvKRBb/P733kLBqFNWXWKTpT008R0KB"
+ + "8kehbx4h0UPz9vp31zhGv169+5iReQUUQSIwTGNWGLzrT8kPdvxiSAvdAJxcbRBm"
+ + "KzDic5I8PoGe48kSCkPpT1oNmnivmcu5j1SMvlx0IS2BkFMksr0OHiAW1elSnE/N"
+ + "RuX2k73b3FucwVxB3NRo3vgoHPCTnh9r4qItAHdxFlF+pPtbw2oHESKRfMRfOIHz"
+ + "CLQWSIa6Tvg4NIV3RRJ0sbCObesyg08lymalQMdkXwtRn5eGE00SHWwEUjSXP2gR"
+ + "3g==");
+
+ static byte[] certWithBaseCertificateID = Base64.decode(
+ "MIIBqzCCARQCAQEwSKBGMD6kPDA6MQswCQYDVQQGEwJJVDEOMAwGA1UEChMFVU5JVE4xDDAKBgNV"
+ + "BAsTA0RJVDENMAsGA1UEAxMEcm9vdAIEAVMVjqB6MHikdjB0MQswCQYDVQQGEwJBVTEoMCYGA1UE"
+ + "ChMfVGhlIExlZ2lvbiBvZiB0aGUgQm91bmN5IENhc3RsZTEjMCEGA1UECxMaQm91bmN5IFByaW1h"
+ + "cnkgQ2VydGlmaWNhdGUxFjAUBgNVBAMTDUJvdW5jeSBDYXN0bGUwDQYJKoZIhvcNAQEFBQACBQKW"
+ + "RhnHMCIYDzIwMDUxMjEyMTIwMDQyWhgPMjAwNTEyMTkxMjAxMzJaMA8wDQYDVRhIMQaBBGVWSVAw"
+ + "DQYJKoZIhvcNAQEFBQADgYEAUAVin9StDaA+InxtXq/av6rUQLI9p1X6louBcj4kYJnxRvTrHpsr"
+ + "N3+i9Uq/uk5lRdAqmPFvcmSbuE3TRAsjrXON5uFiBBKZ1AouLqcr8nHbwcdwjJ9TyUNO9I4hfpSH"
+ + "UHHXMtBKgp4MOkhhX8xTGyWg3hp23d3GaUeg/IYlXBI=");
+
+ byte[] holderCertWithBaseCertificateID = Base64.decode(
+ "MIIBwDCCASmgAwIBAgIEAVMVjjANBgkqhkiG9w0BAQUFADA6MQswCQYDVQQGEwJJVDEOMAwGA1UE"
+ + "ChMFVU5JVE4xDDAKBgNVBAsTA0RJVDENMAsGA1UEAxMEcm9vdDAeFw0wNTExMTExMjAxMzJaFw0w"
+ + "NjA2MTYxMjAxMzJaMD4xCzAJBgNVBAYTAklUMQ4wDAYDVQQKEwVVTklUTjEMMAoGA1UECxMDRElU"
+ + "MREwDwYDVQQDEwhMdWNhQm9yejBaMA0GCSqGSIb3DQEBAQUAA0kAMEYCQQC0p+RhcFdPFqlwgrIr"
+ + "5YtqKmKXmEGb4ShypL26Ymz66ZAPdqv7EhOdzl3lZWT6srZUMWWgQMYGiHQg4z2R7X7XAgERoxUw"
+ + "EzARBglghkgBhvhCAQEEBAMCBDAwDQYJKoZIhvcNAQEFBQADgYEAsX50VPQQCWmHvPq9y9DeCpmS"
+ + "4szcpFAhpZyn6gYRwY9CRZVtmZKH8713XhkGDWcIEMcG0u3oTz3tdKgPU5uyIPrDEWr6w8ClUj4x"
+ + "5aVz5c2223+dVY7KES//JSB2bE/KCIchN3kAioQ4K8O3e0OL6oDVjsqKGw5bfahgKuSIk/Q=");
+
+
+ public String getName()
+ {
+ return "AttrCertTest";
+ }
+
+ private void testCertWithBaseCertificateID()
+ throws Exception
+ {
+ X509AttributeCertificateHolder attrCert = new X509AttributeCertificateHolder(certWithBaseCertificateID);
+ X509CertificateHolder cert = new X509CertificateHolder(holderCertWithBaseCertificateID);
+
+ AttributeCertificateHolder holder = attrCert.getHolder();
+
+ if (holder.getEntityNames() != null)
+ {
+ fail("entity names set when none expected");
+ }
+
+ if (!holder.getSerialNumber().equals(cert.getSerialNumber()))
+ {
+ fail("holder serial number doesn't match");
+ }
+
+ if (!holder.getIssuer()[0].equals(cert.getIssuer()))
+ {
+ fail("holder issuer doesn't match");
+ }
+
+ if (!holder.match(cert))
+ {
+ fail("holder not matching holder certificate");
+ }
+
+ if (!holder.equals(holder.clone()))
+ {
+ fail("holder clone test failed");
+ }
+
+ if (!attrCert.getIssuer().equals(attrCert.getIssuer().clone()))
+ {
+ fail("issuer clone test failed");
+ }
+
+ //equalityAndHashCodeTest(attrCert, certWithBaseCertificateID);
+ }
+
+ private void equalityAndHashCodeTest(X509AttributeCertificateHolder attrCert, byte[] encoding)
+ throws IOException
+ {
+ if (!attrCert.equals(attrCert))
+ {
+ fail("same certificate not equal");
+ }
+
+ if (!attrCert.getHolder().equals(attrCert.getHolder()))
+ {
+ fail("same holder not equal");
+ }
+
+ if (!attrCert.getIssuer().equals(attrCert.getIssuer()))
+ {
+ fail("same issuer not equal");
+ }
+
+ if (attrCert.getHolder().equals(attrCert.getIssuer()))
+ {
+ fail("wrong holder equal");
+ }
+
+ if (attrCert.getIssuer().equals(attrCert.getHolder()))
+ {
+ fail("wrong issuer equal");
+ }
+
+ X509AttributeCertificateHolder attrCert2 = new X509AttributeCertificateHolder(encoding);
+
+ if (attrCert2.getHolder().hashCode() != attrCert.getHolder().hashCode())
+ {
+ fail("holder hashCode test failed");
+ }
+
+ if (!attrCert2.getHolder().equals(attrCert.getHolder()))
+ {
+ fail("holder equals test failed");
+ }
+
+ if (attrCert2.getIssuer().hashCode() != attrCert.getIssuer().hashCode())
+ {
+ fail("issuer hashCode test failed");
+ }
+
+ if (!attrCert2.getIssuer().equals(attrCert.getIssuer()))
+ {
+ fail("issuer equals test failed");
+ }
+ }
+
+ private void testGenerateWithCert()
+ throws Exception
+ {
+ X509CertificateHolder iCert = new X509CertificateHolder(signCert);
+
+ //
+ // a sample key pair.
+ //
+ RSAKeyParameters pubKey = new RSAKeyParameters(false,
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ //
+ // set up the keys
+
+
+ X509v2AttributeCertificateBuilder gen = new X509v2AttributeCertificateBuilder(
+ new AttributeCertificateHolder(iCert),
+ new AttributeCertificateIssuer(new X500Name("cn=test")),
+ BigInteger.ONE,
+ new Date(System.currentTimeMillis() - 50000),
+ new Date(System.currentTimeMillis() + 50000));
+
+ // the actual attributes
+ GeneralName roleName = new GeneralName(GeneralName.rfc822Name, "DAU123456789");
+ ASN1EncodableVector roleSyntax = new ASN1EncodableVector();
+ roleSyntax.add(roleName);
+
+ // roleSyntax OID: 2.5.24.72;
+
+ gen.addAttribute(new ASN1ObjectIdentifier("2.5.24.72"), new DERSequence(roleSyntax));
+
+ AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1WithRSAEncryption");
+ AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
+
+ ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(RSA_PRIVATE_KEY);
+
+ X509AttributeCertificateHolder aCert = gen.build(sigGen);
+
+ if (!aCert.isValidOn(new Date()))
+ {
+ fail("certificate invalid");
+ }
+
+ if (!aCert.isSignatureValid(new BcRSAContentVerifierProviderBuilder(new DefaultDigestAlgorithmIdentifierFinder()).build(pubKey)))
+ {
+ fail("certificate signature not valid");
+ }
+
+ AttributeCertificateHolder holder = aCert.getHolder();
+
+ if (holder.getEntityNames() != null)
+ {
+ fail("entity names set when none expected");
+ }
+
+ if (!holder.getSerialNumber().equals(iCert.getSerialNumber()))
+ {
+ fail("holder serial number doesn't match");
+ }
+
+ if (!holder.getIssuer()[0].equals(iCert.getIssuer()))
+ {
+ fail("holder issuer doesn't match");
+ }
+
+ if (!holder.match(iCert))
+ {
+ fail("generated holder not matching holder certificate");
+ }
+
+ Attribute[] attrs = aCert.getAttributes(new ASN1ObjectIdentifier("2.5.24.72"));
+
+ if (attrs == null)
+ {
+ fail("attributes related to 2.5.24.72 not found");
+ }
+
+ Attribute attr = attrs[0];
+
+ if (!attr.getAttrType().getId().equals("2.5.24.72"))
+ {
+ fail("attribute oid mismatch");
+ }
+
+ ASN1Encodable[] values = attr.getAttrValues().toArray();
+
+ GeneralName role = GeneralNames.getInstance(values[0]).getNames()[0];
+
+ if (role.getTagNo() != GeneralName.rfc822Name)
+ {
+ fail("wrong general name type found in role");
+ }
+
+ if (!((ASN1String)role.getName()).getString().equals("DAU123456789"))
+ {
+ fail("wrong general name value found in role");
+ }
+
+ X509CertificateHolder sCert = new X509CertificateHolder(holderCertWithBaseCertificateID);
+
+ if (holder.match(sCert))
+ {
+ fail("generated holder matching wrong certificate");
+ }
+
+ equalityAndHashCodeTest(aCert, aCert.getEncoded());
+ }
+
+ private void testGenerateWithPrincipal()
+ throws Exception
+ {
+ X509CertificateHolder iCert = new X509CertificateHolder(signCert);
+
+ //
+ // a sample key pair.
+ //
+ RSAKeyParameters pubKey = new RSAKeyParameters(false,
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ //
+ // set up the keys
+ //
+ X509v2AttributeCertificateBuilder gen = new X509v2AttributeCertificateBuilder(
+ new AttributeCertificateHolder(iCert.getSubject()),
+ new AttributeCertificateIssuer(new X500Name("cn=test")),
+ BigInteger.ONE,
+ new Date(System.currentTimeMillis() - 50000),
+ new Date(System.currentTimeMillis() + 50000));
+
+ // the actual attributes
+ GeneralName roleName = new GeneralName(GeneralName.rfc822Name, "DAU123456789");
+ ASN1EncodableVector roleSyntax = new ASN1EncodableVector();
+ roleSyntax.add(roleName);
+
+ // roleSyntax OID: 2.5.24.72
+
+ gen.addAttribute(new ASN1ObjectIdentifier("2.5.24.72"), new DERSequence(roleSyntax));
+
+ AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1WithRSAEncryption");
+ AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
+
+ ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(RSA_PRIVATE_KEY);
+
+ X509AttributeCertificateHolder aCert = gen.build(sigGen);
+
+ if (!aCert.isValidOn(new Date()))
+ {
+ fail("certificate invalid");
+ }
+
+ if (!aCert.isSignatureValid(new BcRSAContentVerifierProviderBuilder(new DefaultDigestAlgorithmIdentifierFinder()).build(pubKey)))
+ {
+ fail("certificate signature not valid");
+ }
+
+ AttributeCertificateHolder holder = aCert.getHolder();
+
+ if (holder.getEntityNames() == null)
+ {
+ fail("entity names not set when expected");
+ }
+
+ if (holder.getSerialNumber() != null)
+ {
+ fail("holder serial number found when none expected");
+ }
+
+ if (holder.getIssuer() != null)
+ {
+ fail("holder issuer found when none expected");
+ }
+
+ if (!holder.match(iCert))
+ {
+ fail("generated holder not matching holder certificate");
+ }
+
+ X509CertificateHolder sCert = new X509CertificateHolder(holderCertWithBaseCertificateID);
+
+ if (holder.match(sCert))
+ {
+ fail("principal generated holder matching wrong certificate");
+ }
+
+ equalityAndHashCodeTest(aCert, aCert.getEncoded());
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ X509AttributeCertificateHolder aCert = new X509AttributeCertificateHolder(attrCert);
+ X509CertificateHolder sCert = new X509CertificateHolder(signCert);
+
+ if (!aCert.isSignatureValid(new BcRSAContentVerifierProviderBuilder(new DefaultDigestAlgorithmIdentifierFinder()).build(sCert)))
+ {
+ fail("certificate signature not valid");
+ }
+
+ //
+ // search test
+ //
+
+ List list = new ArrayList();
+
+ list.add(sCert);
+
+ Store store = new CollectionStore(list);
+
+ Collection certs = store.getMatches(aCert.getIssuer());
+ if (certs.size() != 1 || !certs.contains(sCert))
+ {
+ fail("sCert not found by issuer");
+ }
+
+ Attribute[] attrs = aCert.getAttributes(new ASN1ObjectIdentifier("1.3.6.1.4.1.6760.8.1.1"));
+ if (attrs == null || attrs.length != 1)
+ {
+ fail("attribute not found");
+ }
+
+ //
+ // reencode test
+ //
+ aCert = new X509AttributeCertificateHolder(aCert.getEncoded());
+
+ if (!aCert.isSignatureValid(new BcRSAContentVerifierProviderBuilder(new DefaultDigestAlgorithmIdentifierFinder()).build(sCert)))
+ {
+ fail("certificate signature not valid");
+ }
+
+ X509AttributeCertificateHolder saCert = new X509AttributeCertificateHolder(aCert.getEncoded());
+
+ if (!aCert.getNotAfter().equals(saCert.getNotAfter()))
+ {
+ fail("failed date comparison");
+ }
+
+ // base generator test
+
+ //
+ // a sample key pair.
+ //
+ RSAKeyParameters pubKey = new RSAKeyParameters(false,
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+ //
+ // set up the keys
+ //
+
+ X509v2AttributeCertificateBuilder gen = new X509v2AttributeCertificateBuilder(
+ aCert.getHolder(),
+ aCert.getIssuer(),
+ aCert.getSerialNumber(),
+ new Date(System.currentTimeMillis() - 50000),
+ new Date(System.currentTimeMillis() + 50000));
+
+ gen.addAttribute(attrs[0].getAttrType(), attrs[0].getAttributeValues());
+
+ AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1WithRSAEncryption");
+ AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
+
+ ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(RSA_PRIVATE_KEY);
+
+ aCert = gen.build(sigGen);
+
+ if (!aCert.isValidOn(new Date()))
+ {
+ fail("certificate not valid");
+ }
+
+ if (!aCert.isSignatureValid(new BcRSAContentVerifierProviderBuilder(new DefaultDigestAlgorithmIdentifierFinder()).build(pubKey)))
+ {
+ fail("signature not valid");
+ }
+
+ // as the issuer is the same this should still work (even though it is not
+ // technically correct
+
+ certs = store.getMatches(aCert.getIssuer());
+ if (certs.size() != 1 || !certs.contains(sCert))
+ {
+ fail("sCert not found by issuer");
+ }
+
+ attrs = aCert.getAttributes(new ASN1ObjectIdentifier("1.3.6.1.4.1.6760.8.1.1"));
+ if (attrs == null || attrs.length != 1)
+ {
+ fail("attribute not found");
+ }
+
+ //
+ // reencode test
+ //
+ aCert = new X509AttributeCertificateHolder(aCert.getEncoded());
+
+ if (!aCert.isSignatureValid(new BcRSAContentVerifierProviderBuilder(new DefaultDigestAlgorithmIdentifierFinder()).build(pubKey)))
+ {
+ fail("signature not valid");
+ }
+
+ AttributeCertificateIssuer issuer = aCert.getIssuer();
+
+ X500Name[] principals = issuer.getNames();
+
+ //
+ // test holder
+ //
+ AttributeCertificateHolder holder = aCert.getHolder();
+
+ if (holder.getEntityNames() == null)
+ {
+ fail("entity names not set");
+ }
+
+ if (holder.getSerialNumber() != null)
+ {
+ fail("holder serial number set when none expected");
+ }
+
+ if (holder.getIssuer() != null)
+ {
+ fail("holder issuer set when none expected");
+ }
+
+ principals = holder.getEntityNames();
+
+ X500Name principal0 = X500Name.getInstance(RFC4519Style.INSTANCE, principals[0].getEncoded());
+
+ if (!principal0.toString().equals("c=US,o=vt,ou=Class 2,ou=Virginia Tech User,cn=Markus Lorch (mlorch),1.2.840.113549.1.9.1=mlorch@vt.edu"))
+ {
+ fail("principal[0] for entity names don't match");
+ }
+
+ //
+ // extension test
+ //
+
+ if (aCert.hasExtensions())
+ {
+ fail("hasExtensions true with no extensions");
+ }
+
+ gen.addExtension(new ASN1ObjectIdentifier("1.1"), true, new DEROctetString(new byte[10]));
+
+ gen.addExtension(new ASN1ObjectIdentifier("2.2"), false, new DEROctetString(new byte[20]));
+
+ aCert = gen.build(sigGen);
+
+ Set exts = aCert.getCriticalExtensionOIDs();
+
+ if (exts.size() != 1 || !exts.contains(new ASN1ObjectIdentifier("1.1")))
+ { System.err.println(exts);
+ fail("critical extension test failed");
+ }
+
+ exts = aCert.getNonCriticalExtensionOIDs();
+
+ if (exts.size() != 1 || !exts.contains(new ASN1ObjectIdentifier("2.2")))
+ {
+ fail("non-critical extension test failed");
+ }
+
+ if (aCert.getCriticalExtensionOIDs().isEmpty())
+ {
+ fail("critical extensions not found");
+ }
+
+ Extension ext = aCert.getExtension(new ASN1ObjectIdentifier("1.1"));
+ ASN1Encodable extValue = ext.getParsedValue();
+
+ if (!extValue.equals(new DEROctetString(new byte[10])))
+ {
+ fail("wrong extension value found for 1.1");
+ }
+
+ testCertWithBaseCertificateID();
+ testGenerateWithCert();
+ testGenerateWithPrincipal();
+ }
+
+ public static void main(
+ String[] args)
+ {
+ runTest(new AttrCertTest());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/CertTest.java b/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/CertTest.java
new file mode 100644
index 000000000..554bd18b1
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/CertTest.java
@@ -0,0 +1,1157 @@
+package org.spongycastle.cert.test;
+
+import java.math.BigInteger;
+import java.util.Date;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSAPublicKey;
+import org.spongycastle.asn1.x500.X500NameBuilder;
+import org.spongycastle.asn1.x500.style.BCStyle;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509v3CertificateBuilder;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.bc.BcRSAContentSignerBuilder;
+import org.spongycastle.operator.bc.BcRSAContentVerifierProviderBuilder;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.test.SimpleTest;
+
+public class CertTest
+ extends SimpleTest
+{
+ // test CA
+ byte[] testCAp12 = Base64.decode(
+ "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"
+ + "HLhcYQcQ1R+RucctAgIEAAAA");
+
+ //
+ // server.crt
+ //
+ byte[] cert1 = Base64.decode(
+ "MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx"
+ + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY"
+ + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB"
+ + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ"
+ + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2"
+ + "MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW"
+ + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM"
+ + "dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l"
+ + "Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv"
+ + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re"
+ + "Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO"
+ + "Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE"
+ + "7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy"
+ + "QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0"
+ + "ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw"
+ + "DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL"
+ + "iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4"
+ + "yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF"
+ + "5/8=");
+
+ //
+ // ca.crt
+ //
+ byte[] cert2 = Base64.decode(
+ "MIIDbDCCAtWgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx"
+ + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY"
+ + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB"
+ + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ"
+ + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU1MzNaFw0wMTA2"
+ + "MDIwNzU1MzNaMIG3MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW"
+ + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM"
+ + "dGQxHjAcBgNVBAsTFUNlcnRpZmljYXRlIEF1dGhvcml0eTEVMBMGA1UEAxMMQ29u"
+ + "bmVjdCA0IENBMSgwJgYJKoZIhvcNAQkBFhl3ZWJtYXN0ZXJAY29ubmVjdDQuY29t"
+ + "LmF1MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgs5ptNG6Qv1ZpCDuUNGmv"
+ + "rhjqMDPd3ri8JzZNRiiFlBA4e6/ReaO1U8ASewDeQMH6i9R6degFdQRLngbuJP0s"
+ + "xcEE+SksEWNvygfzLwV9J/q+TQDyJYK52utb++lS0b48A1KPLwEsyL6kOAgelbur"
+ + "ukwxowprKUIV7Knf1ajetQIDAQABo4GFMIGCMCQGA1UdEQQdMBuBGXdlYm1hc3Rl"
+ + "ckBjb25uZWN0NC5jb20uYXUwDwYDVR0TBAgwBgEB/wIBADA2BglghkgBhvhCAQ0E"
+ + "KRYnbW9kX3NzbCBnZW5lcmF0ZWQgY3VzdG9tIENBIGNlcnRpZmljYXRlMBEGCWCG"
+ + "SAGG+EIBAQQEAwICBDANBgkqhkiG9w0BAQQFAAOBgQCsGvfdghH8pPhlwm1r3pQk"
+ + "msnLAVIBb01EhbXm2861iXZfWqGQjrGAaA0ZpXNk9oo110yxoqEoSJSzniZa7Xtz"
+ + "soTwNUpE0SLHvWf/SlKdFWlzXA+vOZbzEv4UmjeelekTm7lc01EEa5QRVzOxHFtQ"
+ + "DhkaJ8VqOMajkQFma2r9iA==");
+
+ //
+ // testx509.pem
+ //
+ byte[] cert3 = Base64.decode(
+ "MIIBWzCCAQYCARgwDQYJKoZIhvcNAQEEBQAwODELMAkGA1UEBhMCQVUxDDAKBgNV"
+ + "BAgTA1FMRDEbMBkGA1UEAxMSU1NMZWF5L3JzYSB0ZXN0IENBMB4XDTk1MDYxOTIz"
+ + "MzMxMloXDTk1MDcxNzIzMzMxMlowOjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA1FM"
+ + "RDEdMBsGA1UEAxMUU1NMZWF5L3JzYSB0ZXN0IGNlcnQwXDANBgkqhkiG9w0BAQEF"
+ + "AANLADBIAkEAqtt6qS5GTxVxGZYWa0/4u+IwHf7p2LNZbcPBp9/OfIcYAXBQn8hO"
+ + "/Re1uwLKXdCjIoaGs4DLdG88rkzfyK5dPQIDAQABMAwGCCqGSIb3DQIFBQADQQAE"
+ + "Wc7EcF8po2/ZO6kNCwK/ICH6DobgLekA5lSLr5EvuioZniZp5lFzAw4+YzPQ7XKJ"
+ + "zl9HYIMxATFyqSiD9jsx");
+
+ //
+ // v3-cert1.pem
+ //
+ byte[] cert4 = Base64.decode(
+ "MIICjTCCAfigAwIBAgIEMaYgRzALBgkqhkiG9w0BAQQwRTELMAkGA1UEBhMCVVMx"
+ + "NjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFuZCBTcGFjZSBBZG1pbmlz"
+ + "dHJhdGlvbjAmFxE5NjA1MjgxMzQ5MDUrMDgwMBcROTgwNTI4MTM0OTA1KzA4MDAw"
+ + "ZzELMAkGA1UEBhMCVVMxNjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFu"
+ + "ZCBTcGFjZSBBZG1pbmlzdHJhdGlvbjEgMAkGA1UEBRMCMTYwEwYDVQQDEwxTdGV2"
+ + "ZSBTY2hvY2gwWDALBgkqhkiG9w0BAQEDSQAwRgJBALrAwyYdgxmzNP/ts0Uyf6Bp"
+ + "miJYktU/w4NG67ULaN4B5CnEz7k57s9o3YY3LecETgQ5iQHmkwlYDTL2fTgVfw0C"
+ + "AQOjgaswgagwZAYDVR0ZAQH/BFowWDBWMFQxCzAJBgNVBAYTAlVTMTYwNAYDVQQK"
+ + "Ey1OYXRpb25hbCBBZXJvbmF1dGljcyBhbmQgU3BhY2UgQWRtaW5pc3RyYXRpb24x"
+ + "DTALBgNVBAMTBENSTDEwFwYDVR0BAQH/BA0wC4AJODMyOTcwODEwMBgGA1UdAgQR"
+ + "MA8ECTgzMjk3MDgyM4ACBSAwDQYDVR0KBAYwBAMCBkAwCwYJKoZIhvcNAQEEA4GB"
+ + "AH2y1VCEw/A4zaXzSYZJTTUi3uawbbFiS2yxHvgf28+8Js0OHXk1H1w2d6qOHH21"
+ + "X82tZXd/0JtG0g1T9usFFBDvYK8O0ebgz/P5ELJnBL2+atObEuJy1ZZ0pBDWINR3"
+ + "WkDNLCGiTkCKp0F5EWIrVDwh54NNevkCQRZita+z4IBO");
+
+ //
+ // v3-cert2.pem
+ //
+ byte[] cert5 = Base64.decode(
+ "MIICiTCCAfKgAwIBAgIEMeZfHzANBgkqhkiG9w0BAQQFADB9MQswCQYDVQQGEwJD"
+ + "YTEPMA0GA1UEBxMGTmVwZWFuMR4wHAYDVQQLExVObyBMaWFiaWxpdHkgQWNjZXB0"
+ + "ZWQxHzAdBgNVBAoTFkZvciBEZW1vIFB1cnBvc2VzIE9ubHkxHDAaBgNVBAMTE0Vu"
+ + "dHJ1c3QgRGVtbyBXZWIgQ0EwHhcNOTYwNzEyMTQyMDE1WhcNOTYxMDEyMTQyMDE1"
+ + "WjB0MSQwIgYJKoZIhvcNAQkBExVjb29rZUBpc3NsLmF0bC5ocC5jb20xCzAJBgNV"
+ + "BAYTAlVTMScwJQYDVQQLEx5IZXdsZXR0IFBhY2thcmQgQ29tcGFueSAoSVNTTCkx"
+ + "FjAUBgNVBAMTDVBhdWwgQS4gQ29va2UwXDANBgkqhkiG9w0BAQEFAANLADBIAkEA"
+ + "6ceSq9a9AU6g+zBwaL/yVmW1/9EE8s5you1mgjHnj0wAILuoB3L6rm6jmFRy7QZT"
+ + "G43IhVZdDua4e+5/n1ZslwIDAQABo2MwYTARBglghkgBhvhCAQEEBAMCB4AwTAYJ"
+ + "YIZIAYb4QgENBD8WPVRoaXMgY2VydGlmaWNhdGUgaXMgb25seSBpbnRlbmRlZCBm"
+ + "b3IgZGVtb25zdHJhdGlvbiBwdXJwb3Nlcy4wDQYJKoZIhvcNAQEEBQADgYEAi8qc"
+ + "F3zfFqy1sV8NhjwLVwOKuSfhR/Z8mbIEUeSTlnH3QbYt3HWZQ+vXI8mvtZoBc2Fz"
+ + "lexKeIkAZXCesqGbs6z6nCt16P6tmdfbZF3I3AWzLquPcOXjPf4HgstkyvVBn0Ap"
+ + "jAFN418KF/Cx4qyHB4cjdvLrRjjQLnb2+ibo7QU=");
+
+ //
+ // pem encoded pkcs7
+ //
+ byte[] cert6 = Base64.decode(
+ "MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIJbzCCAj0w"
+ + "ggGmAhEAzbp/VvDf5LxU/iKss3KqVTANBgkqhkiG9w0BAQIFADBfMQswCQYDVQQGEwJVUzEXMBUG"
+ + "A1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGljIFByaW1hcnkgQ2Vy"
+ + "dGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNOTYwMTI5MDAwMDAwWhcNMjgwODAxMjM1OTU5WjBfMQsw"
+ + "CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVi"
+ + "bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwgZ8wDQYJKoZIhvcNAQEBBQADgY0A"
+ + "MIGJAoGBAOUZv22jVmEtmUhx9mfeuY3rt56GgAqRDvo4Ja9GiILlc6igmyRdDR/MZW4MsNBWhBiH"
+ + "mgabEKFz37RYOWtuwfYV1aioP6oSBo0xrH+wNNePNGeICc0UEeJORVZpH3gCgNrcR5EpuzbJY1zF"
+ + "4Ncth3uhtzKwezC6Ki8xqu6jZ9rbAgMBAAEwDQYJKoZIhvcNAQECBQADgYEATD+4i8Zo3+5DMw5d"
+ + "6abLB4RNejP/khv0Nq3YlSI2aBFsfELM85wuxAc/FLAPT/+Qknb54rxK6Y/NoIAK98Up8YIiXbix"
+ + "3YEjo3slFUYweRb46gVLlH8dwhzI47f0EEA8E8NfH1PoSOSGtHuhNbB7Jbq4046rPzidADQAmPPR"
+ + "cZQwggMuMIICl6ADAgECAhEA0nYujRQMPX2yqCVdr+4NdTANBgkqhkiG9w0BAQIFADBfMQswCQYD"
+ + "VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGlj"
+ + "IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNOTgwNTEyMDAwMDAwWhcNMDgwNTEy"
+ + "MjM1OTU5WjCBzDEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy"
+ + "dXN0IE5ldHdvcmsxRjBEBgNVBAsTPXd3dy52ZXJpc2lnbi5jb20vcmVwb3NpdG9yeS9SUEEgSW5j"
+ + "b3JwLiBCeSBSZWYuLExJQUIuTFREKGMpOTgxSDBGBgNVBAMTP1ZlcmlTaWduIENsYXNzIDEgQ0Eg"
+ + "SW5kaXZpZHVhbCBTdWJzY3JpYmVyLVBlcnNvbmEgTm90IFZhbGlkYXRlZDCBnzANBgkqhkiG9w0B"
+ + "AQEFAAOBjQAwgYkCgYEAu1pEigQWu1X9A3qKLZRPFXg2uA1Ksm+cVL+86HcqnbnwaLuV2TFBcHqB"
+ + "S7lIE1YtxwjhhEKrwKKSq0RcqkLwgg4C6S/7wju7vsknCl22sDZCM7VuVIhPh0q/Gdr5FegPh7Yc"
+ + "48zGmo5/aiSS4/zgZbqnsX7vyds3ashKyAkG5JkCAwEAAaN8MHowEQYJYIZIAYb4QgEBBAQDAgEG"
+ + "MEcGA1UdIARAMD4wPAYLYIZIAYb4RQEHAQEwLTArBggrBgEFBQcCARYfd3d3LnZlcmlzaWduLmNv"
+ + "bS9yZXBvc2l0b3J5L1JQQTAPBgNVHRMECDAGAQH/AgEAMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0B"
+ + "AQIFAAOBgQCIuDc73dqUNwCtqp/hgQFxHpJqbS/28Z3TymQ43BuYDAeGW4UVag+5SYWklfEXfWe0"
+ + "fy0s3ZpCnsM+tI6q5QsG3vJWKvozx74Z11NMw73I4xe1pElCY+zCphcPXVgaSTyQXFWjZSAA/Rgg"
+ + "5V+CprGoksVYasGNAzzrw80FopCubjCCA/gwggNhoAMCAQICEBbbn/1G1zppD6KsP01bwywwDQYJ"
+ + "KoZIhvcNAQEEBQAwgcwxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln"
+ + "biBUcnVzdCBOZXR3b3JrMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvUlBB"
+ + "IEluY29ycC4gQnkgUmVmLixMSUFCLkxURChjKTk4MUgwRgYDVQQDEz9WZXJpU2lnbiBDbGFzcyAx"
+ + "IENBIEluZGl2aWR1YWwgU3Vic2NyaWJlci1QZXJzb25hIE5vdCBWYWxpZGF0ZWQwHhcNMDAxMDAy"
+ + "MDAwMDAwWhcNMDAxMjAxMjM1OTU5WjCCAQcxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYD"
+ + "VQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3Jl"
+ + "cG9zaXRvcnkvUlBBIEluY29ycC4gYnkgUmVmLixMSUFCLkxURChjKTk4MR4wHAYDVQQLExVQZXJz"
+ + "b25hIE5vdCBWYWxpZGF0ZWQxJzAlBgNVBAsTHkRpZ2l0YWwgSUQgQ2xhc3MgMSAtIE1pY3Jvc29m"
+ + "dDETMBEGA1UEAxQKRGF2aWQgUnlhbjElMCMGCSqGSIb3DQEJARYWZGF2aWRAbGl2ZW1lZGlhLmNv"
+ + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqxBsdeNmSvFqhMNwhQgNzM8mdjX9eSXb"
+ + "DawpHtQHjmh0AKJSa3IwUY0VIsyZHuXWktO/CgaMBVPt6OVf/n0R2sQigMP6Y+PhEiS0vCJBL9aK"
+ + "0+pOo2qXrjVBmq+XuCyPTnc+BOSrU26tJsX0P9BYorwySiEGxGanBNATdVL4NdUCAwEAAaOBnDCB"
+ + "mTAJBgNVHRMEAjAAMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQgwKjAoBggrBgEFBQcCARYcaHR0"
+ + "cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYTARBglghkgBhvhCAQEEBAMCB4AwMwYDVR0fBCwwKjAo"
+ + "oCagJIYiaHR0cDovL2NybC52ZXJpc2lnbi5jb20vY2xhc3MxLmNybDANBgkqhkiG9w0BAQQFAAOB"
+ + "gQBC8yIIdVGpFTf8/YiL14cMzcmL0nIRm4kGR3U59z7UtcXlfNXXJ8MyaeI/BnXwG/gD5OKYqW6R"
+ + "yca9vZOxf1uoTBl82gInk865ED3Tej6msCqFzZffnSUQvOIeqLxxDlqYRQ6PmW2nAnZeyjcnbI5Y"
+ + "syQSM2fmo7n6qJFP+GbFezGCAkUwggJBAgEBMIHhMIHMMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5j"
+ + "LjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazFGMEQGA1UECxM9d3d3LnZlcmlzaWdu"
+ + "LmNvbS9yZXBvc2l0b3J5L1JQQSBJbmNvcnAuIEJ5IFJlZi4sTElBQi5MVEQoYyk5ODFIMEYGA1UE"
+ + "AxM/VmVyaVNpZ24gQ2xhc3MgMSBDQSBJbmRpdmlkdWFsIFN1YnNjcmliZXItUGVyc29uYSBOb3Qg"
+ + "VmFsaWRhdGVkAhAW25/9Rtc6aQ+irD9NW8MsMAkGBSsOAwIaBQCggbowGAYJKoZIhvcNAQkDMQsG"
+ + "CSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMDAxMDAyMTczNTE4WjAjBgkqhkiG9w0BCQQxFgQU"
+ + "gZjSaBEY2oxGvlQUIMnxSXhivK8wWwYJKoZIhvcNAQkPMU4wTDAKBggqhkiG9w0DBzAOBggqhkiG"
+ + "9w0DAgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwBwYFKw4DAh0w"
+ + "DQYJKoZIhvcNAQEBBQAEgYAzk+PU91/ZFfoiuKOECjxEh9fDYE2jfDCheBIgh5gdcCo+sS1WQs8O"
+ + "HreQ9Nop/JdJv1DQMBK6weNBBDoP0EEkRm1XCC144XhXZC82jBZohYmi2WvDbbC//YN58kRMYMyy"
+ + "srrfn4Z9I+6kTriGXkrpGk9Q0LSGjmG2BIsqiF0dvwAAAAAAAA==");
+
+ //
+ // dsaWithSHA1 cert
+ //
+ byte[] cert7 = Base64.decode(
+ "MIIEXAYJKoZIhvcNAQcCoIIETTCCBEkCAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+ + "SIb3DQEHAaCCAsMwggK/MIIB4AIBADCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7"
+ + "d8miwTMN55CUSmo3TO8WGCxgY61TX5k+7NU4XPf1TULjw3GobwaJX13kquPh"
+ + "fVXk+gVy46n4Iw3hAhUBSe/QF4BUj+pJOF9ROBM4u+FEWA8CQQD4mSJbrABj"
+ + "TUWrlnAte8pS22Tq4/FPO7jHSqjijUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/z"
+ + "m8Q12PFp/PjOhh+nMA4xDDAKBgNVBAMTA0lEMzAeFw05NzEwMDEwMDAwMDBa"
+ + "Fw0zODAxMDEwMDAwMDBaMA4xDDAKBgNVBAMTA0lEMzCB8DCBpwYFKw4DAhsw"
+ + "gZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxgY61TX5k+7NU4XPf1TULj"
+ + "w3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/QF4BUj+pJOF9ROBM4u+FE"
+ + "WA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jHSqjijUHfXKTrHL1OEqV3"
+ + "SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nA0QAAkEAkYkXLYMtGVGWj9OnzjPn"
+ + "sB9sefSRPrVegZJCZbpW+Iv0/1RP1u04pHG9vtRpIQLjzUiWvLMU9EKQTThc"
+ + "eNMmWDCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxg"
+ + "Y61TX5k+7NU4XPf1TULjw3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/Q"
+ + "F4BUj+pJOF9ROBM4u+FEWA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jH"
+ + "SqjijUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nAy8AMCwC"
+ + "FBY3dBSdeprGcqpr6wr3xbG+6WW+AhRMm/facKJNxkT3iKgJbp7R8Xd3QTGC"
+ + "AWEwggFdAgEBMBMwDjEMMAoGA1UEAxMDSUQzAgEAMAkGBSsOAwIaBQCgXTAY"
+ + "BgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0wMjA1"
+ + "MjQyMzEzMDdaMCMGCSqGSIb3DQEJBDEWBBS4WMsoJhf7CVbZYCFcjoTRzPkJ"
+ + "xjCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxgY61T"
+ + "X5k+7NU4XPf1TULjw3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/QF4BU"
+ + "j+pJOF9ROBM4u+FEWA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jHSqji"
+ + "jUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nBC8wLQIVALID"
+ + "dt+MHwawrDrwsO1Z6sXBaaJsAhRaKssrpevmLkbygKPV07XiAKBG02Zvb2Jh"
+ + "cg==");
+
+ //
+ // testcrl.pem
+ //
+ byte[] crl1 = Base64.decode(
+ "MIICjTCCAfowDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoT"
+ + "F1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVy"
+ + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5Fw05NTA1MDIwMjEyMjZaFw05NTA2MDEw"
+ + "MDAxNDlaMIIBaDAWAgUCQQAABBcNOTUwMjAxMTcyNDI2WjAWAgUCQQAACRcNOTUw"
+ + "MjEwMDIxNjM5WjAWAgUCQQAADxcNOTUwMjI0MDAxMjQ5WjAWAgUCQQAADBcNOTUw"
+ + "MjI1MDA0NjQ0WjAWAgUCQQAAGxcNOTUwMzEzMTg0MDQ5WjAWAgUCQQAAFhcNOTUw"
+ + "MzE1MTkxNjU0WjAWAgUCQQAAGhcNOTUwMzE1MTk0MDQxWjAWAgUCQQAAHxcNOTUw"
+ + "MzI0MTk0NDMzWjAWAgUCcgAABRcNOTUwMzI5MjAwNzExWjAWAgUCcgAAERcNOTUw"
+ + "MzMwMDIzNDI2WjAWAgUCQQAAIBcNOTUwNDA3MDExMzIxWjAWAgUCcgAAHhcNOTUw"
+ + "NDA4MDAwMjU5WjAWAgUCcgAAQRcNOTUwNDI4MTcxNzI0WjAWAgUCcgAAOBcNOTUw"
+ + "NDI4MTcyNzIxWjAWAgUCcgAATBcNOTUwNTAyMDIxMjI2WjANBgkqhkiG9w0BAQIF"
+ + "AAN+AHqOEJXSDejYy0UwxxrH/9+N2z5xu/if0J6qQmK92W0hW158wpJg+ovV3+wQ"
+ + "wvIEPRL2rocL0tKfAsVq1IawSJzSNgxG0lrcla3MrJBnZ4GaZDu4FutZh72MR3Gt"
+ + "JaAL3iTJHJD55kK2D/VoyY1djlsPuNh6AEgdVwFAyp0v");
+
+ //
+ // ecdsa cert with extra octet string.
+ //
+ byte[] oldEcdsa = Base64.decode(
+ "MIICljCCAkCgAwIBAgIBATALBgcqhkjOPQQBBQAwgY8xCzAJBgNVBAYTAkFVMSgwJ"
+ + "gYDVQQKEx9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIwEAYDVQQHEw"
+ + "lNZWxib3VybmUxETAPBgNVBAgTCFZpY3RvcmlhMS8wLQYJKoZIhvcNAQkBFiBmZWV"
+ + "kYmFjay1jcnlwdG9AYm91bmN5Y2FzdGxlLm9yZzAeFw0wMTEyMDcwMTAwMDRaFw0w"
+ + "MTEyMDcwMTAxNDRaMIGPMQswCQYDVQQGEwJBVTEoMCYGA1UEChMfVGhlIExlZ2lvb"
+ + "iBvZiB0aGUgQm91bmN5IENhc3RsZTESMBAGA1UEBxMJTWVsYm91cm5lMREwDwYDVQ"
+ + "QIEwhWaWN0b3JpYTEvMC0GCSqGSIb3DQEJARYgZmVlZGJhY2stY3J5cHRvQGJvdW5"
+ + "jeWNhc3RsZS5vcmcwgeQwgb0GByqGSM49AgEwgbECAQEwKQYHKoZIzj0BAQIef///"
+ + "////////////f///////gAAAAAAAf///////MEAEHn///////////////3///////"
+ + "4AAAAAAAH///////AQeawFsO9zxiUHQ1lSSFHXKcanbL7J9HTd5YYXClCwKBB8CD/"
+ + "qWPNyogWzMM7hkK+35BcPTWFc9Pyf7vTs8uaqvAh5///////////////9///+eXpq"
+ + "fXZBx+9FSJoiQnQsDIgAEHwJbbcU7xholSP+w9nFHLebJUhqdLSU05lq/y9X+DHAw"
+ + "CwYHKoZIzj0EAQUAA0MAMEACHnz6t4UNoVROp74ma4XNDjjGcjaqiIWPZLK8Bdw3G"
+ + "QIeLZ4j3a6ividZl344UH+UPUE7xJxlYGuy7ejTsqRR");
+
+ byte[] uncompressedPtEC = Base64.decode(
+ "MIIDKzCCAsGgAwIBAgICA+kwCwYHKoZIzj0EAQUAMGYxCzAJBgNVBAYTAkpQ"
+ + "MRUwEwYDVQQKEwxuaXRlY2guYWMuanAxDjAMBgNVBAsTBWFpbGFiMQ8wDQYD"
+ + "VQQDEwZ0ZXN0Y2ExHzAdBgkqhkiG9w0BCQEWEHRlc3RjYUBsb2NhbGhvc3Qw"
+ + "HhcNMDExMDEzMTE1MzE3WhcNMjAxMjEyMTE1MzE3WjBmMQswCQYDVQQGEwJK"
+ + "UDEVMBMGA1UEChMMbml0ZWNoLmFjLmpwMQ4wDAYDVQQLEwVhaWxhYjEPMA0G"
+ + "A1UEAxMGdGVzdGNhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0Y2FAbG9jYWxob3N0"
+ + "MIIBczCCARsGByqGSM49AgEwggEOAgEBMDMGByqGSM49AQECKEdYWnajFmnZ"
+ + "tzrukK2XWdle2v+GsD9l1ZiR6g7ozQDbhFH/bBiMDQcwVAQoJ5EQKrI54/CT"
+ + "xOQ2pMsd/fsXD+EX8YREd8bKHWiLz8lIVdD5cBNeVwQoMKSc6HfI7vKZp8Q2"
+ + "zWgIFOarx1GQoWJbMcSt188xsl30ncJuJT2OoARRBAqJ4fD+q6hbqgNSjTQ7"
+ + "htle1KO3eiaZgcJ8rrnyN8P+5A8+5K+H9aQ/NbBR4Gs7yto5PXIUZEUgodHA"
+ + "TZMSAcSq5ZYt4KbnSYaLY0TtH9CqAigEwZ+hglbT21B7ZTzYX2xj0x+qooJD"
+ + "hVTLtIPaYJK2HrMPxTw6/zfrAgEPA1IABAnvfFcFDgD/JicwBGn6vR3N8MIn"
+ + "mptZf/mnJ1y649uCF60zOgdwIyI7pVSxBFsJ7ohqXEHW0x7LrGVkdSEiipiH"
+ + "LYslqh3xrqbAgPbl93GUo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB"
+ + "/wQEAwIBxjAdBgNVHQ4EFgQUAEo62Xm9H6DcsE0zUDTza4BRG90wCwYHKoZI"
+ + "zj0EAQUAA1cAMFQCKAQsCHHSNOqfJXLgt3bg5+k49hIBGVr/bfG0B9JU3rNt"
+ + "Ycl9Y2zfRPUCKAK2ccOQXByAWfsasDu8zKHxkZv7LVDTFjAIffz3HaCQeVhD"
+ + "z+fauEg=");
+
+ byte[] keyUsage = Base64.decode(
+ "MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UE"
+ + "BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50"
+ + "cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBs"
+ + "aW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExp"
+ + "bWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0"
+ + "aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBa"
+ + "MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNV"
+ + "BAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3Jw"
+ + "LiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50"
+ + "cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50"
+ + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GL"
+ + "ADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSv"
+ + "x1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHV"
+ + "iTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173"
+ + "iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkw"
+ + "ggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50"
+ + "cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0Ff"
+ + "SW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UE"
+ + "CxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50"
+ + "cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYD"
+ + "VQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9D"
+ + "bGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkx"
+ + "MDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW"
+ + "/O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwG"
+ + "A1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI"
+ + "hvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQ"
+ + "OokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkU"
+ + "ODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapE"
+ + "PHayXOw=");
+
+ byte[] nameCert = Base64.decode(
+ "MIIEFjCCA3+gAwIBAgIEdS8BozANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJE"+
+ "RTERMA8GA1UEChQIREFURVYgZUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRQ0Eg"+
+ "REFURVYgRDAzIDE6UE4wIhgPMjAwMTA1MTAxMDIyNDhaGA8yMDA0MDUwOTEwMjI0"+
+ "OFowgYQxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIFAZCYXllcm4xEjAQBgNVBAcUCU7I"+
+ "dXJuYmVyZzERMA8GA1UEChQIREFURVYgZUcxHTAbBgNVBAUTFDAwMDAwMDAwMDA4"+
+ "OTU3NDM2MDAxMR4wHAYDVQQDFBVEaWV0bWFyIFNlbmdlbmxlaXRuZXIwgaEwDQYJ"+
+ "KoZIhvcNAQEBBQADgY8AMIGLAoGBAJLI/LJLKaHoMk8fBECW/od8u5erZi6jI8Ug"+
+ "C0a/LZyQUO/R20vWJs6GrClQtXB+AtfiBSnyZOSYzOdfDI8yEKPEv8qSuUPpOHps"+
+ "uNCFdLZF1vavVYGEEWs2+y+uuPmg8q1oPRyRmUZ+x9HrDvCXJraaDfTEd9olmB/Z"+
+ "AuC/PqpjAgUAwAAAAaOCAcYwggHCMAwGA1UdEwEB/wQCMAAwDwYDVR0PAQH/BAUD"+
+ "AwdAADAxBgNVHSAEKjAoMCYGBSskCAEBMB0wGwYIKwYBBQUHAgEWD3d3dy56cy5k"+
+ "YXRldi5kZTApBgNVHREEIjAggR5kaWV0bWFyLnNlbmdlbmxlaXRuZXJAZGF0ZXYu"+
+ "ZGUwgYQGA1UdIwR9MHuhc6RxMG8xCzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1"+
+ "bGllcnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0"+
+ "MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjVSLUNBIDE6UE6CBACm8LkwDgYHAoIG"+
+ "AQoMAAQDAQEAMEcGA1UdHwRAMD4wPKAUoBKGEHd3dy5jcmwuZGF0ZXYuZGWiJKQi"+
+ "MCAxCzAJBgNVBAYTAkRFMREwDwYDVQQKFAhEQVRFViBlRzAWBgUrJAgDBAQNMAsT"+
+ "A0VVUgIBBQIBATAdBgNVHQ4EFgQUfv6xFP0xk7027folhy+ziZvBJiwwLAYIKwYB"+
+ "BQUHAQEEIDAeMBwGCCsGAQUFBzABhhB3d3cuZGlyLmRhdGV2LmRlMA0GCSqGSIb3"+
+ "DQEBBQUAA4GBAEOVX6uQxbgtKzdgbTi6YLffMftFr2mmNwch7qzpM5gxcynzgVkg"+
+ "pnQcDNlm5AIbS6pO8jTCLfCd5TZ5biQksBErqmesIl3QD+VqtB+RNghxectZ3VEs"+
+ "nCUtcE7tJ8O14qwCb3TxS9dvIUFiVi4DjbxX46TdcTbTaK8/qr6AIf+l");
+
+ byte[] probSelfSignedCert = Base64.decode(
+ "MIICxTCCAi6gAwIBAgIQAQAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQUFADBF"
+ + "MScwJQYDVQQKEx4gRElSRUNUSU9OIEdFTkVSQUxFIERFUyBJTVBPVFMxGjAYBgNV"
+ + "BAMTESBBQyBNSU5FRkkgQiBURVNUMB4XDTA0MDUwNzEyMDAwMFoXDTE0MDUwNzEy"
+ + "MDAwMFowRTEnMCUGA1UEChMeIERJUkVDVElPTiBHRU5FUkFMRSBERVMgSU1QT1RT"
+ + "MRowGAYDVQQDExEgQUMgTUlORUZJIEIgVEVTVDCBnzANBgkqhkiG9w0BAQEFAAOB"
+ + "jQAwgYkCgYEAveoCUOAukZdcFCs2qJk76vSqEX0ZFzHqQ6faBPZWjwkgUNwZ6m6m"
+ + "qWvvyq1cuxhoDvpfC6NXILETawYc6MNwwxsOtVVIjuXlcF17NMejljJafbPximEt"
+ + "DQ4LcQeSp4K7FyFlIAMLyt3BQ77emGzU5fjFTvHSUNb3jblx0sV28c0CAwEAAaOB"
+ + "tTCBsjAfBgNVHSMEGDAWgBSEJ4bLbvEQY8cYMAFKPFD1/fFXlzAdBgNVHQ4EFgQU"
+ + "hCeGy27xEGPHGDABSjxQ9f3xV5cwDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIB"
+ + "AQQEAwIBBjA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vYWRvbmlzLnBrNy5jZXJ0"
+ + "cGx1cy5uZXQvZGdpLXRlc3QuY3JsMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN"
+ + "AQEFBQADgYEAmToHJWjd3+4zknfsP09H6uMbolHNGG0zTS2lrLKpzcmkQfjhQpT9"
+ + "LUTBvfs1jdjo9fGmQLvOG+Sm51Rbjglb8bcikVI5gLbclOlvqLkm77otjl4U4Z2/"
+ + "Y0vP14Aov3Sn3k+17EfReYUZI4liuB95ncobC4e8ZM++LjQcIM0s+Vs=");
+
+
+ byte[] gost34102001base = Base64.decode(
+ "MIIB1DCCAYECEEjpVKXP6Wn1yVz3VeeDQa8wCgYGKoUDAgIDBQAwbTEfMB0G"
+ + "A1UEAwwWR29zdFIzNDEwLTIwMDEgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRv"
+ + "UHJvMQswCQYDVQQGEwJSVTEpMCcGCSqGSIb3DQEJARYaR29zdFIzNDEwLTIw"
+ + "MDFAZXhhbXBsZS5jb20wHhcNMDUwMjAzMTUxNjQ2WhcNMTUwMjAzMTUxNjQ2"
+ + "WjBtMR8wHQYDVQQDDBZHb3N0UjM0MTAtMjAwMSBleGFtcGxlMRIwEAYDVQQK"
+ + "DAlDcnlwdG9Qcm8xCzAJBgNVBAYTAlJVMSkwJwYJKoZIhvcNAQkBFhpHb3N0"
+ + "UjM0MTAtMjAwMUBleGFtcGxlLmNvbTBjMBwGBiqFAwICEzASBgcqhQMCAiQA"
+ + "BgcqhQMCAh4BA0MABECElWh1YAIaQHUIzROMMYks/eUFA3pDXPRtKw/nTzJ+"
+ + "V4/rzBa5lYgD0Jp8ha4P5I3qprt+VsfLsN8PZrzK6hpgMAoGBiqFAwICAwUA"
+ + "A0EAHw5dw/aw/OiNvHyOE65kvyo4Hp0sfz3csM6UUkp10VO247ofNJK3tsLb"
+ + "HOLjUaqzefrlGb11WpHYrvWFg+FcLA==");
+
+ byte[] gost341094base = Base64.decode(
+ "MIICDzCCAbwCEBcxKsIb0ghYvAQeUjfQdFAwCgYGKoUDAgIEBQAwaTEdMBsG"
+ + "A1UEAwwUR29zdFIzNDEwLTk0IGV4YW1wbGUxEjAQBgNVBAoMCUNyeXB0b1By"
+ + "bzELMAkGA1UEBhMCUlUxJzAlBgkqhkiG9w0BCQEWGEdvc3RSMzQxMC05NEBl"
+ + "eGFtcGxlLmNvbTAeFw0wNTAyMDMxNTE2NTFaFw0xNTAyMDMxNTE2NTFaMGkx"
+ + "HTAbBgNVBAMMFEdvc3RSMzQxMC05NCBleGFtcGxlMRIwEAYDVQQKDAlDcnlw"
+ + "dG9Qcm8xCzAJBgNVBAYTAlJVMScwJQYJKoZIhvcNAQkBFhhHb3N0UjM0MTAt"
+ + "OTRAZXhhbXBsZS5jb20wgaUwHAYGKoUDAgIUMBIGByqFAwICIAIGByqFAwIC"
+ + "HgEDgYQABIGAu4Rm4XmeWzTYLIB/E6gZZnFX/oxUJSFHbzALJ3dGmMb7R1W+"
+ + "t7Lzk2w5tUI3JoTiDRCKJA4fDEJNKzsRK6i/ZjkyXJSLwaj+G2MS9gklh8x1"
+ + "G/TliYoJgmjTXHemD7aQEBON4z58nJHWrA0ILD54wbXCtrcaqCqLRYGTMjJ2"
+ + "+nswCgYGKoUDAgIEBQADQQBxKNhOmjgz/i5CEgLOyKyz9pFGkDcaymsWYQWV"
+ + "v7CZ0pTM8IzMzkUBW3GHsUjCFpanFZDfg2zuN+3kT+694n9B");
+
+ byte[] gost341094A = Base64.decode(
+ "MIICSDCCAfWgAwIBAgIBATAKBgYqhQMCAgQFADCBgTEXMBUGA1UEAxMOZGVmYXVsdDM0MTAtOTQx"
+ + "DTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1vbGExDDAKBgNVBAgT"
+ + "A01FTDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAzMjkx"
+ + "MzExNTdaFw0wNjAzMjkxMzExNTdaMIGBMRcwFQYDVQQDEw5kZWZhdWx0MzQxMC05NDENMAsGA1UE"
+ + "ChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLW9sYTEMMAoGA1UECBMDTUVMMQsw"
+ + "CQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MIGlMBwGBiqFAwICFDASBgcq"
+ + "hQMCAiACBgcqhQMCAh4BA4GEAASBgIQACDLEuxSdRDGgdZxHmy30g/DUYkRxO9Mi/uSHX5NjvZ31"
+ + "b7JMEMFqBtyhql1HC5xZfUwZ0aT3UnEFDfFjLP+Bf54gA+LPkQXw4SNNGOj+klnqgKlPvoqMGlwa"
+ + "+hLPKbS561WpvB2XSTgbV+pqqXR3j6j30STmybelEV3RdS2Now8wDTALBgNVHQ8EBAMCB4AwCgYG"
+ + "KoUDAgIEBQADQQBCFy7xWRXtNVXflKvDs0pBdBuPzjCMeZAXVxK8vUxsxxKu76d9CsvhgIFknFRi"
+ + "wWTPiZenvNoJ4R1uzeX+vREm");
+
+ byte[] gost341094B = Base64.decode(
+ "MIICSDCCAfWgAwIBAgIBATAKBgYqhQMCAgQFADCBgTEXMBUGA1UEAxMOcGFyYW0xLTM0MTAtOTQx"
+ + "DTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1PbGExDDAKBgNVBAgT"
+ + "A01lbDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAzMjkx"
+ + "MzEzNTZaFw0wNjAzMjkxMzEzNTZaMIGBMRcwFQYDVQQDEw5wYXJhbTEtMzQxMC05NDENMAsGA1UE"
+ + "ChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLU9sYTEMMAoGA1UECBMDTWVsMQsw"
+ + "CQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MIGlMBwGBiqFAwICFDASBgcq"
+ + "hQMCAiADBgcqhQMCAh4BA4GEAASBgEa+AAcZmijWs1M9x5Pn9efE8D9ztG1NMoIt0/hNZNqln3+j"
+ + "lMZjyqPt+kTLIjtmvz9BRDmIDk6FZz+4LhG2OTL7yGpWfrMxMRr56nxomTN9aLWRqbyWmn3brz9Y"
+ + "AUD3ifnwjjIuW7UM84JNlDTOdxx0XRUfLQIPMCXe9cO02Xskow8wDTALBgNVHQ8EBAMCB4AwCgYG"
+ + "KoUDAgIEBQADQQBzFcnuYc/639OTW+L5Ecjw9KxGr+dwex7lsS9S1BUgKa3m1d5c+cqI0B2XUFi5"
+ + "4iaHHJG0dCyjtQYLJr0OZjRw");
+
+ byte[] gost34102001A = Base64.decode(
+ "MIICCzCCAbigAwIBAgIBATAKBgYqhQMCAgMFADCBhDEaMBgGA1UEAxMRZGVmYXVsdC0zNDEwLTIw"
+ + "MDExDTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1PbGExDDAKBgNV"
+ + "BAgTA01lbDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAz"
+ + "MjkxMzE4MzFaFw0wNjAzMjkxMzE4MzFaMIGEMRowGAYDVQQDExFkZWZhdWx0LTM0MTAtMjAwMTEN"
+ + "MAsGA1UEChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLU9sYTEMMAoGA1UECBMD"
+ + "TWVsMQswCQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MGMwHAYGKoUDAgIT"
+ + "MBIGByqFAwICIwEGByqFAwICHgEDQwAEQG/4c+ZWb10IpeHfmR+vKcbpmSOClJioYmCVgnojw0Xn"
+ + "ned0KTg7TJreRUc+VX7vca4hLQaZ1o/TxVtfEApK/O6jDzANMAsGA1UdDwQEAwIHgDAKBgYqhQMC"
+ + "AgMFAANBAN8y2b6HuIdkD3aWujpfQbS1VIA/7hro4vLgDhjgVmev/PLzFB8oTh3gKhExpDo82IEs"
+ + "ZftGNsbbyp1NFg7zda0=");
+
+ byte[] gostCA1 = Base64.decode(
+ "MIIDNDCCAuGgAwIBAgIQZLcKDcWcQopF+jp4p9jylDAKBgYqhQMCAgQFADBm"
+ + "MQswCQYDVQQGEwJSVTEPMA0GA1UEBxMGTW9zY293MRcwFQYDVQQKEw5PT08g"
+ + "Q3J5cHRvLVBybzEUMBIGA1UECxMLRGV2ZWxvcG1lbnQxFzAVBgNVBAMTDkNQ"
+ + "IENTUCBUZXN0IENBMB4XDTAyMDYwOTE1NTIyM1oXDTA5MDYwOTE1NTkyOVow"
+ + "ZjELMAkGA1UEBhMCUlUxDzANBgNVBAcTBk1vc2NvdzEXMBUGA1UEChMOT09P"
+ + "IENyeXB0by1Qcm8xFDASBgNVBAsTC0RldmVsb3BtZW50MRcwFQYDVQQDEw5D"
+ + "UCBDU1AgVGVzdCBDQTCBpTAcBgYqhQMCAhQwEgYHKoUDAgIgAgYHKoUDAgIe"
+ + "AQOBhAAEgYAYglywKuz1nMc9UiBYOaulKy53jXnrqxZKbCCBSVaJ+aCKbsQm"
+ + "glhRFrw6Mwu8Cdeabo/ojmea7UDMZd0U2xhZFRti5EQ7OP6YpqD0alllo7za"
+ + "4dZNXdX+/ag6fOORSLFdMpVx5ganU0wHMPk67j+audnCPUj/plbeyccgcdcd"
+ + "WaOCASIwggEeMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud"
+ + "DgQWBBTe840gTo4zt2twHilw3PD9wJaX0TCBygYDVR0fBIHCMIG/MDygOqA4"
+ + "hjYtaHR0cDovL2ZpZXdhbGwvQ2VydEVucm9sbC9DUCUyMENTUCUyMFRlc3Ql"
+ + "MjBDQSgzKS5jcmwwRKBCoECGPmh0dHA6Ly93d3cuY3J5cHRvcHJvLnJ1L0Nl"
+ + "cnRFbnJvbGwvQ1AlMjBDU1AlMjBUZXN0JTIwQ0EoMykuY3JsMDmgN6A1hjMt"
+ + "ZmlsZTovL1xcZmlld2FsbFxDZXJ0RW5yb2xsXENQIENTUCBUZXN0IENBKDMp"
+ + "LmNybC8wEgYJKwYBBAGCNxUBBAUCAwMAAzAKBgYqhQMCAgQFAANBAIJi7ni7"
+ + "9rwMR5rRGTFftt2k70GbqyUEfkZYOzrgdOoKiB4IIsIstyBX0/ne6GsL9Xan"
+ + "G2IN96RB7KrowEHeW+k=");
+
+ byte[] gostCA2 = Base64.decode(
+ "MIIC2DCCAoWgAwIBAgIQe9ZCugm42pRKNcHD8466zTAKBgYqhQMCAgMFADB+"
+ + "MRowGAYJKoZIhvcNAQkBFgtzYmFAZGlndC5ydTELMAkGA1UEBhMCUlUxDDAK"
+ + "BgNVBAgTA01FTDEUMBIGA1UEBxMLWW9zaGthci1PbGExDTALBgNVBAoTBERp"
+ + "Z3QxDzANBgNVBAsTBkNyeXB0bzEPMA0GA1UEAxMGc2JhLUNBMB4XDTA0MDgw"
+ + "MzEzMzE1OVoXDTE0MDgwMzEzNDAxMVowfjEaMBgGCSqGSIb3DQEJARYLc2Jh"
+ + "QGRpZ3QucnUxCzAJBgNVBAYTAlJVMQwwCgYDVQQIEwNNRUwxFDASBgNVBAcT"
+ + "C1lvc2hrYXItT2xhMQ0wCwYDVQQKEwREaWd0MQ8wDQYDVQQLEwZDcnlwdG8x"
+ + "DzANBgNVBAMTBnNiYS1DQTBjMBwGBiqFAwICEzASBgcqhQMCAiMBBgcqhQMC"
+ + "Ah4BA0MABEDMSy10CuOH+i8QKG2UWA4XmCt6+BFrNTZQtS6bOalyDY8Lz+G7"
+ + "HybyipE3PqdTB4OIKAAPsEEeZOCZd2UXGQm5o4HaMIHXMBMGCSsGAQQBgjcU"
+ + "AgQGHgQAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud"
+ + "DgQWBBRJJl3LcNMxkZI818STfoi3ng1xoDBxBgNVHR8EajBoMDGgL6Athito"
+ + "dHRwOi8vc2JhLmRpZ3QubG9jYWwvQ2VydEVucm9sbC9zYmEtQ0EuY3JsMDOg"
+ + "MaAvhi1maWxlOi8vXFxzYmEuZGlndC5sb2NhbFxDZXJ0RW5yb2xsXHNiYS1D"
+ + "QS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwCgYGKoUDAgIDBQADQQA+BRJHbc/p"
+ + "q8EYl6iJqXCuR+ozRmH7hPAP3c4KqYSC38TClCgBloLapx/3/WdatctFJW/L"
+ + "mcTovpq088927shE");
+
+ byte[] inDirectCrl = Base64.decode(
+ "MIIdXjCCHMcCAQEwDQYJKoZIhvcNAQEFBQAwdDELMAkGA1UEBhMCREUxHDAaBgNV"
+ +"BAoUE0RldXRzY2hlIFRlbGVrb20gQUcxFzAVBgNVBAsUDlQtVGVsZVNlYyBUZXN0"
+ +"MS4wDAYHAoIGAQoHFBMBMTAeBgNVBAMUF1QtVGVsZVNlYyBUZXN0IERJUiA4OlBO"
+ +"Fw0wNjA4MDQwODQ1MTRaFw0wNjA4MDQxNDQ1MTRaMIIbfzB+AgQvrj/pFw0wMzA3"
+ +"MjIwNTQxMjhaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+ +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+ +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP+oXDTAzMDcyMjA1NDEyOFowZzBlBgNV"
+ +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+ +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+ +"UE4wfgIEL64/5xcNMDQwNDA1MTMxODE3WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+ +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC"
+ +"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/oFw0wNDA0"
+ +"MDUxMzE4MTdaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+ +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+ +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP+UXDTAzMDExMzExMTgxMVowZzBlBgNV"
+ +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+ +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+ +"UE4wfgIEL64/5hcNMDMwMTEzMTExODExWjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+ +"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");
+
+ byte[] directCRL = Base64.decode(
+ "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"
+ +"MQ==");
+
+ private final byte[] pkcs7CrlProblem = Base64.decode(
+ "MIIwSAYJKoZIhvcNAQcCoIIwOTCCMDUCAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+ + "SIb3DQEHAaCCEsAwggP4MIIC4KADAgECAgF1MA0GCSqGSIb3DQEBBQUAMEUx"
+ + "CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR4wHAYDVQQD"
+ + "ExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUwHhcNMDQxMjAyMjEyNTM5WhcNMDYx"
+ + "MjMwMjEyNTM5WjBMMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMR2VvVHJ1c3Qg"
+ + "SW5jMSYwJAYDVQQDEx1HZW9UcnVzdCBBZG9iZSBPQ1NQIFJlc3BvbmRlcjCB"
+ + "nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4gnNYhtw7U6QeVXZODnGhHMj"
+ + "+OgZ0DB393rEk6a2q9kq129IA2e03yKBTfJfQR9aWKc2Qj90dsSqPjvTDHFG"
+ + "Qsagm2FQuhnA3fb1UWhPzeEIdm6bxDsnQ8nWqKqxnWZzELZbdp3I9bBLizIq"
+ + "obZovzt60LNMghn/unvvuhpeVSsCAwEAAaOCAW4wggFqMA4GA1UdDwEB/wQE"
+ + "AwIE8DCB5QYDVR0gAQH/BIHaMIHXMIHUBgkqhkiG9y8BAgEwgcYwgZAGCCsG"
+ + "AQUFBwICMIGDGoGAVGhpcyBjZXJ0aWZpY2F0ZSBoYXMgYmVlbiBpc3N1ZWQg"
+ + "aW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBBY3JvYmF0IENyZWRlbnRpYWxzIENQ"
+ + "UyBsb2NhdGVkIGF0IGh0dHA6Ly93d3cuZ2VvdHJ1c3QuY29tL3Jlc291cmNl"
+ + "cy9jcHMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2VvdHJ1c3QuY29tL3Jl"
+ + "c291cmNlcy9jcHMwEwYDVR0lBAwwCgYIKwYBBQUHAwkwOgYDVR0fBDMwMTAv"
+ + "oC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9hZG9iZWNhMS5j"
+ + "cmwwHwYDVR0jBBgwFoAUq4BZw2WDbR19E70Zw+wajw1HaqMwDQYJKoZIhvcN"
+ + "AQEFBQADggEBAENJf1BD7PX5ivuaawt90q1OGzXpIQL/ClzEeFVmOIxqPc1E"
+ + "TFRq92YuxG5b6+R+k+tGkmCwPLcY8ipg6ZcbJ/AirQhohzjlFuT6YAXsTfEj"
+ + "CqEZfWM2sS7crK2EYxCMmKE3xDfPclYtrAoz7qZvxfQj0TuxHSstHZv39wu2"
+ + "ZiG1BWiEcyDQyTgqTOXBoZmfJtshuAcXmTpgkrYSrS37zNlPTGh+pMYQ0yWD"
+ + "c8OQRJR4OY5ZXfdna01mjtJTOmj6/6XPoLPYTq2gQrc2BCeNJ4bEhLb7sFVB"
+ + "PbwPrpzTE/HRbQHDrzj0YimDxeOUV/UXctgvYwHNtEkcBLsOm/uytMYwggSh"
+ + "MIIDiaADAgECAgQ+HL0oMA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNVBAYTAlVT"
+ + "MSMwIQYDVQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UE"
+ + "CxMUQWRvYmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3Qg"
+ + "Q0EwHhcNMDMwMTA4MjMzNzIzWhcNMjMwMTA5MDAwNzIzWjBpMQswCQYDVQQG"
+ + "EwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQxHTAb"
+ + "BgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYwFAYDVQQDEw1BZG9iZSBS"
+ + "b290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzE9UhPen"
+ + "ouczU38/nBKIayyZR2d+Dx65rRSI+cMQ2B3w8NWfaQovWTWwzGypTJwVoJ/O"
+ + "IL+gz1Ti4CBmRT85hjh+nMSOByLGJPYBErA131XqaZCw24U3HuJOB7JCoWoT"
+ + "aaBm6oCREVkqmwh5WiBELcm9cziLPC/gQxtdswvwrzUaKf7vppLdgUydPVmO"
+ + "rTE8QH6bkTYG/OJcjdGNJtVcRc+vZT+xqtJilvSoOOq6YEL09BxKNRXO+E4i"
+ + "Vg+VGMX4lp+f+7C3eCXpgGu91grwxnSUnfMPUNuad85LcIMjjaDKeCBEXDxU"
+ + "ZPHqojAZn+pMBk0GeEtekt8i0slns3rSAQIDAQABo4IBTzCCAUswEQYJYIZI"
+ + "AYb4QgEBBAQDAgAHMIGOBgNVHR8EgYYwgYMwgYCgfqB8pHoweDELMAkGA1UE"
+ + "BhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMgSW5jb3Jwb3JhdGVkMR0w"
+ + "GwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEWMBQGA1UEAxMNQWRvYmUg"
+ + "Um9vdCBDQTENMAsGA1UEAxMEQ1JMMTArBgNVHRAEJDAigA8yMDAzMDEwODIz"
+ + "MzcyM1qBDzIwMjMwMTA5MDAwNzIzWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgw"
+ + "FoAUgrc4SpOqmxDvgLvZVOLxD/uAnN4wHQYDVR0OBBYEFIK3OEqTqpsQ74C7"
+ + "2VTi8Q/7gJzeMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjYu"
+ + "MDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQAy2p9DdcH6b8lv26sdNjc+"
+ + "vGEZNrcCPB0jWZhsnu5NhedUyCAfp9S74r8Ad30ka3AvXME6dkm10+AjhCpx"
+ + "aiLzwScpmBX2NZDkBEzDjbyfYRzn/SSM0URDjBa6m02l1DUvvBHOvfdRN42f"
+ + "kOQU8Rg/vulZEjX5M5LznuDVa5pxm5lLyHHD4bFhCcTl+pHwQjo3fTT5cujN"
+ + "qmIcIenV9IIQ43sFti1oVgt+fpIsb01yggztVnSynbmrLSsdEF/bJ3Vwj/0d"
+ + "1+ICoHnlHOX/r2RAUS2em0fbQqV8H8KmSLDXvpJpTaT2KVfFeBEY3IdRyhOy"
+ + "Yp1PKzK9MaXB+lKrBYjIMIIEyzCCA7OgAwIBAgIEPhy9tTANBgkqhkiG9w0B"
+ + "AQUFADBpMQswCQYDVQQGEwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJ"
+ + "bmNvcnBvcmF0ZWQxHTAbBgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYw"
+ + "FAYDVQQDEw1BZG9iZSBSb290IENBMB4XDTA0MDExNzAwMDMzOVoXDTE1MDEx"
+ + "NTA4MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu"
+ + "Yy4xHjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTCCASIwDQYJKoZI"
+ + "hvcNAQEBBQADggEPADCCAQoCggEBAKfld+BkeFrnOYW8r9L1WygTDlTdSfrO"
+ + "YvWS/Z6Ye5/l+HrBbOHqQCXBcSeCpz7kB2WdKMh1FOE4e9JlmICsHerBLdWk"
+ + "emU+/PDb69zh8E0cLoDfxukF6oVPXj6WSThdSG7H9aXFzRr6S3XGCuvgl+Qw"
+ + "DTLiLYW+ONF6DXwt3TQQtKReJjOJZk46ZZ0BvMStKyBaeB6DKZsmiIo89qso"
+ + "13VDZINH2w1KvXg0ygDizoNtbvgAPFymwnsINS1klfQlcvn0x0RJm9bYQXK3"
+ + "5GNZAgL3M7Lqrld0jMfIUaWvuHCLyivytRuzq1dJ7E8rmidjDEk/G+27pf13"
+ + "fNZ7vR7M+IkCAwEAAaOCAZ0wggGZMBIGA1UdEwEB/wQIMAYBAf8CAQEwUAYD"
+ + "VR0gBEkwRzBFBgkqhkiG9y8BAgEwODA2BggrBgEFBQcCARYqaHR0cHM6Ly93"
+ + "d3cuYWRvYmUuY29tL21pc2MvcGtpL2Nkc19jcC5odG1sMBQGA1UdJQQNMAsG"
+ + "CSqGSIb3LwEBBTCBsgYDVR0fBIGqMIGnMCKgIKAehhxodHRwOi8vY3JsLmFk"
+ + "b2JlLmNvbS9jZHMuY3JsMIGAoH6gfKR6MHgxCzAJBgNVBAYTAlVTMSMwIQYD"
+ + "VQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRv"
+ + "YmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0ExDTAL"
+ + "BgNVBAMTBENSTDEwCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFIK3OEqTqpsQ"
+ + "74C72VTi8Q/7gJzeMB0GA1UdDgQWBBSrgFnDZYNtHX0TvRnD7BqPDUdqozAZ"
+ + "BgkqhkiG9n0HQQAEDDAKGwRWNi4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA"
+ + "PzlZLqIAjrFeEWEs0uC29YyJhkXOE9mf3YSaFGsITF+Gl1j0pajTjyH4R35Q"
+ + "r3floW2q3HfNzTeZ90Jnr1DhVERD6zEMgJpCtJqVuk0sixuXJHghS/KicKf4"
+ + "YXJJPx9epuIRF1siBRnznnF90svmOJMXApc0jGnYn3nQfk4kaShSnDaYaeYR"
+ + "DJKcsiWhl6S5zfwS7Gg8hDeyckhMQKKWnlG1CQrwlSFisKCduoodwRtWgft8"
+ + "kx13iyKK3sbalm6vnVc+5nufS4vI+TwMXoV63NqYaSroafBWk0nL53zGXPEy"
+ + "+A69QhzEViJKn2Wgqt5gt++jMMNImbRObIqgfgF1VjCCBUwwggQ0oAMCAQIC"
+ + "AgGDMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1H"
+ + "ZW9UcnVzdCBJbmMuMR4wHAYDVQQDExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUw"
+ + "HhcNMDYwMzI0MTU0MjI5WhcNMDkwNDA2MTQ0MjI5WjBzMQswCQYDVQQGEwJV"
+ + "UzELMAkGA1UECBMCTUExETAPBgNVBAoTCEdlb1RydXN0MR0wGwYDVQQDExRN"
+ + "YXJrZXRpbmcgRGVwYXJ0bWVudDElMCMGCSqGSIb3DQEJARYWbWFya2V0aW5n"
+ + "QGdlb3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB"
+ + "ANmvajTO4XJvAU2nVcLmXeCnAQX7RZt+7+ML3InmqQ3LCGo1weop09zV069/"
+ + "1x/Nmieol7laEzeXxd2ghjGzwfXafqQEqHn6+vBCvqdNPoSi63fSWhnuDVWp"
+ + "KVDOYgxOonrXl+Cc43lu4zRSq+Pi5phhrjDWcH74a3/rdljUt4c4GFezFXfa"
+ + "w2oTzWkxj2cTSn0Szhpr17+p66UNt8uknlhmu4q44Speqql2HwmCEnpLYJrK"
+ + "W3fOq5D4qdsvsLR2EABLhrBezamLI3iGV8cRHOUTsbTMhWhv/lKfHAyf4XjA"
+ + "z9orzvPN5jthhIfICOFq/nStTgakyL4Ln+nFAB/SMPkCAwEAAaOCAhYwggIS"
+ + "MA4GA1UdDwEB/wQEAwIF4DCB5QYDVR0gAQH/BIHaMIHXMIHUBgkqhkiG9y8B"
+ + "AgEwgcYwgZAGCCsGAQUFBwICMIGDGoGAVGhpcyBjZXJ0aWZpY2F0ZSBoYXMg"
+ + "YmVlbiBpc3N1ZWQgaW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBBY3JvYmF0IENy"
+ + "ZWRlbnRpYWxzIENQUyBsb2NhdGVkIGF0IGh0dHA6Ly93d3cuZ2VvdHJ1c3Qu"
+ + "Y29tL3Jlc291cmNlcy9jcHMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2Vv"
+ + "dHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwOgYDVR0fBDMwMTAvoC2gK4YpaHR0"
+ + "cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9hZG9iZWNhMS5jcmwwHwYDVR0j"
+ + "BBgwFoAUq4BZw2WDbR19E70Zw+wajw1HaqMwRAYIKwYBBQUHAQEEODA2MDQG"
+ + "CCsGAQUFBzABhihodHRwOi8vYWRvYmUtb2NzcC5nZW90cnVzdC5jb20vcmVz"
+ + "cG9uZGVyMBQGA1UdJQQNMAsGCSqGSIb3LwEBBTA8BgoqhkiG9y8BAQkBBC4w"
+ + "LAIBAYYnaHR0cDovL2Fkb2JlLXRpbWVzdGFtcC5nZW90cnVzdC5jb20vdHNh"
+ + "MBMGCiqGSIb3LwEBCQIEBTADAgEBMAwGA1UdEwQFMAMCAQAwDQYJKoZIhvcN"
+ + "AQEFBQADggEBAAOhy6QxOo+i3h877fvDvTa0plGD2bIqK7wMdNqbMDoSWied"
+ + "FIcgcBOIm2wLxOjZBAVj/3lDq59q2rnVeNnfXM0/N0MHI9TumHRjU7WNk9e4"
+ + "+JfJ4M+c3anrWOG3NE5cICDVgles+UHjXetHWql/LlP04+K2ZOLb6LE2xGnI"
+ + "YyLW9REzCYNAVF+/WkYdmyceHtaBZdbyVAJq0NAJPsfgY1pWcBo31Mr1fpX9"
+ + "WrXNTYDCqMyxMImJTmN3iI68tkXlNrhweQoArKFqBysiBkXzG/sGKYY6tWKU"
+ + "pzjLc3vIp/LrXC5zilROes8BSvwu1w9qQrJNcGwo7O4uijoNtyYil1Exgh1Q"
+ + "MIIdTAIBATBLMEUxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJ"
+ + "bmMuMR4wHAYDVQQDExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUCAgGDMAkGBSsO"
+ + "AwIaBQCgggxMMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwIwYJKoZIhvcN"
+ + "AQkEMRYEFP4R6qIdpQJzWyzrqO8X1ZfJOgChMIIMCQYJKoZIhvcvAQEIMYIL"
+ + "+jCCC/agggZ5MIIGdTCCA6gwggKQMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV"
+ + "BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR4wHAYDVQQDExVHZW9U"
+ + "cnVzdCBDQSBmb3IgQWRvYmUXDTA2MDQwNDE3NDAxMFoXDTA2MDQwNTE3NDAx"
+ + "MFowggIYMBMCAgC5Fw0wNTEwMTEyMDM2MzJaMBICAVsXDTA0MTEwNDE1MDk0"
+ + "MVowEwICALgXDTA1MTIxMjIyMzgzOFowEgIBWhcNMDQxMTA0MTUwOTMzWjAT"
+ + "AgIA5hcNMDUwODI3MDQwOTM4WjATAgIAtxcNMDYwMTE2MTc1NTEzWjATAgIA"
+ + "hhcNMDUxMjEyMjIzODU1WjATAgIAtRcNMDUwNzA2MTgzODQwWjATAgIA4BcN"
+ + "MDYwMzIwMDc0ODM0WjATAgIAgRcNMDUwODAyMjIzMTE1WjATAgIA3xcNMDUx"
+ + "MjEyMjIzNjUwWjASAgFKFw0wNDExMDQxNTA5MTZaMBICAUQXDTA0MTEwNDE1"
+ + "MDg1M1owEgIBQxcNMDQxMDAzMDEwMDQwWjASAgFsFw0wNDEyMDYxOTQ0MzFa"
+ + "MBMCAgEoFw0wNjAzMDkxMjA3MTJaMBMCAgEkFw0wNjAxMTYxNzU1MzRaMBIC"
+ + "AWcXDTA1MDMxODE3NTYxNFowEwICAVEXDTA2MDEzMTExMjcxMVowEgIBZBcN"
+ + "MDQxMTExMjI0ODQxWjATAgIA8RcNMDUwOTE2MTg0ODAxWjATAgIBThcNMDYw"
+ + "MjIxMjAxMDM2WjATAgIAwRcNMDUxMjEyMjIzODE2WjASAgFiFw0wNTAxMTAx"
+ + "NjE5MzRaMBICAWAXDTA1MDExMDE5MDAwNFowEwICAL4XDTA1MDUxNzE0NTYx"
+ + "MFowDQYJKoZIhvcNAQEFBQADggEBAEKhRMS3wVho1U3EvEQJZC8+JlUngmZQ"
+ + "A78KQbHPWNZWFlNvPuf/b0s7Lu16GfNHXh1QAW6Y5Hi1YtYZ3YOPyMd4Xugt"
+ + "gCdumbB6xtKsDyN5RvTht6ByXj+CYlYqsL7RX0izJZ6mJn4fjMkqzPKNOjb8"
+ + "kSn5T6rn93BjlATtCE8tPVOM8dnqGccRE0OV59+nDBXc90UMt5LdEbwaUOap"
+ + "snVB0oLcNm8d/HnlVH6RY5LnDjrT4vwfe/FApZtTecEWsllVUXDjSpwfcfD/"
+ + "476/lpGySB2otALqzImlA9R8Ok3hJ8dnF6hhQ5Oe6OJMnGYgdhkKbxsKkdib"
+ + "tTVl3qmH5QAwggLFMIIBrQIBATANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQG"
+ + "EwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQxHTAb"
+ + "BgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYwFAYDVQQDEw1BZG9iZSBS"
+ + "b290IENBFw0wNjAxMjcxODMzMzFaFw0wNzAxMjcwMDAwMDBaMIHeMCMCBD4c"
+ + "vUAXDTAzMDEyMTIzNDY1NlowDDAKBgNVHRUEAwoBBDAjAgQ+HL1BFw0wMzAx"
+ + "MjEyMzQ3MjJaMAwwCgYDVR0VBAMKAQQwIwIEPhy9YhcNMDMwMTIxMjM0NzQy"
+ + "WjAMMAoGA1UdFQQDCgEEMCMCBD4cvWEXDTA0MDExNzAxMDg0OFowDDAKBgNV"
+ + "HRUEAwoBBDAjAgQ+HL2qFw0wNDAxMTcwMTA5MDVaMAwwCgYDVR0VBAMKAQQw"
+ + "IwIEPhy9qBcNMDQwMTE3MDEzOTI5WjAMMAoGA1UdFQQDCgEEoC8wLTAKBgNV"
+ + "HRQEAwIBDzAfBgNVHSMEGDAWgBSCtzhKk6qbEO+Au9lU4vEP+4Cc3jANBgkq"
+ + "hkiG9w0BAQUFAAOCAQEAwtXF9042wG39icUlsotn5tpE3oCusLb/hBpEONhx"
+ + "OdfEQOq0w5hf/vqaxkcf71etA+KpbEUeSVaHMHRPhx/CmPrO9odE139dJdbt"
+ + "9iqbrC9iZokFK3h/es5kg73xujLKd7C/u5ngJ4mwBtvhMLjFjF2vJhPKHL4C"
+ + "IgMwdaUAhrcNzy16v+mw/VGJy3Fvc6oCESW1K9tvFW58qZSNXrMlsuidgunM"
+ + "hPKG+z0SXVyCqL7pnqKiaGddcgujYGOSY4S938oVcfZeZQEODtSYGlzldojX"
+ + "C1U1hCK5+tHAH0Ox/WqRBIol5VCZQwJftf44oG8oviYq52aaqSejXwmfT6zb"
+ + "76GCBXUwggVxMIIFbQoBAKCCBWYwggViBgkrBgEFBQcwAQEEggVTMIIFTzCB"
+ + "taIWBBS+8EpykfXdl4h3z7m/NZfdkAQQERgPMjAwNjA0MDQyMDIwMTVaMGUw"
+ + "YzA7MAkGBSsOAwIaBQAEFEb4BuZYkbjBjOjT6VeA/00fBvQaBBT3fTSQniOp"
+ + "BbHBSkz4xridlX0bsAICAYOAABgPMjAwNjA0MDQyMDIwMTVaoBEYDzIwMDYw"
+ + "NDA1MDgyMDE1WqEjMCEwHwYJKwYBBQUHMAECBBIEEFqooq/R2WltD7TposkT"
+ + "BhMwDQYJKoZIhvcNAQEFBQADgYEAMig6lty4b0JDsT/oanfQG5x6jVKPACpp"
+ + "1UA9SJ0apJJa7LeIdDFmu5C2S/CYiKZm4A4P9cAu0YzgLHxE4r6Op+HfVlAG"
+ + "6bzUe1P/hi1KCJ8r8wxOZAktQFPSzs85RAZwkHMfB0lP2e/h666Oye+Zf8VH"
+ + "RaE+/xZ7aswE89HXoumgggQAMIID/DCCA/gwggLgoAMCAQICAXUwDQYJKoZI"
+ + "hvcNAQEFBQAwRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu"
+ + "Yy4xHjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTAeFw0wNDEyMDIy"
+ + "MTI1MzlaFw0wNjEyMzAyMTI1MzlaMEwxCzAJBgNVBAYTAlVTMRUwEwYDVQQK"
+ + "EwxHZW9UcnVzdCBJbmMxJjAkBgNVBAMTHUdlb1RydXN0IEFkb2JlIE9DU1Ag"
+ + "UmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDiCc1iG3Dt"
+ + "TpB5Vdk4OcaEcyP46BnQMHf3esSTprar2SrXb0gDZ7TfIoFN8l9BH1pYpzZC"
+ + "P3R2xKo+O9MMcUZCxqCbYVC6GcDd9vVRaE/N4Qh2bpvEOydDydaoqrGdZnMQ"
+ + "tlt2ncj1sEuLMiqhtmi/O3rQs0yCGf+6e++6Gl5VKwIDAQABo4IBbjCCAWow"
+ + "DgYDVR0PAQH/BAQDAgTwMIHlBgNVHSABAf8EgdowgdcwgdQGCSqGSIb3LwEC"
+ + "ATCBxjCBkAYIKwYBBQUHAgIwgYMagYBUaGlzIGNlcnRpZmljYXRlIGhhcyBi"
+ + "ZWVuIGlzc3VlZCBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIEFjcm9iYXQgQ3Jl"
+ + "ZGVudGlhbHMgQ1BTIGxvY2F0ZWQgYXQgaHR0cDovL3d3dy5nZW90cnVzdC5j"
+ + "b20vcmVzb3VyY2VzL2NwczAxBggrBgEFBQcCARYlaHR0cDovL3d3dy5nZW90"
+ + "cnVzdC5jb20vcmVzb3VyY2VzL2NwczATBgNVHSUEDDAKBggrBgEFBQcDCTA6"
+ + "BgNVHR8EMzAxMC+gLaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxz"
+ + "L2Fkb2JlY2ExLmNybDAfBgNVHSMEGDAWgBSrgFnDZYNtHX0TvRnD7BqPDUdq"
+ + "ozANBgkqhkiG9w0BAQUFAAOCAQEAQ0l/UEPs9fmK+5prC33SrU4bNekhAv8K"
+ + "XMR4VWY4jGo9zURMVGr3Zi7Eblvr5H6T60aSYLA8txjyKmDplxsn8CKtCGiH"
+ + "OOUW5PpgBexN8SMKoRl9YzaxLtysrYRjEIyYoTfEN89yVi2sCjPupm/F9CPR"
+ + "O7EdKy0dm/f3C7ZmIbUFaIRzINDJOCpM5cGhmZ8m2yG4BxeZOmCSthKtLfvM"
+ + "2U9MaH6kxhDTJYNzw5BElHg5jlld92drTWaO0lM6aPr/pc+gs9hOraBCtzYE"
+ + "J40nhsSEtvuwVUE9vA+unNMT8dFtAcOvOPRiKYPF45RX9Rdy2C9jAc20SRwE"
+ + "uw6b+7K0xjANBgkqhkiG9w0BAQEFAASCAQC7a4yICFGCEMPlJbydK5qLG3rV"
+ + "sip7Ojjz9TB4nLhC2DgsIHds8jjdq2zguInluH2nLaBCVS+qxDVlTjgbI2cB"
+ + "TaWS8nglC7nNjzkKAsa8vThA8FZUVXTW0pb74jNJJU2AA27bb4g+4WgunCrj"
+ + "fpYp+QjDyMmdrJVqRmt5eQN+dpVxMS9oq+NrhOSEhyIb4/rejgNg9wnVK1ms"
+ + "l5PxQ4x7kpm7+Ua41//owkJVWykRo4T1jo4eHEz1DolPykAaKie2VKH/sMqR"
+ + "Spjh4E5biKJLOV9fKivZWKAXByXfwUbbMsJvz4v/2yVHFy9xP+tqB5ZbRoDK"
+ + "k8PzUyCprozn+/22oYIPijCCD4YGCyqGSIb3DQEJEAIOMYIPdTCCD3EGCSqG"
+ + "SIb3DQEHAqCCD2Iwgg9eAgEDMQswCQYFKw4DAhoFADCB+gYLKoZIhvcNAQkQ"
+ + "AQSggeoEgecwgeQCAQEGAikCMCEwCQYFKw4DAhoFAAQUoT97qeCv3FXYaEcS"
+ + "gY8patCaCA8CAiMHGA8yMDA2MDQwNDIwMjA1N1owAwIBPAEB/wIIO0yRre3L"
+ + "8/6ggZCkgY0wgYoxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNl"
+ + "dHRzMRAwDgYDVQQHEwdOZWVkaGFtMRUwEwYDVQQKEwxHZW9UcnVzdCBJbmMx"
+ + "EzARBgNVBAsTClByb2R1Y3Rpb24xJTAjBgNVBAMTHGFkb2JlLXRpbWVzdGFt"
+ + "cC5nZW90cnVzdC5jb22gggzJMIIDUTCCAjmgAwIBAgICAI8wDQYJKoZIhvcN"
+ + "AQEFBQAwRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4x"
+ + "HjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTAeFw0wNTAxMTAwMTI5"
+ + "MTBaFw0xNTAxMTUwODAwMDBaMIGKMQswCQYDVQQGEwJVUzEWMBQGA1UECBMN"
+ + "TWFzc2FjaHVzZXR0czEQMA4GA1UEBxMHTmVlZGhhbTEVMBMGA1UEChMMR2Vv"
+ + "VHJ1c3QgSW5jMRMwEQYDVQQLEwpQcm9kdWN0aW9uMSUwIwYDVQQDExxhZG9i"
+ + "ZS10aW1lc3RhbXAuZ2VvdHJ1c3QuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GN"
+ + "ADCBiQKBgQDRbxJotLFPWQuuEDhKtOMaBUJepGxIvWxeahMbq1DVmqnk88+j"
+ + "w/5lfPICPzQZ1oHrcTLSAFM7Mrz3pyyQKQKMqUyiemzuG/77ESUNfBNSUfAF"
+ + "PdtHuDMU8Is8ABVnFk63L+wdlvvDIlKkE08+VTKCRdjmuBVltMpQ6QcLFQzm"
+ + "AQIDAQABo4GIMIGFMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly9jcmwuZ2Vv"
+ + "dHJ1c3QuY29tL2NybHMvYWRvYmVjYTEuY3JsMB8GA1UdIwQYMBaAFKuAWcNl"
+ + "g20dfRO9GcPsGo8NR2qjMA4GA1UdDwEB/wQEAwIGwDAWBgNVHSUBAf8EDDAK"
+ + "BggrBgEFBQcDCDANBgkqhkiG9w0BAQUFAAOCAQEAmnyXjdtX+F79Nf0KggTd"
+ + "6YC2MQD9s09IeXTd8TP3rBmizfM+7f3icggeCGakNfPRmIUMLoa0VM5Kt37T"
+ + "2X0TqzBWusfbKx7HnX4v1t/G8NJJlT4SShSHv+8bjjU4lUoCmW2oEcC5vXwP"
+ + "R5JfjCyois16npgcO05ZBT+LLDXyeBijE6qWmwLDfEpLyILzVRmyU4IE7jvm"
+ + "rgb3GXwDUvd3yQXGRRHbPCh3nj9hBGbuzyt7GnlqnEie3wzIyMG2ET/wvTX5"
+ + "4BFXKNe7lDLvZj/MXvd3V7gMTSVW0kAszKao56LfrVTgp1VX3UBQYwmQqaoA"
+ + "UwFezih+jEvjW6cYJo/ErDCCBKEwggOJoAMCAQICBD4cvSgwDQYJKoZIhvcN"
+ + "AQEFBQAwaTELMAkGA1UEBhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMg"
+ + "SW5jb3Jwb3JhdGVkMR0wGwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEW"
+ + "MBQGA1UEAxMNQWRvYmUgUm9vdCBDQTAeFw0wMzAxMDgyMzM3MjNaFw0yMzAx"
+ + "MDkwMDA3MjNaMGkxCzAJBgNVBAYTAlVTMSMwIQYDVQQKExpBZG9iZSBTeXN0"
+ + "ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRvYmUgVHJ1c3QgU2Vydmlj"
+ + "ZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUA"
+ + "A4IBDwAwggEKAoIBAQDMT1SE96ei5zNTfz+cEohrLJlHZ34PHrmtFIj5wxDY"
+ + "HfDw1Z9pCi9ZNbDMbKlMnBWgn84gv6DPVOLgIGZFPzmGOH6cxI4HIsYk9gES"
+ + "sDXfVeppkLDbhTce4k4HskKhahNpoGbqgJERWSqbCHlaIEQtyb1zOIs8L+BD"
+ + "G12zC/CvNRop/u+mkt2BTJ09WY6tMTxAfpuRNgb84lyN0Y0m1VxFz69lP7Gq"
+ + "0mKW9Kg46rpgQvT0HEo1Fc74TiJWD5UYxfiWn5/7sLd4JemAa73WCvDGdJSd"
+ + "8w9Q25p3zktwgyONoMp4IERcPFRk8eqiMBmf6kwGTQZ4S16S3yLSyWezetIB"
+ + "AgMBAAGjggFPMIIBSzARBglghkgBhvhCAQEEBAMCAAcwgY4GA1UdHwSBhjCB"
+ + "gzCBgKB+oHykejB4MQswCQYDVQQGEwJVUzEjMCEGA1UEChMaQWRvYmUgU3lz"
+ + "dGVtcyBJbmNvcnBvcmF0ZWQxHTAbBgNVBAsTFEFkb2JlIFRydXN0IFNlcnZp"
+ + "Y2VzMRYwFAYDVQQDEw1BZG9iZSBSb290IENBMQ0wCwYDVQQDEwRDUkwxMCsG"
+ + "A1UdEAQkMCKADzIwMDMwMTA4MjMzNzIzWoEPMjAyMzAxMDkwMDA3MjNaMAsG"
+ + "A1UdDwQEAwIBBjAfBgNVHSMEGDAWgBSCtzhKk6qbEO+Au9lU4vEP+4Cc3jAd"
+ + "BgNVHQ4EFgQUgrc4SpOqmxDvgLvZVOLxD/uAnN4wDAYDVR0TBAUwAwEB/zAd"
+ + "BgkqhkiG9n0HQQAEEDAOGwhWNi4wOjQuMAMCBJAwDQYJKoZIhvcNAQEFBQAD"
+ + "ggEBADLan0N1wfpvyW/bqx02Nz68YRk2twI8HSNZmGye7k2F51TIIB+n1Lvi"
+ + "vwB3fSRrcC9cwTp2SbXT4COEKnFqIvPBJymYFfY1kOQETMONvJ9hHOf9JIzR"
+ + "REOMFrqbTaXUNS+8Ec6991E3jZ+Q5BTxGD++6VkSNfkzkvOe4NVrmnGbmUvI"
+ + "ccPhsWEJxOX6kfBCOjd9NPly6M2qYhwh6dX0ghDjewW2LWhWC35+kixvTXKC"
+ + "DO1WdLKduastKx0QX9sndXCP/R3X4gKgeeUc5f+vZEBRLZ6bR9tCpXwfwqZI"
+ + "sNe+kmlNpPYpV8V4ERjch1HKE7JinU8rMr0xpcH6UqsFiMgwggTLMIIDs6AD"
+ + "AgECAgQ+HL21MA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNVBAYTAlVTMSMwIQYD"
+ + "VQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRv"
+ + "YmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0EwHhcN"
+ + "MDQwMTE3MDAwMzM5WhcNMTUwMTE1MDgwMDAwWjBFMQswCQYDVQQGEwJVUzEW"
+ + "MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgQ0Eg"
+ + "Zm9yIEFkb2JlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+V3"
+ + "4GR4Wuc5hbyv0vVbKBMOVN1J+s5i9ZL9nph7n+X4esFs4epAJcFxJ4KnPuQH"
+ + "ZZ0oyHUU4Th70mWYgKwd6sEt1aR6ZT788Nvr3OHwTRwugN/G6QXqhU9ePpZJ"
+ + "OF1Ibsf1pcXNGvpLdcYK6+CX5DANMuIthb440XoNfC3dNBC0pF4mM4lmTjpl"
+ + "nQG8xK0rIFp4HoMpmyaIijz2qyjXdUNkg0fbDUq9eDTKAOLOg21u+AA8XKbC"
+ + "ewg1LWSV9CVy+fTHREmb1thBcrfkY1kCAvczsuquV3SMx8hRpa+4cIvKK/K1"
+ + "G7OrV0nsTyuaJ2MMST8b7bul/Xd81nu9Hsz4iQIDAQABo4IBnTCCAZkwEgYD"
+ + "VR0TAQH/BAgwBgEB/wIBATBQBgNVHSAESTBHMEUGCSqGSIb3LwECATA4MDYG"
+ + "CCsGAQUFBwIBFipodHRwczovL3d3dy5hZG9iZS5jb20vbWlzYy9wa2kvY2Rz"
+ + "X2NwLmh0bWwwFAYDVR0lBA0wCwYJKoZIhvcvAQEFMIGyBgNVHR8Egaowgacw"
+ + "IqAgoB6GHGh0dHA6Ly9jcmwuYWRvYmUuY29tL2Nkcy5jcmwwgYCgfqB8pHow"
+ + "eDELMAkGA1UEBhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMgSW5jb3Jw"
+ + "b3JhdGVkMR0wGwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEWMBQGA1UE"
+ + "AxMNQWRvYmUgUm9vdCBDQTENMAsGA1UEAxMEQ1JMMTALBgNVHQ8EBAMCAQYw"
+ + "HwYDVR0jBBgwFoAUgrc4SpOqmxDvgLvZVOLxD/uAnN4wHQYDVR0OBBYEFKuA"
+ + "WcNlg20dfRO9GcPsGo8NR2qjMBkGCSqGSIb2fQdBAAQMMAobBFY2LjADAgSQ"
+ + "MA0GCSqGSIb3DQEBBQUAA4IBAQA/OVkuogCOsV4RYSzS4Lb1jImGRc4T2Z/d"
+ + "hJoUawhMX4aXWPSlqNOPIfhHflCvd+Whbarcd83NN5n3QmevUOFUREPrMQyA"
+ + "mkK0mpW6TSyLG5ckeCFL8qJwp/hhckk/H16m4hEXWyIFGfOecX3Sy+Y4kxcC"
+ + "lzSMadifedB+TiRpKFKcNphp5hEMkpyyJaGXpLnN/BLsaDyEN7JySExAopae"
+ + "UbUJCvCVIWKwoJ26ih3BG1aB+3yTHXeLIorextqWbq+dVz7me59Li8j5PAxe"
+ + "hXrc2phpKuhp8FaTScvnfMZc8TL4Dr1CHMRWIkqfZaCq3mC376Mww0iZtE5s"
+ + "iqB+AXVWMYIBgDCCAXwCAQEwSzBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN"
+ + "R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgQ0EgZm9yIEFkb2Jl"
+ + "AgIAjzAJBgUrDgMCGgUAoIGMMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRAB"
+ + "BDAcBgkqhkiG9w0BCQUxDxcNMDYwNDA0MjAyMDU3WjAjBgkqhkiG9w0BCQQx"
+ + "FgQUp7AnXBqoNcarvO7fMJut1og2U5AwKwYLKoZIhvcNAQkQAgwxHDAaMBgw"
+ + "FgQU1dH4eZTNhgxdiSABrat6zsPdth0wDQYJKoZIhvcNAQEBBQAEgYCinr/F"
+ + "rMiQz/MRm9ZD5YGcC0Qo2dRTPd0Aop8mZ4g1xAhKFLnp7lLsjCbkSDpVLDBh"
+ + "cnCk7CV+3FT5hlvt8OqZlR0CnkSnCswLFhrppiWle6cpxlwGqyAteC8uKtQu"
+ + "wjE5GtBKLcCOAzQYyyuNZZeB6oCZ+3mPhZ62FxrvvEGJCgAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==");
+
+ private final byte[] emptyDNCert = Base64.decode(
+ "MIICfTCCAeagAwIBAgIBajANBgkqhkiG9w0BAQQFADB8MQswCQYDVQQGEwJVUzEMMAoGA1UEChMD"
+ + "Q0RXMQkwBwYDVQQLEwAxCTAHBgNVBAcTADEJMAcGA1UECBMAMRowGAYDVQQDExFUZW1wbGFyIFRl"
+ + "c3QgMTAyNDEiMCAGCSqGSIb3DQEJARYTdGVtcGxhcnRlc3RAY2R3LmNvbTAeFw0wNjA1MjIwNTAw"
+ + "MDBaFw0xMDA1MjIwNTAwMDBaMHwxCzAJBgNVBAYTAlVTMQwwCgYDVQQKEwNDRFcxCTAHBgNVBAsT"
+ + "ADEJMAcGA1UEBxMAMQkwBwYDVQQIEwAxGjAYBgNVBAMTEVRlbXBsYXIgVGVzdCAxMDI0MSIwIAYJ"
+ + "KoZIhvcNAQkBFhN0ZW1wbGFydGVzdEBjZHcuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB"
+ + "gQDH3aJpJBfM+A3d84j5YcU6zEQaQ76u5xO9NSBmHjZykKS2kCcUqPpvVOPDA5WgV22dtKPh+lYV"
+ + "iUp7wyCVwAKibq8HIbihHceFqMKzjwC639rMoDJ7bi/yzQWz1Zg+075a4FGPlUKn7Yfu89wKkjdW"
+ + "wDpRPXc/agqBnrx5pJTXzQIDAQABow8wDTALBgNVHQ8EBAMCALEwDQYJKoZIhvcNAQEEBQADgYEA"
+ + "RRsRsjse3i2/KClFVd6YLZ+7K1BE0WxFyY2bbytkwQJSxvv3vLSuweFUbhNxutb68wl/yW4GLy4b"
+ + "1QdyswNxrNDXTuu5ILKhRDDuWeocz83aG2KGtr3JlFyr3biWGEyn5WUOE6tbONoQDJ0oPYgI6CAc"
+ + "EHdUp0lioOCt6UOw7Cs=");
+
+ private final byte[] gostRFC4491_94 = Base64.decode(
+ "MIICCzCCAboCECMO42BGlSTOxwvklBgufuswCAYGKoUDAgIEMGkxHTAbBgNVBAMM" +
+ "FEdvc3RSMzQxMC05NCBleGFtcGxlMRIwEAYDVQQKDAlDcnlwdG9Qcm8xCzAJBgNV" +
+ "BAYTAlJVMScwJQYJKoZIhvcNAQkBFhhHb3N0UjM0MTAtOTRAZXhhbXBsZS5jb20w" +
+ "HhcNMDUwODE2MTIzMjUwWhcNMTUwODE2MTIzMjUwWjBpMR0wGwYDVQQDDBRHb3N0" +
+ "UjM0MTAtOTQgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRvUHJvMQswCQYDVQQGEwJS" +
+ "VTEnMCUGCSqGSIb3DQEJARYYR29zdFIzNDEwLTk0QGV4YW1wbGUuY29tMIGlMBwG" +
+ "BiqFAwICFDASBgcqhQMCAiACBgcqhQMCAh4BA4GEAASBgLuEZuF5nls02CyAfxOo" +
+ "GWZxV/6MVCUhR28wCyd3RpjG+0dVvrey85NsObVCNyaE4g0QiiQOHwxCTSs7ESuo" +
+ "v2Y5MlyUi8Go/htjEvYJJYfMdRv05YmKCYJo01x3pg+2kBATjeM+fJyR1qwNCCw+" +
+ "eMG1wra3Gqgqi0WBkzIydvp7MAgGBiqFAwICBANBABHHCH4S3ALxAiMpR3aPRyqB" +
+ "g1DjB8zy5DEjiULIc+HeIveF81W9lOxGkZxnrFjXBSqnjLeFKgF1hffXOAP7zUM=");
+
+ private final byte[] gostRFC4491_2001 = Base64.decode(
+ "MIIB0DCCAX8CECv1xh7CEb0Xx9zUYma0LiEwCAYGKoUDAgIDMG0xHzAdBgNVBAMM" +
+ "Fkdvc3RSMzQxMC0yMDAxIGV4YW1wbGUxEjAQBgNVBAoMCUNyeXB0b1BybzELMAkG" +
+ "A1UEBhMCUlUxKTAnBgkqhkiG9w0BCQEWGkdvc3RSMzQxMC0yMDAxQGV4YW1wbGUu" +
+ "Y29tMB4XDTA1MDgxNjE0MTgyMFoXDTE1MDgxNjE0MTgyMFowbTEfMB0GA1UEAwwW" +
+ "R29zdFIzNDEwLTIwMDEgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRvUHJvMQswCQYD" +
+ "VQQGEwJSVTEpMCcGCSqGSIb3DQEJARYaR29zdFIzNDEwLTIwMDFAZXhhbXBsZS5j" +
+ "b20wYzAcBgYqhQMCAhMwEgYHKoUDAgIkAAYHKoUDAgIeAQNDAARAhJVodWACGkB1" +
+ "CM0TjDGJLP3lBQN6Q1z0bSsP508yfleP68wWuZWIA9CafIWuD+SN6qa7flbHy7Df" +
+ "D2a8yuoaYDAIBgYqhQMCAgMDQQA8L8kJRLcnqeyn1en7U23Sw6pkfEQu3u0xFkVP" +
+ "vFQ/3cHeF26NG+xxtZPz3TaTVXdoiYkXYiD02rEx1bUcM97i");
+
+ public String getName()
+ {
+ return "CertTest";
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - RSA
+ */
+ public void checkCreation1()
+ throws Exception
+ {
+//
+ // a lightweight key pair.
+ //
+ RSAKeyParameters lwPubKey = new RSAKeyParameters(
+ false,
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ RSAPrivateCrtKeyParameters lwPrivKey = new RSAPrivateCrtKeyParameters(
+ 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));
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
+
+ builder.addRDN(BCStyle.C, "AU");
+ builder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ builder.addRDN(BCStyle.L, "Melbourne");
+ builder.addRDN(BCStyle.ST, "Victoria");
+ builder.addRDN(BCStyle.E, "feedback-crypto@bouncycastle.org");
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3 - without extensions
+ //
+ AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSAEncryption");
+ AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
+
+ ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(lwPrivKey);
+ SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPublicKey(lwPubKey.getModulus(), lwPubKey.getExponent()));
+ X509v3CertificateBuilder certGen = new X509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000), builder.build(), pubInfo);
+
+ X509CertificateHolder certHolder = certGen.build(sigGen);
+
+ ContentVerifierProvider contentVerifierProvider = new BcRSAContentVerifierProviderBuilder(new DefaultDigestAlgorithmIdentifierFinder()).build(lwPubKey);
+
+ if (!certHolder.isSignatureValid(contentVerifierProvider))
+ {
+ fail("lw sig verification failed");
+ }
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ checkCreation1();
+ }
+
+ public static void main(
+ String[] args)
+ {
+ runTest(new CertTest());
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/PKCS10Test.java b/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/PKCS10Test.java
new file mode 100644
index 000000000..8c1bec7b3
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/PKCS10Test.java
@@ -0,0 +1,159 @@
+package org.spongycastle.cert.test;
+
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSAPublicKey;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.X500NameBuilder;
+import org.spongycastle.asn1.x500.style.BCStyle;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.bc.BcRSAContentSignerBuilder;
+import org.spongycastle.operator.bc.BcRSAContentVerifierProviderBuilder;
+import org.spongycastle.pkcs.PKCS10CertificationRequest;
+import org.spongycastle.pkcs.PKCS10CertificationRequestBuilder;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.test.SimpleTest;
+
+/**
+ **/
+public class PKCS10Test
+ extends SimpleTest
+{
+ private byte[] gost3410EC_A = Base64.decode(
+ "MIIBOzCB6wIBADB/MQ0wCwYDVQQDEwR0ZXN0MRUwEwYDVQQKEwxEZW1vcyBDbyBMdGQxHjAcBgNV"
+ +"BAsTFUNyeXB0b2dyYXBoeSBkaXZpc2lvbjEPMA0GA1UEBxMGTW9zY293MQswCQYDVQQGEwJydTEZ"
+ +"MBcGCSqGSIb3DQEJARYKc2RiQGRvbC5ydTBjMBwGBiqFAwICEzASBgcqhQMCAiMBBgcqhQMCAh4B"
+ +"A0MABEBYx0P2D7YuuZo5HgdIAUKAXcLBDZ+4LYFgbKjrfStVfH59lc40BQ2FZ7M703hLpXK8GiBQ"
+ +"GEYpKaAuQZnMIpByoAAwCAYGKoUDAgIDA0EAgXMcTrhdOY2Er2tHOSAgnMezqrYxocZTWhxmW5Rl"
+ +"JY6lbXH5rndCn4swFzXU+YhgAsJv1wQBaoZEWRl5WV4/nA==");
+
+ private byte[] gost3410EC_B = Base64.decode(
+ "MIIBPTCB7QIBADCBgDENMAsGA1UEAxMEdGVzdDEWMBQGA1UEChMNRGVtb3MgQ28gTHRkLjEeMBwG"
+ +"A1UECxMVQ3J5cHRvZ3JhcGh5IGRpdmlzaW9uMQ8wDQYDVQQHEwZNb3Njb3cxCzAJBgNVBAYTAnJ1"
+ +"MRkwFwYJKoZIhvcNAQkBFgpzZGJAZG9sLnJ1MGMwHAYGKoUDAgITMBIGByqFAwICIwIGByqFAwIC"
+ +"HgEDQwAEQI5SLoWT7dZVilbV9j5B/fyIDuDs6x4pjqNC2TtFYbpRHrk/Wc5g/mcHvD80tsm5o1C7"
+ +"7cizNzkvAVUM4VT4Dz6gADAIBgYqhQMCAgMDQQAoT5TwJ8o+bSrxckymyo3diwG7ZbSytX4sRiKy"
+ +"wXPWRS9LlBvPO2NqwpS2HUnxSU8rzfL9fJcybATf7Yt1OEVq");
+
+ private byte[] gost3410EC_C = Base64.decode(
+ "MIIBRDCB9AIBADCBhzEVMBMGA1UEAxMMdGVzdCByZXF1ZXN0MRUwEwYDVQQKEwxEZW1vcyBDbyBM"
+ +"dGQxHjAcBgNVBAsTFUNyeXB0b2dyYXBoeSBkaXZpc2lvbjEPMA0GA1UEBxMGTW9zY293MQswCQYD"
+ +"VQQGEwJydTEZMBcGCSqGSIb3DQEJARYKc2RiQGRvbC5ydTBjMBwGBiqFAwICEzASBgcqhQMCAiMD"
+ +"BgcqhQMCAh4BA0MABEBcmGh7OmR4iqqj+ycYo1S1fS7r5PhisSQU2Ezuz8wmmmR2zeTZkdMYCOBa"
+ +"UTMNms0msW3wuYDho7nTDNscHTB5oAAwCAYGKoUDAgIDA0EAVoOMbfyo1Un4Ss7WQrUjHJoiaYW8"
+ +"Ime5LeGGU2iW3ieAv6es/FdMrwTKkqn5dhd3aL/itFg5oQbhyfXw5yw/QQ==");
+
+ private byte[] gost3410EC_ExA = Base64.decode(
+ "MIIBOzCB6wIBADB/MQ0wCwYDVQQDEwR0ZXN0MRUwEwYDVQQKEwxEZW1vcyBDbyBMdGQxHjAcBgNV"
+ + "BAsTFUNyeXB0b2dyYXBoeSBkaXZpc2lvbjEPMA0GA1UEBxMGTW9zY293MQswCQYDVQQGEwJydTEZ"
+ + "MBcGCSqGSIb3DQEJARYKc2RiQGRvbC5ydTBjMBwGBiqFAwICEzASBgcqhQMCAiQABgcqhQMCAh4B"
+ + "A0MABEDkqNT/3f8NHj6EUiWnK4JbVZBh31bEpkwq9z3jf0u8ZndG56Vt+K1ZB6EpFxLT7hSIos0w"
+ + "weZ2YuTZ4w43OgodoAAwCAYGKoUDAgIDA0EASk/IUXWxoi6NtcUGVF23VRV1L3undB4sRZLp4Vho"
+ + "gQ7m3CMbZFfJ2cPu6QyarseXGYHmazoirH5lGjEo535c1g==");
+
+ private byte[] gost3410EC_ExB = Base64.decode(
+ "MIIBPTCB7QIBADCBgDENMAsGA1UEAxMEdGVzdDEWMBQGA1UEChMNRGVtb3MgQ28gTHRkLjEeMBwG"
+ + "A1UECxMVQ3J5cHRvZ3JhcGh5IGRpdmlzaW9uMQ8wDQYDVQQHEwZNb3Njb3cxCzAJBgNVBAYTAnJ1"
+ + "MRkwFwYJKoZIhvcNAQkBFgpzZGJAZG9sLnJ1MGMwHAYGKoUDAgITMBIGByqFAwICJAEGByqFAwIC"
+ + "HgEDQwAEQMBWYUKPy/1Kxad9ChAmgoSWSYOQxRnXo7KEGLU5RNSXA4qMUvArWzvhav+EYUfTbWLh"
+ + "09nELDyHt2XQcvgQHnSgADAIBgYqhQMCAgMDQQAdaNhgH/ElHp64mbMaEo1tPCg9Q22McxpH8rCz"
+ + "E0QBpF4H5mSSQVGI5OAXHToetnNuh7gHHSynyCupYDEHTbkZ");
+
+ public String getName()
+ {
+ return "PKCS10CertRequest";
+ }
+
+ private void rsaCreationTest()
+ throws Exception
+ {
+ //
+ // a lightweight key pair.
+ //
+ RSAKeyParameters lwPubKey = new RSAKeyParameters(
+ false,
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ RSAPrivateCrtKeyParameters lwPrivKey = new RSAPrivateCrtKeyParameters(
+ 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));
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
+
+ builder.addRDN(BCStyle.C, "AU");
+ builder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ builder.addRDN(BCStyle.L, "Melbourne");
+ builder.addRDN(BCStyle.ST, "Victoria");
+ builder.addRDN(BCStyle.E, "feedback-crypto@bouncycastle.org");
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3 - without extensions
+ //
+ AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSAEncryption");
+ AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
+
+ ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(lwPrivKey);
+ SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPublicKey(lwPubKey.getModulus(), lwPubKey.getExponent()));
+
+ X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE);
+
+ x500NameBld.addRDN(BCStyle.C, "AU");
+ x500NameBld.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ x500NameBld.addRDN(BCStyle.L, "Melbourne");
+ x500NameBld.addRDN(BCStyle.ST, "Victoria");
+ x500NameBld.addRDN(BCStyle.EmailAddress, "feedback-crypto@bouncycastle.org");
+
+ X500Name subject = x500NameBld.build();
+
+ PKCS10CertificationRequestBuilder requestBuilder = new PKCS10CertificationRequestBuilder(subject, pubInfo);
+
+ PKCS10CertificationRequest req1 = requestBuilder.build(sigGen);
+
+ PKCS10CertificationRequest req2 = new PKCS10CertificationRequest(req1.getEncoded());
+
+ if (!req2.isSignatureValid(new BcRSAContentVerifierProviderBuilder(new DefaultDigestAlgorithmIdentifierFinder()).build(lwPubKey)))
+ {
+ fail("Failed verify check.");
+ }
+
+ if (!Arrays.areEqual(req2.getSubjectPublicKeyInfo().getEncoded(), req1.getSubjectPublicKeyInfo().getEncoded()))
+ {
+ fail("Failed public key check.");
+ }
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ rsaCreationTest();
+ }
+
+ public static void main(
+ String[] args)
+ {
+ runTest(new PKCS10Test());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/RegressionTest.java b/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/RegressionTest.java
new file mode 100644
index 000000000..3d79a8569
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cert/test/RegressionTest.java
@@ -0,0 +1,31 @@
+package org.spongycastle.cert.test;
+
+import org.spongycastle.util.test.Test;
+import org.spongycastle.util.test.TestResult;
+
+public class RegressionTest
+{
+ public static Test[] tests = {
+ new AttrCertTest(),
+ new AttrCertSelectorTest(),
+ new CertTest(),
+ new PKCS10Test()
+ };
+
+ public static void main(
+ String[] args)
+ {
+ for (int i = 0; i != tests.length; i++)
+ {
+ TestResult result = tests[i].perform();
+
+ if (result.getException() != null)
+ {
+ result.getException().printStackTrace();
+ }
+
+ System.out.println(result);
+ }
+ }
+}
+
diff --git a/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cms/test/BcEnvelopedDataTest.java b/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cms/test/BcEnvelopedDataTest.java
new file mode 100644
index 000000000..d4d45831f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cms/test/BcEnvelopedDataTest.java
@@ -0,0 +1,119 @@
+package org.spongycastle.cms.test;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cms.CMSEnvelopedData;
+import org.spongycastle.cms.CMSEnvelopedDataGenerator;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.RecipientInformation;
+import org.spongycastle.cms.RecipientInformationStore;
+import org.spongycastle.cms.bc.BcCMSContentEncryptorBuilder;
+import org.spongycastle.cms.bc.BcRSAKeyTransEnvelopedRecipient;
+import org.spongycastle.cms.bc.BcRSAKeyTransRecipientInfoGenerator;
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.test.SimpleTest;
+
+public class BcEnvelopedDataTest
+ extends SimpleTest
+{
+ private static String _origDN;
+ private static AsymmetricCipherKeyPair _origKP;
+ private static X509CertificateHolder _origCert;
+
+ private static String _signDN;
+ private static AsymmetricCipherKeyPair _signKP;
+ private static X509CertificateHolder _signCert;
+
+ private static String _reciDN;
+ private static String _reciDN2;
+ private static AsymmetricCipherKeyPair _reciKP;
+ private static X509CertificateHolder _reciCert;
+
+ private static boolean _initialised = false;
+
+ public String getName()
+ {
+ return "BcEnvelopedData";
+ }
+
+ private void init()
+ throws Exception
+ {
+ if (!_initialised)
+ {
+ _initialised = true;
+
+ _origDN = "O=Bouncy Castle, C=AU";
+ _origKP = CMSTestUtil.makeKeyPair();
+ _origCert = CMSTestUtil.makeCertificate(_origKP, _origDN, _origKP, _origDN);
+
+ _signDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+ _signKP = CMSTestUtil.makeKeyPair();
+ _signCert = CMSTestUtil.makeCertificate(_signKP, _signDN, _origKP, _origDN);
+
+ _reciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+ _reciDN2 = "CN=Fred, OU=Sales, O=Bouncy Castle, C=AU";
+ _reciKP = CMSTestUtil.makeKeyPair();
+ _reciCert = CMSTestUtil.makeCertificate(_reciKP, _reciDN, _signKP, _signDN);
+ }
+ }
+
+ private void testKeyTransLight128RC4()
+ throws Exception
+ {
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new BcRSAKeyTransRecipientInfoGenerator(_reciCert));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new BcCMSContentEncryptorBuilder(NISTObjectIdentifiers.id_aes128_CBC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ if (!ed.getEncryptionAlgOID().equals(NISTObjectIdentifiers.id_aes128_CBC.getId()))
+ {
+ fail("enc oid mismatch");
+ }
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new BcRSAKeyTransEnvelopedRecipient((AsymmetricKeyParameter)_reciKP.getPrivate()));
+
+ if (!Arrays.areEqual(data, recData))
+ {
+ fail("decryption failed");
+ }
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ init();
+
+ testKeyTransLight128RC4();
+ }
+
+ public static void main(
+ String[] args)
+ {
+ runTest(new BcEnvelopedDataTest());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cms/test/BcSignedDataTest.java b/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cms/test/BcSignedDataTest.java
new file mode 100644
index 000000000..b39ca9d77
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cms/test/BcSignedDataTest.java
@@ -0,0 +1,536 @@
+package org.spongycastle.cms.test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.cms.Attribute;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSAttributes;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cms.CMSAbsentContent;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.CMSSignedData;
+import org.spongycastle.cms.CMSSignedDataGenerator;
+import org.spongycastle.cms.CMSTypedData;
+import org.spongycastle.cms.DefaultCMSSignatureAlgorithmNameGenerator;
+import org.spongycastle.cms.DefaultSignedAttributeTableGenerator;
+import org.spongycastle.cms.SignerInfoGeneratorBuilder;
+import org.spongycastle.cms.SignerInformation;
+import org.spongycastle.cms.SignerInformationStore;
+import org.spongycastle.cms.bc.BcRSASignerInfoVerifierBuilder;
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.bc.BcContentSignerBuilder;
+import org.spongycastle.operator.bc.BcDigestCalculatorProvider;
+import org.spongycastle.operator.bc.BcRSAContentSignerBuilder;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.CollectionStore;
+import org.spongycastle.util.Store;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.test.SimpleTest;
+
+public class BcSignedDataTest
+ extends SimpleTest
+{
+ private static String _origDN;
+ private static AsymmetricCipherKeyPair _origKP;
+ private static X509CertificateHolder _origCert;
+
+ private static String _signDN;
+ private static AsymmetricCipherKeyPair _signKP;
+ private static X509CertificateHolder _signCert;
+
+ private static boolean _initialised = false;
+
+ private byte[] disorderedMessage = Base64.decode(
+ "SU9fc3RkaW5fdXNlZABfX2xpYmNfc3RhcnRfbWFpbgBnZXRob3N0aWQAX19n"
+ + "bW9uX3M=");
+
+ private byte[] disorderedSet = Base64.decode(
+ "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"
+ + "gQBpSRdnDb6AcNVaXSmGo6+kVPIBhot1LzJOGaPyDNpGXxd7LV4tMBF1U7gr"
+ + "4k1g9BO6YiMWvw9uiTZmn0CfV8+k4fWEuG/nmafRoGIuay2f+ILuT+C0rnp1"
+ + "4FgMsEhuVNJJAmb12QV0PZII+UneyhAneZuQQzVUkTcVgYxogxdSOzCCAlUw"
+ + "ggHBoAMCAQICBACdekowCgYGKyQDAwECBQAwbzELMAkGA1UEBhMCREUxPTA7"
+ + "BgNVBAoUNFJlZ3VsaWVydW5nc2JlaMhvcmRlIGbIdXIgVGVsZWtvbW11bmlr"
+ + "YXRpb24gdW5kIFBvc3QxITAMBgcCggYBCgcUEwExMBEGA1UEAxQKNlItQ2Eg"
+ + "MTpQTjAiGA8yMDAxMDIwMTEzNDcwN1oYDzIwMDUwMzIyMDg1NTUxWjBvMQsw"
+ + "CQYDVQQGEwJERTE9MDsGA1UEChQ0UmVndWxpZXJ1bmdzYmVoyG9yZGUgZsh1"
+ + "ciBUZWxla29tbXVuaWthdGlvbiB1bmQgUG9zdDEhMAwGBwKCBgEKBxQTATEw"
+ + "EQYDVQQDFAo1Ui1DQSAxOlBOMIGhMA0GCSqGSIb3DQEBAQUAA4GPADCBiwKB"
+ + "gQCKHkFTJx8GmoqFTxEOxpK9XkC3NZ5dBEKiUv0Ife3QMqeGMoCUnyJxwW0k"
+ + "2/53duHxtv2yHSZpFKjrjvE/uGwdOMqBMTjMzkFg19e9JPv061wyADOucOIa"
+ + "NAgha/zFt9XUyrHF21knKCvDNExv2MYIAagkTKajLMAw0bu1J0FadQIFAMAA"
+ + "AAEwCgYGKyQDAwECBQADgYEAV1yTi+2gyB7sUhn4PXmi/tmBxAfe5oBjDW8m"
+ + "gxtfudxKGZ6l/FUPNcrSc5oqBYxKWtLmf3XX87LcblYsch617jtNTkMzhx9e"
+ + "qxiD02ufcrxz2EVt0Akdqiz8mdVeqp3oLcNU/IttpSrcA91CAnoUXtDZYwb/"
+ + "gdQ4FI9l3+qo/0UwggJVMIIBwaADAgECAgQAxIymMAoGBiskAwMBAgUAMG8x"
+ + "CzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1bGllcnVuZ3NiZWjIb3JkZSBm"
+ + "yHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0MSEwDAYHAoIGAQoHFBMB"
+ + "MTARBgNVBAMUCjZSLUNhIDE6UE4wIhgPMjAwMTEwMTUxMzMxNThaGA8yMDA1"
+ + "MDYwMTA5NTIxN1owbzELMAkGA1UEBhMCREUxPTA7BgNVBAoUNFJlZ3VsaWVy"
+ + "dW5nc2JlaMhvcmRlIGbIdXIgVGVsZWtvbW11bmlrYXRpb24gdW5kIFBvc3Qx"
+ + "ITAMBgcCggYBCgcUEwExMBEGA1UEAxQKN1ItQ0EgMTpQTjCBoTANBgkqhkiG"
+ + "9w0BAQEFAAOBjwAwgYsCgYEAiokD/j6lEP4FexF356OpU5teUpGGfUKjIrFX"
+ + "BHc79G0TUzgVxqMoN1PWnWktQvKo8ETaugxLkP9/zfX3aAQzDW4Zki6x6GDq"
+ + "fy09Agk+RJvhfbbIzRkV4sBBco0n73x7TfG/9NTgVr/96U+I+z/1j30aboM6"
+ + "9OkLEhjxAr0/GbsCBQDAAAABMAoGBiskAwMBAgUAA4GBAHWRqRixt+EuqHhR"
+ + "K1kIxKGZL2vZuakYV0R24Gv/0ZR52FE4ECr+I49o8FP1qiGSwnXB0SwjuH2S"
+ + "iGiSJi+iH/MeY85IHwW1P5e+bOMvEOFhZhQXQixOD7totIoFtdyaj1XGYRef"
+ + "0f2cPOjNJorXHGV8wuBk+/j++sxbd/Net3FtMIICVTCCAcGgAwIBAgIEAMSM"
+ + "pzAKBgYrJAMDAQIFADBvMQswCQYDVQQGEwJERTE9MDsGA1UEChQ0UmVndWxp"
+ + "ZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxla29tbXVuaWthdGlvbiB1bmQgUG9z"
+ + "dDEhMAwGBwKCBgEKBxQTATEwEQYDVQQDFAo3Ui1DQSAxOlBOMCIYDzIwMDEx"
+ + "MDE1MTMzNDE0WhgPMjAwNTA2MDEwOTUyMTdaMG8xCzAJBgNVBAYTAkRFMT0w"
+ + "OwYDVQQKFDRSZWd1bGllcnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5p"
+ + "a2F0aW9uIHVuZCBQb3N0MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjZSLUNh"
+ + "IDE6UE4wgaEwDQYJKoZIhvcNAQEBBQADgY8AMIGLAoGBAIOiqxUkzVyqnvth"
+ + "ihnltsE5m1Xn5TZKeR/2MQPStc5hJ+V4yptEtIx+Fn5rOoqT5VEVWhcE35wd"
+ + "bPvgJyQFn5msmhPQT/6XSGOlrWRoFummXN9lQzAjCj1sgTcmoLCVQ5s5WpCA"
+ + "OXFwVWu16qndz3sPItn3jJ0F3Kh3w79NglvPAgUAwAAAATAKBgYrJAMDAQIF"
+ + "AAOBgQBi5W96UVDoNIRkCncqr1LLG9vF9SGBIkvFpLDIIbcvp+CXhlvsdCJl"
+ + "0pt2QEPSDl4cmpOet+CxJTdTuMeBNXxhb7Dvualog69w/+K2JbPhZYxuVFZs"
+ + "Zh5BkPn2FnbNu3YbJhE60aIkikr72J4XZsI5DxpZCGh6xyV/YPRdKSljFjCC"
+ + "AlQwggHAoAMCAQICAwyDqzAKBgYrJAMDAQIFADBvMQswCQYDVQQGEwJERTE9"
+ + "MDsGA1UEChQ0UmVndWxpZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxla29tbXVu"
+ + "aWthdGlvbiB1bmQgUG9zdDEhMAwGBwKCBgEKBxQTATEwEQYDVQQDFAo1Ui1D"
+ + "QSAxOlBOMCIYDzIwMDAwMzIyMDk0MTI3WhgPMjAwNDAxMjExNjA0NTNaMG8x"
+ + "CzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1bGllcnVuZ3NiZWjIb3JkZSBm"
+ + "yHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0MSEwDAYHAoIGAQoHFBMB"
+ + "MTARBgNVBAMUCjRSLUNBIDE6UE4wgaEwDQYJKoZIhvcNAQEBBQADgY8AMIGL"
+ + "AoGBAI8x26tmrFJanlm100B7KGlRemCD1R93PwdnG7svRyf5ZxOsdGrDszNg"
+ + "xg6ouO8ZHQMT3NC2dH8TvO65Js+8bIyTm51azF6clEg0qeWNMKiiXbBXa+ph"
+ + "hTkGbXiLYvACZ6/MTJMJ1lcrjpRF7BXtYeYMcEF6znD4pxOqrtbf9z5hAgUA"
+ + "wAAAATAKBgYrJAMDAQIFAAOBgQB99BjSKlGPbMLQAgXlvA9jUsDNhpnVm3a1"
+ + "YkfxSqS/dbQlYkbOKvCxkPGA9NBxisBM8l1zFynVjJoy++aysRmcnLY/sHaz"
+ + "23BF2iU7WERy18H3lMBfYB6sXkfYiZtvQZcWaO48m73ZBySuiV3iXpb2wgs/"
+ + "Cs20iqroAWxwq/W/9jCCAlMwggG/oAMCAQICBDsFZ9UwCgYGKyQDAwECBQAw"
+ + "bzELMAkGA1UEBhMCREUxITAMBgcCggYBCgcUEwExMBEGA1UEAxQKNFItQ0Eg"
+ + "MTpQTjE9MDsGA1UEChQ0UmVndWxpZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxl"
+ + "a29tbXVuaWthdGlvbiB1bmQgUG9zdDAiGA8xOTk5MDEyMTE3MzUzNFoYDzIw"
+ + "MDQwMTIxMTYwMDAyWjBvMQswCQYDVQQGEwJERTE9MDsGA1UEChQ0UmVndWxp"
+ + "ZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxla29tbXVuaWthdGlvbiB1bmQgUG9z"
+ + "dDEhMAwGBwKCBgEKBxQTATEwEQYDVQQDFAozUi1DQSAxOlBOMIGfMA0GCSqG"
+ + "SIb3DQEBAQUAA4GNADCBiQKBgI4B557mbKQg/AqWBXNJhaT/6lwV93HUl4U8"
+ + "u35udLq2+u9phns1WZkdM3gDfEpL002PeLfHr1ID/96dDYf04lAXQfombils"
+ + "of1C1k32xOvxjlcrDOuPEMxz9/HDAQZA5MjmmYHAIulGI8Qg4Tc7ERRtg/hd"
+ + "0QX0/zoOeXoDSEOBAgTAAAABMAoGBiskAwMBAgUAA4GBAIyzwfT3keHI/n2P"
+ + "LrarRJv96mCohmDZNpUQdZTVjGu5VQjVJwk3hpagU0o/t/FkdzAjOdfEw8Ql"
+ + "3WXhfIbNLv1YafMm2eWSdeYbLcbB5yJ1od+SYyf9+tm7cwfDAcr22jNRBqx8"
+ + "wkWKtKDjWKkevaSdy99sAI8jebHtWz7jzydKMIID9TCCA16gAwIBAgICbMcw"
+ + "DQYJKoZIhvcNAQEFBQAwSzELMAkGA1UEBhMCREUxEjAQBgNVBAoUCVNpZ250"
+ + "cnVzdDEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFDQSBTSUdOVFJVU1QgMTpQ"
+ + "TjAeFw0wNDA3MzAxMzAyNDZaFw0wNzA3MzAxMzAyNDZaMDwxETAPBgNVBAMM"
+ + "CFlhY29tOlBOMQ4wDAYDVQRBDAVZYWNvbTELMAkGA1UEBhMCREUxCjAIBgNV"
+ + "BAUTATEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAIWzLlYLQApocXIp"
+ + "pgCCpkkOUVLgcLYKeOd6/bXAnI2dTHQqT2bv7qzfUnYvOqiNgYdF13pOYtKg"
+ + "XwXMTNFL4ZOI6GoBdNs9TQiZ7KEWnqnr2945HYx7UpgTBclbOK/wGHuCdcwO"
+ + "x7juZs1ZQPFG0Lv8RoiV9s6HP7POqh1sO0P/AgMBAAGjggH1MIIB8TCBnAYD"
+ + "VR0jBIGUMIGRgBQcZzNghfnXoXRm8h1+VITC5caNRqFzpHEwbzELMAkGA1UE"
+ + "BhMCREUxPTA7BgNVBAoUNFJlZ3VsaWVydW5nc2JlaMhvcmRlIGbIdXIgVGVs"
+ + "ZWtvbW11bmlrYXRpb24gdW5kIFBvc3QxITAMBgcCggYBCgcUEwExMBEGA1UE"
+ + "AxQKNVItQ0EgMTpQToIEALs8rjAdBgNVHQ4EFgQU2e5KAzkVuKaM9I5heXkz"
+ + "bcAIuR8wDgYDVR0PAQH/BAQDAgZAMBIGA1UdIAQLMAkwBwYFKyQIAQEwfwYD"
+ + "VR0fBHgwdjB0oCygKoYobGRhcDovL2Rpci5zaWdudHJ1c3QuZGUvbz1TaWdu"
+ + "dHJ1c3QsYz1kZaJEpEIwQDEdMBsGA1UEAxMUQ1JMU2lnblNpZ250cnVzdDE6"
+ + "UE4xEjAQBgNVBAoTCVNpZ250cnVzdDELMAkGA1UEBhMCREUwYgYIKwYBBQUH"
+ + "AQEEVjBUMFIGCCsGAQUFBzABhkZodHRwOi8vZGlyLnNpZ250cnVzdC5kZS9T"
+ + "aWdudHJ1c3QvT0NTUC9zZXJ2bGV0L2h0dHBHYXRld2F5LlBvc3RIYW5kbGVy"
+ + "MBgGCCsGAQUFBwEDBAwwCjAIBgYEAI5GAQEwDgYHAoIGAQoMAAQDAQH/MA0G"
+ + "CSqGSIb3DQEBBQUAA4GBAHn1m3GcoyD5GBkKUY/OdtD6Sj38LYqYCF+qDbJR"
+ + "6pqUBjY2wsvXepUppEler+stH8mwpDDSJXrJyuzf7xroDs4dkLl+Rs2x+2tg"
+ + "BjU+ABkBDMsym2WpwgA8LCdymmXmjdv9tULxY+ec2pjSEzql6nEZNEfrU8nt"
+ + "ZCSCavgqW4TtMYIBejCCAXYCAQEwUTBLMQswCQYDVQQGEwJERTESMBAGA1UE"
+ + "ChQJU2lnbnRydXN0MSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEUNBIFNJR05U"
+ + "UlVTVCAxOlBOAgJsxzAJBgUrDgMCGgUAoIGAMBgGCSqGSIb3DQEJAzELBgkq"
+ + "hkiG9w0BBwEwIwYJKoZIhvcNAQkEMRYEFIYfhPoyfGzkLWWSSLjaHb4HQmaK"
+ + "MBwGCSqGSIb3DQEJBTEPFw0wNTAzMjQwNzM4MzVaMCEGBSskCAYFMRgWFi92"
+ + "YXIvZmlsZXMvdG1wXzEvdGVzdDEwDQYJKoZIhvcNAQEFBQAEgYA2IvA8lhVz"
+ + "VD5e/itUxbFboKxeKnqJ5n/KuO/uBCl1N14+7Z2vtw1sfkIG+bJdp3OY2Cmn"
+ + "mrQcwsN99Vjal4cXVj8t+DJzFG9tK9dSLvD3q9zT/GQ0kJXfimLVwCa4NaSf"
+ + "Qsu4xtG0Rav6bCcnzabAkKuNNvKtH8amSRzk870DBg==");
+
+ public static byte[] xtraCounterSig = Base64.decode(
+ "MIIR/AYJKoZIhvcNAQcCoIIR7TCCEekCAQExCzAJBgUrDgMCGgUAMBoGCSqG"
+ + "SIb3DQEHAaANBAtIZWxsbyB3b3JsZKCCDnkwggTPMIIDt6ADAgECAgRDnYD3"
+ + "MA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNVBAYTAklUMRowGAYDVQQKExFJbi5U"
+ + "ZS5TLkEuIFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5BLiAtIENlcnRpZmlj"
+ + "YXRpb24gQXV0aG9yaXR5MB4XDTA4MDkxMjExNDMxMloXDTEwMDkxMjExNDMx"
+ + "MlowgdgxCzAJBgNVBAYTAklUMSIwIAYDVQQKDBlJbnRlc2EgUy5wLkEuLzA1"
+ + "MjYyODkwMDE0MSowKAYDVQQLDCFCdXNpbmVzcyBDb2xsYWJvcmF0aW9uICYg"
+ + "U2VjdXJpdHkxHjAcBgNVBAMMFU1BU1NJTUlMSUFOTyBaSUNDQVJESTERMA8G"
+ + "A1UEBAwIWklDQ0FSREkxFTATBgNVBCoMDE1BU1NJTUlMSUFOTzEcMBoGA1UE"
+ + "BRMTSVQ6WkNDTVNNNzZIMTRMMjE5WTERMA8GA1UELhMIMDAwMDI1ODUwgaAw"
+ + "DQYJKoZIhvcNAQEBBQADgY4AMIGKAoGBALeJTjmyFgx1SIP6c2AuB/kuyHo5"
+ + "j/prKELTALsFDimre/Hxr3wOSet1TdQfFzU8Lu+EJqgfV9cV+cI1yeH1rZs7"
+ + "lei7L3tX/VR565IywnguX5xwvteASgWZr537Fkws50bvTEMyYOj1Tf3FZvZU"
+ + "z4n4OD39KI4mfR9i1eEVIxR3AgQAizpNo4IBoTCCAZ0wHQYDVR0RBBYwFIES"
+ + "emljY2FyZGlAaW50ZXNhLml0MC8GCCsGAQUFBwEDBCMwITAIBgYEAI5GAQEw"
+ + "CwYGBACORgEDAgEUMAgGBgQAjkYBBDBZBgNVHSAEUjBQME4GBgQAizABATBE"
+ + "MEIGCCsGAQUFBwIBFjZodHRwOi8vZS10cnVzdGNvbS5pbnRlc2EuaXQvY2Ff"
+ + "cHViYmxpY2EvQ1BTX0lOVEVTQS5odG0wDgYDVR0PAQH/BAQDAgZAMIGDBgNV"
+ + "HSMEfDB6gBQZCQOW0bjFWBt+EORuxPagEgkQqKFcpFowWDELMAkGA1UEBhMC"
+ + "SVQxGjAYBgNVBAoTEUluLlRlLlMuQS4gUy5wLkEuMS0wKwYDVQQDEyRJbi5U"
+ + "ZS5TLkEuIC0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHmCBDzRARMwOwYDVR0f"
+ + "BDQwMjAwoC6gLIYqaHR0cDovL2UtdHJ1c3Rjb20uaW50ZXNhLml0L0NSTC9J"
+ + "TlRFU0EuY3JsMB0GA1UdDgQWBBTf5ItL8KmQh541Dxt7YxcWI1254TANBgkq"
+ + "hkiG9w0BAQUFAAOCAQEAgW+uL1CVWQepbC/wfCmR6PN37Sueb4xiKQj2mTD5"
+ + "UZ5KQjpivy/Hbuf0NrfKNiDEhAvoHSPC31ebGiKuTMFNyZPHfPEUnyYGSxea"
+ + "2w837aXJFr6utPNQGBRi89kH90sZDlXtOSrZI+AzJJn5QK3F9gjcayU2NZXQ"
+ + "MJgRwYmFyn2w4jtox+CwXPQ9E5XgxiMZ4WDL03cWVXDLX00EOJwnDDMUNTRI"
+ + "m9Zv+4SKTNlfFbi9UTBqWBySkDzAelsfB2U61oqc2h1xKmCtkGMmN9iZT+Qz"
+ + "ZC/vaaT+hLEBFGAH2gwFrYc4/jTBKyBYeU1vsAxsibIoTs1Apgl6MH75qPDL"
+ + "BzCCBM8wggO3oAMCAQICBEOdgPcwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UE"
+ + "BhMCSVQxGjAYBgNVBAoTEUluLlRlLlMuQS4gUy5wLkEuMS0wKwYDVQQDEyRJ"
+ + "bi5UZS5TLkEuIC0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwOTEy"
+ + "MTE0MzEyWhcNMTAwOTEyMTE0MzEyWjCB2DELMAkGA1UEBhMCSVQxIjAgBgNV"
+ + "BAoMGUludGVzYSBTLnAuQS4vMDUyNjI4OTAwMTQxKjAoBgNVBAsMIUJ1c2lu"
+ + "ZXNzIENvbGxhYm9yYXRpb24gJiBTZWN1cml0eTEeMBwGA1UEAwwVTUFTU0lN"
+ + "SUxJQU5PIFpJQ0NBUkRJMREwDwYDVQQEDAhaSUNDQVJESTEVMBMGA1UEKgwM"
+ + "TUFTU0lNSUxJQU5PMRwwGgYDVQQFExNJVDpaQ0NNU003NkgxNEwyMTlZMREw"
+ + "DwYDVQQuEwgwMDAwMjU4NTCBoDANBgkqhkiG9w0BAQEFAAOBjgAwgYoCgYEA"
+ + "t4lOObIWDHVIg/pzYC4H+S7IejmP+msoQtMAuwUOKat78fGvfA5J63VN1B8X"
+ + "NTwu74QmqB9X1xX5wjXJ4fWtmzuV6Lsve1f9VHnrkjLCeC5fnHC+14BKBZmv"
+ + "nfsWTCznRu9MQzJg6PVN/cVm9lTPifg4Pf0ojiZ9H2LV4RUjFHcCBACLOk2j"
+ + "ggGhMIIBnTAdBgNVHREEFjAUgRJ6aWNjYXJkaUBpbnRlc2EuaXQwLwYIKwYB"
+ + "BQUHAQMEIzAhMAgGBgQAjkYBATALBgYEAI5GAQMCARQwCAYGBACORgEEMFkG"
+ + "A1UdIARSMFAwTgYGBACLMAEBMEQwQgYIKwYBBQUHAgEWNmh0dHA6Ly9lLXRy"
+ + "dXN0Y29tLmludGVzYS5pdC9jYV9wdWJibGljYS9DUFNfSU5URVNBLmh0bTAO"
+ + "BgNVHQ8BAf8EBAMCBkAwgYMGA1UdIwR8MHqAFBkJA5bRuMVYG34Q5G7E9qAS"
+ + "CRCooVykWjBYMQswCQYDVQQGEwJJVDEaMBgGA1UEChMRSW4uVGUuUy5BLiBT"
+ + "LnAuQS4xLTArBgNVBAMTJEluLlRlLlMuQS4gLSBDZXJ0aWZpY2F0aW9uIEF1"
+ + "dGhvcml0eYIEPNEBEzA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vZS10cnVz"
+ + "dGNvbS5pbnRlc2EuaXQvQ1JML0lOVEVTQS5jcmwwHQYDVR0OBBYEFN/ki0vw"
+ + "qZCHnjUPG3tjFxYjXbnhMA0GCSqGSIb3DQEBBQUAA4IBAQCBb64vUJVZB6ls"
+ + "L/B8KZHo83ftK55vjGIpCPaZMPlRnkpCOmK/L8du5/Q2t8o2IMSEC+gdI8Lf"
+ + "V5saIq5MwU3Jk8d88RSfJgZLF5rbDzftpckWvq6081AYFGLz2Qf3SxkOVe05"
+ + "Ktkj4DMkmflArcX2CNxrJTY1ldAwmBHBiYXKfbDiO2jH4LBc9D0TleDGIxnh"
+ + "YMvTdxZVcMtfTQQ4nCcMMxQ1NEib1m/7hIpM2V8VuL1RMGpYHJKQPMB6Wx8H"
+ + "ZTrWipzaHXEqYK2QYyY32JlP5DNkL+9ppP6EsQEUYAfaDAWthzj+NMErIFh5"
+ + "TW+wDGyJsihOzUCmCXowfvmo8MsHMIIEzzCCA7egAwIBAgIEQ52A9zANBgkq"
+ + "hkiG9w0BAQUFADBYMQswCQYDVQQGEwJJVDEaMBgGA1UEChMRSW4uVGUuUy5B"
+ + "LiBTLnAuQS4xLTArBgNVBAMTJEluLlRlLlMuQS4gLSBDZXJ0aWZpY2F0aW9u"
+ + "IEF1dGhvcml0eTAeFw0wODA5MTIxMTQzMTJaFw0xMDA5MTIxMTQzMTJaMIHY"
+ + "MQswCQYDVQQGEwJJVDEiMCAGA1UECgwZSW50ZXNhIFMucC5BLi8wNTI2Mjg5"
+ + "MDAxNDEqMCgGA1UECwwhQnVzaW5lc3MgQ29sbGFib3JhdGlvbiAmIFNlY3Vy"
+ + "aXR5MR4wHAYDVQQDDBVNQVNTSU1JTElBTk8gWklDQ0FSREkxETAPBgNVBAQM"
+ + "CFpJQ0NBUkRJMRUwEwYDVQQqDAxNQVNTSU1JTElBTk8xHDAaBgNVBAUTE0lU"
+ + "OlpDQ01TTTc2SDE0TDIxOVkxETAPBgNVBC4TCDAwMDAyNTg1MIGgMA0GCSqG"
+ + "SIb3DQEBAQUAA4GOADCBigKBgQC3iU45shYMdUiD+nNgLgf5Lsh6OY/6ayhC"
+ + "0wC7BQ4pq3vx8a98DknrdU3UHxc1PC7vhCaoH1fXFfnCNcnh9a2bO5Xouy97"
+ + "V/1UeeuSMsJ4Ll+ccL7XgEoFma+d+xZMLOdG70xDMmDo9U39xWb2VM+J+Dg9"
+ + "/SiOJn0fYtXhFSMUdwIEAIs6TaOCAaEwggGdMB0GA1UdEQQWMBSBEnppY2Nh"
+ + "cmRpQGludGVzYS5pdDAvBggrBgEFBQcBAwQjMCEwCAYGBACORgEBMAsGBgQA"
+ + "jkYBAwIBFDAIBgYEAI5GAQQwWQYDVR0gBFIwUDBOBgYEAIswAQEwRDBCBggr"
+ + "BgEFBQcCARY2aHR0cDovL2UtdHJ1c3Rjb20uaW50ZXNhLml0L2NhX3B1YmJs"
+ + "aWNhL0NQU19JTlRFU0EuaHRtMA4GA1UdDwEB/wQEAwIGQDCBgwYDVR0jBHww"
+ + "eoAUGQkDltG4xVgbfhDkbsT2oBIJEKihXKRaMFgxCzAJBgNVBAYTAklUMRow"
+ + "GAYDVQQKExFJbi5UZS5TLkEuIFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5B"
+ + "LiAtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ80QETMDsGA1UdHwQ0MDIw"
+ + "MKAuoCyGKmh0dHA6Ly9lLXRydXN0Y29tLmludGVzYS5pdC9DUkwvSU5URVNB"
+ + "LmNybDAdBgNVHQ4EFgQU3+SLS/CpkIeeNQ8be2MXFiNdueEwDQYJKoZIhvcN"
+ + "AQEFBQADggEBAIFvri9QlVkHqWwv8Hwpkejzd+0rnm+MYikI9pkw+VGeSkI6"
+ + "Yr8vx27n9Da3yjYgxIQL6B0jwt9XmxoirkzBTcmTx3zxFJ8mBksXmtsPN+2l"
+ + "yRa+rrTzUBgUYvPZB/dLGQ5V7Tkq2SPgMySZ+UCtxfYI3GslNjWV0DCYEcGJ"
+ + "hcp9sOI7aMfgsFz0PROV4MYjGeFgy9N3FlVwy19NBDicJwwzFDU0SJvWb/uE"
+ + "ikzZXxW4vVEwalgckpA8wHpbHwdlOtaKnNodcSpgrZBjJjfYmU/kM2Qv72mk"
+ + "/oSxARRgB9oMBa2HOP40wSsgWHlNb7AMbImyKE7NQKYJejB++ajwywcxggM8"
+ + "MIIDOAIBATBgMFgxCzAJBgNVBAYTAklUMRowGAYDVQQKExFJbi5UZS5TLkEu"
+ + "IFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5BLiAtIENlcnRpZmljYXRpb24g"
+ + "QXV0aG9yaXR5AgRDnYD3MAkGBSsOAwIaBQAwDQYJKoZIhvcNAQEBBQAEgYB+"
+ + "lH2cwLqc91mP8prvgSV+RRzk13dJdZvdoVjgQoFrPhBiZCNIEoHvIhMMA/sM"
+ + "X6euSRZk7EjD24FasCEGYyd0mJVLEy6TSPmuW+wWz/28w3a6IWXBGrbb/ild"
+ + "/CJMkPgLPGgOVD1WDwiNKwfasiQSFtySf5DPn3jFevdLeMmEY6GCAjIwggEV"
+ + "BgkqhkiG9w0BCQYxggEGMIIBAgIBATBgMFgxCzAJBgNVBAYTAklUMRowGAYD"
+ + "VQQKExFJbi5UZS5TLkEuIFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5BLiAt"
+ + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5AgRDnYD3MAkGBSsOAwIaBQAwDQYJ"
+ + "KoZIhvcNAQEBBQAEgYBHlOULfT5GDigIvxP0qZOy8VbpntmzaPF55VV4buKV"
+ + "35J+uHp98gXKp0LrHM69V5IRKuyuQzHHFBqsXxsRI9o6KoOfgliD9Xc+BeMg"
+ + "dKzQhBhBYoFREq8hQM0nSbqDNHYAQyNHMzUA/ZQUO5dlFuH8Dw3iDYAhNtfd"
+ + "PrlchKJthDCCARUGCSqGSIb3DQEJBjGCAQYwggECAgEBMGAwWDELMAkGA1UE"
+ + "BhMCSVQxGjAYBgNVBAoTEUluLlRlLlMuQS4gUy5wLkEuMS0wKwYDVQQDEyRJ"
+ + "bi5UZS5TLkEuIC0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkCBEOdgPcwCQYF"
+ + "Kw4DAhoFADANBgkqhkiG9w0BAQEFAASBgEeU5Qt9PkYOKAi/E/Spk7LxVume"
+ + "2bNo8XnlVXhu4pXfkn64en3yBcqnQusczr1XkhEq7K5DMccUGqxfGxEj2joq"
+ + "g5+CWIP1dz4F4yB0rNCEGEFigVESryFAzSdJuoM0dgBDI0czNQD9lBQ7l2UW"
+ + "4fwPDeINgCE2190+uVyEom2E");
+
+ byte[] noSignedAttrSample2 = Base64.decode(
+ "MIIIlAYJKoZIhvcNAQcCoIIIhTCCCIECAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+ + "SIb3DQEHAaCCB3UwggOtMIIDa6ADAgECAgEzMAsGByqGSM44BAMFADCBkDEL"
+ + "MAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlQYWxvIEFsdG8x"
+ + "HTAbBgNVBAoTFFN1biBNaWNyb3N5c3RlbXMgSW5jMSMwIQYDVQQLExpKYXZh"
+ + "IFNvZnR3YXJlIENvZGUgU2lnbmluZzEcMBoGA1UEAxMTSkNFIENvZGUgU2ln"
+ + "bmluZyBDQTAeFw0wMTA1MjkxNjQ3MTFaFw0wNjA1MjgxNjQ3MTFaMG4xHTAb"
+ + "BgNVBAoTFFN1biBNaWNyb3N5c3RlbXMgSW5jMSMwIQYDVQQLExpKYXZhIFNv"
+ + "ZnR3YXJlIENvZGUgU2lnbmluZzEoMCYGA1UEAxMfVGhlIExlZ2lvbiBvZiB0"
+ + "aGUgQm91bmN5IENhc3RsZTCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OB"
+ + "HXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2"
+ + "y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58aophUP"
+ + "BPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvM"
+ + "spK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9"
+ + "B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCj"
+ + "rh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtV"
+ + "JWQBTDv+z0kqA4GEAAKBgBWry/FCAZ6miyy39+ftsa+h9lxoL+JtV0MJcUyQ"
+ + "E4VAhpAwWb8vyjba9AwOylYQTktHX5sAkFvjBiU0LOYDbFSTVZSHMRJgfjxB"
+ + "SHtICjOEvr1BJrrOrdzqdxcOUge5n7El124BCrv91x5Ol8UTwtiO9LrRXF/d"
+ + "SyK+RT5n1klRo3YwdDARBglghkgBhvhCAQEEBAMCAIcwDgYDVR0PAQH/BAQD"
+ + "AgHGMB0GA1UdDgQWBBQwMY4NRcco1AO3w1YsokfDLVseEjAPBgNVHRMBAf8E"
+ + "BTADAQH/MB8GA1UdIwQYMBaAFGXi9IbJ007wkU5Yomr12HhamsGmMAsGByqG"
+ + "SM44BAMFAAMvADAsAhRmigTu6QV0sTfEkVljgij/hhdVfAIUQZvMxAnIHc30"
+ + "y/u0C1T5UEG9glUwggPAMIIDfqADAgECAgEQMAsGByqGSM44BAMFADCBkDEL"
+ + "MAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlQYWxvIEFsdG8x"
+ + "HTAbBgNVBAoTFFN1biBNaWNyb3N5c3RlbXMgSW5jMSMwIQYDVQQLExpKYXZh"
+ + "IFNvZnR3YXJlIENvZGUgU2lnbmluZzEcMBoGA1UEAxMTSkNFIENvZGUgU2ln"
+ + "bmluZyBDQTAeFw0wMTA0MjUwNzAwMDBaFw0yMDA0MjUwNzAwMDBaMIGQMQsw"
+ + "CQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVBhbG8gQWx0bzEd"
+ + "MBsGA1UEChMUU3VuIE1pY3Jvc3lzdGVtcyBJbmMxIzAhBgNVBAsTGkphdmEg"
+ + "U29mdHdhcmUgQ29kZSBTaWduaW5nMRwwGgYDVQQDExNKQ0UgQ29kZSBTaWdu"
+ + "aW5nIENBMIIBtzCCASwGByqGSM44BAEwggEfAoGBAOuvNwQeylEeaV2w8o/2"
+ + "tUkfxqSZBdcpv3S3avUZ2B7kG/gKAZqY/3Cr4kpWhmxTs/zhyIGMMfDE87CL"
+ + "5nAG7PdpaNuDTHIpiSk2F1w7SgegIAIqRpdRHXDICBgLzgxum3b3BePn+9Nh"
+ + "eeFgmiSNBpWDPFEg4TDPOFeCphpyDc7TAhUAhCVF4bq5qWKreehbMLiJaxv/"
+ + "e3UCgYEAq8l0e3Tv7kK1alNNO92QBnJokQ8LpCl2LlU71a5NZVx+KjoEpmem"
+ + "0HGqpde34sFyDaTRqh6SVEwgAAmisAlBGTMAssNcrkL4sYvKfJbYEH83RFuq"
+ + "zHjI13J2N2tAmahVZvqoAx6LShECactMuCUGHKB30sms0j3pChD6dnC3+9wD"
+ + "gYQAAoGALQmYXKy4nMeZfu4gGSo0kPnXq6uu3WtylQ1m+O8nj0Sy7ShEx/6v"
+ + "sKYnbwBnRYJbB6hWVjvSKVFhXmk51y50dxLPGUr1LcjLcmHETm/6R0M/FLv6"
+ + "vBhmKMLZZot6LS/CYJJLFP5YPiF/aGK+bEhJ+aBLXoWdGRD5FUVRG3HU9wuj"
+ + "ZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1Ud"
+ + "IwQYMBaAFGXi9IbJ007wkU5Yomr12HhamsGmMB0GA1UdDgQWBBRl4vSGydNO"
+ + "8JFOWKJq9dh4WprBpjALBgcqhkjOOAQDBQADLwAwLAIUKvfPPJdd+Xi2CNdB"
+ + "tNkNRUzktJwCFEXNdWkOIfod1rMpsun3Mx0z/fxJMYHoMIHlAgEBMIGWMIGQ"
+ + "MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVBhbG8gQWx0"
+ + "bzEdMBsGA1UEChMUU3VuIE1pY3Jvc3lzdGVtcyBJbmMxIzAhBgNVBAsTGkph"
+ + "dmEgU29mdHdhcmUgQ29kZSBTaWduaW5nMRwwGgYDVQQDExNKQ0UgQ29kZSBT"
+ + "aWduaW5nIENBAgEzMAkGBSsOAwIaBQAwCwYHKoZIzjgEAQUABC8wLQIVAIGV"
+ + "khm+kbV4a/+EP45PHcq0hIViAhR4M9os6IrJnoEDS3Y3l7O6zrSosA==");
+
+ public String getName()
+ {
+ return "BcSignedData";
+ }
+
+ private void init()
+ throws Exception
+ {
+ if (!_initialised)
+ {
+ _initialised = true;
+
+ _origDN = "O=Bouncy Castle, C=AU";
+ _origKP = CMSTestUtil.makeKeyPair();
+ _origCert = CMSTestUtil.makeCertificate(_origKP, _origDN, _origKP, _origDN);
+
+ _signDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+ _signKP = CMSTestUtil.makeKeyPair();
+ _signCert = CMSTestUtil.makeCertificate(_signKP, _signDN, _origKP, _origDN);
+ }
+ }
+
+ private void verifyRSASignatures(CMSSignedData s, byte[] contentDigest)
+ throws Exception
+ {
+ Store certStore = s.getCertificates();
+ SignerInformationStore signers = s.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certStore.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ if (!signer.verify(new BcRSASignerInfoVerifierBuilder(new DefaultCMSSignatureAlgorithmNameGenerator(), new DefaultSignatureAlgorithmIdentifierFinder(), new DefaultDigestAlgorithmIdentifierFinder(), new BcDigestCalculatorProvider()).build(cert)))
+ {
+ fail("signature verification failed");
+ }
+
+ if (contentDigest != null)
+ {
+ if (!Arrays.areEqual(contentDigest, signer.getContentDigest()))
+ {
+ fail("digest verification failed");
+ }
+ }
+ }
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ init();
+
+ testDetachedRSA();
+ testEncapsulatedRSA();
+ }
+
+ private void testDetachedRSA()
+ throws Exception
+ {
+ Digest md = new SHA1Digest();
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new CollectionStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ byte[] digValue = new byte[md.getDigestSize()];
+ byte[] data = "Hello world!".getBytes();
+
+ md.update(data, 0, data.length);
+ md.doFinal(digValue, 0);
+
+ Attribute attr = new Attribute(CMSAttributes.messageDigest,
+ new DERSet(
+ new DEROctetString(
+ digValue)));
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(attr);
+
+ AsymmetricKeyParameter privKey = (AsymmetricKeyParameter)_origKP.getPrivate();
+
+ AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA");
+ AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
+
+ BcContentSignerBuilder contentSignerBuilder = new BcRSAContentSignerBuilder(sigAlgId, digAlgId);
+
+ gen.addSignerInfoGenerator(
+ new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider())
+ .setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)))
+ .build(contentSignerBuilder.build(privKey), _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(new CMSAbsentContent(), false);
+
+ //
+ // the signature is detached, so need to add msg before passing on
+ //
+ s = new CMSSignedData(msg, s.getEncoded());
+ //
+ // compute expected content digest
+ //
+
+ verifyRSASignatures(s, digValue);
+ }
+
+ private void testEncapsulatedRSA()
+ throws Exception
+ {
+ Digest md = new SHA1Digest();
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new CollectionStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ byte[] digValue = new byte[md.getDigestSize()];
+ byte[] data = "Hello world!".getBytes();
+
+ md.update(data, 0, data.length);
+ md.doFinal(digValue, 0);
+
+ Attribute attr = new Attribute(CMSAttributes.messageDigest,
+ new DERSet(
+ new DEROctetString(
+ digValue)));
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(attr);
+
+ AsymmetricKeyParameter privKey = (AsymmetricKeyParameter)_origKP.getPrivate();
+
+ AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA");
+ AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
+
+ BcContentSignerBuilder contentSignerBuilder = new BcRSAContentSignerBuilder(sigAlgId, digAlgId);
+
+ gen.addSignerInfoGenerator(
+ new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider())
+ .build(contentSignerBuilder.build(privKey), _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(new CMSProcessableByteArray(data), true);
+
+ //
+ // the signature is encapsulated, so no need to add msg before passing on
+ //
+ s = new CMSSignedData(s.getEncoded());
+ //
+ // compute expected content digest
+ //
+
+ verifyRSASignatures(s, digValue);
+ }
+
+
+ public static void main(
+ String[] args)
+ {
+ runTest(new BcSignedDataTest());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cms/test/CMSTestUtil.java b/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cms/test/CMSTestUtil.java
new file mode 100644
index 000000000..e4ba8e04c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cms/test/CMSTestUtil.java
@@ -0,0 +1,206 @@
+package org.spongycastle.cms.test;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.Date;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSAPublicKey;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509v1CertificateBuilder;
+import org.spongycastle.cert.X509v3CertificateBuilder;
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.crypto.generators.RSAKeyPairGenerator;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.params.RSAKeyGenerationParameters;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.bc.BcRSAContentSignerBuilder;
+import org.spongycastle.util.encoders.Base64;
+
+public class CMSTestUtil
+{
+
+ public static SecureRandom rand;
+ public static RSAKeyPairGenerator kpg;
+
+ public static BigInteger serialNumber;
+
+ public static final boolean DEBUG = true;
+
+ private static byte[] attrCert = Base64.decode(
+ "MIIHQDCCBqkCAQEwgZChgY2kgYowgYcxHDAaBgkqhkiG9w0BCQEWDW1sb3JjaEB2"
+ + "dC5lZHUxHjAcBgNVBAMTFU1hcmt1cyBMb3JjaCAobWxvcmNoKTEbMBkGA1UECxMS"
+ + "VmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAyMQswCQYDVQQKEwJ2"
+ + "dDELMAkGA1UEBhMCVVMwgYmkgYYwgYMxGzAZBgkqhkiG9w0BCQEWDHNzaGFoQHZ0"
+ + "LmVkdTEbMBkGA1UEAxMSU3VtaXQgU2hhaCAoc3NoYWgpMRswGQYDVQQLExJWaXJn"
+ + "aW5pYSBUZWNoIFVzZXIxEDAOBgNVBAsTB0NsYXNzIDExCzAJBgNVBAoTAnZ0MQsw"
+ + "CQYDVQQGEwJVUzANBgkqhkiG9w0BAQQFAAIBBTAiGA8yMDAzMDcxODE2MDgwMloY"
+ + "DzIwMDMwNzI1MTYwODAyWjCCBU0wggVJBgorBgEEAbRoCAEBMYIFORaCBTU8UnVs"
+ + "ZSBSdWxlSWQ9IkZpbGUtUHJpdmlsZWdlLVJ1bGUiIEVmZmVjdD0iUGVybWl0Ij4K"
+ + "IDxUYXJnZXQ+CiAgPFN1YmplY3RzPgogICA8U3ViamVjdD4KICAgIDxTdWJqZWN0"
+ + "TWF0Y2ggTWF0Y2hJZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5j"
+ + "dGlvbjpzdHJpbmctZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlw"
+ + "ZT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjc3RyaW5nIj4KICAg"
+ + "ICAgIENOPU1hcmt1cyBMb3JjaDwvQXR0cmlidXRlVmFsdWU+CiAgICAgPFN1Ympl"
+ + "Y3RBdHRyaWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFt"
+ + "ZXM6dGM6eGFjbWw6MS4wOnN1YmplY3Q6c3ViamVjdC1pZCIgRGF0YVR5cGU9Imh0"
+ + "dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hI3N0cmluZyIgLz4gCiAgICA8"
+ + "L1N1YmplY3RNYXRjaD4KICAgPC9TdWJqZWN0PgogIDwvU3ViamVjdHM+CiAgPFJl"
+ + "c291cmNlcz4KICAgPFJlc291cmNlPgogICAgPFJlc291cmNlTWF0Y2ggTWF0Y2hJ"
+ + "ZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5jdGlvbjpzdHJpbmct"
+ + "ZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlwZT0iaHR0cDovL3d3"
+ + "dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIj4KICAgICAgaHR0cDovL3p1"
+ + "bmkuY3MudnQuZWR1PC9BdHRyaWJ1dGVWYWx1ZT4KICAgICA8UmVzb3VyY2VBdHRy"
+ + "aWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6"
+ + "eGFjbWw6MS4wOnJlc291cmNlOnJlc291cmNlLWlkIiBEYXRhVHlwZT0iaHR0cDov"
+ + "L3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIiAvPiAKICAgIDwvUmVz"
+ + "b3VyY2VNYXRjaD4KICAgPC9SZXNvdXJjZT4KICA8L1Jlc291cmNlcz4KICA8QWN0"
+ + "aW9ucz4KICAgPEFjdGlvbj4KICAgIDxBY3Rpb25NYXRjaCBNYXRjaElkPSJ1cm46"
+ + "b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmZ1bmN0aW9uOnN0cmluZy1lcXVhbCI+"
+ + "CiAgICAgPEF0dHJpYnV0ZVZhbHVlIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9y"
+ + "Zy8yMDAxL1hNTFNjaGVtYSNzdHJpbmciPgpEZWxlZ2F0ZSBBY2Nlc3MgICAgIDwv"
+ + "QXR0cmlidXRlVmFsdWU+CgkgIDxBY3Rpb25BdHRyaWJ1dGVEZXNpZ25hdG9yIEF0"
+ + "dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmFjdGlvbjph"
+ + "Y3Rpb24taWQiIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNj"
+ + "aGVtYSNzdHJpbmciIC8+IAogICAgPC9BY3Rpb25NYXRjaD4KICAgPC9BY3Rpb24+"
+ + "CiAgPC9BY3Rpb25zPgogPC9UYXJnZXQ+CjwvUnVsZT4KMA0GCSqGSIb3DQEBBAUA"
+ + "A4GBAGiJSM48XsY90HlYxGmGVSmNR6ZW2As+bot3KAfiCIkUIOAqhcphBS23egTr"
+ + "6asYwy151HshbPNYz+Cgeqs45KkVzh7bL/0e1r8sDVIaaGIkjHK3CqBABnfSayr3"
+ + "Rd1yBoDdEv8Qb+3eEPH6ab9021AsLEnJ6LWTmybbOpMNZ3tv");
+
+ static
+ {
+ try
+ {
+ rand = new SecureRandom();
+
+ kpg = new RSAKeyPairGenerator();
+ kpg.init(new RSAKeyGenerationParameters(BigInteger.valueOf(0x11), new SecureRandom(), 1024, 25));
+
+ serialNumber = new BigInteger("1");
+ }
+ catch (Exception ex)
+ {
+ throw new RuntimeException(ex.toString());
+ }
+ }
+
+ public static String dumpBase64(
+ byte[] data)
+ {
+ StringBuffer buf = new StringBuffer();
+
+ data = Base64.encode(data);
+
+ for (int i = 0; i < data.length; i += 64)
+ {
+ if (i + 64 < data.length)
+ {
+ buf.append(new String(data, i, 64));
+ }
+ else
+ {
+ buf.append(new String(data, i, data.length - i));
+ }
+ buf.append('\n');
+ }
+
+ return buf.toString();
+ }
+
+ public static X509AttributeCertificateHolder getAttributeCertificate()
+ throws Exception
+ {
+ return new X509AttributeCertificateHolder(CMSTestUtil.attrCert);
+ }
+
+ public static AsymmetricCipherKeyPair makeKeyPair()
+ {
+ return kpg.generateKeyPair();
+ }
+
+ public static X509CertificateHolder makeCertificate(AsymmetricCipherKeyPair _subKP,
+ String _subDN, AsymmetricCipherKeyPair _issKP, String _issDN)
+ throws IOException, OperatorCreationException
+ {
+
+ return makeCertificate(_subKP, _subDN, _issKP, _issDN, false);
+ }
+
+ public static X509CertificateHolder makeCACertificate(AsymmetricCipherKeyPair _subKP,
+ String _subDN, AsymmetricCipherKeyPair _issKP, String _issDN)
+ throws IOException, OperatorCreationException
+ {
+
+ return makeCertificate(_subKP, _subDN, _issKP, _issDN, true);
+ }
+
+ public static X509CertificateHolder makeV1Certificate(AsymmetricCipherKeyPair subKP, String _subDN, AsymmetricCipherKeyPair issKP, String _issDN)
+ throws IOException, OperatorCreationException
+ {
+ RSAKeyParameters lwPubKey = (RSAKeyParameters)subKP.getPublic();
+
+ X509v1CertificateBuilder v1CertGen = new X509v1CertificateBuilder(
+ new X500Name(_issDN),
+ allocateSerialNumber(),
+ new Date(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)),
+ new X500Name(_subDN),
+ new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPublicKey(lwPubKey.getModulus(), lwPubKey.getExponent()))
+ );
+
+ AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1WithRSAEncryption");
+ AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
+
+ ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build((AsymmetricKeyParameter)issKP.getPrivate());
+
+
+ return v1CertGen.build(sigGen);
+ }
+
+ public static X509CertificateHolder makeCertificate(AsymmetricCipherKeyPair subKP, String _subDN, AsymmetricCipherKeyPair issKP, String _issDN, boolean _ca)
+ throws IOException, OperatorCreationException
+ {
+ RSAKeyParameters lwPubKey = (RSAKeyParameters)subKP.getPublic();
+
+ X509v3CertificateBuilder v3CertGen = new X509v3CertificateBuilder(
+ new X500Name(_issDN),
+ allocateSerialNumber(),
+ new Date(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)),
+ new X500Name(_subDN),
+ new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPublicKey(lwPubKey.getModulus(), lwPubKey.getExponent()))
+ );
+
+ AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1WithRSAEncryption");
+ AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
+
+ ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build((AsymmetricKeyParameter)issKP.getPrivate());
+
+ v3CertGen.addExtension(
+ X509Extension.basicConstraints,
+ false,
+ new BasicConstraints(_ca));
+
+ return v3CertGen.build(sigGen);
+ }
+
+ private static BigInteger allocateSerialNumber()
+ {
+ BigInteger _tmp = serialNumber;
+ serialNumber = serialNumber.add(BigInteger.ONE);
+ return _tmp;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cms/test/RegressionTest.java b/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cms/test/RegressionTest.java
new file mode 100644
index 000000000..63f575c13
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/j2me/org/spongycastle/cms/test/RegressionTest.java
@@ -0,0 +1,29 @@
+package org.spongycastle.cms.test;
+
+import org.spongycastle.util.test.Test;
+import org.spongycastle.util.test.TestResult;
+
+public class RegressionTest
+{
+ public static Test[] tests = {
+ new BcEnvelopedDataTest(),
+ new BcSignedDataTest()
+ };
+
+ public static void main(
+ String[] args)
+ {
+ for (int i = 0; i != tests.length; i++)
+ {
+ TestResult result = tests[i].perform();
+
+ if (result.getException() != null)
+ {
+ result.getException().printStackTrace();
+ }
+
+ System.out.println(result);
+ }
+ }
+}
+
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/cmp/test/AllTests.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/cmp/test/AllTests.java
new file mode 100644
index 000000000..ca633903b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/cmp/test/AllTests.java
@@ -0,0 +1,317 @@
+package org.spongycastle.cert.cmp.test;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.cmp.CertConfirmContent;
+import org.spongycastle.asn1.cmp.CertRepMessage;
+import org.spongycastle.asn1.cmp.PKIBody;
+import org.spongycastle.asn1.cmp.PKIMessage;
+import org.spongycastle.asn1.crmf.CertReqMessages;
+import org.spongycastle.asn1.crmf.CertReqMsg;
+import org.spongycastle.asn1.crmf.ProofOfPossession;
+import org.spongycastle.asn1.crmf.SubsequentMessage;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.cert.CertException;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509v3CertificateBuilder;
+import org.spongycastle.cert.cmp.CertificateConfirmationContent;
+import org.spongycastle.cert.cmp.CertificateConfirmationContentBuilder;
+import org.spongycastle.cert.cmp.CertificateStatus;
+import org.spongycastle.cert.cmp.GeneralPKIMessage;
+import org.spongycastle.cert.cmp.ProtectedPKIMessage;
+import org.spongycastle.cert.cmp.ProtectedPKIMessageBuilder;
+import org.spongycastle.cert.crmf.CertificateRequestMessage;
+import org.spongycastle.cert.crmf.CertificateRequestMessageBuilder;
+import org.spongycastle.cert.crmf.PKMACBuilder;
+import org.spongycastle.cert.crmf.jcajce.JcaCertificateRequestMessageBuilder;
+import org.spongycastle.cert.crmf.jcajce.JcePKMACValuesCalculator;
+import org.spongycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.spongycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+import org.spongycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.spongycastle.util.io.Streams;
+
+public class AllTests
+ extends TestCase
+{
+ private static final byte[] TEST_DATA = "Hello world!".getBytes();
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+ private static final String TEST_DATA_HOME = "bc.test.data.home";
+
+ /*
+ *
+ * INFRASTRUCTURE
+ *
+ */
+
+ public AllTests(String name)
+ {
+ super(name);
+ }
+
+ public static void main(String args[])
+ {
+ junit.textui.TestRunner.run(AllTests.class);
+ }
+
+ public static Test suite()
+ {
+ return new TestSuite(AllTests.class);
+ }
+
+ public void setUp()
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ public void tearDown()
+ {
+
+ }
+
+ public void testProtectedMessage()
+ throws Exception
+ {
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(512);
+
+ KeyPair kp = kGen.generateKeyPair();
+ X509CertificateHolder cert = makeV3Certificate(kp, "CN=Test", kp, "CN=Test");
+
+ GeneralName sender = new GeneralName(new X500Name("CN=Sender"));
+ GeneralName recipient = new GeneralName(new X500Name("CN=Recip"));
+
+ ContentSigner signer = new JcaContentSignerBuilder("MD5WithRSAEncryption").setProvider(BC).build(kp.getPrivate());
+ ProtectedPKIMessage message = new ProtectedPKIMessageBuilder(sender, recipient)
+ .setBody(new PKIBody(PKIBody.TYPE_INIT_REP, CertRepMessage.getInstance(new DERSequence(new DERSequence()))))
+ .addCMPCertificate(cert)
+ .build(signer);
+
+ X509Certificate jcaCert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(message.getCertificates()[0]);
+ ContentVerifierProvider verifierProvider = new JcaContentVerifierProviderBuilder().setProvider(BC).build(jcaCert.getPublicKey());
+
+ assertTrue(message.verify(verifierProvider));
+
+ assertEquals(sender, message.getHeader().getSender());
+ assertEquals(recipient, message.getHeader().getRecipient());
+ }
+
+ public void testMacProtectedMessage()
+ throws Exception
+ {
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(512);
+
+ KeyPair kp = kGen.generateKeyPair();
+ X509CertificateHolder cert = makeV3Certificate(kp, "CN=Test", kp, "CN=Test");
+
+ GeneralName sender = new GeneralName(new X500Name("CN=Sender"));
+ GeneralName recipient = new GeneralName(new X500Name("CN=Recip"));
+
+ ProtectedPKIMessage message = new ProtectedPKIMessageBuilder(sender, recipient)
+ .setBody(new PKIBody(PKIBody.TYPE_INIT_REP, CertRepMessage.getInstance(new DERSequence(new DERSequence()))))
+ .addCMPCertificate(cert)
+ .build(new PKMACBuilder(new JcePKMACValuesCalculator().setProvider(BC)).build("secret".toCharArray()));
+
+ PKMACBuilder pkMacBuilder = new PKMACBuilder(new JcePKMACValuesCalculator().setProvider(BC));
+
+ assertTrue(message.verify(pkMacBuilder, "secret".toCharArray()));
+
+ assertEquals(sender, message.getHeader().getSender());
+ assertEquals(recipient, message.getHeader().getRecipient());
+ }
+
+ public void testConfirmationMessage()
+ throws Exception
+ {
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(512);
+
+ KeyPair kp = kGen.generateKeyPair();
+ X509CertificateHolder cert = makeV3Certificate(kp, "CN=Test", kp, "CN=Test");
+
+ GeneralName sender = new GeneralName(new X500Name("CN=Sender"));
+ GeneralName recipient = new GeneralName(new X500Name("CN=Recip"));
+
+ CertificateConfirmationContent content = new CertificateConfirmationContentBuilder()
+ .addAcceptedCertificate(cert, BigInteger.valueOf(1))
+ .build(new JcaDigestCalculatorProviderBuilder().build());
+
+ ContentSigner signer = new JcaContentSignerBuilder("MD5WithRSAEncryption").setProvider(BC).build(kp.getPrivate());
+ ProtectedPKIMessage message = new ProtectedPKIMessageBuilder(sender, recipient)
+ .setBody(new PKIBody(PKIBody.TYPE_CERT_CONFIRM, content.toASN1Structure()))
+ .addCMPCertificate(cert)
+ .build(signer);
+
+ X509Certificate jcaCert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(message.getCertificates()[0]);
+ ContentVerifierProvider verifierProvider = new JcaContentVerifierProviderBuilder().setProvider(BC).build(jcaCert.getPublicKey());
+
+ assertTrue(message.verify(verifierProvider));
+
+ assertEquals(sender, message.getHeader().getSender());
+ assertEquals(recipient, message.getHeader().getRecipient());
+
+ content = new CertificateConfirmationContent(CertConfirmContent.getInstance(message.getBody().getContent()));
+
+ CertificateStatus[] statusList = content.getStatusMessages();
+
+ assertEquals(1, statusList.length);
+ assertTrue(statusList[0].isVerified(cert, new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()));
+ }
+
+ public void testSampleCr()
+ throws Exception
+ {
+ PKIMessage msg = loadMessage("sample_cr.der");
+ ProtectedPKIMessage procMsg = new ProtectedPKIMessage(new GeneralPKIMessage(msg));
+
+ assertTrue(procMsg.verify(new PKMACBuilder(new JcePKMACValuesCalculator().setProvider(BC)), "TopSecret1234".toCharArray()));
+ }
+
+ public void testSubsequentMessage()
+ throws Exception
+ {
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(512);
+
+ KeyPair kp = kGen.generateKeyPair();
+ X509CertificateHolder cert = makeV3Certificate(kp, "CN=Test", kp, "CN=Test");
+
+ ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA").setProvider(BC).build(
+ kp.getPrivate());
+
+ GeneralName user = new GeneralName(new X500Name("CN=Test"));
+
+ CertificateRequestMessageBuilder builder = new JcaCertificateRequestMessageBuilder(
+ BigInteger.valueOf(1)).setPublicKey(kp.getPublic()).setProofOfPossessionSubsequentMessage(
+ SubsequentMessage.encrCert);
+
+ ProtectedPKIMessage certRequestMsg = new ProtectedPKIMessageBuilder(user,
+ user).setTransactionID(new byte[] { 1, 2, 3, 4, 5 }).setBody(
+ new PKIBody(PKIBody.TYPE_KEY_UPDATE_REQ, new CertReqMessages(builder.build().toASN1Structure()))).addCMPCertificate(
+ cert).build(signer);
+
+ ProtectedPKIMessage msg = new ProtectedPKIMessage(new GeneralPKIMessage(certRequestMsg.toASN1Structure().getEncoded()));
+
+ CertReqMessages reqMsgs = CertReqMessages.getInstance(msg.getBody().getContent());
+
+ CertReqMsg reqMsg = reqMsgs.toCertReqMsgArray()[0];
+
+ assertEquals(ProofOfPossession.TYPE_KEY_ENCIPHERMENT, reqMsg.getPopo().getType());
+ }
+
+ public void testNotBeforeNotAfter()
+ throws Exception
+ {
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(512);
+
+ KeyPair kp = kGen.generateKeyPair();
+
+ doNotBeforeNotAfterTest(kp, new Date(0L), new Date(60000L));
+ doNotBeforeNotAfterTest(kp, null, new Date(60000L));
+ doNotBeforeNotAfterTest(kp, new Date(0L), null);
+ }
+
+ private void doNotBeforeNotAfterTest(KeyPair kp, Date notBefore, Date notAfter)
+ throws Exception
+ {
+ CertificateRequestMessageBuilder builder = new JcaCertificateRequestMessageBuilder(
+ BigInteger.valueOf(1)).setPublicKey(kp.getPublic()).setProofOfPossessionSubsequentMessage(
+ SubsequentMessage.encrCert);
+
+ builder.setValidity(notBefore, notAfter);
+
+ CertificateRequestMessage message = builder.build();
+
+ if (notBefore != null)
+ {
+ assertEquals(notBefore.getTime(), message.getCertTemplate().getValidity().getNotBefore().getDate().getTime());
+ }
+ else
+ {
+ assertNull(message.getCertTemplate().getValidity().getNotBefore());
+ }
+
+ if (notAfter != null)
+ {
+ assertEquals(notAfter.getTime(), message.getCertTemplate().getValidity().getNotAfter().getDate().getTime());
+ }
+ else
+ {
+ assertNull(message.getCertTemplate().getValidity().getNotAfter());
+ }
+ }
+
+ private static X509CertificateHolder makeV3Certificate(KeyPair subKP, String _subDN, KeyPair issKP, String _issDN)
+ throws GeneralSecurityException, IOException, OperatorCreationException, CertException
+ {
+
+ PublicKey subPub = subKP.getPublic();
+ PrivateKey issPriv = issKP.getPrivate();
+ PublicKey issPub = issKP.getPublic();
+
+ X509v3CertificateBuilder v1CertGen = new JcaX509v3CertificateBuilder(
+ new X500Name(_issDN),
+ BigInteger.valueOf(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)),
+ new X500Name(_subDN),
+ subPub);
+
+ ContentSigner signer = new JcaContentSignerBuilder("SHA1WithRSA").setProvider(BC).build(issPriv);
+
+ X509CertificateHolder certHolder = v1CertGen.build(signer);
+
+ ContentVerifierProvider verifier = new JcaContentVerifierProviderBuilder().setProvider(BC).build(issPub);
+
+ assertTrue(certHolder.isSignatureValid(verifier));
+
+ return certHolder;
+ }
+
+ private static PKIMessage loadMessage(String name)
+ {
+ String dataHome = System.getProperty(TEST_DATA_HOME);
+
+ if (dataHome == null)
+ {
+ throw new IllegalStateException(TEST_DATA_HOME + " property not set");
+ }
+
+ try
+ {
+ return PKIMessage.getInstance(ASN1Primitive.fromByteArray(Streams.readAll(new FileInputStream(dataHome + "/cmp/" + name))));
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/crmf/test/AllTests.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/crmf/test/AllTests.java
new file mode 100644
index 000000000..1504f3ff8
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/crmf/test/AllTests.java
@@ -0,0 +1,384 @@
+package org.spongycastle.cert.crmf.test;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Date;
+
+import javax.security.auth.x500.X500Principal;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.crmf.CRMFObjectIdentifiers;
+import org.spongycastle.asn1.crmf.EncKeyWithID;
+import org.spongycastle.asn1.crmf.EncryptedValue;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509v1CertificateBuilder;
+import org.spongycastle.cert.crmf.EncryptedValueBuilder;
+import org.spongycastle.cert.crmf.EncryptedValuePadder;
+import org.spongycastle.cert.crmf.EncryptedValueParser;
+import org.spongycastle.cert.crmf.FixedLengthMGF1Padder;
+import org.spongycastle.cert.crmf.PKIArchiveControl;
+import org.spongycastle.cert.crmf.PKMACBuilder;
+import org.spongycastle.cert.crmf.ValueDecryptorGenerator;
+import org.spongycastle.cert.crmf.jcajce.JcaCertificateRequestMessage;
+import org.spongycastle.cert.crmf.jcajce.JcaCertificateRequestMessageBuilder;
+import org.spongycastle.cert.crmf.jcajce.JcaEncryptedValueBuilder;
+import org.spongycastle.cert.crmf.jcajce.JcaPKIArchiveControlBuilder;
+import org.spongycastle.cert.crmf.jcajce.JceAsymmetricValueDecryptorGenerator;
+import org.spongycastle.cert.crmf.jcajce.JceCRMFEncryptorBuilder;
+import org.spongycastle.cert.crmf.jcajce.JcePKMACValuesCalculator;
+import org.spongycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.spongycastle.cert.jcajce.JcaX509v1CertificateBuilder;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSEnvelopedDataGenerator;
+import org.spongycastle.cms.RecipientId;
+import org.spongycastle.cms.RecipientInformation;
+import org.spongycastle.cms.RecipientInformationStore;
+import org.spongycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
+import org.spongycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
+import org.spongycastle.cms.jcajce.JceKeyTransRecipientId;
+import org.spongycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+import org.spongycastle.operator.jcajce.JceAsymmetricKeyWrapper;
+import org.spongycastle.util.Arrays;
+
+public class AllTests
+ extends TestCase
+{
+ private static final byte[] TEST_DATA = "Hello world!".getBytes();
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+ private static final String PASSPHRASE = "hello world";
+
+ /*
+ *
+ * INFRASTRUCTURE
+ *
+ */
+
+ public AllTests(String name)
+ {
+ super(name);
+ }
+
+ public static void main(String args[])
+ {
+ junit.textui.TestRunner.run(AllTests.class);
+ }
+
+ public static Test suite()
+ {
+ return new TestSuite(AllTests.class);
+ }
+
+ public void setUp()
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ public void tearDown()
+ {
+
+ }
+
+ public void testBasicMessageWithArchiveControl()
+ throws Exception
+ {
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(512);
+
+ KeyPair kp = kGen.generateKeyPair();
+ X509Certificate cert = makeV1Certificate(kp, "CN=Test", kp, "CN=Test");
+
+ JcaCertificateRequestMessageBuilder certReqBuild = new JcaCertificateRequestMessageBuilder(BigInteger.ONE);
+
+ certReqBuild.setSubject(new X500Principal("CN=Test"))
+ .setPublicKey(kp.getPublic());
+
+ certReqBuild.addControl(new JcaPKIArchiveControlBuilder(kp.getPrivate(), new X500Principal("CN=Test"))
+ .addRecipientGenerator(new JceKeyTransRecipientInfoGenerator(cert).setProvider(BC))
+ .build(new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier(CMSEnvelopedDataGenerator.AES128_CBC)).setProvider(BC).build()));
+
+ JcaCertificateRequestMessage certReqMsg = new JcaCertificateRequestMessage(certReqBuild.build());
+
+ assertEquals(new X500Principal("CN=Test"), certReqMsg.getSubjectX500Principal());
+ assertEquals(kp.getPublic(), certReqMsg.getPublicKey());
+
+ PKIArchiveControl archiveControl = (PKIArchiveControl)certReqMsg.getControl(CRMFObjectIdentifiers.id_regCtrl_pkiArchiveOptions);
+
+ assertEquals(PKIArchiveControl.encryptedPrivKey, archiveControl.getArchiveType());
+
+ assertTrue(archiveControl.isEnvelopedData());
+
+ RecipientInformationStore recips = archiveControl.getEnvelopedData().getRecipientInfos();
+
+ RecipientId recipientId = new JceKeyTransRecipientId(cert);
+
+ RecipientInformation recipientInformation = recips.get(recipientId);
+
+ assertNotNull(recipientInformation);
+
+ EncKeyWithID encKeyWithID = EncKeyWithID.getInstance(recipientInformation.getContent(new JceKeyTransEnvelopedRecipient(kp.getPrivate()).setProvider(BC)));
+
+ assertTrue(encKeyWithID.hasIdentifier());
+ assertFalse(encKeyWithID.isIdentifierUTF8String());
+
+ assertEquals(new GeneralName(X500Name.getInstance(new X500Principal("CN=Test").getEncoded())), encKeyWithID.getIdentifier());
+ assertTrue(Arrays.areEqual(kp.getPrivate().getEncoded(), encKeyWithID.getPrivateKey().getEncoded()));
+ }
+
+ public void testProofOfPossessionWithoutSender()
+ throws Exception
+ {
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(512);
+
+ KeyPair kp = kGen.generateKeyPair();
+ X509Certificate cert = makeV1Certificate(kp, "CN=Test", kp, "CN=Test");
+
+ JcaCertificateRequestMessageBuilder certReqBuild = new JcaCertificateRequestMessageBuilder(BigInteger.ONE);
+
+ certReqBuild.setPublicKey(kp.getPublic())
+ .setAuthInfoPKMAC(new PKMACBuilder(new JcePKMACValuesCalculator()), "fred".toCharArray())
+ .setProofOfPossessionSigningKeySigner(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(kp.getPrivate()));
+
+ certReqBuild.addControl(new JcaPKIArchiveControlBuilder(kp.getPrivate(), new X500Principal("CN=test"))
+ .addRecipientGenerator(new JceKeyTransRecipientInfoGenerator(cert).setProvider(BC))
+ .build(new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier(CMSEnvelopedDataGenerator.AES128_CBC)).setProvider(BC).build()));
+
+ JcaCertificateRequestMessage certReqMsg = new JcaCertificateRequestMessage(certReqBuild.build().getEncoded());
+
+ // check that internal check on popo signing is working okay
+ try
+ {
+ certReqMsg.isValidSigningKeyPOP(new JcaContentVerifierProviderBuilder().setProvider(BC).build(kp.getPublic()));
+ fail("IllegalStateException not thrown");
+ }
+ catch (IllegalStateException e)
+ {
+ // ignore
+ }
+
+ assertTrue(certReqMsg.isValidSigningKeyPOP(new JcaContentVerifierProviderBuilder().setProvider(BC).build(kp.getPublic()), new PKMACBuilder(new JcePKMACValuesCalculator().setProvider(BC)), "fred".toCharArray()));
+
+ assertEquals(kp.getPublic(), certReqMsg.getPublicKey());
+ }
+
+ public void testProofOfPossessionWithSender()
+ throws Exception
+ {
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(512);
+
+ KeyPair kp = kGen.generateKeyPair();
+ X509Certificate cert = makeV1Certificate(kp, "CN=Test", kp, "CN=Test");
+
+ JcaCertificateRequestMessageBuilder certReqBuild = new JcaCertificateRequestMessageBuilder(BigInteger.ONE);
+
+ certReqBuild.setPublicKey(kp.getPublic())
+ .setAuthInfoSender(new X500Principal("CN=Test"))
+ .setProofOfPossessionSigningKeySigner(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(kp.getPrivate()));
+
+ certReqBuild.addControl(new JcaPKIArchiveControlBuilder(kp.getPrivate(), new X500Principal("CN=test"))
+ .addRecipientGenerator(new JceKeyTransRecipientInfoGenerator(cert).setProvider(BC))
+ .build(new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier(CMSEnvelopedDataGenerator.AES128_CBC)).setProvider(BC).build()));
+
+ JcaCertificateRequestMessage certReqMsg = new JcaCertificateRequestMessage(certReqBuild.build().getEncoded());
+
+ // check that internal check on popo signing is working okay
+ try
+ {
+ certReqMsg.isValidSigningKeyPOP(new JcaContentVerifierProviderBuilder().setProvider(BC).build(kp.getPublic()), new PKMACBuilder(new JcePKMACValuesCalculator().setProvider(BC)), "fred".toCharArray());
+
+ fail("IllegalStateException not thrown");
+ }
+ catch (IllegalStateException e)
+ {
+ // ignore
+ }
+
+
+ assertTrue(certReqMsg.isValidSigningKeyPOP(new JcaContentVerifierProviderBuilder().setProvider(BC).build(kp.getPublic())));
+
+ assertEquals(kp.getPublic(), certReqMsg.getPublicKey());
+ }
+
+ public void testProofOfPossessionWithTemplate()
+ throws Exception
+ {
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(512);
+
+ KeyPair kp = kGen.generateKeyPair();
+ X509Certificate cert = makeV1Certificate(kp, "CN=Test", kp, "CN=Test");
+
+ JcaCertificateRequestMessageBuilder certReqBuild = new JcaCertificateRequestMessageBuilder(BigInteger.ONE);
+
+ certReqBuild.setPublicKey(kp.getPublic())
+ .setSubject(new X500Principal("CN=Test"))
+ .setAuthInfoSender(new X500Principal("CN=Test"))
+ .setProofOfPossessionSigningKeySigner(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(kp.getPrivate()));
+
+ certReqBuild.addControl(new JcaPKIArchiveControlBuilder(kp.getPrivate(), new X500Principal("CN=test"))
+ .addRecipientGenerator(new JceKeyTransRecipientInfoGenerator(cert).setProvider(BC))
+ .build(new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier(CMSEnvelopedDataGenerator.AES128_CBC)).setProvider(BC).build()));
+
+ JcaCertificateRequestMessage certReqMsg = new JcaCertificateRequestMessage(certReqBuild.build().getEncoded());
+
+ assertTrue(certReqMsg.isValidSigningKeyPOP(new JcaContentVerifierProviderBuilder().setProvider(BC).build(kp.getPublic())));
+
+ assertEquals(kp.getPublic(), certReqMsg.getPublicKey());
+ }
+
+ public void testEncryptedValue()
+ throws Exception
+ {
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(512);
+
+ KeyPair kp = kGen.generateKeyPair();
+ X509Certificate cert = makeV1Certificate(kp, "CN=Test", kp, "CN=Test");
+
+ JcaEncryptedValueBuilder build = new JcaEncryptedValueBuilder(new JceAsymmetricKeyWrapper(cert.getPublicKey()).setProvider(BC), new JceCRMFEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+ EncryptedValue value = build.build(cert);
+ ValueDecryptorGenerator decGen = new JceAsymmetricValueDecryptorGenerator(kp.getPrivate()).setProvider(BC);
+
+ // try direct
+ encryptedValueParserTest(value, decGen, cert);
+
+ // try indirect
+ encryptedValueParserTest(EncryptedValue.getInstance(value.getEncoded()), decGen, cert);
+ }
+
+ private void encryptedValueParserTest(EncryptedValue value, ValueDecryptorGenerator decGen, X509Certificate cert)
+ throws Exception
+ {
+ EncryptedValueParser parser = new EncryptedValueParser(value);
+
+ X509CertificateHolder holder = parser.readCertificateHolder(decGen);
+
+ assertTrue(Arrays.areEqual(cert.getEncoded(), holder.getEncoded()));
+ }
+
+ public void testEncryptedValuePassphrase()
+ throws Exception
+ {
+ char[] passphrase = PASSPHRASE.toCharArray();
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(512);
+
+ KeyPair kp = kGen.generateKeyPair();
+ X509Certificate cert = makeV1Certificate(kp, "CN=Test", kp, "CN=Test");
+
+ EncryptedValueBuilder build = new EncryptedValueBuilder(new JceAsymmetricKeyWrapper(cert.getPublicKey()).setProvider(BC), new JceCRMFEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+ EncryptedValue value = build.build(passphrase);
+ ValueDecryptorGenerator decGen = new JceAsymmetricValueDecryptorGenerator(kp.getPrivate()).setProvider(BC);
+
+ // try direct
+ encryptedValuePassphraseParserTest(value, null, decGen, cert);
+
+ // try indirect
+ encryptedValuePassphraseParserTest(EncryptedValue.getInstance(value.getEncoded()), null, decGen, cert);
+ }
+
+ public void testEncryptedValuePassphraseWithPadding()
+ throws Exception
+ {
+ char[] passphrase = PASSPHRASE.toCharArray();
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(512);
+
+ KeyPair kp = kGen.generateKeyPair();
+ X509Certificate cert = makeV1Certificate(kp, "CN=Test", kp, "CN=Test");
+
+ FixedLengthMGF1Padder mgf1Padder = new FixedLengthMGF1Padder(200, new SecureRandom());
+ EncryptedValueBuilder build = new EncryptedValueBuilder(new JceAsymmetricKeyWrapper(cert.getPublicKey()).setProvider(BC), new JceCRMFEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build(), mgf1Padder);
+ EncryptedValue value = build.build(passphrase);
+ ValueDecryptorGenerator decGen = new JceAsymmetricValueDecryptorGenerator(kp.getPrivate()).setProvider(BC);
+
+ // try direct
+ encryptedValuePassphraseParserTest(value, mgf1Padder, decGen, cert);
+
+ // try indirect
+ encryptedValuePassphraseParserTest(EncryptedValue.getInstance(value.getEncoded()), mgf1Padder, decGen, cert);
+ }
+
+ private void encryptedValuePassphraseParserTest(EncryptedValue value, EncryptedValuePadder padder, ValueDecryptorGenerator decGen, X509Certificate cert)
+ throws Exception
+ {
+ EncryptedValueParser parser = new EncryptedValueParser(value, padder);
+
+ assertTrue(Arrays.areEqual(PASSPHRASE.toCharArray(), parser.readPassphrase(decGen)));
+ }
+
+ private static X509Certificate makeV1Certificate(KeyPair subKP, String _subDN, KeyPair issKP, String _issDN)
+ throws GeneralSecurityException, IOException, OperatorCreationException
+ {
+
+ PublicKey subPub = subKP.getPublic();
+ PrivateKey issPriv = issKP.getPrivate();
+ PublicKey issPub = issKP.getPublic();
+
+ X509v1CertificateBuilder v1CertGen = new JcaX509v1CertificateBuilder(
+ new X500Name(_issDN),
+ BigInteger.valueOf(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)),
+ new X500Name(_subDN),
+ subPub);
+
+ JcaContentSignerBuilder signerBuilder = null;
+
+ if (issPub instanceof RSAPublicKey)
+ {
+ signerBuilder = new JcaContentSignerBuilder("SHA1WithRSA");
+ }
+ else if (issPub.getAlgorithm().equals("DSA"))
+ {
+ signerBuilder = new JcaContentSignerBuilder("SHA1withDSA");
+ }
+ else if (issPub.getAlgorithm().equals("ECDSA"))
+ {
+ signerBuilder = new JcaContentSignerBuilder("SHA1withECDSA");
+ }
+ else if (issPub.getAlgorithm().equals("ECGOST3410"))
+ {
+ signerBuilder = new JcaContentSignerBuilder("GOST3411withECGOST3410");
+ }
+ else
+ {
+ signerBuilder = new JcaContentSignerBuilder("GOST3411WithGOST3410");
+ }
+
+ signerBuilder.setProvider(BC);
+
+ X509Certificate _cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(v1CertGen.build(signerBuilder.build(issPriv)));
+
+ _cert.checkValidity(new Date());
+ _cert.verify(issPub);
+
+ return _cert;
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/ocsp/test/AllTests.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/ocsp/test/AllTests.java
new file mode 100644
index 000000000..cd739e62f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/ocsp/test/AllTests.java
@@ -0,0 +1,44 @@
+package org.spongycastle.cert.ocsp.test;
+
+import java.security.Security;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.test.SimpleTestResult;
+
+public class AllTests
+ extends TestCase
+{
+ public void testOCSP()
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ org.spongycastle.util.test.Test[] tests = new org.spongycastle.util.test.Test[] { new OCSPTest() };
+
+ for (int i = 0; i != tests.length; i++)
+ {
+ SimpleTestResult result = (SimpleTestResult)tests[i].perform();
+
+ if (!result.isSuccessful())
+ {
+ fail(result.toString());
+ }
+ }
+ }
+
+ public static void main (String[] args)
+ {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite()
+ {
+ TestSuite suite = new TestSuite("OCSP Tests");
+
+ suite.addTestSuite(AllTests.class);
+
+ return suite;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/ocsp/test/OCSPTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/ocsp/test/OCSPTest.java
new file mode 100644
index 000000000..137ef9c8c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/ocsp/test/OCSPTest.java
@@ -0,0 +1,973 @@
+package org.spongycastle.cert.ocsp.test;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.Security;
+import java.util.Date;
+import java.util.Random;
+import java.util.Set;
+import java.util.Vector;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Exception;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.ocsp.OCSPObjectIdentifiers;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.ExtensionsGenerator;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.cert.CertIOException;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.cert.ocsp.BasicOCSPResp;
+import org.spongycastle.cert.ocsp.BasicOCSPRespBuilder;
+import org.spongycastle.cert.ocsp.CertificateID;
+import org.spongycastle.cert.ocsp.CertificateStatus;
+import org.spongycastle.cert.ocsp.OCSPReq;
+import org.spongycastle.cert.ocsp.OCSPReqBuilder;
+import org.spongycastle.cert.ocsp.OCSPResp;
+import org.spongycastle.cert.ocsp.OCSPRespBuilder;
+import org.spongycastle.cert.ocsp.Req;
+import org.spongycastle.cert.ocsp.RespID;
+import org.spongycastle.cert.ocsp.SingleResp;
+import org.spongycastle.cert.ocsp.jcajce.JcaBasicOCSPRespBuilder;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.ocsp.test.OCSPTestUtil;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+import org.spongycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.test.SimpleTest;
+
+public class OCSPTest
+ extends SimpleTest
+{
+ byte[] testResp1 = Base64.decode(
+ "MIIFnAoBAKCCBZUwggWRBgkrBgEFBQcwAQEEggWCMIIFfjCCARehgZ8wgZwx"
+ + "CzAJBgNVBAYTAklOMRcwFQYDVQQIEw5BbmRocmEgcHJhZGVzaDESMBAGA1UE"
+ + "BxMJSHlkZXJhYmFkMQwwCgYDVQQKEwNUQ1MxDDAKBgNVBAsTA0FUQzEeMBwG"
+ + "A1UEAxMVVENTLUNBIE9DU1AgUmVzcG9uZGVyMSQwIgYJKoZIhvcNAQkBFhVv"
+ + "Y3NwQHRjcy1jYS50Y3MuY28uaW4YDzIwMDMwNDAyMTIzNDU4WjBiMGAwOjAJ"
+ + "BgUrDgMCGgUABBRs07IuoCWNmcEl1oHwIak1BPnX8QQUtGyl/iL9WJ1VxjxF"
+ + "j0hAwJ/s1AcCAQKhERgPMjAwMjA4MjkwNzA5MjZaGA8yMDAzMDQwMjEyMzQ1"
+ + "OFowDQYJKoZIhvcNAQEFBQADgYEAfbN0TCRFKdhsmvOdUoiJ+qvygGBzDxD/"
+ + "VWhXYA+16AphHLIWNABR3CgHB3zWtdy2j7DJmQ/R7qKj7dUhWLSqclAiPgFt"
+ + "QQ1YvSJAYfEIdyHkxv4NP0LSogxrumANcDyC9yt/W9yHjD2ICPBIqCsZLuLk"
+ + "OHYi5DlwWe9Zm9VFwCGgggPMMIIDyDCCA8QwggKsoAMCAQICAQYwDQYJKoZI"
+ + "hvcNAQEFBQAwgZQxFDASBgNVBAMTC1RDUy1DQSBPQ1NQMSYwJAYJKoZIhvcN"
+ + "AQkBFhd0Y3MtY2FAdGNzLWNhLnRjcy5jby5pbjEMMAoGA1UEChMDVENTMQww"
+ + "CgYDVQQLEwNBVEMxEjAQBgNVBAcTCUh5ZGVyYWJhZDEXMBUGA1UECBMOQW5k"
+ + "aHJhIHByYWRlc2gxCzAJBgNVBAYTAklOMB4XDTAyMDgyOTA3MTE0M1oXDTAz"
+ + "MDgyOTA3MTE0M1owgZwxCzAJBgNVBAYTAklOMRcwFQYDVQQIEw5BbmRocmEg"
+ + "cHJhZGVzaDESMBAGA1UEBxMJSHlkZXJhYmFkMQwwCgYDVQQKEwNUQ1MxDDAK"
+ + "BgNVBAsTA0FUQzEeMBwGA1UEAxMVVENTLUNBIE9DU1AgUmVzcG9uZGVyMSQw"
+ + "IgYJKoZIhvcNAQkBFhVvY3NwQHRjcy1jYS50Y3MuY28uaW4wgZ8wDQYJKoZI"
+ + "hvcNAQEBBQADgY0AMIGJAoGBAM+XWW4caMRv46D7L6Bv8iwtKgmQu0SAybmF"
+ + "RJiz12qXzdvTLt8C75OdgmUomxp0+gW/4XlTPUqOMQWv463aZRv9Ust4f8MH"
+ + "EJh4ekP/NS9+d8vEO3P40ntQkmSMcFmtA9E1koUtQ3MSJlcs441JjbgUaVnm"
+ + "jDmmniQnZY4bU3tVAgMBAAGjgZowgZcwDAYDVR0TAQH/BAIwADALBgNVHQ8E"
+ + "BAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwkwNgYIKwYBBQUHAQEEKjAoMCYG"
+ + "CCsGAQUFBzABhhpodHRwOi8vMTcyLjE5LjQwLjExMDo3NzAwLzAtBgNVHR8E"
+ + "JjAkMCKgIKAehhxodHRwOi8vMTcyLjE5LjQwLjExMC9jcmwuY3JsMA0GCSqG"
+ + "SIb3DQEBBQUAA4IBAQB6FovM3B4VDDZ15o12gnADZsIk9fTAczLlcrmXLNN4"
+ + "PgmqgnwF0Ymj3bD5SavDOXxbA65AZJ7rBNAguLUo+xVkgxmoBH7R2sBxjTCc"
+ + "r07NEadxM3HQkt0aX5XYEl8eRoifwqYAI9h0ziZfTNes8elNfb3DoPPjqq6V"
+ + "mMg0f0iMS4W8LjNPorjRB+kIosa1deAGPhq0eJ8yr0/s2QR2/WFD5P4aXc8I"
+ + "KWleklnIImS3zqiPrq6tl2Bm8DZj7vXlTOwmraSQxUwzCKwYob1yGvNOUQTq"
+ + "pG6jxn7jgDawHU1+WjWQe4Q34/pWeGLysxTraMa+Ug9kPe+jy/qRX2xwvKBZ");
+
+ byte[] testResp2 = Base64.decode(
+ "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"
+ + "A5oyOoNv0w+8bbtMNEc1");
+
+ /**
+ * extra version number encoding.
+ */
+ private static byte[] irregReq = Base64.decode(
+ "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");
+
+ private static byte[] invalidResp = Base64.decode(
+ "MIIGggoAoIIGfDCCBngGCSsGAQUFBzABAQSCBmkwggZlMIHeoTQwMjELMAkG"
+ + "A1UEBhMCVVMxDTALBgNVBAoMBGlXYXkxFDASBgNVBAMMC2lXYXkgT3BlbkNB"
+ + "GA8yMDEyMDEyMzIxMjkxMVowbjBsMEQwCQYFKw4DAhoFAAQUPA5ymcOyHyZJ"
+ + "d7DAidsEh79Uh6QEFMHnDLGSc/VElMBzr5f0+LQnpN2YAgsA5xIzv2Ln0dAa"
+ + "94IAGA8yMDEyMDEyMzIxMjkxMVqgERgPMjAxMjAxMjMyMTM0MTFaoSUwIzAh"
+ + "BgkrBgEFBQcwAQIEFCHEdgCz5w64KgppPIetaRzxewinMA0GCSqGSIb3DQEB"
+ + "CwUAA4IBAQBsW8cXR4eOLgclY/uRodjso/5xkHIAiJy+DpgqELRrnzKe87HO"
+ + "Km7DCicz1nwsPJskK14xtIw1rfQ8nzgztriComAUVc/pxJ9wQWGZI3d2dNbW"
+ + "AmecKb/mG0QrJrt3U5D0+CFTUq5u7NOs1jZRe+df9TDLBr0vIA6a0I6K9M9F"
+ + "ZOPWU/j5KVjoi0/kv4wnxRzQ2zc4Z3b5gm9T0MXMH5bST3z4yhOs/NRezNTA"
+ + "fBQvimS60d4fybH0pXcVYUH81y5fm9rCpuwQ6rMt2vi0ZKrfyVom4OIAr/gh"
+ + "Doj8Yh/LdtI1RvFkAL3pvzs06cfg3qM38b9Uh9w93w4/Hguw14eroIIEbDCC"
+ + "BGgwggRkMIIDTKADAgECAgEBMA0GCSqGSIb3DQEBCwUAMDIxCzAJBgNVBAYT"
+ + "AlVTMQ0wCwYDVQQKDARpV2F5MRQwEgYDVQQDDAtpV2F5IE9wZW5DQTAeFw0x"
+ + "MjAxMjAxNTIyMjFaFw0zMjAxMTUxNTIyMjFaMDIxCzAJBgNVBAYTAlVTMQ0w"
+ + "CwYDVQQKDARpV2F5MRQwEgYDVQQDDAtpV2F5IE9wZW5DQTCCASIwDQYJKoZI"
+ + "hvcNAQEBBQADggEPADCCAQoCggEBALOnLWYPvGNLxodQQ16tqCKflpEQF2OA"
+ + "0inZbIeUVxOgph5Qf562XV1Mtbv5Agv+z4/LSLbwuo28NTkhSlEEwf1k9vL9"
+ + "/wFvpPZ4ecpqXOS6LJ6khmMh53IwK/QpG8CeF9UxTZskjQzD9XgnNGYd2BIj"
+ + "qVbzU5qWhsPYPRrsAaE2jS6My5+xfiw46/Xj26VZQ/PR/rVURsc40fpCE30y"
+ + "TyORQeeZfjb/LxXH3e/3wjya04MBACv+uX89n5YXG7OH6zTriMAOn/aiXPfE"
+ + "E8g834RKvVS7ruELWG/IcZDC+Eoy2qtgG7y1rFlXd3H/6rny+Xd+BZrt0WP/"
+ + "hfezklVw3asCAwEAAaOCAYMwggF/MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0P"
+ + "BAQDAgEGMB0GA1UdDgQWBBTB5wyxknP1RJTAc6+X9Pi0J6TdmDAfBgNVHSME"
+ + "GDAWgBTB5wyxknP1RJTAc6+X9Pi0J6TdmDAjBgNVHREEHDAagRhzdXBwb3J0"
+ + "QGl3YXlzb2Z0d2FyZS5jb20wIwYDVR0SBBwwGoEYc3VwcG9ydEBpd2F5c29m"
+ + "dHdhcmUuY29tMIGYBggrBgEFBQcBAQSBizCBiDA5BggrBgEFBQcwAoYtaHR0"
+ + "cDovL2l3NTRjZW50LXZtMi9wa2kvcHViL2NhY2VydC9jYWNlcnQuY3J0MCUG"
+ + "CCsGAQUFBzABhhlodHRwOi8vaXc1NGNlbnQtdm0yOjI1NjAvMCQGCCsGAQUF"
+ + "BzAMhhhodHRwOi8vaXc1NGNlbnQtdm0yOjgzMC8wOgYDVR0fBDMwMTAvoC2g"
+ + "K4YpaHR0cDovL2l3NTRjZW50LXZtMi9wa2kvcHViL2NybC9jYWNybC5jcmww"
+ + "DQYJKoZIhvcNAQELBQADggEBAE9wBjQ1c+HAO2gIzT+J5Gqgrcu/m7t4hnHN"
+ + "m5eyIfwXD1T6wOhovFmzPTaO9BSNsi4G5R7yZxOHeLN4PIY2kwFIbSkg7mwe"
+ + "5aGp2RPIuK/MtzMZT6pq8uMGhzyHGsqtdkz7p26/G0anU2u59eimcvISdwNE"
+ + "QXOIp/KNUC+Vx+Pmfw8PuFYDNacZ6YXp5qKoEjyUoBhNicmVINTNfDu0CQhu"
+ + "pDr2UmDMDT2cdmTSRC0rcTe3BNzWqtsXNmIBFL1oB7B0PZbmFm8Bgvk1azxa"
+ + "ClrcOKZWKOWa14XJy/DJk6nlOiq5W2AglUt8JVOpa5oVdiNRIT2WoGnpqVV9"
+ + "tUeoWog=");
+
+ private static final String BC = "SC";
+
+ public String getName()
+ {
+ return "OCSP";
+ }
+
+ private void testECDSA()
+ throws Exception
+ {
+ String signDN = "O=Bouncy Castle, C=AU";
+ KeyPair signKP = OCSPTestUtil.makeECKeyPair();
+ X509CertificateHolder testCert = new JcaX509CertificateHolder(OCSPTestUtil.makeECDSACertificate(signKP, signDN, signKP, signDN));
+ DigestCalculatorProvider digCalcProv = new JcaDigestCalculatorProviderBuilder().setProvider(BC).build();
+
+ String origDN = "CN=Eric H. Echidna, E=eric@bouncycastle.org, O=Bouncy Castle, C=AU";
+ GeneralName origName = new GeneralName(new X509Name(origDN));
+
+ //
+ // general id value for our test issuer cert and a serial number.
+ //
+ CertificateID id = new CertificateID(digCalcProv.get(CertificateID.HASH_SHA1), testCert, BigInteger.valueOf(1));
+
+ //
+ // basic request generation
+ //
+ OCSPReqBuilder gen = new OCSPReqBuilder();
+ gen.addRequest(id);
+
+ OCSPReq req = gen.build();
+
+ if (req.isSigned())
+ {
+ fail("signed but shouldn't be");
+ }
+
+ X509CertificateHolder[] certs = req.getCerts();
+
+ if (certs.length != 0)
+ {
+ fail("0 certs expected, but not found");
+ }
+
+ Req[] requests = req.getRequestList();
+
+ if (!requests[0].getCertID().equals(id))
+ {
+ fail("Failed isFor test");
+ }
+
+ //
+ // request generation with signing
+ //
+ X509CertificateHolder[] chain = new X509CertificateHolder[1];
+
+ gen = new OCSPReqBuilder();
+
+ gen.setRequestorName(new GeneralName(GeneralName.directoryName, new X509Principal("CN=fred")));
+
+ gen.addRequest(
+ new CertificateID(digCalcProv.get(CertificateID.HASH_SHA1), testCert, BigInteger.valueOf(1)));
+
+ chain[0] = testCert;
+
+ req = gen.build(new JcaContentSignerBuilder("SHA1withECDSA").setProvider(BC).build( signKP.getPrivate()), chain);
+
+ if (!req.isSigned())
+ {
+ fail("not signed but should be");
+ }
+
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(signKP.getPublic())))
+ {
+ fail("signature failed to verify");
+ }
+
+ requests = req.getRequestList();
+
+ if (!requests[0].getCertID().equals(id))
+ {
+ fail("Failed isFor test");
+ }
+
+ certs = req.getCerts();
+
+ if (certs == null)
+ {
+ fail("null certs found");
+ }
+
+ if (certs.length != 1 || !certs[0].equals(testCert))
+ {
+ fail("incorrect certs found in request");
+ }
+
+ //
+ // encoding test
+ //
+ byte[] reqEnc = req.getEncoded();
+
+ OCSPReq newReq = new OCSPReq(reqEnc);
+
+ if (!newReq.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(signKP.getPublic())))
+ {
+ fail("newReq signature failed to verify");
+ }
+
+ //
+ // request generation with signing and nonce
+ //
+ chain = new X509CertificateHolder[1];
+
+ gen = new OCSPReqBuilder();
+
+ Vector oids = new Vector();
+ Vector values = new Vector();
+ byte[] sampleNonce = new byte[16];
+ Random rand = new Random();
+
+ rand.nextBytes(sampleNonce);
+
+ gen.setRequestorName(new GeneralName(GeneralName.directoryName, new X509Principal("CN=fred")));
+
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+
+ extGen.addExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false, new DEROctetString(sampleNonce));
+
+ gen.setRequestExtensions(extGen.generate());
+
+ gen.addRequest(
+ new CertificateID(digCalcProv.get(CertificateID.HASH_SHA1), testCert, BigInteger.valueOf(1)));
+
+ chain[0] = testCert;
+
+ req = gen.build(new JcaContentSignerBuilder("SHA1withECDSA").setProvider(BC).build(signKP.getPrivate()), chain);
+
+ if (!req.isSigned())
+ {
+ fail("not signed but should be");
+ }
+
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(signKP.getPublic())))
+ {
+ fail("signature failed to verify");
+ }
+
+ //
+ // extension check.
+ //
+ Set extOids = req.getCriticalExtensionOIDs();
+
+ if (extOids.size() != 0)
+ {
+ fail("wrong number of critical extensions in OCSP request.");
+ }
+
+ extOids = req.getNonCriticalExtensionOIDs();
+
+ if (extOids.size() != 1)
+ {
+ fail("wrong number of non-critical extensions in OCSP request.");
+ }
+
+ Extension extValue = req.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce);
+
+ ASN1Encodable extObj = extValue.getParsedValue();
+
+ if (!(extObj instanceof ASN1OctetString))
+ {
+ fail("wrong extension type found.");
+ }
+
+ if (!areEqual(((ASN1OctetString)extObj).getOctets(), sampleNonce))
+ {
+ fail("wrong extension value found.");
+ }
+
+ //
+ // request list check
+ //
+ requests = req.getRequestList();
+
+ if (!requests[0].getCertID().equals(id))
+ {
+ fail("Failed isFor test");
+ }
+
+ //
+ // response generation
+ //
+ BasicOCSPRespBuilder respGen = new JcaBasicOCSPRespBuilder(signKP.getPublic(), digCalcProv.get(RespID.HASH_SHA1));
+
+ respGen.addResponse(id, CertificateStatus.GOOD);
+
+ BasicOCSPResp resp = respGen.build(new JcaContentSignerBuilder("SHA1withECDSA").setProvider(BC).build(signKP.getPrivate()), chain, new Date());
+ }
+
+ private void testRSA()
+ throws Exception
+ {
+ String signDN = "O=Bouncy Castle, C=AU";
+ KeyPair signKP = OCSPTestUtil.makeKeyPair();
+ X509CertificateHolder testCert = new JcaX509CertificateHolder(OCSPTestUtil.makeCertificate(signKP, signDN, signKP, signDN));
+ DigestCalculatorProvider digCalcProv = new JcaDigestCalculatorProviderBuilder().setProvider(BC).build();
+
+ String origDN = "CN=Eric H. Echidna, E=eric@bouncycastle.org, O=Bouncy Castle, C=AU";
+ GeneralName origName = new GeneralName(new X509Name(origDN));
+
+ //
+ // general id value for our test issuer cert and a serial number.
+ //
+ CertificateID id = new CertificateID(digCalcProv.get(CertificateID.HASH_SHA1), testCert, BigInteger.valueOf(1));
+
+ //
+ // basic request generation
+ //
+ OCSPReqBuilder gen = new OCSPReqBuilder();
+
+ gen.addRequest(
+ new CertificateID(digCalcProv.get(CertificateID.HASH_SHA1), testCert, BigInteger.valueOf(1)));
+
+ OCSPReq req = gen.build();
+
+ if (req.isSigned())
+ {
+ fail("signed but shouldn't be");
+ }
+
+ X509CertificateHolder[] certs = req.getCerts();
+
+ if (certs.length != 0)
+ {
+ fail("0 certs expected, but not found");
+ }
+
+ Req[] requests = req.getRequestList();
+
+ if (!requests[0].getCertID().equals(id))
+ {
+ fail("Failed isFor test");
+ }
+
+ //
+ // request generation with signing
+ //
+ X509CertificateHolder[] chain = new X509CertificateHolder[1];
+
+ gen = new OCSPReqBuilder();
+
+ gen.setRequestorName(new GeneralName(GeneralName.directoryName, new X509Principal("CN=fred")));
+
+ gen.addRequest(
+ new CertificateID(digCalcProv.get(CertificateID.HASH_SHA1), testCert, BigInteger.valueOf(1)));
+
+ chain[0] = testCert;
+
+ req = gen.build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(signKP.getPrivate()), chain);
+
+ if (!req.isSigned())
+ {
+ fail("not signed but should be");
+ }
+
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(signKP.getPublic())))
+ {
+ fail("signature failed to verify");
+ }
+
+ requests = req.getRequestList();
+
+ if (!requests[0].getCertID().equals(id))
+ {
+ fail("Failed isFor test");
+ }
+
+ certs = req.getCerts();
+
+ if (certs == null)
+ {
+ fail("null certs found");
+ }
+
+ if (certs.length != 1 || !certs[0].equals(testCert))
+ {
+ fail("incorrect certs found in request");
+ }
+
+ //
+ // encoding test
+ //
+ byte[] reqEnc = req.getEncoded();
+
+ OCSPReq newReq = new OCSPReq(reqEnc);
+
+ if (!newReq.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(signKP.getPublic())))
+ {
+ fail("newReq signature failed to verify");
+ }
+
+ //
+ // request generation with signing and nonce
+ //
+ chain = new X509CertificateHolder[1];
+
+ gen = new OCSPReqBuilder();
+
+ byte[] sampleNonce = new byte[16];
+ Random rand = new Random();
+
+ rand.nextBytes(sampleNonce);
+
+ gen.setRequestorName(new GeneralName(GeneralName.directoryName, new X509Principal("CN=fred")));
+
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+
+ extGen.addExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false, new DEROctetString(sampleNonce));
+
+ gen.setRequestExtensions(extGen.generate());
+
+ gen.addRequest(
+ new CertificateID(digCalcProv.get(CertificateID.HASH_SHA1), testCert, BigInteger.valueOf(1)));
+
+ chain[0] = testCert;
+
+ req = gen.build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(signKP.getPrivate()), chain);
+
+ if (!req.isSigned())
+ {
+ fail("not signed but should be");
+ }
+
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(signKP.getPublic())))
+ {
+ fail("signature failed to verify");
+ }
+
+ //
+ // extension check.
+ //
+ Set extOids = req.getCriticalExtensionOIDs();
+
+ if (extOids.size() != 0)
+ {
+ fail("wrong number of critical extensions in OCSP request.");
+ }
+
+ extOids = req.getNonCriticalExtensionOIDs();
+
+ if (extOids.size() != 1)
+ {
+ fail("wrong number of non-critical extensions in OCSP request.");
+ }
+
+ Extension ext = req.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce);
+
+ ASN1Encodable extObj = ext.getParsedValue();
+
+ if (!(extObj instanceof ASN1OctetString))
+ {
+ fail("wrong extension type found.");
+ }
+
+ if (!areEqual(((ASN1OctetString)extObj).getOctets(), sampleNonce))
+ {
+ fail("wrong extension value found.");
+ }
+
+ //
+ // request list check
+ //
+ requests = req.getRequestList();
+
+ if (!requests[0].getCertID().equals(id))
+ {
+ fail("Failed isFor test");
+ }
+
+ //
+ // response generation
+ //
+ BasicOCSPRespBuilder respGen = new JcaBasicOCSPRespBuilder(signKP.getPublic(), digCalcProv.get(RespID.HASH_SHA1));
+
+ respGen.addResponse(id, CertificateStatus.GOOD);
+
+ BasicOCSPResp resp = respGen.build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(signKP.getPrivate()), chain, new Date());
+ OCSPRespBuilder rGen = new OCSPRespBuilder();
+
+ byte[] enc = rGen.build(OCSPRespBuilder.SUCCESSFUL, resp).getEncoded();
+ }
+
+ private void testIrregularVersionReq()
+ throws Exception
+ {
+ OCSPReq ocspRequest = new OCSPReq(irregReq);
+ X509CertificateHolder cert = ocspRequest.getCerts()[0];
+ if (!ocspRequest.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(cert)))
+ {
+ fail("extra version encoding test failed");
+ }
+ }
+
+ public void testInvalidResp()
+ throws Exception
+ {
+ try
+ {
+ OCSPResp response = new OCSPResp(invalidResp);
+ }
+ catch (CertIOException e)
+ {
+ if (e.getCause() instanceof ASN1Exception)
+ {
+ Throwable c = ((ASN1Exception)e.getCause()).getCause();
+
+ if (!c.getMessage().equals("ENUMERATED has zero length"))
+ {
+ fail("parsing failed, but for wrong reason: " + c.getMessage());
+ }
+ }
+ else
+ {
+ fail("parsing failed, but for wrong reason: " + e.getMessage());
+ }
+ }
+
+
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ String signDN = "O=Bouncy Castle, C=AU";
+ KeyPair signKP = OCSPTestUtil.makeKeyPair();
+ X509CertificateHolder testCert = new JcaX509CertificateHolder(OCSPTestUtil.makeCertificate(signKP, signDN, signKP, signDN));
+
+ String origDN = "CN=Eric H. Echidna, E=eric@bouncycastle.org, O=Bouncy Castle, C=AU";
+ GeneralName origName = new GeneralName(new X509Name(origDN));
+ DigestCalculatorProvider digCalcProv = new JcaDigestCalculatorProviderBuilder().setProvider(BC).build();
+
+ //
+ // general id value for our test issuer cert and a serial number.
+ //
+ CertificateID id = new CertificateID(digCalcProv.get(CertificateID.HASH_SHA1), testCert, BigInteger.valueOf(1));
+
+ //
+ // basic request generation
+ //
+ OCSPReqBuilder gen = new OCSPReqBuilder();
+
+ gen.addRequest(
+ new CertificateID(digCalcProv.get(CertificateID.HASH_SHA1), testCert, BigInteger.valueOf(1)));
+
+ OCSPReq req = gen.build();
+
+ if (req.isSigned())
+ {
+ fail("signed but shouldn't be");
+ }
+
+ X509CertificateHolder[] certs = req.getCerts();
+
+ if (certs.length != 0)
+ {
+ fail("0 certs expected, but not found");
+ }
+
+ Req[] requests = req.getRequestList();
+
+ if (!requests[0].getCertID().equals(id))
+ {
+ fail("Failed isFor test");
+ }
+
+ //
+ // request generation with signing
+ //
+ X509CertificateHolder[] chain = new X509CertificateHolder[1];
+
+ gen = new OCSPReqBuilder();
+
+ gen.setRequestorName(new GeneralName(GeneralName.directoryName, new X509Principal("CN=fred")));
+
+ gen.addRequest(
+ new CertificateID(digCalcProv.get(CertificateID.HASH_SHA1), testCert, BigInteger.valueOf(1)));
+
+ chain[0] = testCert;
+
+ req = gen.build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(signKP.getPrivate()), chain);
+
+ if (!req.isSigned())
+ {
+ fail("not signed but should be");
+ }
+
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(signKP.getPublic())))
+ {
+ fail("signature failed to verify");
+ }
+
+ requests = req.getRequestList();
+
+ if (!requests[0].getCertID().equals(id))
+ {
+ fail("Failed isFor test");
+ }
+
+ certs = req.getCerts();
+
+ if (certs == null)
+ {
+ fail("null certs found");
+ }
+
+ if (certs.length != 1 || !certs[0].equals(testCert))
+ {
+ fail("incorrect certs found in request");
+ }
+
+ //
+ // encoding test
+ //
+ byte[] reqEnc = req.getEncoded();
+
+ OCSPReq newReq = new OCSPReq(reqEnc);
+
+ if (!newReq.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(signKP.getPublic())))
+ {
+ fail("newReq signature failed to verify");
+ }
+
+ //
+ // request generation with signing and nonce
+ //
+ chain = new X509CertificateHolder[1];
+
+ gen = new OCSPReqBuilder();
+
+ Vector oids = new Vector();
+ Vector values = new Vector();
+ byte[] sampleNonce = new byte[16];
+ Random rand = new Random();
+
+ rand.nextBytes(sampleNonce);
+
+ gen.setRequestorName(new GeneralName(GeneralName.directoryName, new X509Principal("CN=fred")));
+
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+
+ extGen.addExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false, new DEROctetString(sampleNonce));
+
+ gen.setRequestExtensions(extGen.generate());
+
+ gen.addRequest(
+ new CertificateID(digCalcProv.get(CertificateID.HASH_SHA1), testCert, BigInteger.valueOf(1)));
+
+ chain[0] = testCert;
+
+ req = gen.build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(signKP.getPrivate()), chain);
+
+ if (!req.isSigned())
+ {
+ fail("not signed but should be");
+ }
+
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(signKP.getPublic())))
+ {
+ fail("signature failed to verify");
+ }
+
+ //
+ // extension check.
+ //
+ Set extOids = req.getCriticalExtensionOIDs();
+
+ if (extOids.size() != 0)
+ {
+ fail("wrong number of critical extensions in OCSP request.");
+ }
+
+ extOids = req.getNonCriticalExtensionOIDs();
+
+ if (extOids.size() != 1)
+ {
+ fail("wrong number of non-critical extensions in OCSP request.");
+ }
+
+ Extension ext = req.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce);
+
+ ASN1Encodable extObj = ext.getParsedValue();
+
+ if (!(extObj instanceof ASN1OctetString))
+ {
+ fail("wrong extension type found.");
+ }
+
+ if (!areEqual(((ASN1OctetString)extObj).getOctets(), sampleNonce))
+ {
+ fail("wrong extension value found.");
+ }
+
+ //
+ // request list check
+ //
+ requests = req.getRequestList();
+
+ if (!requests[0].getCertID().equals(id))
+ {
+ fail("Failed isFor test");
+ }
+
+ //
+ // response parsing - test 1
+ //
+ OCSPResp response = new OCSPResp(testResp1);
+
+ if (response.getStatus() != 0)
+ {
+ fail("response status not zero.");
+ }
+
+ BasicOCSPResp brep = (BasicOCSPResp)response.getResponseObject();
+ chain = brep.getCerts();
+
+ if (!brep.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(chain[0])))
+ {
+ fail("response 1 failed to verify.");
+ }
+
+ //
+ // test 2
+ //
+ SingleResp[] singleResp = brep.getResponses();
+
+ response = new OCSPResp(testResp2);
+
+ if (response.getStatus() != 0)
+ {
+ fail("response status not zero.");
+ }
+
+ brep = (BasicOCSPResp)response.getResponseObject();
+ chain = brep.getCerts();
+
+ if (!brep.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(chain[0])))
+ {
+ fail("response 2 failed to verify.");
+ }
+
+ singleResp = brep.getResponses();
+
+ //
+ // simple response generation
+ //
+ OCSPRespBuilder respGen = new OCSPRespBuilder();
+ OCSPResp resp = respGen.build(OCSPRespBuilder.SUCCESSFUL, response.getResponseObject());
+
+ if (!resp.getResponseObject().equals(response.getResponseObject()))
+ {
+ fail("response fails to match");
+ }
+
+ testECDSA();
+ testRSA();
+ testIrregularVersionReq();
+ testInvalidResp();
+
+ //
+ // Empty data test
+ //
+ try
+ {
+ response = new OCSPResp(new byte[0]);
+ fail("no exception thrown");
+ }
+ catch (IOException e)
+ {
+ if (!e.getMessage().equals("malformed response: no response data found"))
+ {
+ fail("wrong exception");
+ }
+ }
+
+ try
+ {
+ req = new OCSPReq(new byte[0]);
+ fail("no exception thrown");
+ }
+ catch (IOException e)
+ {
+ if (!e.getMessage().equals("malformed request: no request data found"))
+ {
+ fail("wrong exception");
+ }
+ }
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new OCSPTest());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/path/test/CertPathTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/path/test/CertPathTest.java
new file mode 100644
index 000000000..d166d9359
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/path/test/CertPathTest.java
@@ -0,0 +1,369 @@
+package org.spongycastle.cert.path.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectOutputStream;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.SignatureException;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathBuilder;
+import java.security.cert.CertPathBuilderException;
+import java.security.cert.CertPathBuilderResult;
+import java.security.cert.CertStore;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CollectionCertStoreParameters;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.Vector;
+
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.test.SimpleTest;
+
+public class CertPathTest
+ extends SimpleTest
+{
+ public static byte[] rootCertBin = Base64.decode(
+ "MIIBqzCCARQCAQEwDQYJKoZIhvcNAQEFBQAwHjEcMBoGA1UEAxMTVGVzdCBDQSBDZXJ0aWZpY2F0ZTAeFw0wODA5MDQwNDQ1MDhaFw0wODA5MTEwNDQ1MDhaMB4xHDAaBgNVBAMTE1Rlc3QgQ0EgQ2VydGlmaWNhdGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMRLUjhPe4YUdLo6EcjKcWUOG7CydFTH53Pr1lWjOkbmszYDpkhCTT9LOsI+disk18nkBxSl8DAHTqV+VxtuTPt64iyi10YxyDeep+DwZG/f8cVQv97U3hA9cLurZ2CofkMLGr6JpSGCMZ9FcstcTdHB4lbErIJ54YqfF4pNOs4/AgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAgyrTEFY7ALpeY59jL6xFOLpuPqoBOWrUWv6O+zy5BCU0qiX71r3BpigtxRj+DYcfLIM9FNERDoHu3TthD3nwYWUBtFX8N0QUJIdJabxqAMhLjSC744koiFpCYse5Ye3ZvEdFwDzgAQsJTp5eFGgTZPkPzcdhkFJ2p9+OWs+cb24=");
+
+
+ static byte[] interCertBin = Base64.decode(
+ "MIICSzCCAbSgAwIBAgIBATANBgkqhkiG9w0BAQUFADAeMRwwGgYDVQQDExNUZXN0IENBIENlcnRpZmljYXRlMB4XDTA4MDkwNDA0NDUwOFoXDTA4MDkxMTA0NDUwOFowKDEmMCQGA1UEAxMdVGVzdCBJbnRlcm1lZGlhdGUgQ2VydGlmaWNhdGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAISS9OOZ2wxzdWny9aVvk4Joq+dwSJ+oqvHUxX3PflZyuiLiCBUOUE4q59dGKdtNX5fIfwyK3cpV0e73Y/0fwfM3m9rOWFrCKOhfeswNTes0w/2PqPVVDDsF/nj7NApuqXwioeQlgTL251RDF4sVoxXqAU7lRkcqwZt3mwqS4KTJAgMBAAGjgY4wgYswRgYDVR0jBD8wPYAUhv8BOT27EB9JaCccJD4YASPP5XWhIqQgMB4xHDAaBgNVBAMTE1Rlc3QgQ0EgQ2VydGlmaWNhdGWCAQEwHQYDVR0OBBYEFL/IwAGOkHzaQyPZegy79CwM5oTFMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4GBAE4TRgUz4sUvZyVdZxqV+XyNRnqXAeLOOqFGYv2D96tQrS+zjd0elVlT6lFrtchZdOmmX7R6/H/tjMWMcTBICZyRYrvK8cCAmDOI+EIdq5p6lj2Oq6Pbw/wruojAqNrpaR6IkwNpWtdOSSupv4IJL+YU9q2YFTh4R1j3tOkPoFGr");
+
+ static byte[] finalCertBin = Base64.decode(
+ "MIICRjCCAa+gAwIBAgIBATANBgkqhkiG9w0BAQUFADAoMSYwJAYDVQQDEx1UZXN0IEludGVybWVkaWF0ZSBDZXJ0aWZpY2F0ZTAeFw0wODA5MDQwNDQ1MDhaFw0wODA5MTEwNDQ1MDhaMB8xHTAbBgNVBAMTFFRlc3QgRW5kIENlcnRpZmljYXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChpUeo0tPYywWKiLlbWKNJBcCpSaLSlaZ+4+yer1AxI5yJIVHP6SAlBghlbD5Qne5ImnN/15cz1xwYAiul6vGKJkVPlFEe2Mr+g/J/WJPQQPsjbZ1G+vxbAwXEDA4KaQrnpjRZFq+CdKHwOjuPLYS/MYQNgdIvDVEQcTbPQ8GaiQIDAQABo4GIMIGFMEYGA1UdIwQ/MD2AFL/IwAGOkHzaQyPZegy79CwM5oTFoSKkIDAeMRwwGgYDVQQDExNUZXN0IENBIENlcnRpZmljYXRlggEBMB0GA1UdDgQWBBSVkw+VpqBf3zsLc/9GdkK9TzHPwDAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIFoDANBgkqhkiG9w0BAQUFAAOBgQBLv/0bVDjzTs/y1vN3FUiZNknEbzupIZduTuXJjqv/vBX+LDPjUfu/+iOCXOSKoRn6nlOWhwB1z6taG2usQkFG8InMkRcPREi2uVgFdhJ/1C3dAWhsdlubjdL926bftXvxnx/koDzyrePW5U96RlOQM2qLvbaky2Giz6hrc3Wl+w==");
+ public static byte[] rootCrlBin = Base64.decode(
+ "MIIBYjCBzAIBATANBgkqhkiG9w0BAQsFADAeMRwwGgYDVQQDExNUZXN0IENBIENlcnRpZmljYXRlFw0wODA5MDQwNDQ1MDhaFw0wODA5MDQwNzMxNDhaMCIwIAIBAhcNMDgwOTA0MDQ0NTA4WjAMMAoGA1UdFQQDCgEJoFYwVDBGBgNVHSMEPzA9gBSG/wE5PbsQH0loJxwkPhgBI8/ldaEipCAwHjEcMBoGA1UEAxMTVGVzdCBDQSBDZXJ0aWZpY2F0ZYIBATAKBgNVHRQEAwIBATANBgkqhkiG9w0BAQsFAAOBgQCAbaFCo0BNG4AktVf6jjBLeawP1u0ELYkOCEGvYZE0mBpQ+OvFg7subZ6r3lRIj030nUli28sPFtu5ZQMBNcpE4nS1ziF44RfT3Lp5UgHx9x17Krz781iEyV+7zU8YxYMY9wULD+DCuK294kGKIssVNbmTYXZatBNoXQN5CLIocA==");
+ static byte[] interCrlBin = Base64.decode(
+ "MIIBbDCB1gIBATANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQDEx1UZXN0IEludGVybWVkaWF0ZSBDZXJ0aWZpY2F0ZRcNMDgwOTA0MDQ0NTA4WhcNMDgwOTA0MDczMTQ4WjAiMCACAQIXDTA4MDkwNDA0NDUwOFowDDAKBgNVHRUEAwoBCaBWMFQwRgYDVR0jBD8wPYAUv8jAAY6QfNpDI9l6DLv0LAzmhMWhIqQgMB4xHDAaBgNVBAMTE1Rlc3QgQ0EgQ2VydGlmaWNhdGWCAQEwCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQADgYEAEVCr5TKs5yguGgLH+dBzmSPoeSIWJFLsgWwJEit/iUDJH3dgYmaczOcGxIDtbYYHLWIHM+P2YRyQz3MEkCXEgm/cx4y7leAmux5l+xQWgmxFPz+197vaphPeCZo+B7V1CWtm518gcq4mrs9ovfgNqgyFj7KGjcBpWdJE32KMt50=");
+
+ /*
+ * certpath with a circular reference
+ */
+ static byte[] certA = Base64.decode(
+ "MIIC6jCCAlOgAwIBAgIBBTANBgkqhkiG9w0BAQUFADCBjTEPMA0GA1UEAxMGSW50"
+ + "ZXIzMQswCQYDVQQGEwJDSDEPMA0GA1UEBxMGWnVyaWNoMQswCQYDVQQIEwJaSDEX"
+ + "MBUGA1UEChMOUHJpdmFzcGhlcmUgQUcxEDAOBgNVBAsTB1Rlc3RpbmcxJDAiBgkq"
+ + "hkiG9w0BCQEWFWFybWluQHByaXZhc3BoZXJlLmNvbTAeFw0wNzA0MDIwODQ2NTda"
+ + "Fw0xNzAzMzAwODQ0MDBaMIGlMScwJQYDVQQDHh4AQQByAG0AaQBuACAASADkAGIA"
+ + "ZQByAGwAaQBuAGcxCzAJBgNVBAYTAkNIMQ8wDQYDVQQHEwZadXJpY2gxCzAJBgNV"
+ + "BAgTAlpIMRcwFQYDVQQKEw5Qcml2YXNwaGVyZSBBRzEQMA4GA1UECxMHVGVzdGlu"
+ + "ZzEkMCIGCSqGSIb3DQEJARYVYXJtaW5AcHJpdmFzcGhlcmUuY29tMIGfMA0GCSqG"
+ + "SIb3DQEBAQUAA4GNADCBiQKBgQCfHfyVs5dbxG35H/Thd29qR4NZU88taCu/OWA1"
+ + "GdACI02lXWYpmLWiDgnU0ULP+GG8OnVp1IES9fz2zcrXKQ19xZzsen/To3h5sNte"
+ + "cJpS00XMM24q/jDwy5NvkBP9YIfFKQ1E/0hFHXcqwlw+b/y/v6YGsZCU2h6QDzc4"
+ + "5m0+BwIDAQABo0AwPjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIE8DAeBglg"
+ + "hkgBhvhCAQ0EERYPeGNhIGNlcnRpZmljYXRlMA0GCSqGSIb3DQEBBQUAA4GBAJEu"
+ + "KiSfIwsY7SfobMLrv2v/BtLhGLi4RnmjiwzBhuv5rn4rRfBpq1ppmqQMJ2pmA67v"
+ + "UWCY+mNwuyjHyivpCCyJGsZ9d5H09g2vqxzkDBMz7X9VNMZYFH8j/R3/Cfvqks31"
+ + "z0OFslJkeKLa1I0P/dfVHsRKNkLRT3Ws5LKksErQ");
+
+ static byte[] certB = Base64.decode(
+ "MIICtTCCAh6gAwIBAgIBBDANBgkqhkiG9w0BAQQFADCBjTEPMA0GA1UEAxMGSW50"
+ + "ZXIyMQswCQYDVQQGEwJDSDEPMA0GA1UEBxMGWnVyaWNoMQswCQYDVQQIEwJaSDEX"
+ + "MBUGA1UEChMOUHJpdmFzcGhlcmUgQUcxEDAOBgNVBAsTB1Rlc3RpbmcxJDAiBgkq"
+ + "hkiG9w0BCQEWFWFybWluQHByaXZhc3BoZXJlLmNvbTAeFw0wNzA0MDIwODQ2Mzha"
+ + "Fw0xNzAzMzAwODQ0MDBaMIGNMQ8wDQYDVQQDEwZJbnRlcjMxCzAJBgNVBAYTAkNI"
+ + "MQ8wDQYDVQQHEwZadXJpY2gxCzAJBgNVBAgTAlpIMRcwFQYDVQQKEw5Qcml2YXNw"
+ + "aGVyZSBBRzEQMA4GA1UECxMHVGVzdGluZzEkMCIGCSqGSIb3DQEJARYVYXJtaW5A"
+ + "cHJpdmFzcGhlcmUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxCXIB"
+ + "QRnmVvl2h7Q+0SsRxDLnyM1dJG9jMa+UCCmHy0k/ZHs5VirSbjEJSjkQ9BGeh9SC"
+ + "7JwbMpXO7UE+gcVc2RnWUY+MA+fWIeTV4KtkYA8WPu8wVGCXbN8wwh/StOocszxb"
+ + "g+iLvGeh8CYSRqg6QN3S/02etH3o8H4e7Z0PZwIDAQABoyMwITAPBgNVHRMBAf8E"
+ + "BTADAQH/MA4GA1UdDwEB/wQEAwIB9jANBgkqhkiG9w0BAQQFAAOBgQCtWdirSsmt"
+ + "+CBBCNn6ZnbU3QqQfiiQIomjenNEHESJgaS/+PvPE5i3xWFXsunTHLW321/Km16I"
+ + "7+ZvT8Su1cqHg79NAT8QB0yke1saKSy2C0Pic4HwrNqVBWFNSxMU0hQzpx/ZXDbZ"
+ + "DqIXAp5EfyRYBy2ul+jm6Rot6aFgzuopKg==");
+
+ static byte[] certC = Base64.decode(
+ "MIICtTCCAh6gAwIBAgIBAjANBgkqhkiG9w0BAQQFADCBjTEPMA0GA1UEAxMGSW50"
+ + "ZXIxMQswCQYDVQQGEwJDSDEPMA0GA1UEBxMGWnVyaWNoMQswCQYDVQQIEwJaSDEX"
+ + "MBUGA1UEChMOUHJpdmFzcGhlcmUgQUcxEDAOBgNVBAsTB1Rlc3RpbmcxJDAiBgkq"
+ + "hkiG9w0BCQEWFWFybWluQHByaXZhc3BoZXJlLmNvbTAeFw0wNzA0MDIwODQ0Mzla"
+ + "Fw0xNzAzMzAwODQ0MDBaMIGNMQ8wDQYDVQQDEwZJbnRlcjIxCzAJBgNVBAYTAkNI"
+ + "MQ8wDQYDVQQHEwZadXJpY2gxCzAJBgNVBAgTAlpIMRcwFQYDVQQKEw5Qcml2YXNw"
+ + "aGVyZSBBRzEQMA4GA1UECxMHVGVzdGluZzEkMCIGCSqGSIb3DQEJARYVYXJtaW5A"
+ + "cHJpdmFzcGhlcmUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD0rLr6"
+ + "f2/ONeJzTb0q9M/NNX+MnAFMSqiQGVBkT76u5nOH4KLkpHXkzI82JI7GuQMzoT3a"
+ + "+RP1hO6FneO92ms2soC6xiOFb4EC69Dfhh87Nww5O35JxVF0bzmbmIAWd6P/7zGh"
+ + "nd2S4tKkaZcubps+C0j9Fgi0hipVicAOUVVoDQIDAQABoyMwITAPBgNVHRMBAf8E"
+ + "BTADAQH/MA4GA1UdDwEB/wQEAwIB9jANBgkqhkiG9w0BAQQFAAOBgQCLPvc1IMA4"
+ + "YP+PmnEldyUoRWRnvPWjBGeu0WheBP7fdcnGBf93Nmc5j68ZN+eTZ5VMuZ99YdvH"
+ + "CXGNX6oodONLU//LlFKdLl5xjLAS5X9p1RbOEGytnalqeiEpjk4+C/7rIBG1kllO"
+ + "dItmI6LlEMV09Hkpg6ZRAUmRkb8KrM4X7A==");
+
+ static byte[] certD = Base64.decode(
+ "MIICtTCCAh6gAwIBAgIBBjANBgkqhkiG9w0BAQQFADCBjTEPMA0GA1UEAxMGSW50"
+ + "ZXIzMQswCQYDVQQGEwJDSDEPMA0GA1UEBxMGWnVyaWNoMQswCQYDVQQIEwJaSDEX"
+ + "MBUGA1UEChMOUHJpdmFzcGhlcmUgQUcxEDAOBgNVBAsTB1Rlc3RpbmcxJDAiBgkq"
+ + "hkiG9w0BCQEWFWFybWluQHByaXZhc3BoZXJlLmNvbTAeFw0wNzA0MDIwODQ5NTNa"
+ + "Fw0xNzAzMzAwODQ0MDBaMIGNMQ8wDQYDVQQDEwZJbnRlcjExCzAJBgNVBAYTAkNI"
+ + "MQ8wDQYDVQQHEwZadXJpY2gxCzAJBgNVBAgTAlpIMRcwFQYDVQQKEw5Qcml2YXNw"
+ + "aGVyZSBBRzEQMA4GA1UECxMHVGVzdGluZzEkMCIGCSqGSIb3DQEJARYVYXJtaW5A"
+ + "cHJpdmFzcGhlcmUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCae3TP"
+ + "jIVKeASqvNabaiUHAMGUgFxB7L0yUsIj39azLcLtUj4S7XkDf7SMGtYV0JY1XNaQ"
+ + "sHJAsnJivDZc50oiYvqDYfgFZx5+AsN5l5X5rjRzs/OX+Jo+k1OgsIyu6+mf9Kfb"
+ + "5IdWOVB2EcOg4f9tPjLM8CIj9Pp7RbKLyqUUgwIDAQABoyMwITAPBgNVHRMBAf8E"
+ + "BTADAQH/MA4GA1UdDwEB/wQEAwIB9jANBgkqhkiG9w0BAQQFAAOBgQCgr9kUdWUT"
+ + "Lt9UcztSzR3pnHRsyvS0E/z850OKQKS5/VxLEalpFvhj+3EcZ7Y6mFxaaS2B7vXg"
+ + "2YWyqV1PRb6iF7/u9EXkpSTKGrJahwANirCa3V/HTUuPdCE2GITlnWI8h3eVA+xQ"
+ + "D4LF0PXHOkXbwmhXRSb10lW1bSGkUxE9jg==");
+
+ private void testExceptions()
+ throws Exception
+ {
+ byte[] enc = { (byte)0, (byte)2, (byte)3, (byte)4, (byte)5 };
+ MyCertPath mc = new MyCertPath(enc);
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ ByteArrayInputStream is;
+ byte[] arr;
+
+ ObjectOutputStream oOut = new ObjectOutputStream(os);
+ oOut.writeObject(mc);
+ oOut.flush();
+ oOut.close();
+
+ try
+ {
+ CertificateFactory cFac = CertificateFactory.getInstance("X.509",
+ "SC");
+ arr = os.toByteArray();
+ is = new ByteArrayInputStream(arr);
+ cFac.generateCertPath(is);
+ }
+ catch (CertificateException e)
+ {
+ // ignore okay
+ }
+
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ List certCol = new ArrayList();
+
+ certCol.add(cf.generateCertificate(new ByteArrayInputStream(certA)));
+ certCol.add(cf.generateCertificate(new ByteArrayInputStream(certB)));
+ certCol.add(cf.generateCertificate(new ByteArrayInputStream(certC)));
+ certCol.add(cf.generateCertificate(new ByteArrayInputStream(certD)));
+
+ CertPathBuilder pathBuilder = CertPathBuilder.getInstance("PKIX", "SC");
+ X509CertSelector select = new X509CertSelector();
+ select.setSubject(((X509Certificate)certCol.get(0)).getSubjectX500Principal().getEncoded());
+
+ Set trustanchors = new HashSet();
+ trustanchors.add(new TrustAnchor((X509Certificate)cf.generateCertificate(new ByteArrayInputStream(rootCertBin)), null));
+
+ CertStore certStore = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certCol));
+
+ PKIXBuilderParameters params = new PKIXBuilderParameters(trustanchors, select);
+ params.addCertStore(certStore);
+
+ try
+ {
+ CertPathBuilderResult result = pathBuilder.build(params);
+ CertPath path = result.getCertPath();
+ fail("found cert path in circular set");
+ }
+ catch (CertPathBuilderException e)
+ {
+ // expected
+ }
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509", "SC");
+
+ X509Certificate rootCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(rootCertBin));
+ X509Certificate interCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(interCertBin));
+ X509Certificate finalCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(finalCertBin));
+
+ //Testing CertPath generation from List
+ List list = new ArrayList();
+ list.add(interCert);
+ CertPath certPath1 = cf.generateCertPath(list);
+
+ //Testing CertPath encoding as PkiPath
+ byte[] encoded = certPath1.getEncoded("PkiPath");
+
+ //Testing CertPath generation from InputStream
+ ByteArrayInputStream inStream = new ByteArrayInputStream(encoded);
+ CertPath certPath2 = cf.generateCertPath(inStream, "PkiPath");
+
+ //Comparing both CertPathes
+ if (!certPath2.equals(certPath1))
+ {
+ fail("CertPath differ after encoding and decoding.");
+ }
+
+ encoded = certPath1.getEncoded("PKCS7");
+
+ //Testing CertPath generation from InputStream
+ inStream = new ByteArrayInputStream(encoded);
+ certPath2 = cf.generateCertPath(inStream, "PKCS7");
+
+ //Comparing both CertPathes
+ if (!certPath2.equals(certPath1))
+ {
+ fail("CertPath differ after encoding and decoding.");
+ }
+
+ encoded = certPath1.getEncoded("PEM");
+
+ //Testing CertPath generation from InputStream
+ inStream = new ByteArrayInputStream(encoded);
+ certPath2 = cf.generateCertPath(inStream, "PEM");
+
+ //Comparing both CertPathes
+ if (!certPath2.equals(certPath1))
+ {
+ fail("CertPath differ after encoding and decoding.");
+ }
+
+ //
+ // empty list test
+ //
+ list = new ArrayList();
+
+ CertPath certPath = CertificateFactory.getInstance("X.509","SC").generateCertPath(list);
+ if (certPath.getCertificates().size() != 0)
+ {
+ fail("list wrong size.");
+ }
+
+ //
+ // exception tests
+ //
+ testExceptions();
+ }
+
+ public String getName()
+ {
+ return "CertPath";
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new CertPathTest());
+ }
+
+ private static class MyCertificate extends Certificate
+ {
+ private final byte[] encoding;
+
+ public MyCertificate(String type, byte[] encoding)
+ {
+ super(type);
+ // don't copy to allow null parameter in test
+ this.encoding = encoding;
+ }
+
+ public byte[] getEncoded() throws CertificateEncodingException
+ {
+ // do copy to force NPE in test
+ return (byte[])encoding.clone();
+ }
+
+ public void verify(PublicKey key) throws CertificateException,
+ NoSuchAlgorithmException, InvalidKeyException,
+ NoSuchProviderException, SignatureException
+ {
+ }
+
+ public void verify(PublicKey key, String sigProvider)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException,
+ SignatureException
+ {
+ }
+
+ public String toString()
+ {
+ return "[My test Certificate, type: " + getType() + "]";
+ }
+
+ public PublicKey getPublicKey()
+ {
+ return new PublicKey()
+ {
+ public String getAlgorithm()
+ {
+ return "TEST";
+ }
+
+ public byte[] getEncoded()
+ {
+ return new byte[] { (byte)1, (byte)2, (byte)3 };
+ }
+
+ public String getFormat()
+ {
+ return "TEST_FORMAT";
+ }
+ };
+ }
+ }
+
+ private static class MyCertPath extends CertPath
+ {
+ private final Vector certificates;
+
+ private final Vector encodingNames;
+
+ private final byte[] encoding;
+
+ public MyCertPath(byte[] encoding)
+ {
+ super("MyEncoding");
+ this.encoding = encoding;
+ certificates = new Vector();
+ certificates.add(new MyCertificate("MyEncoding", encoding));
+ encodingNames = new Vector();
+ encodingNames.add("MyEncoding");
+ }
+
+ public List getCertificates()
+ {
+ return Collections.unmodifiableList(certificates);
+ }
+
+ public byte[] getEncoded() throws CertificateEncodingException
+ {
+ return (byte[])encoding.clone();
+ }
+
+ public byte[] getEncoded(String encoding)
+ throws CertificateEncodingException
+ {
+ if (getType().equals(encoding))
+ {
+ return (byte[])this.encoding.clone();
+ }
+ throw new CertificateEncodingException("Encoding not supported: "
+ + encoding);
+ }
+
+ public Iterator getEncodings()
+ {
+ return Collections.unmodifiableCollection(encodingNames).iterator();
+ }
+ }
+}
+
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/path/test/CertPathValidationTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/path/test/CertPathValidationTest.java
new file mode 100644
index 000000000..b168342c6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/path/test/CertPathValidationTest.java
@@ -0,0 +1,403 @@
+package org.spongycastle.cert.path.test;
+
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.cert.X509CRLHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509ContentVerifierProviderBuilder;
+import org.spongycastle.cert.jcajce.JcaX509ContentVerifierProviderBuilder;
+import org.spongycastle.cert.path.CertPath;
+import org.spongycastle.cert.path.CertPathValidation;
+import org.spongycastle.cert.path.CertPathValidationResult;
+import org.spongycastle.cert.path.validations.BasicConstraintsValidation;
+import org.spongycastle.cert.path.validations.CRLValidation;
+import org.spongycastle.cert.path.validations.KeyUsageValidation;
+import org.spongycastle.cert.path.validations.ParentCertIssuedValidation;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.CollectionStore;
+import org.spongycastle.util.Store;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.test.SimpleTest;
+
+public class CertPathValidationTest
+ extends SimpleTest
+{
+ private byte[] AC_PR = Base64.decode(
+ "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlFU1RDQ0F6R2dBd0lC"
+ + "QWdJQkJUQU5CZ2txaGtpRzl3MEJBUVVGQURDQnRERUxNQWtHQTFVRUJoTUNR"
+ + "bEl4DQpFekFSQmdOVkJBb1RDa2xEVUMxQ2NtRnphV3d4UFRBN0JnTlZCQXNU"
+ + "TkVsdWMzUnBkSFYwYnlCT1lXTnBiMjVoDQpiQ0JrWlNCVVpXTnViMnh2WjJs"
+ + "aElHUmhJRWx1Wm05eWJXRmpZVzhnTFNCSlZFa3hFVEFQQmdOVkJBY1RDRUp5"
+ + "DQpZWE5wYkdsaE1Rc3dDUVlEVlFRSUV3SkVSakV4TUM4R0ExVUVBeE1vUVhW"
+ + "MGIzSnBaR0ZrWlNCRFpYSjBhV1pwDQpZMkZrYjNKaElGSmhhWG9nUW5KaGMy"
+ + "bHNaV2x5WVRBZUZ3MHdNakEwTURReE9UTTVNREJhRncwd05UQTBNRFF5DQpN"
+ + "elU1TURCYU1HRXhDekFKQmdOVkJBWVRBa0pTTVJNd0VRWURWUVFLRXdwSlEx"
+ + "QXRRbkpoYzJsc01UMHdPd1lEDQpWUVFERXpSQmRYUnZjbWxrWVdSbElFTmxj"
+ + "blJwWm1sallXUnZjbUVnWkdFZ1VISmxjMmxrWlc1amFXRWdaR0VnDQpVbVZ3"
+ + "ZFdKc2FXTmhNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJD"
+ + "Z0tDQVFFQXMwc0t5NGsrDQp6b016aldyMTQxeTVYQ045UGJMZERFQXN2cjZ4"
+ + "Z0NCN1l5bEhIQ1NBYmpGR3dOQ0R5NlVxN1h0VjZ6UHdIMXpGDQpFWENlS3Jm"
+ + "UUl5YXBXSEZ4V1VKajBMblFrY1RZM1FOR1huK0JuVk9EVTZDV3M1c3NoZktH"
+ + "RXZyVlQ1Z214V1NmDQp4OFlsdDgzY1dwUE1QZzg3VDlCaHVIbHQzazh2M2Ev"
+ + "NmRPbmF2dytOYTAyZExBaDBlNzZqcCtQUS9LK0pHZlBuDQphQjVVWURrZkd0"
+ + "em5uTTNBV01tY3VJK0o0ek5OMDZaa3ZnbDFsdEo2UU1qcnZEUFlSak9ndDlT"
+ + "cklpY1NmbEo4DQptVDdHWGRRaXJnQUNXc3g1QURBSklRK253TU1vNHlyTUtx"
+ + "SlFhNFFDMHhhT0QvdkdVcG9SaDQzT0FTZFp3c3YvDQpPWFlybmVJeVAwVCs4"
+ + "UUlEQVFBQm80RzNNSUcwTUQwR0ExVWRId1EyTURRd01xQXdvQzZHTEdoMGRI"
+ + "QTZMeTloDQpZM0poYVhvdWFXTndZbkpoYzJsc0xtZHZkaTVpY2k5TVExSmhZ"
+ + "M0poYVhvdVkzSnNNQklHQTFVZElBUUxNQWt3DQpCd1lGWUV3QkFRRXdIUVlE"
+ + "VlIwT0JCWUVGREpUVFlKNE9TWVB5T09KZkVMZXhDaHppK2hiTUI4R0ExVWRJ"
+ + "d1FZDQpNQmFBRklyNjhWZUVFUk0xa0VMNlYwbFVhUTJreFBBM01BNEdBMVVk"
+ + "RHdFQi93UUVBd0lCQmpBUEJnTlZIUk1CDQpBZjhFQlRBREFRSC9NQTBHQ1Nx"
+ + "R1NJYjNEUUVCQlFVQUE0SUJBUUJRUFNoZ1lidnFjaWV2SDVVb3ZMeXhkbkYr"
+ + "DQpFcjlOeXF1SWNkMnZ3Y0N1SnpKMkQ3WDBUcWhHQ0JmUEpVVkdBVWorS0NP"
+ + "SDFCVkgva1l1OUhsVHB1MGtKWFBwDQpBQlZkb2hJUERqRHhkbjhXcFFSL0Yr"
+ + "ejFDaWtVcldIMDR4eTd1N1p6UUpLSlBuR0loY1FpOElyRm1PYkllMEc3DQpY"
+ + "WTZPTjdPRUZxY21KTFFHWWdtRzFXMklXcytQd1JwWTdENGhLVEFoVjFSNkVv"
+ + "amE1L3BPcmVDL09kZXlQWmVxDQo1SUZTOUZZZk02U0Npd2hrK3l2Q1FHbVo0"
+ + "YzE5SjM0ZjVFYkRrK1NQR2tEK25EQ0E3L3VMUWNUMlJURE14SzBaDQpuZlo2"
+ + "Nm1Sc0ZjcXRGaWdScjVFcmtKZDdoUVV6eHNOV0VrNzJEVUFIcVgvNlNjeWtt"
+ + "SkR2V0plSUpqZlcNCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0NCg==");
+
+ private byte[] AC_RAIZ_ICPBRASIL = Base64.decode(
+ "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlFdURDQ0E2Q2dBd0lC"
+ + "QWdJQkJEQU5CZ2txaGtpRzl3MEJBUVVGQURDQnRERUxNQWtHQTFVRUJoTUNR"
+ + "bEl4DQpFekFSQmdOVkJBb1RDa2xEVUMxQ2NtRnphV3d4UFRBN0JnTlZCQXNU"
+ + "TkVsdWMzUnBkSFYwYnlCT1lXTnBiMjVoDQpiQ0JrWlNCVVpXTnViMnh2WjJs"
+ + "aElHUmhJRWx1Wm05eWJXRmpZVzhnTFNCSlZFa3hFVEFQQmdOVkJBY1RDRUp5"
+ + "DQpZWE5wYkdsaE1Rc3dDUVlEVlFRSUV3SkVSakV4TUM4R0ExVUVBeE1vUVhW"
+ + "MGIzSnBaR0ZrWlNCRFpYSjBhV1pwDQpZMkZrYjNKaElGSmhhWG9nUW5KaGMy"
+ + "bHNaV2x5WVRBZUZ3MHdNVEV4TXpBeE1qVTRNREJhRncweE1URXhNekF5DQpN"
+ + "elU1TURCYU1JRzBNUXN3Q1FZRFZRUUdFd0pDVWpFVE1CRUdBMVVFQ2hNS1NV"
+ + "TlFMVUp5WVhOcGJERTlNRHNHDQpBMVVFQ3hNMFNXNXpkR2wwZFhSdklFNWhZ"
+ + "Mmx2Ym1Gc0lHUmxJRlJsWTI1dmJHOW5hV0VnWkdFZ1NXNW1iM0p0DQpZV05o"
+ + "YnlBdElFbFVTVEVSTUE4R0ExVUVCeE1JUW5KaGMybHNhV0V4Q3pBSkJnTlZC"
+ + "QWdUQWtSR01URXdMd1lEDQpWUVFERXloQmRYUnZjbWxrWVdSbElFTmxjblJw"
+ + "Wm1sallXUnZjbUVnVW1GcGVpQkNjbUZ6YVd4bGFYSmhNSUlCDQpJakFOQmdr"
+ + "cWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBd1BNdWR3WC9odm0r"
+ + "VWgyYi9sUUFjSFZBDQppc2FtYUxrV2Rrd1A5L1MvdE9LSWdSckw2T3krWklH"
+ + "bE9VZGQ2dVl0azlNYS8zcFVwZ2NmTkFqMHZZbTVnc3lqDQpRbzllbXNjK3g2"
+ + "bTRWV3drOWlxTVpTQ0s1RVFrQXEvVXQ0bjdLdUxFMStnZGZ0d2RJZ3hmVXNQ"
+ + "dDRDeU5yWTUwDQpRVjU3S00yVVQ4eDVycm16RWpyN1RJQ0dwU1VBbDJnVnFl"
+ + "NnhhaWkrYm1ZUjFRcm1XYUJTQUc1OUxya3Jqcll0DQpiUmhGYm9VRGUxREsr"
+ + "NlQ4czVMNms4Yzhva3BiSHBhOXZlTXp0RFZDOXNQSjYwTVdYaDZhblZLbzFV"
+ + "Y0xjYlVSDQp5RWVOdlpuZVZSS0FBVTZvdXdkakR2d2xzYUt5ZEZLd2VkMFRv"
+ + "UTQ3Ym1VS2djbSt3VjNlVFJrMzZVT25Ud0lEDQpBUUFCbzRIU01JSFBNRTRH"
+ + "QTFVZElBUkhNRVV3UXdZRllFd0JBUUF3T2pBNEJnZ3JCZ0VGQlFjQ0FSWXNh"
+ + "SFIwDQpjRG92TDJGamNtRnBlaTVwWTNCaWNtRnphV3d1WjI5MkxtSnlMMFJR"
+ + "UTJGamNtRnBlaTV3WkdZd1BRWURWUjBmDQpCRFl3TkRBeW9EQ2dMb1lzYUhS"
+ + "MGNEb3ZMMkZqY21GcGVpNXBZM0JpY21GemFXd3VaMjkyTG1KeUwweERVbUZq"
+ + "DQpjbUZwZWk1amNtd3dIUVlEVlIwT0JCWUVGSXI2OFZlRUVSTTFrRUw2VjBs"
+ + "VWFRMmt4UEEzTUE4R0ExVWRFd0VCDQovd1FGTUFNQkFmOHdEZ1lEVlIwUEFR"
+ + "SC9CQVFEQWdFR01BMEdDU3FHU0liM0RRRUJCUVVBQTRJQkFRQVpBNWMxDQpV"
+ + "L2hnSWg2T2NnTEFmaUpnRldwdm1EWldxbFYzMC9iSEZwajhpQm9iSlNtNXVE"
+ + "cHQ3VGlyWWgxVXhlM2ZRYUdsDQpZakplKzl6ZCtpelBSYkJxWFBWUUEzNEVY"
+ + "Y3drNHFwV3VmMWhIcmlXZmRyeDhBY3FTcXI2Q3VRRndTcjc1Rm9zDQpTemx3"
+ + "REFEYTcwbVQ3d1pqQW1RaG5aeDJ4SjZ3ZldsVDlWUWZTLy9KWWVJYzdGdWUy"
+ + "Sk5MZDAwVU9TTU1haUsvDQp0NzllbktOSEVBMmZ1cEgzdkVpZ2Y1RWg0YlZB"
+ + "TjVWb2hyVG02TVk1M3g3WFFaWnIxTUU3YTU1bEZFblNlVDB1DQptbE9BalIy"
+ + "bUFidlNNNVg1b1NaTnJtZXRkenlUajJmbENNOENDN01MYWIwa2tkbmdSSWxV"
+ + "QkdIRjEvUzVubVBiDQpLKzlBNDZzZDMzb3FLOG44DQotLS0tLUVORCBDRVJU"
+ + "SUZJQ0FURS0tLS0tDQo=");
+
+ private byte[] schefer = Base64.decode(
+ "MIIEnDCCBAWgAwIBAgICIPAwDQYJKoZIhvcNAQEEBQAwgcAxCzAJBgNVBAYT"
+ + "AkRFMQ8wDQYDVQQIEwZIRVNTRU4xGDAWBgNVBAcTDzY1MDA4IFdpZXNiYWRl"
+ + "bjEaMBgGA1UEChMRU0NIVUZBIEhPTERJTkcgQUcxGjAYBgNVBAsTEVNDSFVG"
+ + "QSBIT0xESU5HIEFHMSIwIAYDVQQDExlJbnRlcm5ldCBCZW51dHplciBTZXJ2"
+ + "aWNlMSowKAYJKoZIhvcNAQkBFht6ZXJ0aWZpa2F0QHNjaHVmYS1vbmxpbmUu"
+ + "ZGUwHhcNMDQwMzMwMTEwODAzWhcNMDUwMzMwMTEwODAzWjCBnTELMAkGA1UE"
+ + "BhMCREUxCjAIBgNVBAcTASAxIzAhBgNVBAoTGlNIUyBJbmZvcm1hdGlvbnNz"
+ + "eXN0ZW1lIEFHMRwwGgYDVQQLExM2MDAvMDU5NDktNjAwLzA1OTQ5MRgwFgYD"
+ + "VQQDEw9TY2hldHRlciBTdGVmYW4xJTAjBgkqhkiG9w0BCQEWFlN0ZWZhbi5T"
+ + "Y2hldHRlckBzaHMuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJD0"
+ + "95Bi76fkAMjJNTGPDiLPHmZXNsmakngDeS0juzKMeJA+TjXFouhYh6QyE4Bl"
+ + "Nf18fT4mInlgLefwf4t6meIWbiseeTo7VQdM+YrbXERMx2uHsRcgZMsiMYHM"
+ + "kVfYMK3SMJ4nhCmZxrBkoTRed4gXzVA1AA8YjjTqMyyjvt4TAgMBAAGjggHE"
+ + "MIIBwDAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIEsDALBgNVHQ8EBAMC"
+ + "BNAwOQYJYIZIAYb4QgENBCwWKlplcnRpZmlrYXQgbnVyIGZ1ZXIgU0NIVUZB"
+ + "LU9ubGluZSBndWVsdGlnLjAdBgNVHQ4EFgQUXReirhBfg0Yhf6MsBWoo/nPa"
+ + "hGwwge0GA1UdIwSB5TCB4oAUf2UyCaBV9JUeG9lS1Yo6OFBUdEKhgcakgcMw"
+ + "gcAxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIEwZIRVNTRU4xGDAWBgNVBAcTDzY1"
+ + "MDA4IFdpZXNiYWRlbjEaMBgGA1UEChMRU0NIVUZBIEhPTERJTkcgQUcxGjAY"
+ + "BgNVBAsTEVNDSFVGQSBIT0xESU5HIEFHMSIwIAYDVQQDExlJbnRlcm5ldCBC"
+ + "ZW51dHplciBTZXJ2aWNlMSowKAYJKoZIhvcNAQkBFht6ZXJ0aWZpa2F0QHNj"
+ + "aHVmYS1vbmxpbmUuZGWCAQAwIQYDVR0RBBowGIEWU3RlZmFuLlNjaGV0dGVy"
+ + "QHNocy5kZTAmBgNVHRIEHzAdgRt6ZXJ0aWZpa2F0QHNjaHVmYS1vbmxpbmUu"
+ + "ZGUwDQYJKoZIhvcNAQEEBQADgYEAWzZtN9XQ9uyrFXqSy3hViYwV751+XZr0"
+ + "YH5IFhIS+9ixNAu8orP3bxqTaMhpwoU7T/oSsyGGSkb3fhzclgUADbA2lrOI"
+ + "GkeB/m+FArTwRbwpqhCNTwZywOp0eDosgPjCX1t53BB/m/2EYkRiYdDGsot0"
+ + "kQPOVGSjQSQ4+/D+TM8=");
+
+ // circular dependency certificates
+ private static final byte[] circCA = Base64.decode(
+ "MIIDTzCCAjegAwIBAgIDARAAMA0GCSqGSIb3DQEBBQUAMDkxCzAJBgNVBAYT"
+ + "AkZSMRAwDgYDVQQKEwdHSVAtQ1BTMRgwFgYDVQQLEw9HSVAtQ1BTIEFOT05Z"
+ + "TUUwHhcNMDQxMDExMDAwMDAxWhcNMTQxMjMxMjM1OTU5WjA5MQswCQYDVQQG"
+ + "EwJGUjEQMA4GA1UEChMHR0lQLUNQUzEYMBYGA1UECxMPR0lQLUNQUyBBTk9O"
+ + "WU1FMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3WyWDwcM58aU"
+ + "hPX4ueI1mwETt3WdQtMfIdRiCXeBrjCkYCc7nIgCmGbnfTzXSplHRgKColWh"
+ + "q/Z+1rHYayje1gjAEU2+4/r1P2pnBmPgquDuguktCIbDtCcGZu0ylyKeHh37"
+ + "aeIKzkcmRSLRzvGf/eO3RdFksrvaPaSjqCVfGRXVDKK2uftE8rIFJE+bCqow"
+ + "6+WiaAaDDiJaSJPuu5hC1NA5jw0/BFodlCuAvl1GJ8A+TICkYWcSpKS9bkSC"
+ + "0i8xdGbSSk94shA1PdDvRdFMfFys8g4aupBXV8yqqEAUkBYmOtZSJckc3W4y"
+ + "2Gx53y7vY07Xh63mcgtJs2T82WJICwIDAQABo2AwXjAdBgNVHQ4EFgQU8c/P"
+ + "NNJaL0srd9SwHwgtvwPB/3cwDgYDVR0PAQH/BAQDAgIEMBkGA1UdIAQSMBAw"
+ + "DgYMKoF6AUcDBwgAAAABMBIGA1UdEwEB/wQIMAYBAf8CAQEwDQYJKoZIhvcN"
+ + "AQEFBQADggEBAHRjYDPJKlfUzID0YzajZpgR/i2ngJrJqYeaWCmwzBgNUPad"
+ + "uBKSGHmPVg21sfULMSnirnR+e90i/D0EVzLwQzcbjPDD/85rp9QDCeMxqqPe"
+ + "9ZCHGs2BpE/HOQMP0QfQ3/Kpk7SvOH/ZcpIf6+uE6lLBQYAGs5cxvtTGOzZk"
+ + "jCVFG+TrAnF4V5sNkn3maCWiYLmyqcnxtKEFSONy2bYqqudx/dBBlRrDbRfZ"
+ + "9XsCBdiXAHY1hFHldbfDs8rslmkXJi3fJC028HZYB6oiBX/JE7BbMk7bRnUf"
+ + "HSpP7Sjxeso2SY7Yit+hQDVAlqTDGmh6kLt/hQMpsOMry4vgBL6XHKw=");
+
+ private static final byte[] circCRLCA = Base64.decode(
+ "MIIDXDCCAkSgAwIBAgIDASAAMA0GCSqGSIb3DQEBBQUAMDkxCzAJBgNVBAYT"
+ + "AkZSMRAwDgYDVQQKEwdHSVAtQ1BTMRgwFgYDVQQLEw9HSVAtQ1BTIEFOT05Z"
+ + "TUUwHhcNMDQxMDExMDAwMDAxWhcNMTQxMjMxMjM1OTU5WjA5MQswCQYDVQQG"
+ + "EwJGUjEQMA4GA1UEChMHR0lQLUNQUzEYMBYGA1UECxMPR0lQLUNQUyBBTk9O"
+ + "WU1FMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwfEcFK0g7Kfo"
+ + "o5f2IBF7VEd/AG+RVGSds0Yg+u2kNYu4k04HR/+tOdBQtJvyr4W5jrQKsC5X"
+ + "skeFWMyWaFKzAjZDWB52HWp/kiMivGcxnYDuYf5piukSC+d2+vL8YaAphDzV"
+ + "HPnxEKqoM/J66uUussDTqfcL3JC/Bc7kBwn4srrsZOsamMWTQQtEqVQxNN7A"
+ + "ROSRsdiTt3hMOKditc9/NBNmjZWxgc7Twr/SaZ8CfN5wf2wuOl23knWL0QsJ"
+ + "0lSMBSBTzTcfAke4/jIT7d4nVMp3t7dsna8rt56pFK4wpRFGuCt+1P5gi51x"
+ + "xVSdI+JoNXv6zGO4o8YVaRpC5rQeGQIDAQABo20wazAfBgNVHSMEGDAWgBTx"
+ + "z8800lovSyt31LAfCC2/A8H/dzAdBgNVHQ4EFgQUGa3SbBrJx/wa2MQwhWPl"
+ + "dwLw1+IwDgYDVR0PAQH/BAQDAgECMBkGA1UdIAQSMBAwDgYMKoF6AUcDBwgA"
+ + "AAABMA0GCSqGSIb3DQEBBQUAA4IBAQAPDpYe2WPYnXTLsXSIUREBNMLmg+/7"
+ + "4Yhq9uOm5Hb5LVkDuHoEHGfmpXXEvucx5Ehu69hw+F4YSrd9wPjOiG8G6GXi"
+ + "RcrK8nE8XDvvV+E1HpJ7NKN4fSAoSb+0gliiq3aF15bvXP8nfespdd/x1xWQ"
+ + "mpYCx/mJeuqONQv2/D/7hfRKYoDBaAkWGodenPFPVs6FxwnEuH2R+KWCUdA9"
+ + "L04v8JBeL3kZiALkU7+DCCm7A0imUAgeeArbAbfIPu6eDygm+XndZ9qi7o4O"
+ + "AntPxrqbeXFIbDrQ4GV1kpxnW+XpSGDd96SWKe715gxkkDBppR5IKYJwRb6O"
+ + "1TRQIf2F+muQ");
+
+ private static final byte[] circCRL = Base64.decode(
+ "MIIB1DCBvQIBATANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGUjEQMA4G"
+ + "A1UEChMHR0lQLUNQUzEYMBYGA1UECxMPR0lQLUNQUyBBTk9OWU1FFw0xMDAx"
+ + "MDcwMzAwMTVaFw0xMDAxMTMwMzAwMTVaMACgTjBMMB8GA1UdIwQYMBaAFBmt"
+ + "0mwaycf8GtjEMIVj5XcC8NfiMAsGA1UdFAQEAgILgzAcBgNVHRIEFTATgRFh"
+ + "Yy1naXBAZ2lwLWNwcy5mcjANBgkqhkiG9w0BAQUFAAOCAQEAtF1DdFl1MQvf"
+ + "vNkbrCPuppNYcHen4+za/ZDepKuwHsH/OpKuaDJc4LndRgd5IwzfpCHkQGzt"
+ + "shK50bakN8oaYJgthKIOIJzR+fn6NMjftfR2a27Hdk2o3eQXRHQ360qMbpSy"
+ + "qPb3WfuBhxO2/DlLChJP+OxZIHtT/rNYgE0tlIv7swYi81Gq+DafzaZ9+A5t"
+ + "I0L2Gp/NUDsp5dF6PllAGiXQzl27qkcu+r50w+u0gul3nobXgbwPcMSYuWUz"
+ + "1lhA+uDn/EUWV4RSiJciCGSS10WCkFh1/YPo++mV15KDB0m+8chscrSu/bAl"
+ + "B19LxL/pCX3qr5iLE9ss3olVImyFZg==");
+
+// private void checkCircProcessing()
+// throws Exception
+// {
+// CertificateFactory cf = CertificateFactory.getInstance("X.509", "SC");
+//
+// X509Certificate caCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(circCA));
+// X509Certificate crlCaCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(circCRLCA));
+// X509CRL crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(circCRL));
+//
+// List list = new ArrayList();
+//
+// list.add(caCert);
+// list.add(crlCaCert);
+// list.add(crl);
+//
+// CertStoreParameters ccsp = new CollectionCertStoreParameters(list);
+// CertStore store = CertStore.getInstance("Collection", ccsp);
+//
+// Calendar validDate = Calendar.getInstance();
+// validDate.set(2010,0,8,2,21,10);
+//
+// //validating path
+// List certchain = new ArrayList();
+//
+// certchain.add(crlCaCert);
+// CertPath cp = CertificateFactory.getInstance("X.509","SC").generateCertPath(certchain);
+//
+// Set trust = new HashSet();
+// trust.add(new TrustAnchor(caCert, null));
+//
+// CertPathValidator cpv = CertPathValidator.getInstance("PKIX","SC");
+// //PKIXParameters param = new PKIXParameters(trust);
+//
+// PKIXBuilderParameters param = new PKIXBuilderParameters(trust, null);
+// X509CertSelector certSelector = new X509CertSelector();
+// certSelector.setCertificate(crlCaCert);
+// param.setTargetCertConstraints(certSelector);
+// param.addCertStore(store);
+// param.setRevocationEnabled(true);
+// param.setDate(validDate.getTime());
+//
+// PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult)cpv.validate(cp, param);
+// }
+
+ public void performTest()
+ throws Exception
+ {
+ // initialise CertStore
+ X509CertificateHolder rootCert = new X509CertificateHolder(CertPathTest.rootCertBin);
+ X509CertificateHolder interCert = new X509CertificateHolder(CertPathTest.interCertBin);
+ X509CertificateHolder finalCert = new X509CertificateHolder(CertPathTest.finalCertBin);
+ X509CRLHolder rootCrl = new X509CRLHolder(CertPathTest.rootCrlBin);
+ X509CRLHolder interCrl = new X509CRLHolder(CertPathTest.interCrlBin);
+
+ CertPath path = new CertPath(new X509CertificateHolder[] { finalCert, interCert });
+ X509ContentVerifierProviderBuilder verifier = new JcaX509ContentVerifierProviderBuilder().setProvider(BouncyCastleProvider.PROVIDER_NAME);
+
+ CertPathValidationResult result = path.validate(new CertPathValidation[]{new ParentCertIssuedValidation(verifier), new BasicConstraintsValidation(), new KeyUsageValidation()});
+
+ if (!result.isValid())
+ {
+ fail("basic validation (1) not working");
+ }
+
+ List crlList = new ArrayList();
+
+ crlList.add(rootCrl);
+ crlList.add(interCrl);
+
+ Store crls = new CollectionStore(crlList);
+
+ result = path.validate(new CertPathValidation[]{new ParentCertIssuedValidation(verifier), new BasicConstraintsValidation(), new KeyUsageValidation(), new CRLValidation(rootCert.getSubject(), crls)});
+
+ if (!result.isValid())
+ {
+ fail("basic validation (2) not working");
+ }
+
+ result = path.validate(new CertPathValidation[]{new ParentCertIssuedValidation(verifier), new KeyUsageValidation(), new CRLValidation(rootCert.getSubject(), crls)});
+
+ if (result.isValid() || result.getUnhandledCriticalExtensionOIDs().size() != 1
+ || !result.getUnhandledCriticalExtensionOIDs().contains(Extension.basicConstraints))
+ {
+ fail("basic validation (3) not working");
+ }
+
+ result = path.validate(new CertPathValidation[]{new ParentCertIssuedValidation(verifier), new CRLValidation(rootCert.getSubject(), crls)});
+
+ if (result.isValid() || result.getUnhandledCriticalExtensionOIDs().size() != 2
+ || !result.getUnhandledCriticalExtensionOIDs().contains(Extension.basicConstraints)
+ || !result.getUnhandledCriticalExtensionOIDs().contains(Extension.keyUsage))
+ {
+ fail("basic validation (4) not working");
+ }
+
+ path = new CertPath(new X509CertificateHolder[] { interCert, finalCert });
+
+ result = path.validate(new CertPathValidation[]{new ParentCertIssuedValidation(verifier)});
+
+ if (result.isValid())
+ {
+ fail("incorrect path validated!!");
+ }
+
+
+
+// List list = new ArrayList();
+// list.add(rootCert);
+// list.add(interCert);
+// list.add(finalCert);
+// list.add(rootCrl);
+// list.add(interCrl);
+// CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(list);
+// CertStore store = CertStore.getInstance("Collection", ccsp, "SC");
+// Calendar validDate = Calendar.getInstance();
+// validDate.set(2008,8,4,14,49,10);
+// //validating path
+// List certchain = new ArrayList();
+// certchain.add(finalCert);
+// certchain.add(interCert);
+// CertPath cp = CertificateFactory.getInstance("X.509","SC").generateCertPath(certchain);
+// Set trust = new HashSet();
+// trust.add(new TrustAnchor(rootCert, null));
+//
+// CertPathValidator cpv = CertPathValidator.getInstance("PKIX","SC");
+// PKIXParameters param = new PKIXParameters(trust);
+// param.addCertStore(store);
+// param.setDate(validDate.getTime());
+// MyChecker checker = new MyChecker();
+// param.addCertPathChecker(checker);
+//
+// PKIXCertPathValidatorResult result =
+// (PKIXCertPathValidatorResult) cpv.validate(cp, param);
+// PolicyNode policyTree = result.getPolicyTree();
+// PublicKey subjectPublicKey = result.getPublicKey();
+//
+// if (checker.getCount() != 2)
+// {
+// fail("checker not evaluated for each certificate");
+// }
+//
+// if (!subjectPublicKey.equals(finalCert.getPublicKey()))
+// {
+// fail("wrong public key returned");
+// }
+//
+// //
+// // invalid path containing a valid one test
+// //
+// try
+// {
+// // initialise CertStore
+// rootCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(AC_RAIZ_ICPBRASIL));
+// interCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(AC_PR));
+// finalCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(schefer));
+//
+// list = new ArrayList();
+// list.add(rootCert);
+// list.add(interCert);
+// list.add(finalCert);
+//
+// ccsp = new CollectionCertStoreParameters(list);
+// store = CertStore.getInstance("Collection", ccsp);
+// validDate = Calendar.getInstance();
+// validDate.set(2004,2,21,2,21,10);
+//
+// //validating path
+// certchain = new ArrayList();
+// certchain.add(finalCert);
+// certchain.add(interCert);
+// cp = CertificateFactory.getInstance("X.509","SC").generateCertPath(certchain);
+// trust = new HashSet();
+// trust.add(new TrustAnchor(rootCert, null));
+//
+// cpv = CertPathValidator.getInstance("PKIX","SC");
+// param = new PKIXParameters(trust);
+// param.addCertStore(store);
+// param.setRevocationEnabled(false);
+// param.setDate(validDate.getTime());
+//
+// result =(PKIXCertPathValidatorResult) cpv.validate(cp, param);
+// policyTree = result.getPolicyTree();
+// subjectPublicKey = result.getPublicKey();
+//
+// fail("Invalid path validated");
+// }
+// catch (Exception e)
+// {
+// if (!(e instanceof CertPathValidatorException
+// && e.getMessage().startsWith("Could not validate certificate signature.")))
+// {
+// fail("unexpected exception", e);
+// }
+// }
+//
+// checkCircProcessing();
+ }
+
+ public String getName()
+ {
+ return "CertPathValidator";
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new CertPathValidationTest());
+ }
+}
+
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/AllTests.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/AllTests.java
new file mode 100644
index 000000000..162abafb8
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/AllTests.java
@@ -0,0 +1,57 @@
+package org.spongycastle.cert.test;
+
+import java.security.Security;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.test.SimpleTestResult;
+
+public class AllTests
+ extends TestCase
+{
+ public void testSimpleTests()
+ {
+ org.spongycastle.util.test.Test[] tests = new org.spongycastle.util.test.Test[] { new CertTest(), new PKCS10Test(), new AttrCertSelectorTest(), new AttrCertTest(), new X509ExtensionUtilsTest() };
+
+ for (int i = 0; i != tests.length; i++)
+ {
+ SimpleTestResult result = (SimpleTestResult)tests[i].perform();
+
+ if (!result.isSuccessful())
+ {
+ if (result.getException() != null)
+ {
+ result.getException().printStackTrace();
+ }
+ fail(result.toString());
+ }
+ }
+ }
+
+ public static void main (String[] args)
+ {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite()
+ {
+ TestSuite suite = new TestSuite("Cert Tests");
+
+ if (Security.getProvider("SC") == null)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ suite.addTestSuite(AllTests.class);
+ suite.addTestSuite(BcAttrCertSelectorTest.class);
+ suite.addTestSuite(BcAttrCertSelectorTest.class);
+ suite.addTestSuite(BcAttrCertTest.class);
+ suite.addTestSuite(BcCertTest.class);
+ suite.addTestSuite(BcPKCS10Test.class);
+ suite.addTest(ConverterTest.suite());
+
+ return suite;
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/AttrCertSelectorTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/AttrCertSelectorTest.java
new file mode 100644
index 000000000..99412f08e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/AttrCertSelectorTest.java
@@ -0,0 +1,243 @@
+package org.spongycastle.cert.test;
+
+import java.io.ByteArrayInputStream;
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.util.Date;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.Target;
+import org.spongycastle.asn1.x509.TargetInformation;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.cert.AttributeCertificateHolder;
+import org.spongycastle.cert.AttributeCertificateIssuer;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509v2AttributeCertificateBuilder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.cert.selector.X509AttributeCertificateHolderSelectorBuilder;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.test.SimpleTest;
+import org.spongycastle.util.test.Test;
+import org.spongycastle.util.test.TestResult;
+
+public class AttrCertSelectorTest
+ extends SimpleTest
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ static final RSAPrivateCrtKeySpec RSA_PRIVATE_KEY_SPEC = 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));
+
+ static final byte[] holderCert = Base64
+ .decode("MIIGjTCCBXWgAwIBAgICAPswDQYJKoZIhvcNAQEEBQAwaTEdMBsGCSqGSIb3DQEJ"
+ + "ARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZpcmdpbmlhIFRlY2ggQ2VydGlm"
+ + "aWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0MQswCQYDVQQGEwJVUzAeFw0w"
+ + "MzAxMzExMzUyMTRaFw0wNDAxMzExMzUyMTRaMIGDMRswGQYJKoZIhvcNAQkBFgxz"
+ + "c2hhaEB2dC5lZHUxGzAZBgNVBAMTElN1bWl0IFNoYWggKHNzaGFoKTEbMBkGA1UE"
+ + "CxMSVmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAxMQswCQYDVQQK"
+ + "EwJ2dDELMAkGA1UEBhMCVVMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPDc"
+ + "scgSKmsEp0VegFkuitD5j5PUkDuzLjlfaYONt2SN8WeqU4j2qtlCnsipa128cyKS"
+ + "JzYe9duUdNxquh5BPIkMkHBw4jHoQA33tk0J/sydWdN74/AHPpPieK5GHwhU7GTG"
+ + "rCCS1PJRxjXqse79ExAlul+gjQwHeldAC+d4A6oZAgMBAAGjggOmMIIDojAMBgNV"
+ + "HRMBAf8EAjAAMBEGCWCGSAGG+EIBAQQEAwIFoDAOBgNVHQ8BAf8EBAMCA/gwHQYD"
+ + "VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMB0GA1UdDgQWBBRUIoWAzlXbzBYE"
+ + "yVTjQFWyMMKo1jCBkwYDVR0jBIGLMIGIgBTgc3Fm+TGqKDhen+oKfbl+xVbj2KFt"
+ + "pGswaTEdMBsGCSqGSIb3DQEJARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZp"
+ + "cmdpbmlhIFRlY2ggQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0"
+ + "MQswCQYDVQQGEwJVU4IBADCBiwYJYIZIAYb4QgENBH4WfFZpcmdpbmlhIFRlY2gg"
+ + "Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgZGlnaXRhbCBjZXJ0aWZpY2F0ZXMgYXJl"
+ + "IHN1YmplY3QgdG8gcG9saWNpZXMgbG9jYXRlZCBhdCBodHRwOi8vd3d3LnBraS52"
+ + "dC5lZHUvY2EvY3BzLy4wFwYDVR0RBBAwDoEMc3NoYWhAdnQuZWR1MBkGA1UdEgQS"
+ + "MBCBDmlybWhlbHBAdnQuZWR1MEMGCCsGAQUFBwEBBDcwNTAzBggrBgEFBQcwAoYn"
+ + "aHR0cDovL2JveDE3Ny5jYy52dC5lZHUvY2EvaXNzdWVycy5odG1sMEQGA1UdHwQ9"
+ + "MDswOaA3oDWGM2h0dHA6Ly9ib3gxNzcuY2MudnQuZWR1L2h0ZG9jcy1wdWJsaWMv"
+ + "Y3JsL2NhY3JsLmNybDBUBgNVHSAETTBLMA0GCysGAQQBtGgFAQEBMDoGCysGAQQB"
+ + "tGgFAQEBMCswKQYIKwYBBQUHAgEWHWh0dHA6Ly93d3cucGtpLnZ0LmVkdS9jYS9j"
+ + "cHMvMD8GCWCGSAGG+EIBBAQyFjBodHRwOi8vYm94MTc3LmNjLnZ0LmVkdS9jZ2kt"
+ + "cHVibGljL2NoZWNrX3Jldl9jYT8wPAYJYIZIAYb4QgEDBC8WLWh0dHA6Ly9ib3gx"
+ + "NzcuY2MudnQuZWR1L2NnaS1wdWJsaWMvY2hlY2tfcmV2PzBLBglghkgBhvhCAQcE"
+ + "PhY8aHR0cHM6Ly9ib3gxNzcuY2MudnQuZWR1L35PcGVuQ0E4LjAxMDYzMC9jZ2kt"
+ + "cHVibGljL3JlbmV3YWw/MCwGCWCGSAGG+EIBCAQfFh1odHRwOi8vd3d3LnBraS52"
+ + "dC5lZHUvY2EvY3BzLzANBgkqhkiG9w0BAQQFAAOCAQEAHJ2ls9yjpZVcu5DqiE67"
+ + "r7BfkdMnm7IOj2v8cd4EAlPp6OPBmjwDMwvKRBb/P733kLBqFNWXWKTpT008R0KB"
+ + "8kehbx4h0UPz9vp31zhGv169+5iReQUUQSIwTGNWGLzrT8kPdvxiSAvdAJxcbRBm"
+ + "KzDic5I8PoGe48kSCkPpT1oNmnivmcu5j1SMvlx0IS2BkFMksr0OHiAW1elSnE/N"
+ + "RuX2k73b3FucwVxB3NRo3vgoHPCTnh9r4qItAHdxFlF+pPtbw2oHESKRfMRfOIHz"
+ + "CLQWSIa6Tvg4NIV3RRJ0sbCObesyg08lymalQMdkXwtRn5eGE00SHWwEUjSXP2gR"
+ + "3g==");
+
+ public String getName()
+ {
+ return "AttrCertSelector";
+ }
+
+ private X509AttributeCertificateHolder createAttrCert() throws Exception
+ {
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+ X509Certificate iCert = (X509Certificate) fact
+ .generateCertificate(new ByteArrayInputStream(holderCert));
+ X509CertificateHolder iCertHolder = new JcaX509CertificateHolder(iCert);
+ //
+ // a sample key pair.
+ //
+ // RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ // new BigInteger(
+ // "b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7",
+ // 16), new BigInteger("11", 16));
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+
+ KeyFactory kFact = KeyFactory.getInstance("RSA", "SC");
+
+ privKey = kFact.generatePrivate(RSA_PRIVATE_KEY_SPEC);
+
+ X509v2AttributeCertificateBuilder gen = new X509v2AttributeCertificateBuilder(
+ new AttributeCertificateHolder(iCertHolder.getSubject()),
+ new AttributeCertificateIssuer(new X500Name("cn=test")),
+ BigInteger.valueOf(1),
+ new Date(System.currentTimeMillis() - 50000),
+ new Date(System.currentTimeMillis() + 50000));
+
+ // the actual attributes
+ GeneralName roleName = new GeneralName(GeneralName.rfc822Name,
+ "DAU123456789@test.com");
+ ASN1EncodableVector roleSyntax = new ASN1EncodableVector();
+ roleSyntax.add(roleName);
+
+ // roleSyntax OID: 2.5.24.72
+ gen.addAttribute(new ASN1ObjectIdentifier("2.5.24.72"), new DERSequence(roleSyntax));
+
+
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA1WithRSAEncryption").setProvider(BC).build(privKey);
+
+ Target targetName = new Target(Target.targetName, new GeneralName(GeneralName.dNSName,
+ "www.test.com"));
+
+ Target targetGroup = new Target(Target.targetGroup, new GeneralName(
+ GeneralName.directoryName, "o=Test, ou=Test"));
+ Target[] targets = new Target[2];
+ targets[0] = targetName;
+ targets[1] = targetGroup;
+ TargetInformation targetInformation = new TargetInformation(targets);
+
+ gen.addExtension(X509Extension.targetInformation, true, targetInformation);
+
+ return gen.build(sigGen);
+ }
+
+ public void testSelector() throws Exception
+ {
+ X509AttributeCertificateHolder aCert = createAttrCert();
+ X509AttributeCertificateHolderSelectorBuilder sel = new X509AttributeCertificateHolderSelectorBuilder();
+ sel.setAttributeCert(aCert);
+ boolean match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate.");
+ }
+ sel.setAttributeCert(null);
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate.");
+ }
+ sel.setHolder(aCert.getHolder());
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate holder.");
+ }
+ sel.setHolder(null);
+ sel.setIssuer(aCert.getIssuer());
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate issuer.");
+ }
+ sel.setIssuer(null);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+ X509CertificateHolder iCert = new JcaX509CertificateHolder((X509Certificate) fact
+ .generateCertificate(new ByteArrayInputStream(holderCert)));
+ match = aCert.getHolder().match(iCert);
+ if (!match)
+ {
+ fail("Issuer holder does not match signing certificate of attribute certificate.");
+ }
+
+ sel.setSerialNumber(aCert.getSerialNumber());
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate serial number.");
+ }
+
+ sel.setAttributeCertificateValid(new Date());
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate time.");
+ }
+
+ sel.addTargetName(new GeneralName(2, "www.test.com"));
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate target name.");
+ }
+ sel.setTargetNames(null);
+ sel.addTargetGroup(new GeneralName(4, "o=Test, ou=Test"));
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate target group.");
+ }
+ sel.setTargetGroups(null);
+ }
+
+ public void performTest() throws Exception
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ testSelector();
+ }
+
+ public static void main(String[] args)
+ {
+ Test test = new AttrCertSelectorTest();
+ TestResult result = test.perform();
+ System.out.println(result);
+ }
+}
+
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/AttrCertTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/AttrCertTest.java
new file mode 100644
index 000000000..ea3504263
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/AttrCertTest.java
@@ -0,0 +1,667 @@
+package org.spongycastle.cert.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+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.Attribute;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.cert.AttributeCertificateHolder;
+import org.spongycastle.cert.AttributeCertificateIssuer;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.cert.X509v2AttributeCertificateBuilder;
+import org.spongycastle.cert.jcajce.JcaCertStore;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+import org.spongycastle.util.Store;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.test.SimpleTest;
+
+public class AttrCertTest
+ extends SimpleTest
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ private static final RSAPrivateCrtKeySpec RSA_PRIVATE_KEY_SPEC = 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));
+
+ public static byte[] attrCert = Base64.decode(
+ "MIIHQDCCBqkCAQEwgZChgY2kgYowgYcxHDAaBgkqhkiG9w0BCQEWDW1sb3JjaEB2"
+ + "dC5lZHUxHjAcBgNVBAMTFU1hcmt1cyBMb3JjaCAobWxvcmNoKTEbMBkGA1UECxMS"
+ + "VmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAyMQswCQYDVQQKEwJ2"
+ + "dDELMAkGA1UEBhMCVVMwgYmkgYYwgYMxGzAZBgkqhkiG9w0BCQEWDHNzaGFoQHZ0"
+ + "LmVkdTEbMBkGA1UEAxMSU3VtaXQgU2hhaCAoc3NoYWgpMRswGQYDVQQLExJWaXJn"
+ + "aW5pYSBUZWNoIFVzZXIxEDAOBgNVBAsTB0NsYXNzIDExCzAJBgNVBAoTAnZ0MQsw"
+ + "CQYDVQQGEwJVUzANBgkqhkiG9w0BAQQFAAIBBTAiGA8yMDAzMDcxODE2MDgwMloY"
+ + "DzIwMDMwNzI1MTYwODAyWjCCBU0wggVJBgorBgEEAbRoCAEBMYIFORaCBTU8UnVs"
+ + "ZSBSdWxlSWQ9IkZpbGUtUHJpdmlsZWdlLVJ1bGUiIEVmZmVjdD0iUGVybWl0Ij4K"
+ + "IDxUYXJnZXQ+CiAgPFN1YmplY3RzPgogICA8U3ViamVjdD4KICAgIDxTdWJqZWN0"
+ + "TWF0Y2ggTWF0Y2hJZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5j"
+ + "dGlvbjpzdHJpbmctZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlw"
+ + "ZT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjc3RyaW5nIj4KICAg"
+ + "ICAgIENOPU1hcmt1cyBMb3JjaDwvQXR0cmlidXRlVmFsdWU+CiAgICAgPFN1Ympl"
+ + "Y3RBdHRyaWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFt"
+ + "ZXM6dGM6eGFjbWw6MS4wOnN1YmplY3Q6c3ViamVjdC1pZCIgRGF0YVR5cGU9Imh0"
+ + "dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hI3N0cmluZyIgLz4gCiAgICA8"
+ + "L1N1YmplY3RNYXRjaD4KICAgPC9TdWJqZWN0PgogIDwvU3ViamVjdHM+CiAgPFJl"
+ + "c291cmNlcz4KICAgPFJlc291cmNlPgogICAgPFJlc291cmNlTWF0Y2ggTWF0Y2hJ"
+ + "ZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5jdGlvbjpzdHJpbmct"
+ + "ZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlwZT0iaHR0cDovL3d3"
+ + "dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIj4KICAgICAgaHR0cDovL3p1"
+ + "bmkuY3MudnQuZWR1PC9BdHRyaWJ1dGVWYWx1ZT4KICAgICA8UmVzb3VyY2VBdHRy"
+ + "aWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6"
+ + "eGFjbWw6MS4wOnJlc291cmNlOnJlc291cmNlLWlkIiBEYXRhVHlwZT0iaHR0cDov"
+ + "L3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIiAvPiAKICAgIDwvUmVz"
+ + "b3VyY2VNYXRjaD4KICAgPC9SZXNvdXJjZT4KICA8L1Jlc291cmNlcz4KICA8QWN0"
+ + "aW9ucz4KICAgPEFjdGlvbj4KICAgIDxBY3Rpb25NYXRjaCBNYXRjaElkPSJ1cm46"
+ + "b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmZ1bmN0aW9uOnN0cmluZy1lcXVhbCI+"
+ + "CiAgICAgPEF0dHJpYnV0ZVZhbHVlIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9y"
+ + "Zy8yMDAxL1hNTFNjaGVtYSNzdHJpbmciPgpEZWxlZ2F0ZSBBY2Nlc3MgICAgIDwv"
+ + "QXR0cmlidXRlVmFsdWU+CgkgIDxBY3Rpb25BdHRyaWJ1dGVEZXNpZ25hdG9yIEF0"
+ + "dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmFjdGlvbjph"
+ + "Y3Rpb24taWQiIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNj"
+ + "aGVtYSNzdHJpbmciIC8+IAogICAgPC9BY3Rpb25NYXRjaD4KICAgPC9BY3Rpb24+"
+ + "CiAgPC9BY3Rpb25zPgogPC9UYXJnZXQ+CjwvUnVsZT4KMA0GCSqGSIb3DQEBBAUA"
+ + "A4GBAGiJSM48XsY90HlYxGmGVSmNR6ZW2As+bot3KAfiCIkUIOAqhcphBS23egTr"
+ + "6asYwy151HshbPNYz+Cgeqs45KkVzh7bL/0e1r8sDVIaaGIkjHK3CqBABnfSayr3"
+ + "Rd1yBoDdEv8Qb+3eEPH6ab9021AsLEnJ6LWTmybbOpMNZ3tv");
+
+ byte[] signCert = Base64.decode(
+ "MIIGjTCCBXWgAwIBAgICAPswDQYJKoZIhvcNAQEEBQAwaTEdMBsGCSqGSIb3DQEJ"
+ + "ARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZpcmdpbmlhIFRlY2ggQ2VydGlm"
+ + "aWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0MQswCQYDVQQGEwJVUzAeFw0w"
+ + "MzAxMzExMzUyMTRaFw0wNDAxMzExMzUyMTRaMIGDMRswGQYJKoZIhvcNAQkBFgxz"
+ + "c2hhaEB2dC5lZHUxGzAZBgNVBAMTElN1bWl0IFNoYWggKHNzaGFoKTEbMBkGA1UE"
+ + "CxMSVmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAxMQswCQYDVQQK"
+ + "EwJ2dDELMAkGA1UEBhMCVVMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPDc"
+ + "scgSKmsEp0VegFkuitD5j5PUkDuzLjlfaYONt2SN8WeqU4j2qtlCnsipa128cyKS"
+ + "JzYe9duUdNxquh5BPIkMkHBw4jHoQA33tk0J/sydWdN74/AHPpPieK5GHwhU7GTG"
+ + "rCCS1PJRxjXqse79ExAlul+gjQwHeldAC+d4A6oZAgMBAAGjggOmMIIDojAMBgNV"
+ + "HRMBAf8EAjAAMBEGCWCGSAGG+EIBAQQEAwIFoDAOBgNVHQ8BAf8EBAMCA/gwHQYD"
+ + "VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMB0GA1UdDgQWBBRUIoWAzlXbzBYE"
+ + "yVTjQFWyMMKo1jCBkwYDVR0jBIGLMIGIgBTgc3Fm+TGqKDhen+oKfbl+xVbj2KFt"
+ + "pGswaTEdMBsGCSqGSIb3DQEJARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZp"
+ + "cmdpbmlhIFRlY2ggQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0"
+ + "MQswCQYDVQQGEwJVU4IBADCBiwYJYIZIAYb4QgENBH4WfFZpcmdpbmlhIFRlY2gg"
+ + "Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgZGlnaXRhbCBjZXJ0aWZpY2F0ZXMgYXJl"
+ + "IHN1YmplY3QgdG8gcG9saWNpZXMgbG9jYXRlZCBhdCBodHRwOi8vd3d3LnBraS52"
+ + "dC5lZHUvY2EvY3BzLy4wFwYDVR0RBBAwDoEMc3NoYWhAdnQuZWR1MBkGA1UdEgQS"
+ + "MBCBDmlybWhlbHBAdnQuZWR1MEMGCCsGAQUFBwEBBDcwNTAzBggrBgEFBQcwAoYn"
+ + "aHR0cDovL2JveDE3Ny5jYy52dC5lZHUvY2EvaXNzdWVycy5odG1sMEQGA1UdHwQ9"
+ + "MDswOaA3oDWGM2h0dHA6Ly9ib3gxNzcuY2MudnQuZWR1L2h0ZG9jcy1wdWJsaWMv"
+ + "Y3JsL2NhY3JsLmNybDBUBgNVHSAETTBLMA0GCysGAQQBtGgFAQEBMDoGCysGAQQB"
+ + "tGgFAQEBMCswKQYIKwYBBQUHAgEWHWh0dHA6Ly93d3cucGtpLnZ0LmVkdS9jYS9j"
+ + "cHMvMD8GCWCGSAGG+EIBBAQyFjBodHRwOi8vYm94MTc3LmNjLnZ0LmVkdS9jZ2kt"
+ + "cHVibGljL2NoZWNrX3Jldl9jYT8wPAYJYIZIAYb4QgEDBC8WLWh0dHA6Ly9ib3gx"
+ + "NzcuY2MudnQuZWR1L2NnaS1wdWJsaWMvY2hlY2tfcmV2PzBLBglghkgBhvhCAQcE"
+ + "PhY8aHR0cHM6Ly9ib3gxNzcuY2MudnQuZWR1L35PcGVuQ0E4LjAxMDYzMC9jZ2kt"
+ + "cHVibGljL3JlbmV3YWw/MCwGCWCGSAGG+EIBCAQfFh1odHRwOi8vd3d3LnBraS52"
+ + "dC5lZHUvY2EvY3BzLzANBgkqhkiG9w0BAQQFAAOCAQEAHJ2ls9yjpZVcu5DqiE67"
+ + "r7BfkdMnm7IOj2v8cd4EAlPp6OPBmjwDMwvKRBb/P733kLBqFNWXWKTpT008R0KB"
+ + "8kehbx4h0UPz9vp31zhGv169+5iReQUUQSIwTGNWGLzrT8kPdvxiSAvdAJxcbRBm"
+ + "KzDic5I8PoGe48kSCkPpT1oNmnivmcu5j1SMvlx0IS2BkFMksr0OHiAW1elSnE/N"
+ + "RuX2k73b3FucwVxB3NRo3vgoHPCTnh9r4qItAHdxFlF+pPtbw2oHESKRfMRfOIHz"
+ + "CLQWSIa6Tvg4NIV3RRJ0sbCObesyg08lymalQMdkXwtRn5eGE00SHWwEUjSXP2gR"
+ + "3g==");
+
+ static byte[] certWithBaseCertificateID = Base64.decode(
+ "MIIBqzCCARQCAQEwSKBGMD6kPDA6MQswCQYDVQQGEwJJVDEOMAwGA1UEChMFVU5JVE4xDDAKBgNV"
+ + "BAsTA0RJVDENMAsGA1UEAxMEcm9vdAIEAVMVjqB6MHikdjB0MQswCQYDVQQGEwJBVTEoMCYGA1UE"
+ + "ChMfVGhlIExlZ2lvbiBvZiB0aGUgQm91bmN5IENhc3RsZTEjMCEGA1UECxMaQm91bmN5IFByaW1h"
+ + "cnkgQ2VydGlmaWNhdGUxFjAUBgNVBAMTDUJvdW5jeSBDYXN0bGUwDQYJKoZIhvcNAQEFBQACBQKW"
+ + "RhnHMCIYDzIwMDUxMjEyMTIwMDQyWhgPMjAwNTEyMTkxMjAxMzJaMA8wDQYDVRhIMQaBBGVWSVAw"
+ + "DQYJKoZIhvcNAQEFBQADgYEAUAVin9StDaA+InxtXq/av6rUQLI9p1X6louBcj4kYJnxRvTrHpsr"
+ + "N3+i9Uq/uk5lRdAqmPFvcmSbuE3TRAsjrXON5uFiBBKZ1AouLqcr8nHbwcdwjJ9TyUNO9I4hfpSH"
+ + "UHHXMtBKgp4MOkhhX8xTGyWg3hp23d3GaUeg/IYlXBI=");
+
+ byte[] holderCertWithBaseCertificateID = Base64.decode(
+ "MIIBwDCCASmgAwIBAgIEAVMVjjANBgkqhkiG9w0BAQUFADA6MQswCQYDVQQGEwJJVDEOMAwGA1UE"
+ + "ChMFVU5JVE4xDDAKBgNVBAsTA0RJVDENMAsGA1UEAxMEcm9vdDAeFw0wNTExMTExMjAxMzJaFw0w"
+ + "NjA2MTYxMjAxMzJaMD4xCzAJBgNVBAYTAklUMQ4wDAYDVQQKEwVVTklUTjEMMAoGA1UECxMDRElU"
+ + "MREwDwYDVQQDEwhMdWNhQm9yejBaMA0GCSqGSIb3DQEBAQUAA0kAMEYCQQC0p+RhcFdPFqlwgrIr"
+ + "5YtqKmKXmEGb4ShypL26Ymz66ZAPdqv7EhOdzl3lZWT6srZUMWWgQMYGiHQg4z2R7X7XAgERoxUw"
+ + "EzARBglghkgBhvhCAQEEBAMCBDAwDQYJKoZIhvcNAQEFBQADgYEAsX50VPQQCWmHvPq9y9DeCpmS"
+ + "4szcpFAhpZyn6gYRwY9CRZVtmZKH8713XhkGDWcIEMcG0u3oTz3tdKgPU5uyIPrDEWr6w8ClUj4x"
+ + "5aVz5c2223+dVY7KES//JSB2bE/KCIchN3kAioQ4K8O3e0OL6oDVjsqKGw5bfahgKuSIk/Q=");
+
+
+ public String getName()
+ {
+ return "AttrCertTest";
+ }
+
+ private void testCertWithBaseCertificateID()
+ throws Exception
+ {
+ X509AttributeCertificateHolder attrCert = new X509AttributeCertificateHolder(certWithBaseCertificateID);
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+ X509Certificate cert = (X509Certificate)fact.generateCertificate(new ByteArrayInputStream(holderCertWithBaseCertificateID));
+
+ AttributeCertificateHolder holder = attrCert.getHolder();
+
+ if (holder.getEntityNames() != null)
+ {
+ fail("entity names set when none expected");
+ }
+
+ if (!holder.getSerialNumber().equals(cert.getSerialNumber()))
+ {
+ fail("holder serial number doesn't match");
+ }
+
+ if (!holder.getIssuer()[0].equals(X500Name.getInstance(cert.getIssuerX500Principal().getEncoded())))
+ {
+ fail("holder issuer doesn't match");
+ }
+
+ if (!holder.match(new JcaX509CertificateHolder(cert)))
+ {
+ fail("holder not matching holder certificate");
+ }
+
+ if (!holder.equals(holder.clone()))
+ {
+ fail("holder clone test failed");
+ }
+
+ if (!attrCert.getIssuer().equals(attrCert.getIssuer().clone()))
+ {
+ fail("issuer clone test failed");
+ }
+
+ //equalityAndHashCodeTest(attrCert, certWithBaseCertificateID);
+ }
+
+ private void equalityAndHashCodeTest(X509AttributeCertificateHolder attrCert, byte[] encoding)
+ throws IOException
+ {
+ if (!attrCert.equals(attrCert))
+ {
+ fail("same certificate not equal");
+ }
+
+ if (!attrCert.getHolder().equals(attrCert.getHolder()))
+ {
+ fail("same holder not equal");
+ }
+
+ if (!attrCert.getIssuer().equals(attrCert.getIssuer()))
+ {
+ fail("same issuer not equal");
+ }
+
+ if (attrCert.getHolder().equals(attrCert.getIssuer()))
+ {
+ fail("wrong holder equal");
+ }
+
+ if (attrCert.getIssuer().equals(attrCert.getHolder()))
+ {
+ fail("wrong issuer equal");
+ }
+
+ X509AttributeCertificateHolder attrCert2 = new X509AttributeCertificateHolder(encoding);
+
+ if (attrCert2.getHolder().hashCode() != attrCert.getHolder().hashCode())
+ {
+ fail("holder hashCode test failed");
+ }
+
+ if (!attrCert2.getHolder().equals(attrCert.getHolder()))
+ {
+ fail("holder equals test failed");
+ }
+
+ if (attrCert2.getIssuer().hashCode() != attrCert.getIssuer().hashCode())
+ {
+ fail("issuer hashCode test failed");
+ }
+
+ if (!attrCert2.getIssuer().equals(attrCert.getIssuer()))
+ {
+ fail("issuer equals test failed");
+ }
+ }
+
+ private void testGenerateWithCert()
+ throws Exception
+ {
+ CertificateFactory fact = CertificateFactory.getInstance("X.509","SC");
+ X509Certificate iCert = (X509Certificate)fact.generateCertificate(new ByteArrayInputStream(signCert));
+
+ //
+ // a sample key pair.
+ //
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory kFact = KeyFactory.getInstance("RSA", "SC");
+
+ privKey = kFact.generatePrivate(RSA_PRIVATE_KEY_SPEC);
+ pubKey = kFact.generatePublic(pubKeySpec);
+
+ X509v2AttributeCertificateBuilder gen = new X509v2AttributeCertificateBuilder(
+ new AttributeCertificateHolder(new JcaX509CertificateHolder(iCert)),
+ new AttributeCertificateIssuer(new X500Name("cn=test")),
+ BigInteger.ONE,
+ new Date(System.currentTimeMillis() - 50000),
+ new Date(System.currentTimeMillis() + 50000));
+
+ // the actual attributes
+ GeneralName roleName = new GeneralName(GeneralName.rfc822Name, "DAU123456789");
+ ASN1EncodableVector roleSyntax = new ASN1EncodableVector();
+ roleSyntax.add(roleName);
+
+ // roleSyntax OID: 2.5.24.72;
+
+ gen.addAttribute(new ASN1ObjectIdentifier("2.5.24.72"), new DERSequence(roleSyntax));
+
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA1WithRSAEncryption").setProvider(BC).build(privKey);
+
+ X509AttributeCertificateHolder aCert = gen.build(sigGen);
+
+ if (!aCert.isValidOn(new Date()))
+ {
+ fail("certificate invalid");
+ }
+
+ if (!aCert.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("certificate signature not valid");
+ }
+
+ AttributeCertificateHolder holder = aCert.getHolder();
+
+ if (holder.getEntityNames() != null)
+ {
+ fail("entity names set when none expected");
+ }
+
+ if (!holder.getSerialNumber().equals(iCert.getSerialNumber()))
+ {
+ fail("holder serial number doesn't match");
+ }
+
+ if (!holder.getIssuer()[0].equals(X500Name.getInstance(iCert.getIssuerX500Principal().getEncoded())))
+ {
+ fail("holder issuer doesn't match");
+ }
+
+ if (!holder.match(new JcaX509CertificateHolder(iCert)))
+ {
+ fail("generated holder not matching holder certificate");
+ }
+
+ Attribute[] attrs = aCert.getAttributes(new ASN1ObjectIdentifier("2.5.24.72"));
+
+ if (attrs == null)
+ {
+ fail("attributes related to 2.5.24.72 not found");
+ }
+
+ Attribute attr = attrs[0];
+
+ if (!attr.getAttrType().getId().equals("2.5.24.72"))
+ {
+ fail("attribute oid mismatch");
+ }
+
+ ASN1Encodable[] values = attr.getAttrValues().toArray();
+
+ GeneralName role = GeneralNames.getInstance(values[0]).getNames()[0];
+
+ if (role.getTagNo() != GeneralName.rfc822Name)
+ {
+ fail("wrong general name type found in role");
+ }
+
+ if (!((ASN1String)role.getName()).getString().equals("DAU123456789"))
+ {
+ fail("wrong general name value found in role");
+ }
+
+ X509Certificate sCert = (X509Certificate)fact.generateCertificate(new ByteArrayInputStream(holderCertWithBaseCertificateID));
+
+ if (holder.match(new JcaX509CertificateHolder(sCert)))
+ {
+ fail("generated holder matching wrong certificate");
+ }
+
+ equalityAndHashCodeTest(aCert, aCert.getEncoded());
+ }
+
+ private void testGenerateWithPrincipal()
+ throws Exception
+ {
+ CertificateFactory fact = CertificateFactory.getInstance("X.509","SC");
+ X509Certificate iCert = (X509Certificate)fact.generateCertificate(new ByteArrayInputStream(signCert));
+
+ //
+ // a sample key pair.
+ //
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory kFact = KeyFactory.getInstance("RSA", "SC");
+
+ privKey = kFact.generatePrivate(RSA_PRIVATE_KEY_SPEC);
+ pubKey = kFact.generatePublic(pubKeySpec);
+
+ X509v2AttributeCertificateBuilder gen = new X509v2AttributeCertificateBuilder(
+ new AttributeCertificateHolder(new JcaX509CertificateHolder(iCert).getSubject()),
+ new AttributeCertificateIssuer(new X500Name("cn=test")),
+ BigInteger.ONE,
+ new Date(System.currentTimeMillis() - 50000),
+ new Date(System.currentTimeMillis() + 50000));
+
+ // the actual attributes
+ GeneralName roleName = new GeneralName(GeneralName.rfc822Name, "DAU123456789");
+ ASN1EncodableVector roleSyntax = new ASN1EncodableVector();
+ roleSyntax.add(roleName);
+
+ // roleSyntax OID: 2.5.24.72
+
+ gen.addAttribute(new ASN1ObjectIdentifier("2.5.24.72"), new DERSequence(roleSyntax));
+
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA1WithRSAEncryption").setProvider(BC).build(privKey);
+
+ X509AttributeCertificateHolder aCert = gen.build(sigGen);
+
+ if (!aCert.isValidOn(new Date()))
+ {
+ fail("certificate invalid");
+ }
+
+ if (!aCert.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("certificate signature not valid");
+ }
+
+ AttributeCertificateHolder holder = aCert.getHolder();
+
+ if (holder.getEntityNames() == null)
+ {
+ fail("entity names not set when expected");
+ }
+
+ if (holder.getSerialNumber() != null)
+ {
+ fail("holder serial number found when none expected");
+ }
+
+ if (holder.getIssuer() != null)
+ {
+ fail("holder issuer found when none expected");
+ }
+
+ if (!holder.match(new JcaX509CertificateHolder(iCert)))
+ {
+ fail("generated holder not matching holder certificate");
+ }
+
+ X509Certificate sCert = (X509Certificate)fact.generateCertificate(new ByteArrayInputStream(holderCertWithBaseCertificateID));
+
+ if (holder.match(sCert))
+ {
+ fail("principal generated holder matching wrong certificate");
+ }
+
+ equalityAndHashCodeTest(aCert, aCert.getEncoded());
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ X509AttributeCertificateHolder aCert = new X509AttributeCertificateHolder(attrCert);
+ CertificateFactory fact = CertificateFactory.getInstance("X.509","SC");
+ X509Certificate sCert = (X509Certificate)fact.generateCertificate(new ByteArrayInputStream(signCert));
+
+ if (!aCert.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(sCert)))
+ {
+ fail("certificate signature not valid");
+ }
+
+ //
+ // search test
+ //
+
+ List list = new ArrayList();
+
+ list.add(sCert);
+
+ Store store = new JcaCertStore(list);
+
+ Collection certs = store.getMatches(aCert.getIssuer());
+ if (certs.size() != 1 || !certs.contains(new JcaX509CertificateHolder(sCert)))
+ {
+ fail("sCert not found by issuer");
+ }
+
+ Attribute[] attrs = aCert.getAttributes(new ASN1ObjectIdentifier("1.3.6.1.4.1.6760.8.1.1"));
+ if (attrs == null || attrs.length != 1)
+ {
+ fail("attribute not found");
+ }
+
+ //
+ // reencode test
+ //
+ aCert = new X509AttributeCertificateHolder(aCert.getEncoded());
+
+ if (!aCert.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(sCert)))
+ {
+ fail("certificate signature not valid");
+ }
+
+ X509AttributeCertificateHolder saCert = new X509AttributeCertificateHolder(aCert.getEncoded());
+
+ if (!aCert.getNotAfter().equals(saCert.getNotAfter()))
+ {
+ fail("failed date comparison");
+ }
+
+ // base generator test
+
+ //
+ // a sample key pair.
+ //
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ RSAPrivateCrtKeySpec privKeySpec = RSA_PRIVATE_KEY_SPEC;
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory kFact = KeyFactory.getInstance("RSA", "SC");
+
+ privKey = kFact.generatePrivate(privKeySpec);
+ pubKey = kFact.generatePublic(pubKeySpec);
+
+ X509v2AttributeCertificateBuilder gen = new X509v2AttributeCertificateBuilder(
+ aCert.getHolder(),
+ aCert.getIssuer(),
+ aCert.getSerialNumber(),
+ new Date(System.currentTimeMillis() - 50000),
+ new Date(System.currentTimeMillis() + 50000));
+
+ gen.addAttribute(attrs[0].getAttrType(), attrs[0].getAttributeValues());
+
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA1WithRSAEncryption").setProvider(BC).build(privKey);
+
+ aCert = gen.build(sigGen);
+
+ if (!aCert.isValidOn(new Date()))
+ {
+ fail("certificate not valid");
+ }
+
+ if (!aCert.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("signature not valid");
+ }
+
+ // as the issuer is the same this should still work (even though it is not
+ // technically correct
+
+ certs = store.getMatches(aCert.getIssuer());
+ if (certs.size() != 1 || !certs.contains(new JcaX509CertificateHolder(sCert)))
+ {
+ fail("sCert not found by issuer");
+ }
+
+ attrs = aCert.getAttributes(new ASN1ObjectIdentifier("1.3.6.1.4.1.6760.8.1.1"));
+ if (attrs == null || attrs.length != 1)
+ {
+ fail("attribute not found");
+ }
+
+ //
+ // reencode test
+ //
+ aCert = new X509AttributeCertificateHolder(aCert.getEncoded());
+
+ if (!aCert.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("signature not valid");
+ }
+
+ AttributeCertificateIssuer issuer = aCert.getIssuer();
+
+ X500Name[] principals = issuer.getNames();
+
+ //
+ // test holder
+ //
+ AttributeCertificateHolder holder = aCert.getHolder();
+
+ if (holder.getEntityNames() == null)
+ {
+ fail("entity names not set");
+ }
+
+ if (holder.getSerialNumber() != null)
+ {
+ fail("holder serial number set when none expected");
+ }
+
+ if (holder.getIssuer() != null)
+ {
+ fail("holder issuer set when none expected");
+ }
+
+ principals = holder.getEntityNames();
+
+ X500Principal principal0 = new X500Principal(principals[0].getEncoded());
+ if (!principal0.toString().equals("C=US, O=vt, OU=Class 2, OU=Virginia Tech User, CN=Markus Lorch (mlorch), EMAILADDRESS=mlorch@vt.edu"))
+ {
+ fail("principal[0] for entity names don't match");
+ }
+
+ //
+ // extension test
+ //
+
+ if (aCert.hasExtensions())
+ {
+ fail("hasExtensions true with no extensions");
+ }
+
+ gen.addExtension(new ASN1ObjectIdentifier("1.1"), true, new DEROctetString(new byte[10]));
+
+ gen.addExtension(new ASN1ObjectIdentifier("2.2"), false, new DEROctetString(new byte[20]));
+
+ aCert = gen.build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(privKey));
+
+ Set exts = aCert.getCriticalExtensionOIDs();
+
+ if (exts.size() != 1 || !exts.contains(new ASN1ObjectIdentifier("1.1")))
+ { System.err.println(exts);
+ fail("critical extension test failed");
+ }
+
+ exts = aCert.getNonCriticalExtensionOIDs();
+
+ if (exts.size() != 1 || !exts.contains(new ASN1ObjectIdentifier("2.2")))
+ {
+ fail("non-critical extension test failed");
+ }
+
+ if (aCert.getCriticalExtensionOIDs().isEmpty())
+ {
+ fail("critical extensions not found");
+ }
+
+ Extension ext = aCert.getExtension(new ASN1ObjectIdentifier("1.1"));
+ ASN1Encodable extValue = ext.getParsedValue();
+
+ if (!extValue.equals(new DEROctetString(new byte[10])))
+ {
+ fail("wrong extension value found for 1.1");
+ }
+
+ testCertWithBaseCertificateID();
+ testGenerateWithCert();
+ testGenerateWithPrincipal();
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new AttrCertTest());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/BcAttrCertSelectorTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/BcAttrCertSelectorTest.java
new file mode 100644
index 000000000..bf5557fda
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/BcAttrCertSelectorTest.java
@@ -0,0 +1,212 @@
+package org.spongycastle.cert.test;
+
+import java.math.BigInteger;
+import java.util.Date;
+
+import junit.framework.TestCase;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.Target;
+import org.spongycastle.asn1.x509.TargetInformation;
+import org.spongycastle.cert.AttributeCertificateHolder;
+import org.spongycastle.cert.AttributeCertificateIssuer;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509v2AttributeCertificateBuilder;
+import org.spongycastle.cert.selector.X509AttributeCertificateHolderSelectorBuilder;
+import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.bc.BcRSAContentSignerBuilder;
+import org.spongycastle.util.encoders.Base64;
+
+public class BcAttrCertSelectorTest
+ extends TestCase
+{
+ DefaultSignatureAlgorithmIdentifierFinder sigAlgFinder = new DefaultSignatureAlgorithmIdentifierFinder();
+ DefaultDigestAlgorithmIdentifierFinder digAlgFinder = new DefaultDigestAlgorithmIdentifierFinder();
+
+ static final RSAPrivateCrtKeyParameters RSA_PRIVATE_KEY_SPEC = new RSAPrivateCrtKeyParameters(
+ 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));
+
+ static final byte[] holderCert = Base64
+ .decode("MIIGjTCCBXWgAwIBAgICAPswDQYJKoZIhvcNAQEEBQAwaTEdMBsGCSqGSIb3DQEJ"
+ + "ARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZpcmdpbmlhIFRlY2ggQ2VydGlm"
+ + "aWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0MQswCQYDVQQGEwJVUzAeFw0w"
+ + "MzAxMzExMzUyMTRaFw0wNDAxMzExMzUyMTRaMIGDMRswGQYJKoZIhvcNAQkBFgxz"
+ + "c2hhaEB2dC5lZHUxGzAZBgNVBAMTElN1bWl0IFNoYWggKHNzaGFoKTEbMBkGA1UE"
+ + "CxMSVmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAxMQswCQYDVQQK"
+ + "EwJ2dDELMAkGA1UEBhMCVVMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPDc"
+ + "scgSKmsEp0VegFkuitD5j5PUkDuzLjlfaYONt2SN8WeqU4j2qtlCnsipa128cyKS"
+ + "JzYe9duUdNxquh5BPIkMkHBw4jHoQA33tk0J/sydWdN74/AHPpPieK5GHwhU7GTG"
+ + "rCCS1PJRxjXqse79ExAlul+gjQwHeldAC+d4A6oZAgMBAAGjggOmMIIDojAMBgNV"
+ + "HRMBAf8EAjAAMBEGCWCGSAGG+EIBAQQEAwIFoDAOBgNVHQ8BAf8EBAMCA/gwHQYD"
+ + "VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMB0GA1UdDgQWBBRUIoWAzlXbzBYE"
+ + "yVTjQFWyMMKo1jCBkwYDVR0jBIGLMIGIgBTgc3Fm+TGqKDhen+oKfbl+xVbj2KFt"
+ + "pGswaTEdMBsGCSqGSIb3DQEJARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZp"
+ + "cmdpbmlhIFRlY2ggQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0"
+ + "MQswCQYDVQQGEwJVU4IBADCBiwYJYIZIAYb4QgENBH4WfFZpcmdpbmlhIFRlY2gg"
+ + "Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgZGlnaXRhbCBjZXJ0aWZpY2F0ZXMgYXJl"
+ + "IHN1YmplY3QgdG8gcG9saWNpZXMgbG9jYXRlZCBhdCBodHRwOi8vd3d3LnBraS52"
+ + "dC5lZHUvY2EvY3BzLy4wFwYDVR0RBBAwDoEMc3NoYWhAdnQuZWR1MBkGA1UdEgQS"
+ + "MBCBDmlybWhlbHBAdnQuZWR1MEMGCCsGAQUFBwEBBDcwNTAzBggrBgEFBQcwAoYn"
+ + "aHR0cDovL2JveDE3Ny5jYy52dC5lZHUvY2EvaXNzdWVycy5odG1sMEQGA1UdHwQ9"
+ + "MDswOaA3oDWGM2h0dHA6Ly9ib3gxNzcuY2MudnQuZWR1L2h0ZG9jcy1wdWJsaWMv"
+ + "Y3JsL2NhY3JsLmNybDBUBgNVHSAETTBLMA0GCysGAQQBtGgFAQEBMDoGCysGAQQB"
+ + "tGgFAQEBMCswKQYIKwYBBQUHAgEWHWh0dHA6Ly93d3cucGtpLnZ0LmVkdS9jYS9j"
+ + "cHMvMD8GCWCGSAGG+EIBBAQyFjBodHRwOi8vYm94MTc3LmNjLnZ0LmVkdS9jZ2kt"
+ + "cHVibGljL2NoZWNrX3Jldl9jYT8wPAYJYIZIAYb4QgEDBC8WLWh0dHA6Ly9ib3gx"
+ + "NzcuY2MudnQuZWR1L2NnaS1wdWJsaWMvY2hlY2tfcmV2PzBLBglghkgBhvhCAQcE"
+ + "PhY8aHR0cHM6Ly9ib3gxNzcuY2MudnQuZWR1L35PcGVuQ0E4LjAxMDYzMC9jZ2kt"
+ + "cHVibGljL3JlbmV3YWw/MCwGCWCGSAGG+EIBCAQfFh1odHRwOi8vd3d3LnBraS52"
+ + "dC5lZHUvY2EvY3BzLzANBgkqhkiG9w0BAQQFAAOCAQEAHJ2ls9yjpZVcu5DqiE67"
+ + "r7BfkdMnm7IOj2v8cd4EAlPp6OPBmjwDMwvKRBb/P733kLBqFNWXWKTpT008R0KB"
+ + "8kehbx4h0UPz9vp31zhGv169+5iReQUUQSIwTGNWGLzrT8kPdvxiSAvdAJxcbRBm"
+ + "KzDic5I8PoGe48kSCkPpT1oNmnivmcu5j1SMvlx0IS2BkFMksr0OHiAW1elSnE/N"
+ + "RuX2k73b3FucwVxB3NRo3vgoHPCTnh9r4qItAHdxFlF+pPtbw2oHESKRfMRfOIHz"
+ + "CLQWSIa6Tvg4NIV3RRJ0sbCObesyg08lymalQMdkXwtRn5eGE00SHWwEUjSXP2gR"
+ + "3g==");
+
+ public String getName()
+ {
+ return "AttrCertSelector";
+ }
+
+ private X509AttributeCertificateHolder createAttrCert() throws Exception
+ {
+ X509CertificateHolder iCertHolder = new X509CertificateHolder(holderCert);
+ //
+ // a sample key pair.
+ //
+ // RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ // new BigInteger(
+ // "b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7",
+ // 16), new BigInteger("11", 16));
+
+ X509v2AttributeCertificateBuilder gen = new X509v2AttributeCertificateBuilder(
+ new AttributeCertificateHolder(iCertHolder.getSubject()),
+ new AttributeCertificateIssuer(new X500Name("cn=test")),
+ BigInteger.ONE,
+ new Date(System.currentTimeMillis() - 50000),
+ new Date(System.currentTimeMillis() + 50000));
+
+ // the actual attributes
+ GeneralName roleName = new GeneralName(GeneralName.rfc822Name,
+ "DAU123456789@test.com");
+ ASN1EncodableVector roleSyntax = new ASN1EncodableVector();
+ roleSyntax.add(roleName);
+
+ // roleSyntax OID: 2.5.24.72
+ gen.addAttribute(new ASN1ObjectIdentifier("2.5.24.72"), new DERSequence(roleSyntax));
+
+
+ AlgorithmIdentifier sigAlg = sigAlgFinder.find("SHA1withRSA");
+ AlgorithmIdentifier digAlg = digAlgFinder.find(sigAlg);
+
+ ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlg, digAlg).build(RSA_PRIVATE_KEY_SPEC);
+ Target targetName = new Target(Target.targetName, new GeneralName(GeneralName.dNSName,
+ "www.test.com"));
+
+ Target targetGroup = new Target(Target.targetGroup, new GeneralName(
+ GeneralName.directoryName, "o=Test, ou=Test"));
+ Target[] targets = new Target[2];
+ targets[0] = targetName;
+ targets[1] = targetGroup;
+ TargetInformation targetInformation = new TargetInformation(targets);
+
+ gen.addExtension(Extension.targetInformation, true, targetInformation);
+
+ return gen.build(sigGen);
+ }
+
+ public void testSelector() throws Exception
+ {
+ X509AttributeCertificateHolder aCert = createAttrCert();
+ X509AttributeCertificateHolderSelectorBuilder sel = new X509AttributeCertificateHolderSelectorBuilder();
+ sel.setAttributeCert(aCert);
+ boolean match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate.");
+ }
+ sel.setAttributeCert(null);
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate.");
+ }
+ sel.setHolder(aCert.getHolder());
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate holder.");
+ }
+ sel.setHolder(null);
+ sel.setIssuer(aCert.getIssuer());
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate issuer.");
+ }
+ sel.setIssuer(null);
+
+ X509CertificateHolder iCert = new X509CertificateHolder(holderCert);
+ match = aCert.getHolder().match(iCert);
+ if (!match)
+ {
+ fail("Issuer holder does not match signing certificate of attribute certificate.");
+ }
+
+ sel.setSerialNumber(aCert.getSerialNumber());
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate serial number.");
+ }
+
+ sel.setAttributeCertificateValid(new Date());
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate time.");
+ }
+
+ sel.addTargetName(new GeneralName(2, "www.test.com"));
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate target name.");
+ }
+ sel.setTargetNames(null);
+ sel.addTargetGroup(new GeneralName(4, "o=Test, ou=Test"));
+ match = sel.build().match(aCert);
+ if (!match)
+ {
+ fail("Selector does not match attribute certificate target group.");
+ }
+ sel.setTargetGroups(null);
+ }
+}
+
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/BcAttrCertTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/BcAttrCertTest.java
new file mode 100644
index 000000000..6603e4d5d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/BcAttrCertTest.java
@@ -0,0 +1,636 @@
+package org.spongycastle.cert.test;
+
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import junit.framework.TestCase;
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+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.x500.style.RFC4519Style;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.Attribute;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.cert.AttributeCertificateHolder;
+import org.spongycastle.cert.AttributeCertificateIssuer;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509v2AttributeCertificateBuilder;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.bc.BcRSAContentSignerBuilder;
+import org.spongycastle.operator.bc.BcRSAContentVerifierProviderBuilder;
+import org.spongycastle.util.CollectionStore;
+import org.spongycastle.util.Store;
+import org.spongycastle.util.encoders.Base64;
+
+public class BcAttrCertTest
+ extends TestCase
+{
+ DefaultSignatureAlgorithmIdentifierFinder sigAlgFinder = new DefaultSignatureAlgorithmIdentifierFinder();
+ DefaultDigestAlgorithmIdentifierFinder digAlgFinder = new DefaultDigestAlgorithmIdentifierFinder();
+
+ private static final AsymmetricKeyParameter RSA_PRIVATE_KEY_SPEC = new RSAPrivateCrtKeyParameters(
+ 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));
+
+ public static byte[] attrCert = Base64.decode(
+ "MIIHQDCCBqkCAQEwgZChgY2kgYowgYcxHDAaBgkqhkiG9w0BCQEWDW1sb3JjaEB2"
+ + "dC5lZHUxHjAcBgNVBAMTFU1hcmt1cyBMb3JjaCAobWxvcmNoKTEbMBkGA1UECxMS"
+ + "VmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAyMQswCQYDVQQKEwJ2"
+ + "dDELMAkGA1UEBhMCVVMwgYmkgYYwgYMxGzAZBgkqhkiG9w0BCQEWDHNzaGFoQHZ0"
+ + "LmVkdTEbMBkGA1UEAxMSU3VtaXQgU2hhaCAoc3NoYWgpMRswGQYDVQQLExJWaXJn"
+ + "aW5pYSBUZWNoIFVzZXIxEDAOBgNVBAsTB0NsYXNzIDExCzAJBgNVBAoTAnZ0MQsw"
+ + "CQYDVQQGEwJVUzANBgkqhkiG9w0BAQQFAAIBBTAiGA8yMDAzMDcxODE2MDgwMloY"
+ + "DzIwMDMwNzI1MTYwODAyWjCCBU0wggVJBgorBgEEAbRoCAEBMYIFORaCBTU8UnVs"
+ + "ZSBSdWxlSWQ9IkZpbGUtUHJpdmlsZWdlLVJ1bGUiIEVmZmVjdD0iUGVybWl0Ij4K"
+ + "IDxUYXJnZXQ+CiAgPFN1YmplY3RzPgogICA8U3ViamVjdD4KICAgIDxTdWJqZWN0"
+ + "TWF0Y2ggTWF0Y2hJZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5j"
+ + "dGlvbjpzdHJpbmctZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlw"
+ + "ZT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjc3RyaW5nIj4KICAg"
+ + "ICAgIENOPU1hcmt1cyBMb3JjaDwvQXR0cmlidXRlVmFsdWU+CiAgICAgPFN1Ympl"
+ + "Y3RBdHRyaWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFt"
+ + "ZXM6dGM6eGFjbWw6MS4wOnN1YmplY3Q6c3ViamVjdC1pZCIgRGF0YVR5cGU9Imh0"
+ + "dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hI3N0cmluZyIgLz4gCiAgICA8"
+ + "L1N1YmplY3RNYXRjaD4KICAgPC9TdWJqZWN0PgogIDwvU3ViamVjdHM+CiAgPFJl"
+ + "c291cmNlcz4KICAgPFJlc291cmNlPgogICAgPFJlc291cmNlTWF0Y2ggTWF0Y2hJ"
+ + "ZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5jdGlvbjpzdHJpbmct"
+ + "ZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlwZT0iaHR0cDovL3d3"
+ + "dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIj4KICAgICAgaHR0cDovL3p1"
+ + "bmkuY3MudnQuZWR1PC9BdHRyaWJ1dGVWYWx1ZT4KICAgICA8UmVzb3VyY2VBdHRy"
+ + "aWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6"
+ + "eGFjbWw6MS4wOnJlc291cmNlOnJlc291cmNlLWlkIiBEYXRhVHlwZT0iaHR0cDov"
+ + "L3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIiAvPiAKICAgIDwvUmVz"
+ + "b3VyY2VNYXRjaD4KICAgPC9SZXNvdXJjZT4KICA8L1Jlc291cmNlcz4KICA8QWN0"
+ + "aW9ucz4KICAgPEFjdGlvbj4KICAgIDxBY3Rpb25NYXRjaCBNYXRjaElkPSJ1cm46"
+ + "b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmZ1bmN0aW9uOnN0cmluZy1lcXVhbCI+"
+ + "CiAgICAgPEF0dHJpYnV0ZVZhbHVlIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9y"
+ + "Zy8yMDAxL1hNTFNjaGVtYSNzdHJpbmciPgpEZWxlZ2F0ZSBBY2Nlc3MgICAgIDwv"
+ + "QXR0cmlidXRlVmFsdWU+CgkgIDxBY3Rpb25BdHRyaWJ1dGVEZXNpZ25hdG9yIEF0"
+ + "dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmFjdGlvbjph"
+ + "Y3Rpb24taWQiIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNj"
+ + "aGVtYSNzdHJpbmciIC8+IAogICAgPC9BY3Rpb25NYXRjaD4KICAgPC9BY3Rpb24+"
+ + "CiAgPC9BY3Rpb25zPgogPC9UYXJnZXQ+CjwvUnVsZT4KMA0GCSqGSIb3DQEBBAUA"
+ + "A4GBAGiJSM48XsY90HlYxGmGVSmNR6ZW2As+bot3KAfiCIkUIOAqhcphBS23egTr"
+ + "6asYwy151HshbPNYz+Cgeqs45KkVzh7bL/0e1r8sDVIaaGIkjHK3CqBABnfSayr3"
+ + "Rd1yBoDdEv8Qb+3eEPH6ab9021AsLEnJ6LWTmybbOpMNZ3tv");
+
+ byte[] signCert = Base64.decode(
+ "MIIGjTCCBXWgAwIBAgICAPswDQYJKoZIhvcNAQEEBQAwaTEdMBsGCSqGSIb3DQEJ"
+ + "ARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZpcmdpbmlhIFRlY2ggQ2VydGlm"
+ + "aWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0MQswCQYDVQQGEwJVUzAeFw0w"
+ + "MzAxMzExMzUyMTRaFw0wNDAxMzExMzUyMTRaMIGDMRswGQYJKoZIhvcNAQkBFgxz"
+ + "c2hhaEB2dC5lZHUxGzAZBgNVBAMTElN1bWl0IFNoYWggKHNzaGFoKTEbMBkGA1UE"
+ + "CxMSVmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAxMQswCQYDVQQK"
+ + "EwJ2dDELMAkGA1UEBhMCVVMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPDc"
+ + "scgSKmsEp0VegFkuitD5j5PUkDuzLjlfaYONt2SN8WeqU4j2qtlCnsipa128cyKS"
+ + "JzYe9duUdNxquh5BPIkMkHBw4jHoQA33tk0J/sydWdN74/AHPpPieK5GHwhU7GTG"
+ + "rCCS1PJRxjXqse79ExAlul+gjQwHeldAC+d4A6oZAgMBAAGjggOmMIIDojAMBgNV"
+ + "HRMBAf8EAjAAMBEGCWCGSAGG+EIBAQQEAwIFoDAOBgNVHQ8BAf8EBAMCA/gwHQYD"
+ + "VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMB0GA1UdDgQWBBRUIoWAzlXbzBYE"
+ + "yVTjQFWyMMKo1jCBkwYDVR0jBIGLMIGIgBTgc3Fm+TGqKDhen+oKfbl+xVbj2KFt"
+ + "pGswaTEdMBsGCSqGSIb3DQEJARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZp"
+ + "cmdpbmlhIFRlY2ggQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0"
+ + "MQswCQYDVQQGEwJVU4IBADCBiwYJYIZIAYb4QgENBH4WfFZpcmdpbmlhIFRlY2gg"
+ + "Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgZGlnaXRhbCBjZXJ0aWZpY2F0ZXMgYXJl"
+ + "IHN1YmplY3QgdG8gcG9saWNpZXMgbG9jYXRlZCBhdCBodHRwOi8vd3d3LnBraS52"
+ + "dC5lZHUvY2EvY3BzLy4wFwYDVR0RBBAwDoEMc3NoYWhAdnQuZWR1MBkGA1UdEgQS"
+ + "MBCBDmlybWhlbHBAdnQuZWR1MEMGCCsGAQUFBwEBBDcwNTAzBggrBgEFBQcwAoYn"
+ + "aHR0cDovL2JveDE3Ny5jYy52dC5lZHUvY2EvaXNzdWVycy5odG1sMEQGA1UdHwQ9"
+ + "MDswOaA3oDWGM2h0dHA6Ly9ib3gxNzcuY2MudnQuZWR1L2h0ZG9jcy1wdWJsaWMv"
+ + "Y3JsL2NhY3JsLmNybDBUBgNVHSAETTBLMA0GCysGAQQBtGgFAQEBMDoGCysGAQQB"
+ + "tGgFAQEBMCswKQYIKwYBBQUHAgEWHWh0dHA6Ly93d3cucGtpLnZ0LmVkdS9jYS9j"
+ + "cHMvMD8GCWCGSAGG+EIBBAQyFjBodHRwOi8vYm94MTc3LmNjLnZ0LmVkdS9jZ2kt"
+ + "cHVibGljL2NoZWNrX3Jldl9jYT8wPAYJYIZIAYb4QgEDBC8WLWh0dHA6Ly9ib3gx"
+ + "NzcuY2MudnQuZWR1L2NnaS1wdWJsaWMvY2hlY2tfcmV2PzBLBglghkgBhvhCAQcE"
+ + "PhY8aHR0cHM6Ly9ib3gxNzcuY2MudnQuZWR1L35PcGVuQ0E4LjAxMDYzMC9jZ2kt"
+ + "cHVibGljL3JlbmV3YWw/MCwGCWCGSAGG+EIBCAQfFh1odHRwOi8vd3d3LnBraS52"
+ + "dC5lZHUvY2EvY3BzLzANBgkqhkiG9w0BAQQFAAOCAQEAHJ2ls9yjpZVcu5DqiE67"
+ + "r7BfkdMnm7IOj2v8cd4EAlPp6OPBmjwDMwvKRBb/P733kLBqFNWXWKTpT008R0KB"
+ + "8kehbx4h0UPz9vp31zhGv169+5iReQUUQSIwTGNWGLzrT8kPdvxiSAvdAJxcbRBm"
+ + "KzDic5I8PoGe48kSCkPpT1oNmnivmcu5j1SMvlx0IS2BkFMksr0OHiAW1elSnE/N"
+ + "RuX2k73b3FucwVxB3NRo3vgoHPCTnh9r4qItAHdxFlF+pPtbw2oHESKRfMRfOIHz"
+ + "CLQWSIa6Tvg4NIV3RRJ0sbCObesyg08lymalQMdkXwtRn5eGE00SHWwEUjSXP2gR"
+ + "3g==");
+
+ static byte[] certWithBaseCertificateID = Base64.decode(
+ "MIIBqzCCARQCAQEwSKBGMD6kPDA6MQswCQYDVQQGEwJJVDEOMAwGA1UEChMFVU5JVE4xDDAKBgNV"
+ + "BAsTA0RJVDENMAsGA1UEAxMEcm9vdAIEAVMVjqB6MHikdjB0MQswCQYDVQQGEwJBVTEoMCYGA1UE"
+ + "ChMfVGhlIExlZ2lvbiBvZiB0aGUgQm91bmN5IENhc3RsZTEjMCEGA1UECxMaQm91bmN5IFByaW1h"
+ + "cnkgQ2VydGlmaWNhdGUxFjAUBgNVBAMTDUJvdW5jeSBDYXN0bGUwDQYJKoZIhvcNAQEFBQACBQKW"
+ + "RhnHMCIYDzIwMDUxMjEyMTIwMDQyWhgPMjAwNTEyMTkxMjAxMzJaMA8wDQYDVRhIMQaBBGVWSVAw"
+ + "DQYJKoZIhvcNAQEFBQADgYEAUAVin9StDaA+InxtXq/av6rUQLI9p1X6louBcj4kYJnxRvTrHpsr"
+ + "N3+i9Uq/uk5lRdAqmPFvcmSbuE3TRAsjrXON5uFiBBKZ1AouLqcr8nHbwcdwjJ9TyUNO9I4hfpSH"
+ + "UHHXMtBKgp4MOkhhX8xTGyWg3hp23d3GaUeg/IYlXBI=");
+
+ byte[] holderCertWithBaseCertificateID = Base64.decode(
+ "MIIBwDCCASmgAwIBAgIEAVMVjjANBgkqhkiG9w0BAQUFADA6MQswCQYDVQQGEwJJVDEOMAwGA1UE"
+ + "ChMFVU5JVE4xDDAKBgNVBAsTA0RJVDENMAsGA1UEAxMEcm9vdDAeFw0wNTExMTExMjAxMzJaFw0w"
+ + "NjA2MTYxMjAxMzJaMD4xCzAJBgNVBAYTAklUMQ4wDAYDVQQKEwVVTklUTjEMMAoGA1UECxMDRElU"
+ + "MREwDwYDVQQDEwhMdWNhQm9yejBaMA0GCSqGSIb3DQEBAQUAA0kAMEYCQQC0p+RhcFdPFqlwgrIr"
+ + "5YtqKmKXmEGb4ShypL26Ymz66ZAPdqv7EhOdzl3lZWT6srZUMWWgQMYGiHQg4z2R7X7XAgERoxUw"
+ + "EzARBglghkgBhvhCAQEEBAMCBDAwDQYJKoZIhvcNAQEFBQADgYEAsX50VPQQCWmHvPq9y9DeCpmS"
+ + "4szcpFAhpZyn6gYRwY9CRZVtmZKH8713XhkGDWcIEMcG0u3oTz3tdKgPU5uyIPrDEWr6w8ClUj4x"
+ + "5aVz5c2223+dVY7KES//JSB2bE/KCIchN3kAioQ4K8O3e0OL6oDVjsqKGw5bfahgKuSIk/Q=");
+
+
+ public String getName()
+ {
+ return "AttrCertTest";
+ }
+
+ public void testCertWithBaseCertificateID()
+ throws Exception
+ {
+ X509AttributeCertificateHolder attrCert = new X509AttributeCertificateHolder(certWithBaseCertificateID);
+ X509CertificateHolder cert = new X509CertificateHolder(holderCertWithBaseCertificateID);
+
+ AttributeCertificateHolder holder = attrCert.getHolder();
+
+ if (holder.getEntityNames() != null)
+ {
+ fail("entity names set when none expected");
+ }
+
+ if (!holder.getSerialNumber().equals(cert.getSerialNumber()))
+ {
+ fail("holder serial number doesn't match");
+ }
+
+ if (!holder.getIssuer()[0].equals(cert.getIssuer()))
+ {
+ fail("holder issuer doesn't match");
+ }
+
+ if (!holder.match(cert))
+ {
+ fail("holder not matching holder certificate");
+ }
+
+ if (!holder.equals(holder.clone()))
+ {
+ fail("holder clone test failed");
+ }
+
+ if (!attrCert.getIssuer().equals(attrCert.getIssuer().clone()))
+ {
+ fail("issuer clone test failed");
+ }
+
+ //equalityAndHashCodeTest(attrCert, certWithBaseCertificateID);
+ }
+
+ private void equalityAndHashCodeTest(X509AttributeCertificateHolder attrCert, byte[] encoding)
+ throws IOException
+ {
+ if (!attrCert.equals(attrCert))
+ {
+ fail("same certificate not equal");
+ }
+
+ if (!attrCert.getHolder().equals(attrCert.getHolder()))
+ {
+ fail("same holder not equal");
+ }
+
+ if (!attrCert.getIssuer().equals(attrCert.getIssuer()))
+ {
+ fail("same issuer not equal");
+ }
+
+ if (attrCert.getHolder().equals(attrCert.getIssuer()))
+ {
+ fail("wrong holder equal");
+ }
+
+ if (attrCert.getIssuer().equals(attrCert.getHolder()))
+ {
+ fail("wrong issuer equal");
+ }
+
+ X509AttributeCertificateHolder attrCert2 = new X509AttributeCertificateHolder(encoding);
+
+ if (attrCert2.getHolder().hashCode() != attrCert.getHolder().hashCode())
+ {
+ fail("holder hashCode test failed");
+ }
+
+ if (!attrCert2.getHolder().equals(attrCert.getHolder()))
+ {
+ fail("holder equals test failed");
+ }
+
+ if (attrCert2.getIssuer().hashCode() != attrCert.getIssuer().hashCode())
+ {
+ fail("issuer hashCode test failed");
+ }
+
+ if (!attrCert2.getIssuer().equals(attrCert.getIssuer()))
+ {
+ fail("issuer equals test failed");
+ }
+ }
+
+ public void testGenerateWithCert()
+ throws Exception
+ {
+ X509CertificateHolder iCert = new X509CertificateHolder(signCert);
+
+ //
+ // a sample key pair.
+ //
+ AsymmetricKeyParameter pubKey = new RSAKeyParameters(
+ false,
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ //
+ // set up the keys
+ //
+ AsymmetricKeyParameter privKey = RSA_PRIVATE_KEY_SPEC;
+
+ X509v2AttributeCertificateBuilder gen = new X509v2AttributeCertificateBuilder(
+ new AttributeCertificateHolder(iCert),
+ new AttributeCertificateIssuer(new X500Name("cn=test")),
+ BigInteger.ONE,
+ new Date(System.currentTimeMillis() - 50000),
+ new Date(System.currentTimeMillis() + 50000));
+
+ // the actual attributes
+ GeneralName roleName = new GeneralName(GeneralName.rfc822Name, "DAU123456789");
+ ASN1EncodableVector roleSyntax = new ASN1EncodableVector();
+ roleSyntax.add(roleName);
+
+ // roleSyntax OID: 2.5.24.72;
+
+ gen.addAttribute(new ASN1ObjectIdentifier("2.5.24.72"), new DERSequence(roleSyntax));
+
+ AlgorithmIdentifier sigAlg = sigAlgFinder.find("SHA1withRSA");
+ AlgorithmIdentifier digAlg = digAlgFinder.find(sigAlg);
+
+ ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlg, digAlg).build(privKey);
+
+ X509AttributeCertificateHolder aCert = gen.build(sigGen);
+
+ if (!aCert.isValidOn(new Date()))
+ {
+ fail("certificate invalid");
+ }
+
+ if (!aCert.isSignatureValid(new BcRSAContentVerifierProviderBuilder(digAlgFinder).build(pubKey)))
+ {
+ fail("certificate signature not valid");
+ }
+
+ AttributeCertificateHolder holder = aCert.getHolder();
+
+ if (holder.getEntityNames() != null)
+ {
+ fail("entity names set when none expected");
+ }
+
+ if (!holder.getSerialNumber().equals(iCert.getSerialNumber()))
+ {
+ fail("holder serial number doesn't match");
+ }
+
+ if (!holder.getIssuer()[0].equals(iCert.getIssuer()))
+ {
+ fail("holder issuer doesn't match");
+ }
+
+ if (!holder.match(iCert))
+ {
+ fail("generated holder not matching holder certificate");
+ }
+
+ Attribute[] attrs = aCert.getAttributes(new ASN1ObjectIdentifier("2.5.24.72"));
+
+ if (attrs == null)
+ {
+ fail("attributes related to 2.5.24.72 not found");
+ }
+
+ Attribute attr = attrs[0];
+
+ if (!attr.getAttrType().getId().equals("2.5.24.72"))
+ {
+ fail("attribute oid mismatch");
+ }
+
+ ASN1Encodable[] values = attr.getAttrValues().toArray();
+
+ GeneralName role = GeneralNames.getInstance(values[0]).getNames()[0];
+
+ if (role.getTagNo() != GeneralName.rfc822Name)
+ {
+ fail("wrong general name type found in role");
+ }
+
+ if (!((ASN1String)role.getName()).getString().equals("DAU123456789"))
+ {
+ fail("wrong general name value found in role");
+ }
+
+ X509CertificateHolder sCert = new X509CertificateHolder(holderCertWithBaseCertificateID);
+
+ if (holder.match(sCert))
+ {
+ fail("generated holder matching wrong certificate");
+ }
+
+ equalityAndHashCodeTest(aCert, aCert.getEncoded());
+ }
+
+ public void testGenerateWithPrincipal()
+ throws Exception
+ {
+ X509CertificateHolder iCert = new X509CertificateHolder(signCert);
+
+ //
+ // a sample key pair.
+ //
+ RSAKeyParameters pubKey = new RSAKeyParameters(
+ false,
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ //
+ // set up the keys
+ //
+ AsymmetricKeyParameter privKey = RSA_PRIVATE_KEY_SPEC;
+
+ X509v2AttributeCertificateBuilder gen = new X509v2AttributeCertificateBuilder(
+ new AttributeCertificateHolder(iCert.getSubject()),
+ new AttributeCertificateIssuer(new X500Name("cn=test")),
+ BigInteger.ONE,
+ new Date(System.currentTimeMillis() - 50000),
+ new Date(System.currentTimeMillis() + 50000));
+
+ // the actual attributes
+ GeneralName roleName = new GeneralName(GeneralName.rfc822Name, "DAU123456789");
+ ASN1EncodableVector roleSyntax = new ASN1EncodableVector();
+ roleSyntax.add(roleName);
+
+ // roleSyntax OID: 2.5.24.72
+
+ gen.addAttribute(new ASN1ObjectIdentifier("2.5.24.72"), new DERSequence(roleSyntax));
+
+ AlgorithmIdentifier sigAlg = sigAlgFinder.find("SHA1withRSA");
+ AlgorithmIdentifier digAlg = digAlgFinder.find(sigAlg);
+
+ ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlg, digAlg).build(privKey);
+ X509AttributeCertificateHolder aCert = gen.build(sigGen);
+
+ if (!aCert.isValidOn(new Date()))
+ {
+ fail("certificate invalid");
+ }
+
+ if (!aCert.isSignatureValid(new BcRSAContentVerifierProviderBuilder(digAlgFinder).build(pubKey)))
+ {
+ fail("certificate signature not valid");
+ }
+
+ AttributeCertificateHolder holder = aCert.getHolder();
+
+ if (holder.getEntityNames() == null)
+ {
+ fail("entity names not set when expected");
+ }
+
+ if (holder.getSerialNumber() != null)
+ {
+ fail("holder serial number found when none expected");
+ }
+
+ if (holder.getIssuer() != null)
+ {
+ fail("holder issuer found when none expected");
+ }
+
+ if (!holder.match(iCert))
+ {
+ fail("generated holder not matching holder certificate");
+ }
+
+ X509CertificateHolder sCert = new X509CertificateHolder(holderCertWithBaseCertificateID);
+
+ if (holder.match(sCert))
+ {
+ fail("principal generated holder matching wrong certificate");
+ }
+
+ equalityAndHashCodeTest(aCert, aCert.getEncoded());
+ }
+
+ public void testFully()
+ throws Exception
+ {
+ X509AttributeCertificateHolder aCert = new X509AttributeCertificateHolder(attrCert);
+ X509CertificateHolder sCert = new X509CertificateHolder(signCert);
+
+ if (!aCert.isSignatureValid(new BcRSAContentVerifierProviderBuilder(digAlgFinder).build(sCert)))
+ {
+ fail("certificate signature not valid");
+ }
+
+ //
+ // search test
+ //
+
+ List list = new ArrayList();
+
+ list.add(sCert);
+
+ Store store = new CollectionStore(list);
+
+ Collection certs = store.getMatches(aCert.getIssuer());
+ if (certs.size() != 1 || !certs.contains(sCert))
+ {
+ fail("sCert not found by issuer");
+ }
+
+ Attribute[] attrs = aCert.getAttributes(new ASN1ObjectIdentifier("1.3.6.1.4.1.6760.8.1.1"));
+ if (attrs == null || attrs.length != 1)
+ {
+ fail("attribute not found");
+ }
+
+ //
+ // reencode test
+ //
+ aCert = new X509AttributeCertificateHolder(aCert.getEncoded());
+
+ if (!aCert.isSignatureValid(new BcRSAContentVerifierProviderBuilder(digAlgFinder).build(sCert)))
+ {
+ fail("certificate signature not valid");
+ }
+
+ X509AttributeCertificateHolder saCert = new X509AttributeCertificateHolder(aCert.getEncoded());
+
+ if (!aCert.getNotAfter().equals(saCert.getNotAfter()))
+ {
+ fail("failed date comparison");
+ }
+
+ // base generator test
+
+ //
+ // a sample key pair.
+ //
+ AsymmetricKeyParameter pubKey = new RSAKeyParameters(
+ false,
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ AsymmetricKeyParameter privKey = RSA_PRIVATE_KEY_SPEC;
+
+ X509v2AttributeCertificateBuilder gen = new X509v2AttributeCertificateBuilder(
+ aCert.getHolder(),
+ aCert.getIssuer(),
+ aCert.getSerialNumber(),
+ new Date(System.currentTimeMillis() - 50000),
+ new Date(System.currentTimeMillis() + 50000));
+
+ gen.addAttribute(attrs[0].getAttrType(), attrs[0].getAttributeValues());
+
+ AlgorithmIdentifier sigAlg = sigAlgFinder.find("SHA1withRSA");
+ AlgorithmIdentifier digAlg = digAlgFinder.find(sigAlg);
+
+ ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlg, digAlg).build(privKey);
+ aCert = gen.build(sigGen);
+
+ if (!aCert.isValidOn(new Date()))
+ {
+ fail("certificate not valid");
+ }
+
+ if (!aCert.isSignatureValid(new BcRSAContentVerifierProviderBuilder(digAlgFinder).build(pubKey)))
+ {
+ fail("signature not valid");
+ }
+
+ // as the issuer is the same this should still work (even though it is not
+ // technically correct
+
+ certs = store.getMatches(aCert.getIssuer());
+ if (certs.size() != 1 || !certs.contains(sCert))
+ {
+ fail("sCert not found by issuer");
+ }
+
+ attrs = aCert.getAttributes(new ASN1ObjectIdentifier("1.3.6.1.4.1.6760.8.1.1"));
+ if (attrs == null || attrs.length != 1)
+ {
+ fail("attribute not found");
+ }
+
+ //
+ // reencode test
+ //
+ aCert = new X509AttributeCertificateHolder(aCert.getEncoded());
+
+ if (!aCert.isSignatureValid(new BcRSAContentVerifierProviderBuilder(digAlgFinder).build(pubKey)))
+ {
+ fail("signature not valid");
+ }
+
+ AttributeCertificateIssuer issuer = aCert.getIssuer();
+
+ X500Name[] principals = issuer.getNames();
+
+ //
+ // test holder
+ //
+ AttributeCertificateHolder holder = aCert.getHolder();
+
+ if (holder.getEntityNames() == null)
+ {
+ fail("entity names not set");
+ }
+
+ if (holder.getSerialNumber() != null)
+ {
+ fail("holder serial number set when none expected");
+ }
+
+ if (holder.getIssuer() != null)
+ {
+ fail("holder issuer set when none expected");
+ }
+
+ principals = holder.getEntityNames();
+
+ X500Name principal0 = new X500Name(RFC4519Style.INSTANCE, principals[0]);
+ if (!principal0.toString().equals("c=US,o=vt,ou=Class 2,ou=Virginia Tech User,cn=Markus Lorch (mlorch),1.2.840.113549.1.9.1=mlorch@vt.edu"))
+ {
+ System.err.println(principal0.toString());
+ fail("principal[0] for entity names don't match");
+ }
+
+ //
+ // extension test
+ //
+
+ if (aCert.hasExtensions())
+ {
+ fail("hasExtensions true with no extensions");
+ }
+
+ gen.addExtension(new ASN1ObjectIdentifier("1.1"), true, new DEROctetString(new byte[10]));
+
+ gen.addExtension(new ASN1ObjectIdentifier("2.2"), false, new DEROctetString(new byte[20]));
+
+ aCert = gen.build(sigGen);
+
+ Set exts = aCert.getCriticalExtensionOIDs();
+
+ if (exts.size() != 1 || !exts.contains(new ASN1ObjectIdentifier("1.1")))
+ {
+ fail("critical extension test failed");
+ }
+
+ exts = aCert.getNonCriticalExtensionOIDs();
+
+ if (exts.size() != 1 || !exts.contains(new ASN1ObjectIdentifier("2.2")))
+ {
+ fail("non-critical extension test failed");
+ }
+
+ if (aCert.getCriticalExtensionOIDs().isEmpty())
+ {
+ fail("critical extensions not found");
+ }
+
+ Extension ext = aCert.getExtension(new ASN1ObjectIdentifier("1.1"));
+ ASN1Encodable extValue = ext.getParsedValue();
+
+ if (!extValue.equals(new DEROctetString(new byte[10])))
+ {
+ fail("wrong extension value found for 1.1");
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/BcCertTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/BcCertTest.java
new file mode 100644
index 000000000..81d97ae0b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/BcCertTest.java
@@ -0,0 +1,1435 @@
+package org.spongycastle.cert.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.security.cert.CRL;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import junit.framework.TestCase;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Enumerated;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.X500NameBuilder;
+import org.spongycastle.asn1.x500.style.RFC4519Style;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.ExtensionsGenerator;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.KeyPurposeId;
+import org.spongycastle.asn1.x509.KeyUsage;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.CertException;
+import org.spongycastle.cert.X509CRLEntryHolder;
+import org.spongycastle.cert.X509CRLHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509v1CertificateBuilder;
+import org.spongycastle.cert.X509v2CRLBuilder;
+import org.spongycastle.cert.X509v3CertificateBuilder;
+import org.spongycastle.cert.bc.BcX509ExtensionUtils;
+import org.spongycastle.cert.bc.BcX509v1CertificateBuilder;
+import org.spongycastle.cert.bc.BcX509v3CertificateBuilder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.spongycastle.crypto.generators.DSAKeyPairGenerator;
+import org.spongycastle.crypto.generators.DSAParametersGenerator;
+import org.spongycastle.crypto.generators.RSAKeyPairGenerator;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.params.DSAKeyGenerationParameters;
+import org.spongycastle.crypto.params.DSAParameters;
+import org.spongycastle.crypto.params.RSAKeyGenerationParameters;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.spongycastle.crypto.util.SubjectPublicKeyInfoFactory;
+import org.spongycastle.cert.test.PEMData;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.bc.BcDSAContentSignerBuilder;
+import org.spongycastle.operator.bc.BcDSAContentVerifierProviderBuilder;
+import org.spongycastle.operator.bc.BcRSAContentSignerBuilder;
+import org.spongycastle.operator.bc.BcRSAContentVerifierProviderBuilder;
+import org.spongycastle.util.encoders.Base64;
+
+public class BcCertTest
+ extends TestCase
+{
+ DefaultSignatureAlgorithmIdentifierFinder sigAlgFinder = new DefaultSignatureAlgorithmIdentifierFinder();
+ DefaultDigestAlgorithmIdentifierFinder digAlgFinder = new DefaultDigestAlgorithmIdentifierFinder();
+
+ //
+ // server.crt
+ //
+ byte[] cert1 = Base64.decode(
+ "MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx"
+ + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY"
+ + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB"
+ + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ"
+ + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2"
+ + "MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW"
+ + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM"
+ + "dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l"
+ + "Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv"
+ + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re"
+ + "Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO"
+ + "Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE"
+ + "7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy"
+ + "QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0"
+ + "ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw"
+ + "DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL"
+ + "iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4"
+ + "yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF"
+ + "5/8=");
+
+ //
+ // ca.crt
+ //
+ byte[] cert2 = Base64.decode(
+ "MIIDbDCCAtWgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx"
+ + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY"
+ + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB"
+ + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ"
+ + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU1MzNaFw0wMTA2"
+ + "MDIwNzU1MzNaMIG3MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW"
+ + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM"
+ + "dGQxHjAcBgNVBAsTFUNlcnRpZmljYXRlIEF1dGhvcml0eTEVMBMGA1UEAxMMQ29u"
+ + "bmVjdCA0IENBMSgwJgYJKoZIhvcNAQkBFhl3ZWJtYXN0ZXJAY29ubmVjdDQuY29t"
+ + "LmF1MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgs5ptNG6Qv1ZpCDuUNGmv"
+ + "rhjqMDPd3ri8JzZNRiiFlBA4e6/ReaO1U8ASewDeQMH6i9R6degFdQRLngbuJP0s"
+ + "xcEE+SksEWNvygfzLwV9J/q+TQDyJYK52utb++lS0b48A1KPLwEsyL6kOAgelbur"
+ + "ukwxowprKUIV7Knf1ajetQIDAQABo4GFMIGCMCQGA1UdEQQdMBuBGXdlYm1hc3Rl"
+ + "ckBjb25uZWN0NC5jb20uYXUwDwYDVR0TBAgwBgEB/wIBADA2BglghkgBhvhCAQ0E"
+ + "KRYnbW9kX3NzbCBnZW5lcmF0ZWQgY3VzdG9tIENBIGNlcnRpZmljYXRlMBEGCWCG"
+ + "SAGG+EIBAQQEAwICBDANBgkqhkiG9w0BAQQFAAOBgQCsGvfdghH8pPhlwm1r3pQk"
+ + "msnLAVIBb01EhbXm2861iXZfWqGQjrGAaA0ZpXNk9oo110yxoqEoSJSzniZa7Xtz"
+ + "soTwNUpE0SLHvWf/SlKdFWlzXA+vOZbzEv4UmjeelekTm7lc01EEa5QRVzOxHFtQ"
+ + "DhkaJ8VqOMajkQFma2r9iA==");
+
+ //
+ // testx509.pem
+ //
+ byte[] cert3 = Base64.decode(
+ "MIIBWzCCAQYCARgwDQYJKoZIhvcNAQEEBQAwODELMAkGA1UEBhMCQVUxDDAKBgNV"
+ + "BAgTA1FMRDEbMBkGA1UEAxMSU1NMZWF5L3JzYSB0ZXN0IENBMB4XDTk1MDYxOTIz"
+ + "MzMxMloXDTk1MDcxNzIzMzMxMlowOjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA1FM"
+ + "RDEdMBsGA1UEAxMUU1NMZWF5L3JzYSB0ZXN0IGNlcnQwXDANBgkqhkiG9w0BAQEF"
+ + "AANLADBIAkEAqtt6qS5GTxVxGZYWa0/4u+IwHf7p2LNZbcPBp9/OfIcYAXBQn8hO"
+ + "/Re1uwLKXdCjIoaGs4DLdG88rkzfyK5dPQIDAQABMAwGCCqGSIb3DQIFBQADQQAE"
+ + "Wc7EcF8po2/ZO6kNCwK/ICH6DobgLekA5lSLr5EvuioZniZp5lFzAw4+YzPQ7XKJ"
+ + "zl9HYIMxATFyqSiD9jsx");
+
+ //
+ // v3-cert1.pem
+ //
+ byte[] cert4 = Base64.decode(
+ "MIICjTCCAfigAwIBAgIEMaYgRzALBgkqhkiG9w0BAQQwRTELMAkGA1UEBhMCVVMx"
+ + "NjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFuZCBTcGFjZSBBZG1pbmlz"
+ + "dHJhdGlvbjAmFxE5NjA1MjgxMzQ5MDUrMDgwMBcROTgwNTI4MTM0OTA1KzA4MDAw"
+ + "ZzELMAkGA1UEBhMCVVMxNjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFu"
+ + "ZCBTcGFjZSBBZG1pbmlzdHJhdGlvbjEgMAkGA1UEBRMCMTYwEwYDVQQDEwxTdGV2"
+ + "ZSBTY2hvY2gwWDALBgkqhkiG9w0BAQEDSQAwRgJBALrAwyYdgxmzNP/ts0Uyf6Bp"
+ + "miJYktU/w4NG67ULaN4B5CnEz7k57s9o3YY3LecETgQ5iQHmkwlYDTL2fTgVfw0C"
+ + "AQOjgaswgagwZAYDVR0ZAQH/BFowWDBWMFQxCzAJBgNVBAYTAlVTMTYwNAYDVQQK"
+ + "Ey1OYXRpb25hbCBBZXJvbmF1dGljcyBhbmQgU3BhY2UgQWRtaW5pc3RyYXRpb24x"
+ + "DTALBgNVBAMTBENSTDEwFwYDVR0BAQH/BA0wC4AJODMyOTcwODEwMBgGA1UdAgQR"
+ + "MA8ECTgzMjk3MDgyM4ACBSAwDQYDVR0KBAYwBAMCBkAwCwYJKoZIhvcNAQEEA4GB"
+ + "AH2y1VCEw/A4zaXzSYZJTTUi3uawbbFiS2yxHvgf28+8Js0OHXk1H1w2d6qOHH21"
+ + "X82tZXd/0JtG0g1T9usFFBDvYK8O0ebgz/P5ELJnBL2+atObEuJy1ZZ0pBDWINR3"
+ + "WkDNLCGiTkCKp0F5EWIrVDwh54NNevkCQRZita+z4IBO");
+
+ //
+ // v3-cert2.pem
+ //
+ byte[] cert5 = Base64.decode(
+ "MIICiTCCAfKgAwIBAgIEMeZfHzANBgkqhkiG9w0BAQQFADB9MQswCQYDVQQGEwJD"
+ + "YTEPMA0GA1UEBxMGTmVwZWFuMR4wHAYDVQQLExVObyBMaWFiaWxpdHkgQWNjZXB0"
+ + "ZWQxHzAdBgNVBAoTFkZvciBEZW1vIFB1cnBvc2VzIE9ubHkxHDAaBgNVBAMTE0Vu"
+ + "dHJ1c3QgRGVtbyBXZWIgQ0EwHhcNOTYwNzEyMTQyMDE1WhcNOTYxMDEyMTQyMDE1"
+ + "WjB0MSQwIgYJKoZIhvcNAQkBExVjb29rZUBpc3NsLmF0bC5ocC5jb20xCzAJBgNV"
+ + "BAYTAlVTMScwJQYDVQQLEx5IZXdsZXR0IFBhY2thcmQgQ29tcGFueSAoSVNTTCkx"
+ + "FjAUBgNVBAMTDVBhdWwgQS4gQ29va2UwXDANBgkqhkiG9w0BAQEFAANLADBIAkEA"
+ + "6ceSq9a9AU6g+zBwaL/yVmW1/9EE8s5you1mgjHnj0wAILuoB3L6rm6jmFRy7QZT"
+ + "G43IhVZdDua4e+5/n1ZslwIDAQABo2MwYTARBglghkgBhvhCAQEEBAMCB4AwTAYJ"
+ + "YIZIAYb4QgENBD8WPVRoaXMgY2VydGlmaWNhdGUgaXMgb25seSBpbnRlbmRlZCBm"
+ + "b3IgZGVtb25zdHJhdGlvbiBwdXJwb3Nlcy4wDQYJKoZIhvcNAQEEBQADgYEAi8qc"
+ + "F3zfFqy1sV8NhjwLVwOKuSfhR/Z8mbIEUeSTlnH3QbYt3HWZQ+vXI8mvtZoBc2Fz"
+ + "lexKeIkAZXCesqGbs6z6nCt16P6tmdfbZF3I3AWzLquPcOXjPf4HgstkyvVBn0Ap"
+ + "jAFN418KF/Cx4qyHB4cjdvLrRjjQLnb2+ibo7QU=");
+
+ //
+ // pem encoded pkcs7
+ //
+ byte[] cert6 = Base64.decode(
+ "MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIJbzCCAj0w"
+ + "ggGmAhEAzbp/VvDf5LxU/iKss3KqVTANBgkqhkiG9w0BAQIFADBfMQswCQYDVQQGEwJVUzEXMBUG"
+ + "A1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGljIFByaW1hcnkgQ2Vy"
+ + "dGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNOTYwMTI5MDAwMDAwWhcNMjgwODAxMjM1OTU5WjBfMQsw"
+ + "CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVi"
+ + "bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwgZ8wDQYJKoZIhvcNAQEBBQADgY0A"
+ + "MIGJAoGBAOUZv22jVmEtmUhx9mfeuY3rt56GgAqRDvo4Ja9GiILlc6igmyRdDR/MZW4MsNBWhBiH"
+ + "mgabEKFz37RYOWtuwfYV1aioP6oSBo0xrH+wNNePNGeICc0UEeJORVZpH3gCgNrcR5EpuzbJY1zF"
+ + "4Ncth3uhtzKwezC6Ki8xqu6jZ9rbAgMBAAEwDQYJKoZIhvcNAQECBQADgYEATD+4i8Zo3+5DMw5d"
+ + "6abLB4RNejP/khv0Nq3YlSI2aBFsfELM85wuxAc/FLAPT/+Qknb54rxK6Y/NoIAK98Up8YIiXbix"
+ + "3YEjo3slFUYweRb46gVLlH8dwhzI47f0EEA8E8NfH1PoSOSGtHuhNbB7Jbq4046rPzidADQAmPPR"
+ + "cZQwggMuMIICl6ADAgECAhEA0nYujRQMPX2yqCVdr+4NdTANBgkqhkiG9w0BAQIFADBfMQswCQYD"
+ + "VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGlj"
+ + "IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNOTgwNTEyMDAwMDAwWhcNMDgwNTEy"
+ + "MjM1OTU5WjCBzDEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy"
+ + "dXN0IE5ldHdvcmsxRjBEBgNVBAsTPXd3dy52ZXJpc2lnbi5jb20vcmVwb3NpdG9yeS9SUEEgSW5j"
+ + "b3JwLiBCeSBSZWYuLExJQUIuTFREKGMpOTgxSDBGBgNVBAMTP1ZlcmlTaWduIENsYXNzIDEgQ0Eg"
+ + "SW5kaXZpZHVhbCBTdWJzY3JpYmVyLVBlcnNvbmEgTm90IFZhbGlkYXRlZDCBnzANBgkqhkiG9w0B"
+ + "AQEFAAOBjQAwgYkCgYEAu1pEigQWu1X9A3qKLZRPFXg2uA1Ksm+cVL+86HcqnbnwaLuV2TFBcHqB"
+ + "S7lIE1YtxwjhhEKrwKKSq0RcqkLwgg4C6S/7wju7vsknCl22sDZCM7VuVIhPh0q/Gdr5FegPh7Yc"
+ + "48zGmo5/aiSS4/zgZbqnsX7vyds3ashKyAkG5JkCAwEAAaN8MHowEQYJYIZIAYb4QgEBBAQDAgEG"
+ + "MEcGA1UdIARAMD4wPAYLYIZIAYb4RQEHAQEwLTArBggrBgEFBQcCARYfd3d3LnZlcmlzaWduLmNv"
+ + "bS9yZXBvc2l0b3J5L1JQQTAPBgNVHRMECDAGAQH/AgEAMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0B"
+ + "AQIFAAOBgQCIuDc73dqUNwCtqp/hgQFxHpJqbS/28Z3TymQ43BuYDAeGW4UVag+5SYWklfEXfWe0"
+ + "fy0s3ZpCnsM+tI6q5QsG3vJWKvozx74Z11NMw73I4xe1pElCY+zCphcPXVgaSTyQXFWjZSAA/Rgg"
+ + "5V+CprGoksVYasGNAzzrw80FopCubjCCA/gwggNhoAMCAQICEBbbn/1G1zppD6KsP01bwywwDQYJ"
+ + "KoZIhvcNAQEEBQAwgcwxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln"
+ + "biBUcnVzdCBOZXR3b3JrMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvUlBB"
+ + "IEluY29ycC4gQnkgUmVmLixMSUFCLkxURChjKTk4MUgwRgYDVQQDEz9WZXJpU2lnbiBDbGFzcyAx"
+ + "IENBIEluZGl2aWR1YWwgU3Vic2NyaWJlci1QZXJzb25hIE5vdCBWYWxpZGF0ZWQwHhcNMDAxMDAy"
+ + "MDAwMDAwWhcNMDAxMjAxMjM1OTU5WjCCAQcxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYD"
+ + "VQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3Jl"
+ + "cG9zaXRvcnkvUlBBIEluY29ycC4gYnkgUmVmLixMSUFCLkxURChjKTk4MR4wHAYDVQQLExVQZXJz"
+ + "b25hIE5vdCBWYWxpZGF0ZWQxJzAlBgNVBAsTHkRpZ2l0YWwgSUQgQ2xhc3MgMSAtIE1pY3Jvc29m"
+ + "dDETMBEGA1UEAxQKRGF2aWQgUnlhbjElMCMGCSqGSIb3DQEJARYWZGF2aWRAbGl2ZW1lZGlhLmNv"
+ + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqxBsdeNmSvFqhMNwhQgNzM8mdjX9eSXb"
+ + "DawpHtQHjmh0AKJSa3IwUY0VIsyZHuXWktO/CgaMBVPt6OVf/n0R2sQigMP6Y+PhEiS0vCJBL9aK"
+ + "0+pOo2qXrjVBmq+XuCyPTnc+BOSrU26tJsX0P9BYorwySiEGxGanBNATdVL4NdUCAwEAAaOBnDCB"
+ + "mTAJBgNVHRMEAjAAMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQgwKjAoBggrBgEFBQcCARYcaHR0"
+ + "cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYTARBglghkgBhvhCAQEEBAMCB4AwMwYDVR0fBCwwKjAo"
+ + "oCagJIYiaHR0cDovL2NybC52ZXJpc2lnbi5jb20vY2xhc3MxLmNybDANBgkqhkiG9w0BAQQFAAOB"
+ + "gQBC8yIIdVGpFTf8/YiL14cMzcmL0nIRm4kGR3U59z7UtcXlfNXXJ8MyaeI/BnXwG/gD5OKYqW6R"
+ + "yca9vZOxf1uoTBl82gInk865ED3Tej6msCqFzZffnSUQvOIeqLxxDlqYRQ6PmW2nAnZeyjcnbI5Y"
+ + "syQSM2fmo7n6qJFP+GbFezGCAkUwggJBAgEBMIHhMIHMMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5j"
+ + "LjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazFGMEQGA1UECxM9d3d3LnZlcmlzaWdu"
+ + "LmNvbS9yZXBvc2l0b3J5L1JQQSBJbmNvcnAuIEJ5IFJlZi4sTElBQi5MVEQoYyk5ODFIMEYGA1UE"
+ + "AxM/VmVyaVNpZ24gQ2xhc3MgMSBDQSBJbmRpdmlkdWFsIFN1YnNjcmliZXItUGVyc29uYSBOb3Qg"
+ + "VmFsaWRhdGVkAhAW25/9Rtc6aQ+irD9NW8MsMAkGBSsOAwIaBQCggbowGAYJKoZIhvcNAQkDMQsG"
+ + "CSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMDAxMDAyMTczNTE4WjAjBgkqhkiG9w0BCQQxFgQU"
+ + "gZjSaBEY2oxGvlQUIMnxSXhivK8wWwYJKoZIhvcNAQkPMU4wTDAKBggqhkiG9w0DBzAOBggqhkiG"
+ + "9w0DAgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwBwYFKw4DAh0w"
+ + "DQYJKoZIhvcNAQEBBQAEgYAzk+PU91/ZFfoiuKOECjxEh9fDYE2jfDCheBIgh5gdcCo+sS1WQs8O"
+ + "HreQ9Nop/JdJv1DQMBK6weNBBDoP0EEkRm1XCC144XhXZC82jBZohYmi2WvDbbC//YN58kRMYMyy"
+ + "srrfn4Z9I+6kTriGXkrpGk9Q0LSGjmG2BIsqiF0dvwAAAAAAAA==");
+
+ //
+ // dsaWithSHA1 cert
+ //
+ byte[] cert7 = Base64.decode(
+ "MIIEXAYJKoZIhvcNAQcCoIIETTCCBEkCAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+ + "SIb3DQEHAaCCAsMwggK/MIIB4AIBADCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7"
+ + "d8miwTMN55CUSmo3TO8WGCxgY61TX5k+7NU4XPf1TULjw3GobwaJX13kquPh"
+ + "fVXk+gVy46n4Iw3hAhUBSe/QF4BUj+pJOF9ROBM4u+FEWA8CQQD4mSJbrABj"
+ + "TUWrlnAte8pS22Tq4/FPO7jHSqjijUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/z"
+ + "m8Q12PFp/PjOhh+nMA4xDDAKBgNVBAMTA0lEMzAeFw05NzEwMDEwMDAwMDBa"
+ + "Fw0zODAxMDEwMDAwMDBaMA4xDDAKBgNVBAMTA0lEMzCB8DCBpwYFKw4DAhsw"
+ + "gZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxgY61TX5k+7NU4XPf1TULj"
+ + "w3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/QF4BUj+pJOF9ROBM4u+FE"
+ + "WA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jHSqjijUHfXKTrHL1OEqV3"
+ + "SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nA0QAAkEAkYkXLYMtGVGWj9OnzjPn"
+ + "sB9sefSRPrVegZJCZbpW+Iv0/1RP1u04pHG9vtRpIQLjzUiWvLMU9EKQTThc"
+ + "eNMmWDCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxg"
+ + "Y61TX5k+7NU4XPf1TULjw3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/Q"
+ + "F4BUj+pJOF9ROBM4u+FEWA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jH"
+ + "SqjijUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nAy8AMCwC"
+ + "FBY3dBSdeprGcqpr6wr3xbG+6WW+AhRMm/facKJNxkT3iKgJbp7R8Xd3QTGC"
+ + "AWEwggFdAgEBMBMwDjEMMAoGA1UEAxMDSUQzAgEAMAkGBSsOAwIaBQCgXTAY"
+ + "BgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0wMjA1"
+ + "MjQyMzEzMDdaMCMGCSqGSIb3DQEJBDEWBBS4WMsoJhf7CVbZYCFcjoTRzPkJ"
+ + "xjCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxgY61T"
+ + "X5k+7NU4XPf1TULjw3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/QF4BU"
+ + "j+pJOF9ROBM4u+FEWA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jHSqji"
+ + "jUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nBC8wLQIVALID"
+ + "dt+MHwawrDrwsO1Z6sXBaaJsAhRaKssrpevmLkbygKPV07XiAKBG02Zvb2Jh"
+ + "cg==");
+
+ //
+ // testcrl.pem
+ //
+ byte[] crl1 = Base64.decode(
+ "MIICjTCCAfowDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoT"
+ + "F1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVy"
+ + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5Fw05NTA1MDIwMjEyMjZaFw05NTA2MDEw"
+ + "MDAxNDlaMIIBaDAWAgUCQQAABBcNOTUwMjAxMTcyNDI2WjAWAgUCQQAACRcNOTUw"
+ + "MjEwMDIxNjM5WjAWAgUCQQAADxcNOTUwMjI0MDAxMjQ5WjAWAgUCQQAADBcNOTUw"
+ + "MjI1MDA0NjQ0WjAWAgUCQQAAGxcNOTUwMzEzMTg0MDQ5WjAWAgUCQQAAFhcNOTUw"
+ + "MzE1MTkxNjU0WjAWAgUCQQAAGhcNOTUwMzE1MTk0MDQxWjAWAgUCQQAAHxcNOTUw"
+ + "MzI0MTk0NDMzWjAWAgUCcgAABRcNOTUwMzI5MjAwNzExWjAWAgUCcgAAERcNOTUw"
+ + "MzMwMDIzNDI2WjAWAgUCQQAAIBcNOTUwNDA3MDExMzIxWjAWAgUCcgAAHhcNOTUw"
+ + "NDA4MDAwMjU5WjAWAgUCcgAAQRcNOTUwNDI4MTcxNzI0WjAWAgUCcgAAOBcNOTUw"
+ + "NDI4MTcyNzIxWjAWAgUCcgAATBcNOTUwNTAyMDIxMjI2WjANBgkqhkiG9w0BAQIF"
+ + "AAN+AHqOEJXSDejYy0UwxxrH/9+N2z5xu/if0J6qQmK92W0hW158wpJg+ovV3+wQ"
+ + "wvIEPRL2rocL0tKfAsVq1IawSJzSNgxG0lrcla3MrJBnZ4GaZDu4FutZh72MR3Gt"
+ + "JaAL3iTJHJD55kK2D/VoyY1djlsPuNh6AEgdVwFAyp0v");
+
+ //
+ // ecdsa cert with extra octet string.
+ //
+ byte[] oldEcdsa = Base64.decode(
+ "MIICljCCAkCgAwIBAgIBATALBgcqhkjOPQQBBQAwgY8xCzAJBgNVBAYTAkFVMSgwJ"
+ + "gYDVQQKEx9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIwEAYDVQQHEw"
+ + "lNZWxib3VybmUxETAPBgNVBAgTCFZpY3RvcmlhMS8wLQYJKoZIhvcNAQkBFiBmZWV"
+ + "kYmFjay1jcnlwdG9AYm91bmN5Y2FzdGxlLm9yZzAeFw0wMTEyMDcwMTAwMDRaFw0w"
+ + "MTEyMDcwMTAxNDRaMIGPMQswCQYDVQQGEwJBVTEoMCYGA1UEChMfVGhlIExlZ2lvb"
+ + "iBvZiB0aGUgQm91bmN5IENhc3RsZTESMBAGA1UEBxMJTWVsYm91cm5lMREwDwYDVQ"
+ + "QIEwhWaWN0b3JpYTEvMC0GCSqGSIb3DQEJARYgZmVlZGJhY2stY3J5cHRvQGJvdW5"
+ + "jeWNhc3RsZS5vcmcwgeQwgb0GByqGSM49AgEwgbECAQEwKQYHKoZIzj0BAQIef///"
+ + "////////////f///////gAAAAAAAf///////MEAEHn///////////////3///////"
+ + "4AAAAAAAH///////AQeawFsO9zxiUHQ1lSSFHXKcanbL7J9HTd5YYXClCwKBB8CD/"
+ + "qWPNyogWzMM7hkK+35BcPTWFc9Pyf7vTs8uaqvAh5///////////////9///+eXpq"
+ + "fXZBx+9FSJoiQnQsDIgAEHwJbbcU7xholSP+w9nFHLebJUhqdLSU05lq/y9X+DHAw"
+ + "CwYHKoZIzj0EAQUAA0MAMEACHnz6t4UNoVROp74ma4XNDjjGcjaqiIWPZLK8Bdw3G"
+ + "QIeLZ4j3a6ividZl344UH+UPUE7xJxlYGuy7ejTsqRR");
+
+ byte[] keyUsage = Base64.decode(
+ "MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UE"
+ + "BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50"
+ + "cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBs"
+ + "aW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExp"
+ + "bWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0"
+ + "aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBa"
+ + "MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNV"
+ + "BAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3Jw"
+ + "LiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50"
+ + "cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50"
+ + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GL"
+ + "ADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSv"
+ + "x1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHV"
+ + "iTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173"
+ + "iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkw"
+ + "ggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50"
+ + "cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0Ff"
+ + "SW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UE"
+ + "CxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50"
+ + "cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYD"
+ + "VQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9D"
+ + "bGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkx"
+ + "MDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW"
+ + "/O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwG"
+ + "A1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI"
+ + "hvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQ"
+ + "OokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkU"
+ + "ODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapE"
+ + "PHayXOw=");
+
+ byte[] nameCert = Base64.decode(
+ "MIIEFjCCA3+gAwIBAgIEdS8BozANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJE"+
+ "RTERMA8GA1UEChQIREFURVYgZUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRQ0Eg"+
+ "REFURVYgRDAzIDE6UE4wIhgPMjAwMTA1MTAxMDIyNDhaGA8yMDA0MDUwOTEwMjI0"+
+ "OFowgYQxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIFAZCYXllcm4xEjAQBgNVBAcUCU7I"+
+ "dXJuYmVyZzERMA8GA1UEChQIREFURVYgZUcxHTAbBgNVBAUTFDAwMDAwMDAwMDA4"+
+ "OTU3NDM2MDAxMR4wHAYDVQQDFBVEaWV0bWFyIFNlbmdlbmxlaXRuZXIwgaEwDQYJ"+
+ "KoZIhvcNAQEBBQADgY8AMIGLAoGBAJLI/LJLKaHoMk8fBECW/od8u5erZi6jI8Ug"+
+ "C0a/LZyQUO/R20vWJs6GrClQtXB+AtfiBSnyZOSYzOdfDI8yEKPEv8qSuUPpOHps"+
+ "uNCFdLZF1vavVYGEEWs2+y+uuPmg8q1oPRyRmUZ+x9HrDvCXJraaDfTEd9olmB/Z"+
+ "AuC/PqpjAgUAwAAAAaOCAcYwggHCMAwGA1UdEwEB/wQCMAAwDwYDVR0PAQH/BAUD"+
+ "AwdAADAxBgNVHSAEKjAoMCYGBSskCAEBMB0wGwYIKwYBBQUHAgEWD3d3dy56cy5k"+
+ "YXRldi5kZTApBgNVHREEIjAggR5kaWV0bWFyLnNlbmdlbmxlaXRuZXJAZGF0ZXYu"+
+ "ZGUwgYQGA1UdIwR9MHuhc6RxMG8xCzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1"+
+ "bGllcnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0"+
+ "MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjVSLUNBIDE6UE6CBACm8LkwDgYHAoIG"+
+ "AQoMAAQDAQEAMEcGA1UdHwRAMD4wPKAUoBKGEHd3dy5jcmwuZGF0ZXYuZGWiJKQi"+
+ "MCAxCzAJBgNVBAYTAkRFMREwDwYDVQQKFAhEQVRFViBlRzAWBgUrJAgDBAQNMAsT"+
+ "A0VVUgIBBQIBATAdBgNVHQ4EFgQUfv6xFP0xk7027folhy+ziZvBJiwwLAYIKwYB"+
+ "BQUHAQEEIDAeMBwGCCsGAQUFBzABhhB3d3cuZGlyLmRhdGV2LmRlMA0GCSqGSIb3"+
+ "DQEBBQUAA4GBAEOVX6uQxbgtKzdgbTi6YLffMftFr2mmNwch7qzpM5gxcynzgVkg"+
+ "pnQcDNlm5AIbS6pO8jTCLfCd5TZ5biQksBErqmesIl3QD+VqtB+RNghxectZ3VEs"+
+ "nCUtcE7tJ8O14qwCb3TxS9dvIUFiVi4DjbxX46TdcTbTaK8/qr6AIf+l");
+
+ byte[] probSelfSignedCert = Base64.decode(
+ "MIICxTCCAi6gAwIBAgIQAQAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQUFADBF"
+ + "MScwJQYDVQQKEx4gRElSRUNUSU9OIEdFTkVSQUxFIERFUyBJTVBPVFMxGjAYBgNV"
+ + "BAMTESBBQyBNSU5FRkkgQiBURVNUMB4XDTA0MDUwNzEyMDAwMFoXDTE0MDUwNzEy"
+ + "MDAwMFowRTEnMCUGA1UEChMeIERJUkVDVElPTiBHRU5FUkFMRSBERVMgSU1QT1RT"
+ + "MRowGAYDVQQDExEgQUMgTUlORUZJIEIgVEVTVDCBnzANBgkqhkiG9w0BAQEFAAOB"
+ + "jQAwgYkCgYEAveoCUOAukZdcFCs2qJk76vSqEX0ZFzHqQ6faBPZWjwkgUNwZ6m6m"
+ + "qWvvyq1cuxhoDvpfC6NXILETawYc6MNwwxsOtVVIjuXlcF17NMejljJafbPximEt"
+ + "DQ4LcQeSp4K7FyFlIAMLyt3BQ77emGzU5fjFTvHSUNb3jblx0sV28c0CAwEAAaOB"
+ + "tTCBsjAfBgNVHSMEGDAWgBSEJ4bLbvEQY8cYMAFKPFD1/fFXlzAdBgNVHQ4EFgQU"
+ + "hCeGy27xEGPHGDABSjxQ9f3xV5cwDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIB"
+ + "AQQEAwIBBjA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vYWRvbmlzLnBrNy5jZXJ0"
+ + "cGx1cy5uZXQvZGdpLXRlc3QuY3JsMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN"
+ + "AQEFBQADgYEAmToHJWjd3+4zknfsP09H6uMbolHNGG0zTS2lrLKpzcmkQfjhQpT9"
+ + "LUTBvfs1jdjo9fGmQLvOG+Sm51Rbjglb8bcikVI5gLbclOlvqLkm77otjl4U4Z2/"
+ + "Y0vP14Aov3Sn3k+17EfReYUZI4liuB95ncobC4e8ZM++LjQcIM0s+Vs=");
+
+
+ byte[] gost34102001base = Base64.decode(
+ "MIIB1DCCAYECEEjpVKXP6Wn1yVz3VeeDQa8wCgYGKoUDAgIDBQAwbTEfMB0G"
+ + "A1UEAwwWR29zdFIzNDEwLTIwMDEgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRv"
+ + "UHJvMQswCQYDVQQGEwJSVTEpMCcGCSqGSIb3DQEJARYaR29zdFIzNDEwLTIw"
+ + "MDFAZXhhbXBsZS5jb20wHhcNMDUwMjAzMTUxNjQ2WhcNMTUwMjAzMTUxNjQ2"
+ + "WjBtMR8wHQYDVQQDDBZHb3N0UjM0MTAtMjAwMSBleGFtcGxlMRIwEAYDVQQK"
+ + "DAlDcnlwdG9Qcm8xCzAJBgNVBAYTAlJVMSkwJwYJKoZIhvcNAQkBFhpHb3N0"
+ + "UjM0MTAtMjAwMUBleGFtcGxlLmNvbTBjMBwGBiqFAwICEzASBgcqhQMCAiQA"
+ + "BgcqhQMCAh4BA0MABECElWh1YAIaQHUIzROMMYks/eUFA3pDXPRtKw/nTzJ+"
+ + "V4/rzBa5lYgD0Jp8ha4P5I3qprt+VsfLsN8PZrzK6hpgMAoGBiqFAwICAwUA"
+ + "A0EAHw5dw/aw/OiNvHyOE65kvyo4Hp0sfz3csM6UUkp10VO247ofNJK3tsLb"
+ + "HOLjUaqzefrlGb11WpHYrvWFg+FcLA==");
+
+ private final byte[] emptyDNCert = Base64.decode(
+ "MIICfTCCAeagAwIBAgIBajANBgkqhkiG9w0BAQQFADB8MQswCQYDVQQGEwJVUzEMMAoGA1UEChMD"
+ + "Q0RXMQkwBwYDVQQLEwAxCTAHBgNVBAcTADEJMAcGA1UECBMAMRowGAYDVQQDExFUZW1wbGFyIFRl"
+ + "c3QgMTAyNDEiMCAGCSqGSIb3DQEJARYTdGVtcGxhcnRlc3RAY2R3LmNvbTAeFw0wNjA1MjIwNTAw"
+ + "MDBaFw0xMDA1MjIwNTAwMDBaMHwxCzAJBgNVBAYTAlVTMQwwCgYDVQQKEwNDRFcxCTAHBgNVBAsT"
+ + "ADEJMAcGA1UEBxMAMQkwBwYDVQQIEwAxGjAYBgNVBAMTEVRlbXBsYXIgVGVzdCAxMDI0MSIwIAYJ"
+ + "KoZIhvcNAQkBFhN0ZW1wbGFydGVzdEBjZHcuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB"
+ + "gQDH3aJpJBfM+A3d84j5YcU6zEQaQ76u5xO9NSBmHjZykKS2kCcUqPpvVOPDA5WgV22dtKPh+lYV"
+ + "iUp7wyCVwAKibq8HIbihHceFqMKzjwC639rMoDJ7bi/yzQWz1Zg+075a4FGPlUKn7Yfu89wKkjdW"
+ + "wDpRPXc/agqBnrx5pJTXzQIDAQABow8wDTALBgNVHQ8EBAMCALEwDQYJKoZIhvcNAQEEBQADgYEA"
+ + "RRsRsjse3i2/KClFVd6YLZ+7K1BE0WxFyY2bbytkwQJSxvv3vLSuweFUbhNxutb68wl/yW4GLy4b"
+ + "1QdyswNxrNDXTuu5ILKhRDDuWeocz83aG2KGtr3JlFyr3biWGEyn5WUOE6tbONoQDJ0oPYgI6CAc"
+ + "EHdUp0lioOCt6UOw7Cs=");
+
+ private AsymmetricKeyParameter dudPublicKey = new AsymmetricKeyParameter(true)
+ {
+ public String getAlgorithm()
+ {
+ return null;
+ }
+
+ public String getFormat()
+ {
+ return null;
+ }
+
+ public byte[] getEncoded()
+ {
+ return null;
+ }
+
+ };
+
+ public String getName()
+ {
+ return "CertTest";
+ }
+
+ public void checkCertificate(
+ int id,
+ byte[] bytes)
+ {
+ try
+ {
+ X509CertificateHolder certHldr = new X509CertificateHolder(bytes);
+
+ SubjectPublicKeyInfo k = certHldr.getSubjectPublicKeyInfo();
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(e.toString());
+ }
+ }
+ /*
+ public void checkNameCertificate(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "LKBX-BC");
+
+ X509Certificate cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ AsymmetricKeyParameter k = cert.getAsymmetricKeyParameter();
+ if (!cert.getIssuerDN().toString().equals("C=DE,O=DATEV eG,0.2.262.1.10.7.20=1+CN=CA DATEV D03 1:PN"))
+ {
+ fail(id + " failed - name test.");
+ }
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+ */
+ public void checkKeyUsage(
+ int id,
+ byte[] bytes)
+ throws IOException
+ {
+
+ X509CertificateHolder certHld = new X509CertificateHolder(bytes);
+
+ if ((DERBitString.getInstance(certHld.getExtension(Extension.keyUsage).getParsedValue()).getBytes()[0] & 0x01) != 0)
+ {
+ fail("error generating cert - key usage wrong.");
+ }
+
+
+ }
+
+
+ public void checkSelfSignedCertificate(
+ int id,
+ byte[] bytes)
+ throws OperatorCreationException, IOException, CertException
+ {
+
+ X509CertificateHolder certHolder = new X509CertificateHolder(bytes);
+
+ assertTrue(certHolder.isSignatureValid(new BcRSAContentVerifierProviderBuilder(digAlgFinder).build(certHolder)));
+
+
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - RSA
+ */
+ public void checkCreation1()
+ throws Exception
+ {
+ //
+ // a sample key pair.
+ //
+ AsymmetricKeyParameter pubKey = new RSAKeyParameters(
+ false,
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ AsymmetricKeyParameter privKey = new RSAPrivateCrtKeyParameters(
+ 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));
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = new X500NameBuilder(RFC4519Style.INSTANCE);
+
+ builder.addRDN(RFC4519Style.c, "AU");
+ builder.addRDN(RFC4519Style.o, "The Legion of the Bouncy Castle");
+ builder.addRDN(RFC4519Style.l, "Melbourne");
+ builder.addRDN(RFC4519Style.st, "Victoria");
+ builder.addRDN(PKCSObjectIdentifiers.pkcs_9_at_emailAddress, "feedback-crypto@bouncycastle.org");
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3 - without extensions
+ //
+ AlgorithmIdentifier sigAlg = sigAlgFinder.find("SHA256WithRSAEncryption");
+ ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlg, digAlgFinder.find(sigAlg)).build(privKey);
+ X509v3CertificateBuilder certGen = new BcX509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000),builder.build(), pubKey);
+
+ X509CertificateHolder certH = certGen.build(sigGen);
+
+ assertTrue(certH.isValidOn(new Date()));
+
+ ContentVerifierProvider contentVerifierProvider = new BcRSAContentVerifierProviderBuilder(new DefaultDigestAlgorithmIdentifierFinder()).build(pubKey);
+
+ assertTrue(certH.isSignatureValid(contentVerifierProvider));
+
+ X509Certificate cert = new JcaX509CertificateConverter().getCertificate(certH);
+ Set dummySet = cert.getNonCriticalExtensionOIDs();
+ if (dummySet != null)
+ {
+ fail("non-critical oid set should be null");
+ }
+ dummySet = cert.getCriticalExtensionOIDs();
+ if (dummySet != null)
+ {
+ fail("critical oid set should be null");
+ }
+
+ //
+ // create the certificate - version 3 - with extensions
+ //
+ sigGen = new BcRSAContentSignerBuilder(sigAlgFinder.find("MD5WithRSA"), digAlgFinder.find(sigAlgFinder.find("MD5withRSA"))).build(privKey);
+ certGen = new BcX509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1)
+ , new Date(System.currentTimeMillis() - 50000)
+ , new Date(System.currentTimeMillis() + 50000)
+ , builder.build()
+ , pubKey)
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true,
+ new KeyUsage(KeyUsage.encipherOnly))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.37"), true,
+ new DERSequence(KeyPurposeId.anyExtendedKeyUsage))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true,
+ new GeneralNames(new GeneralName(GeneralName.rfc822Name, "test@test.test")));
+
+ X509CertificateHolder certHolder = certGen.build(sigGen);
+
+ assertTrue(certHolder.isValidOn(new Date()));
+
+ contentVerifierProvider = new BcRSAContentVerifierProviderBuilder(digAlgFinder).build(pubKey);
+ if (!certHolder.isSignatureValid(contentVerifierProvider))
+ {
+ fail("signature test failed");
+ }
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(certHolder.getEncoded());
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509");
+
+ cert = (X509Certificate)certFact.generateCertificate(bIn);
+
+ if (!cert.getKeyUsage()[7])
+ {
+ fail("error generating cert - key usage wrong.");
+ }
+
+ List l = cert.getExtendedKeyUsage();
+ if (!l.get(0).equals(KeyPurposeId.anyExtendedKeyUsage.getId()))
+ {
+ fail("failed extended key usage test");
+ }
+
+ Collection c = cert.getSubjectAlternativeNames();
+ Iterator it = c.iterator();
+ while (it.hasNext())
+ {
+ List gn = (List)it.next();
+ if (!gn.get(1).equals("test@test.test"))
+ {
+ fail("failed subject alternative names test");
+ }
+ }
+
+ // System.out.println(cert);
+
+ //
+ // create the certificate - version 1
+ //
+ sigGen = new BcRSAContentSignerBuilder(sigAlgFinder.find("MD5WithRSA"), digAlgFinder.find(sigAlgFinder.find("MD5withRSA"))).build(privKey);
+ X509v1CertificateBuilder certGen1 = new BcX509v1CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ cert = new JcaX509CertificateConverter().getCertificate(certGen1.build(sigGen));
+
+ assertTrue(certHolder.isValidOn(new Date()));
+
+ contentVerifierProvider = new BcRSAContentVerifierProviderBuilder(new DefaultDigestAlgorithmIdentifierFinder()).build(pubKey);
+
+ assertTrue(certHolder.isSignatureValid(contentVerifierProvider));
+
+ bIn = new ByteArrayInputStream(cert.getEncoded());
+ certFact = CertificateFactory.getInstance("X.509");
+
+ cert = (X509Certificate)certFact.generateCertificate(bIn);
+
+ // System.out.println(cert);
+ if (!cert.getIssuerDN().equals(cert.getSubjectDN()))
+ {
+ fail("name comparison fails");
+ }
+
+//
+ // a lightweight key pair.
+ //
+ RSAKeyParameters lwPubKey = new RSAKeyParameters(
+ false,
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ RSAPrivateCrtKeyParameters lwPrivKey = new RSAPrivateCrtKeyParameters(
+ 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));
+
+ //
+ // distinguished name table.
+ //
+ builder = new X500NameBuilder(RFC4519Style.INSTANCE);
+
+ builder.addRDN(RFC4519Style.c, "AU");
+ builder.addRDN(RFC4519Style.o, "The Legion of the Bouncy Castle");
+ builder.addRDN(RFC4519Style.l, "Melbourne");
+ builder.addRDN(RFC4519Style.st, "Victoria");
+ builder.addRDN(PKCSObjectIdentifiers.pkcs_9_at_emailAddress, "feedback-crypto@bouncycastle.org");
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3 - without extensions
+ //
+ AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSAEncryption");
+ AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
+
+ sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(lwPrivKey);
+ SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(lwPubKey);
+ certGen = new X509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000), builder.build(), pubInfo);
+
+ certHolder = certGen.build(sigGen);
+
+ assertTrue(certHolder.isValidOn(new Date()));
+
+ contentVerifierProvider = new BcRSAContentVerifierProviderBuilder(new DefaultDigestAlgorithmIdentifierFinder()).build(lwPubKey);
+
+ assertTrue(certHolder.isSignatureValid(contentVerifierProvider));
+
+ if (!certHolder.isSignatureValid(contentVerifierProvider))
+ {
+ fail("lw sig verification failed");
+ }
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - DSA
+ */
+ public void checkCreation2()
+ throws Exception
+ {
+ //
+ // set up the keys
+ //
+ AsymmetricKeyParameter privKey;
+ AsymmetricKeyParameter pubKey;
+
+ AsymmetricCipherKeyPairGenerator kpg = new DSAKeyPairGenerator();
+ BigInteger r = new BigInteger("68076202252361894315274692543577577550894681403");
+ BigInteger s = new BigInteger("1089214853334067536215539335472893651470583479365");
+ DSAParametersGenerator pGen = new DSAParametersGenerator();
+
+ pGen.init(512, 80, new SecureRandom());
+
+ DSAParameters params = pGen.generateParameters();
+ DSAKeyGenerationParameters genParam = new DSAKeyGenerationParameters(new SecureRandom(), params);
+
+ kpg.init(genParam);
+
+ AsymmetricCipherKeyPair pair = kpg.generateKeyPair();
+
+ privKey = (AsymmetricKeyParameter)pair.getPrivate();
+ pubKey = (AsymmetricKeyParameter)pair.getPublic();
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3
+ //
+ AlgorithmIdentifier sigAlgId = sigAlgFinder.find("SHA1withDSA");
+ AlgorithmIdentifier digAlgId = digAlgFinder.find(sigAlgId);
+
+ ContentSigner sigGen = new BcDSAContentSignerBuilder(sigAlgId, digAlgId).build(privKey);
+ X509v3CertificateBuilder certGen = new BcX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+
+ X509CertificateHolder cert = certGen.build(sigGen);
+
+ assertTrue(cert.isValidOn(new Date()));
+
+ assertTrue(cert.isSignatureValid(new BcDSAContentVerifierProviderBuilder(digAlgFinder).build(pubKey)));
+
+
+ //
+ // create the certificate - version 1
+ //
+ sigAlgId = sigAlgFinder.find("SHA1withDSA");
+ digAlgId = digAlgFinder.find(sigAlgId);
+
+ sigGen = new BcDSAContentSignerBuilder(sigAlgId, digAlgId).build(privKey);
+ X509v1CertificateBuilder certGen1 = new BcX509v1CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ cert = certGen1.build(sigGen);
+
+ assertTrue(cert.isValidOn(new Date()));
+
+ assertTrue(cert.isSignatureValid(new BcDSAContentVerifierProviderBuilder(digAlgFinder).build(pubKey)));
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory fact = CertificateFactory.getInstance("X.509");
+
+ X509Certificate x509cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ //System.out.println(cert);
+ }
+
+ private X500NameBuilder createStdBuilder()
+ {
+ X500NameBuilder builder = new X500NameBuilder(RFC4519Style.INSTANCE);
+
+ builder.addRDN(RFC4519Style.c, "AU");
+ builder.addRDN(RFC4519Style.o, "The Legion of the Bouncy Castle");
+ builder.addRDN(RFC4519Style.l, "Melbourne");
+ builder.addRDN(RFC4519Style.st, "Victoria");
+ builder.addRDN(PKCSObjectIdentifiers.pkcs_9_at_emailAddress, "feedback-crypto@bouncycastle.org");
+
+ return builder;
+ }
+
+ private void checkCRL(
+ int id,
+ byte[] bytes)
+ {
+ String dump = "";
+
+ try
+ {
+ X509CRLHolder crlHolder = new X509CRLHolder(bytes);
+
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString());
+ }
+
+ }
+
+ public void checkCRLCreation1()
+ throws Exception
+ {
+ AsymmetricCipherKeyPairGenerator kpg = new RSAKeyPairGenerator();
+ RSAKeyGenerationParameters genParam = new RSAKeyGenerationParameters(
+ BigInteger.valueOf(0x1001), new SecureRandom(), 1024, 25);
+
+ kpg.init(genParam);
+
+ AsymmetricCipherKeyPair pair = kpg.generateKeyPair();
+ Date now = new Date();
+
+ X509v2CRLBuilder crlGen = new X509v2CRLBuilder(new X500Name("CN=Test CA"), now);
+
+ BcX509ExtensionUtils extFact = new BcX509ExtensionUtils(new SHA1DigestCalculator());
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ crlGen.addCRLEntry(BigInteger.ONE, now, CRLReason.privilegeWithdrawn);
+
+ crlGen.addExtension(Extension.authorityKeyIdentifier, false, extFact.createAuthorityKeyIdentifier(pair.getPublic()));
+
+ AlgorithmIdentifier sigAlg = sigAlgFinder.find("SHA256withRSAEncryption");
+ AlgorithmIdentifier digAlg = digAlgFinder.find(sigAlg);
+
+ X509CRLHolder crl = crlGen.build(new BcRSAContentSignerBuilder(sigAlg, digAlg).build(pair.getPrivate()));
+
+ if (!crl.getIssuer().equals(new X500Name("CN=Test CA")))
+ {
+ fail("failed CRL issuer test");
+ }
+
+ Extension authExt = crl.getExtension(Extension.authorityKeyIdentifier);
+
+ if (authExt == null)
+ {
+ fail("failed to find CRL extension");
+ }
+
+ AuthorityKeyIdentifier authId = AuthorityKeyIdentifier.getInstance(authExt.getParsedValue());
+
+ X509CRLEntryHolder entry = crl.getRevokedCertificate(BigInteger.ONE);
+
+ if (entry == null)
+ {
+ fail("failed to find CRL entry");
+ }
+
+ if (!entry.getSerialNumber().equals(BigInteger.ONE))
+ {
+ fail("CRL cert serial number does not match");
+ }
+
+ if (!entry.hasExtensions())
+ {
+ fail("CRL entry extension not found");
+ }
+
+ Extension ext = entry.getExtension(Extension.reasonCode);
+
+ if (ext != null)
+ {
+ ASN1Enumerated reasonCode = ASN1Enumerated.getInstance(ext.getParsedValue());
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found");
+ }
+ }
+
+ public void checkCRLCreation2()
+ throws Exception
+ {
+ AsymmetricCipherKeyPairGenerator kpg = new RSAKeyPairGenerator();
+ RSAKeyGenerationParameters genParam = new RSAKeyGenerationParameters(
+ BigInteger.valueOf(0x1001), new SecureRandom(), 1024, 25);
+
+ kpg.init(genParam);
+
+ AsymmetricCipherKeyPair pair = kpg.generateKeyPair();
+ Date now = new Date();
+
+ X509v2CRLBuilder crlGen = new X509v2CRLBuilder(new X500Name("CN=Test CA"), now);
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+
+ CRLReason crlReason = CRLReason.lookup(CRLReason.privilegeWithdrawn);
+
+ extGen.addExtension(Extension.reasonCode, false, crlReason);
+
+ BcX509ExtensionUtils extFact = new BcX509ExtensionUtils(new SHA1DigestCalculator());
+
+ crlGen.addCRLEntry(BigInteger.ONE, now, extGen.generate());
+
+ crlGen.addExtension(Extension.authorityKeyIdentifier, false, extFact.createAuthorityKeyIdentifier((AsymmetricKeyParameter)pair.getPublic()));
+
+ AlgorithmIdentifier sigAlg = sigAlgFinder.find("SHA256withRSAEncryption");
+ AlgorithmIdentifier digAlg = digAlgFinder.find(sigAlg);
+
+ X509CRLHolder crlHolder = crlGen.build(new BcRSAContentSignerBuilder(sigAlg, digAlg).build((AsymmetricKeyParameter)pair.getPrivate()));
+
+ if (!crlHolder.getIssuer().equals(new X500Name("CN=Test CA")))
+ {
+ fail("failed CRL issuer test");
+ }
+
+ Extension authExt = crlHolder.getExtension(Extension.authorityKeyIdentifier);
+
+ if (authExt == null)
+ {
+ fail("failed to find CRL extension");
+ }
+
+ AuthorityKeyIdentifier authId = AuthorityKeyIdentifier.getInstance(authExt.getParsedValue());
+
+ X509CRLEntryHolder entry = crlHolder.getRevokedCertificate(BigInteger.ONE);
+
+ if (entry == null)
+ {
+ fail("failed to find CRL entry");
+ }
+
+ if (!entry.getSerialNumber().equals(BigInteger.ONE))
+ {
+ fail("CRL cert serial number does not match");
+ }
+
+ if (!entry.hasExtensions())
+ {
+ fail("CRL entry extension not found");
+ }
+
+ Extension ext = entry.getExtension(Extension.reasonCode);
+
+ if (ext != null)
+ {
+ ASN1Enumerated reasonCode = ASN1Enumerated.getInstance(ext.getParsedValue());
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found");
+ }
+ }
+
+ public void checkCRLCreation3()
+ throws Exception
+ {
+ AsymmetricCipherKeyPairGenerator kpg = new RSAKeyPairGenerator();
+ RSAKeyGenerationParameters genParam = new RSAKeyGenerationParameters(
+ BigInteger.valueOf(0x1001), new SecureRandom(), 1024, 25);
+
+ kpg.init(genParam);
+
+ AsymmetricCipherKeyPair pair = kpg.generateKeyPair();
+ Date now = new Date();
+ X509v2CRLBuilder crlGen = new X509v2CRLBuilder(new X500Name("CN=Test CA"), now);
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+
+ CRLReason crlReason = CRLReason.lookup(CRLReason.privilegeWithdrawn);
+
+ extGen.addExtension(Extension.reasonCode, false, crlReason);
+
+ BcX509ExtensionUtils extFact = new BcX509ExtensionUtils(new SHA1DigestCalculator());
+
+ Extensions entryExtensions = extGen.generate();
+
+ crlGen.addCRLEntry(BigInteger.ONE, now, entryExtensions);
+
+ crlGen.addExtension(Extension.authorityKeyIdentifier, false, extFact.createAuthorityKeyIdentifier((AsymmetricKeyParameter)pair.getPublic()));
+
+ AlgorithmIdentifier sigAlg = sigAlgFinder.find("SHA256withRSAEncryption");
+ AlgorithmIdentifier digAlg = digAlgFinder.find(sigAlg);
+
+ X509CRLHolder crlHolder = crlGen.build(new BcRSAContentSignerBuilder(sigAlg, digAlg).build((AsymmetricKeyParameter)pair.getPrivate()));
+
+ if (!crlHolder.getIssuer().equals(new X500Name("CN=Test CA")))
+ {
+ fail("failed CRL issuer test");
+ }
+
+ Extension authExt = crlHolder.getExtension(Extension.authorityKeyIdentifier);
+
+ if (authExt == null)
+ {
+ fail("failed to find CRL extension");
+ }
+
+ AuthorityKeyIdentifier authId = AuthorityKeyIdentifier.getInstance(authExt.getParsedValue());
+
+ X509CRLEntryHolder entry = crlHolder.getRevokedCertificate(BigInteger.ONE);
+
+ if (entry == null)
+ {
+ fail("failed to find CRL entry");
+ }
+
+ if (!entry.getSerialNumber().equals(BigInteger.ONE))
+ {
+ fail("CRL cert serial number does not match");
+ }
+
+ if (!entry.hasExtensions())
+ {
+ fail("CRL entry extension not found");
+ }
+
+ Extension ext = entry.getExtension(Extension.reasonCode);
+
+ if (ext != null)
+ {
+ ASN1Enumerated reasonCode = ASN1Enumerated.getInstance(ext.getParsedValue());
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found");
+ }
+
+ //
+ // check loading of existing CRL
+ //
+ now = new Date();
+ crlGen = new X509v2CRLBuilder(new X500Name("CN=Test CA"), now);
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ crlGen.addCRL(crlHolder);
+
+ crlGen.addCRLEntry(BigInteger.valueOf(2), now, entryExtensions);
+
+ crlGen.addExtension(Extension.authorityKeyIdentifier, false, extFact.createAuthorityKeyIdentifier(pair.getPublic()));
+
+ crlHolder = crlGen.build(new BcRSAContentSignerBuilder(sigAlg, digAlg).build(pair.getPrivate()));
+
+ int count = 0;
+ boolean oneFound = false;
+ boolean twoFound = false;
+
+ Iterator it = crlHolder.getRevokedCertificates().iterator();
+ while (it.hasNext())
+ {
+ X509CRLEntryHolder crlEnt = (X509CRLEntryHolder)it.next();
+
+ if (crlEnt.getSerialNumber().intValue() == 1)
+ {
+ oneFound = true;
+ Extension extn = crlEnt.getExtension(Extension.reasonCode);
+
+ if (extn != null)
+ {
+ ASN1Enumerated reasonCode = ASN1Enumerated.getInstance(extn.getParsedValue());
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong on recheck");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found on recheck");
+ }
+ }
+ else if (crlEnt.getSerialNumber().intValue() == 2)
+ {
+ twoFound = true;
+ }
+
+ count++;
+ }
+
+ if (count != 2)
+ {
+ fail("wrong number of CRLs found, got: " + count);
+ }
+
+ if (!oneFound || !twoFound)
+ {
+ fail("wrong CRLs found in copied list");
+ }
+
+ //
+ // check factory read back
+ //
+ CertificateFactory cFact = CertificateFactory.getInstance("X.509");
+
+ X509CRL readCrl = (X509CRL)cFact.generateCRL(new ByteArrayInputStream(crlHolder.getEncoded()));
+
+ if (readCrl == null)
+ {
+ fail("crl not returned!");
+ }
+
+ Collection col = cFact.generateCRLs(new ByteArrayInputStream(crlHolder.getEncoded()));
+
+ if (col.size() != 1)
+ {
+ fail("wrong number of CRLs found in collection");
+ }
+ }
+
+ public void checkCreation5()
+ throws Exception
+ {
+ //
+ // a sample key pair.
+ //
+ AsymmetricKeyParameter pubKey = new RSAKeyParameters(
+ false,
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ AsymmetricKeyParameter privKey = new RSAPrivateCrtKeyParameters(
+ 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));
+
+ //
+ // set up the keys
+ //
+ SecureRandom rand = new SecureRandom();
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // create base certificate - version 3
+ //
+ AlgorithmIdentifier sigAlg = sigAlgFinder.find("MD5WithRSA");
+ AlgorithmIdentifier digAlg = digAlgFinder.find(sigAlg);
+
+ ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlg, digAlg).build(privKey);
+ ASN1ObjectIdentifier extOid = new ASN1ObjectIdentifier("2.5.29.37");
+ X509v3CertificateBuilder certGen = new BcX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey)
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true,
+ new KeyUsage(KeyUsage.encipherOnly))
+ .addExtension(extOid, true,
+ new DERSequence(KeyPurposeId.anyExtendedKeyUsage))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true,
+ new GeneralNames(new GeneralName(GeneralName.rfc822Name, "test@test.test")));
+
+ X509CertificateHolder baseCert = certGen.build(sigGen);
+
+ //
+ // copy certificate
+ //
+
+ certGen = new BcX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey)
+ .copyAndAddExtension(new ASN1ObjectIdentifier("2.5.29.15"), true, baseCert)
+ .copyAndAddExtension(extOid, false, baseCert);
+
+ X509CertificateHolder cert = certGen.build(sigGen);
+
+ assertTrue(cert.isValidOn(new Date()));
+
+ assertTrue(cert.isSignatureValid(new BcRSAContentVerifierProviderBuilder(digAlgFinder).build(pubKey)));
+
+ if (!baseCert.getExtension(new ASN1ObjectIdentifier("2.5.29.15")).equals(cert.getExtension(new ASN1ObjectIdentifier("2.5.29.15"))))
+ {
+ fail("2.5.29.15 differs");
+ }
+
+ assertTrue(baseCert.getExtension(extOid).getExtnId().equals(cert.getExtension(extOid).getExtnId()));
+ assertFalse(baseCert.getExtension(extOid).isCritical() == cert.getExtension(extOid).isCritical());
+ if (!baseCert.getExtension(extOid).getParsedValue().equals(cert.getExtension(extOid).getParsedValue()))
+ {
+ fail("2.5.29.37 differs");
+ }
+
+ //
+ // exception test
+ //
+
+ try
+ {
+ certGen.copyAndAddExtension(new ASN1ObjectIdentifier("2.5.99.99"), true, baseCert);
+
+ fail("exception not thrown on dud extension copy");
+ }
+ catch (NullPointerException e)
+ {
+ // expected
+ }
+
+// try
+// {
+// certGen.setPublicKey(dudPublicKey);
+//
+// certGen.generate(privKey, BC);
+//
+// fail("key without encoding not detected in v3");
+// }
+// catch (IllegalArgumentException e)
+// {
+// // expected
+// }
+
+ }
+
+ public void testForgedSignature()
+ throws Exception
+ {
+ String cert = "MIIBsDCCAVoCAQYwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCQVUxEzARBgNV"
+ + "BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMSMwIQYD"
+ + "VQQDExpTZXJ2ZXIgdGVzdCBjZXJ0ICg1MTIgYml0KTAeFw0wNjA5MTEyMzU4NTVa"
+ + "Fw0wNjEwMTEyMzU4NTVaMGMxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpRdWVlbnNs"
+ + "YW5kMRowGAYDVQQKExFDcnlwdFNvZnQgUHR5IEx0ZDEjMCEGA1UEAxMaU2VydmVy"
+ + "IHRlc3QgY2VydCAoNTEyIGJpdCkwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAn7PD"
+ + "hCeV/xIxUg8V70YRxK2A5jZbD92A12GN4PxyRQk0/lVmRUNMaJdq/qigpd9feP/u"
+ + "12S4PwTLb/8q/v657QIDAQABMA0GCSqGSIb3DQEBBQUAA0EAbynCRIlUQgaqyNgU"
+ + "DF6P14yRKUtX8akOP2TwStaSiVf/akYqfLFm3UGka5XbPj4rifrZ0/sOoZEEBvHQ"
+ + "e20sRA==";
+
+ X509CertificateHolder hldr = new X509CertificateHolder(Base64.decode(cert));
+
+ assertFalse(hldr.isSignatureValid(new BcRSAContentVerifierProviderBuilder(digAlgFinder).build(hldr)));
+ }
+
+ private void pemTest()
+ throws Exception
+ {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509", "SC");
+
+ X509Certificate cert = readPEMCert(cf, PEMData.CERTIFICATE_1);
+ if (cert == null)
+ {
+ fail("PEM cert not read");
+ }
+ cert = readPEMCert(cf, "-----BEGIN CERTIFICATE-----" + PEMData.CERTIFICATE_2);
+ if (cert == null)
+ {
+ fail("PEM cert with extraneous header not read");
+ }
+ CRL crl = cf.generateCRL(new ByteArrayInputStream(PEMData.CRL_1.getBytes("US-ASCII")));
+ if (crl == null)
+ {
+ fail("PEM crl not read");
+ }
+ Collection col = cf.generateCertificates(new ByteArrayInputStream(PEMData.CERTIFICATE_2.getBytes("US-ASCII")));
+ if (col.size() != 1 || !col.contains(cert))
+ {
+ fail("PEM cert collection not right");
+ }
+ col = cf.generateCRLs(new ByteArrayInputStream(PEMData.CRL_2.getBytes("US-ASCII")));
+ if (col.size() != 1 || !col.contains(crl))
+ {
+ fail("PEM crl collection not right");
+ }
+ }
+
+ private static X509Certificate readPEMCert(CertificateFactory cf, String pemData)
+ throws CertificateException, UnsupportedEncodingException
+ {
+ return (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(pemData.getBytes("US-ASCII")));
+ }
+
+ private void createPSSCert(String algorithm)
+ throws Exception
+ {
+ AsymmetricCipherKeyPair pair = generateLongFixedKeys();
+
+ AsymmetricKeyParameter privKey = (AsymmetricKeyParameter)pair.getPrivate();
+ AsymmetricKeyParameter pubKey = (AsymmetricKeyParameter)pair.getPublic();
+
+ //
+ // distinguished name table.
+ //
+
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // create base certificate - version 3
+ //
+ BcX509ExtensionUtils extFact = new BcX509ExtensionUtils(new SHA1DigestCalculator());
+
+ AlgorithmIdentifier sigAlgId = sigAlgFinder.find(algorithm);
+ AlgorithmIdentifier digAlgId = digAlgFinder.find(sigAlgId);
+
+ ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(privKey);
+ BcX509v3CertificateBuilder certGen = new BcX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),
+ new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ certGen.addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true,
+ new KeyUsage(KeyUsage.encipherOnly));
+ certGen.addExtension(new ASN1ObjectIdentifier("2.5.29.37"), true,
+ new DERSequence(KeyPurposeId.anyExtendedKeyUsage));
+ certGen.addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true,
+ new GeneralNames(new GeneralName(GeneralName.rfc822Name, "test@test.test")));
+
+ certGen.addExtension(Extension.authorityKeyIdentifier, true, extFact.createAuthorityKeyIdentifier(pubKey));
+
+ X509CertificateHolder baseCert = certGen.build(sigGen);
+
+ assertTrue(baseCert.isSignatureValid(new BcRSAContentVerifierProviderBuilder(digAlgFinder).build(pubKey)));
+ }
+
+ private AsymmetricCipherKeyPair generateLongFixedKeys()
+ {
+ RSAKeyParameters pubKeySpec = new RSAKeyParameters(
+ false,
+ new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+ new BigInteger("010001",16));
+
+ RSAKeyParameters privKeySpec = new RSAPrivateCrtKeyParameters(
+ new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+ new BigInteger("010001",16),
+ new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16),
+ new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16),
+ new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16),
+ new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16),
+ new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16),
+ new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16));
+
+ return new AsymmetricCipherKeyPair(pubKeySpec, privKeySpec);
+ }
+
+ public void testNullDerNullCert()
+ throws Exception
+ {
+ AsymmetricCipherKeyPair pair = generateLongFixedKeys();
+ AsymmetricKeyParameter pubKey = (AsymmetricKeyParameter)pair.getPublic();
+ AsymmetricKeyParameter privKey = (AsymmetricKeyParameter)pair.getPrivate();
+
+ DefaultSignatureAlgorithmIdentifierFinder sigAlgFinder = new DefaultSignatureAlgorithmIdentifierFinder();
+ DefaultDigestAlgorithmIdentifierFinder digAlgFinder = new DefaultDigestAlgorithmIdentifierFinder();
+
+ AlgorithmIdentifier sigAlgId = sigAlgFinder.find("MD5withRSA");
+ AlgorithmIdentifier digAlgId = digAlgFinder.find(sigAlgId);
+
+ ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(privKey);
+ BcX509v3CertificateBuilder certGen = new BcX509v3CertificateBuilder(new X500Name("CN=Test"),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),new X500Name("CN=Test"),pubKey);
+ X509CertificateHolder cert = certGen.build(sigGen);
+
+ Certificate struct = Certificate.getInstance(cert.getEncoded());
+
+ ASN1Object tbsCertificate = struct.getTBSCertificate();
+ AlgorithmIdentifier sig = struct.getSignatureAlgorithm();
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCertificate);
+ v.add(new AlgorithmIdentifier(sig.getAlgorithm()));
+ v.add(struct.getSignature());
+
+ // verify
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ bIn = new ByteArrayInputStream(new DERSequence(v).getEncoded());
+
+ cert = new X509CertificateHolder(new DERSequence(v).getEncoded());
+
+ assertTrue(cert.isSignatureValid(new BcRSAContentVerifierProviderBuilder(digAlgFinder).build(pubKey)));
+ }
+
+ public void testCertificates()
+ throws Exception
+ {
+ checkCertificate(1, cert1);
+ checkCertificate(2, cert2);
+ checkCertificate(3, cert3);
+ checkCertificate(4, cert4);
+ checkCertificate(5, cert5);
+ //checkCertificate(7, cert7);
+
+ checkKeyUsage(8, keyUsage);
+
+ checkSelfSignedCertificate(11, probSelfSignedCert);
+
+ checkCRL(1, crl1);
+
+ checkCreation1();
+ checkCreation2();
+ checkCreation5();
+
+ createPSSCert("SHA1withRSAandMGF1");
+ createPSSCert("SHA224withRSAandMGF1");
+ createPSSCert("SHA256withRSAandMGF1");
+ createPSSCert("SHA384withRSAandMGF1");
+
+ checkCRLCreation1();
+ checkCRLCreation2();
+ checkCRLCreation3();
+
+ pemTest();
+
+ checkCertificate(18, emptyDNCert);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/BcPKCS10Test.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/BcPKCS10Test.java
new file mode 100644
index 000000000..0d019764d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/BcPKCS10Test.java
@@ -0,0 +1,230 @@
+package org.spongycastle.cert.test;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import junit.framework.TestCase;
+import org.spongycastle.asn1.pkcs.Attribute;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.X500NameBuilder;
+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.ExtensionsGenerator;
+import org.spongycastle.asn1.x509.KeyUsage;
+import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
+import org.spongycastle.cert.bc.BcX509ExtensionUtils;
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.spongycastle.crypto.generators.RSAKeyPairGenerator;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.params.RSAKeyGenerationParameters;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.bc.BcContentSignerBuilder;
+import org.spongycastle.operator.bc.BcRSAContentSignerBuilder;
+import org.spongycastle.operator.bc.BcRSAContentVerifierProviderBuilder;
+import org.spongycastle.pkcs.PKCS10CertificationRequest;
+import org.spongycastle.pkcs.PKCS10CertificationRequestBuilder;
+import org.spongycastle.pkcs.bc.BcPKCS10CertificationRequest;
+import org.spongycastle.pkcs.bc.BcPKCS10CertificationRequestBuilder;
+import org.spongycastle.util.Arrays;
+
+public class BcPKCS10Test
+ extends TestCase
+{
+ public String getName()
+ {
+ return "PKCS10CertRequest";
+ }
+
+ private void generationTest(int keySize, String keyName, String sigName)
+ throws Exception
+ {
+ AsymmetricCipherKeyPairGenerator kpg = new RSAKeyPairGenerator();
+ RSAKeyGenerationParameters genParam = new RSAKeyGenerationParameters(
+ BigInteger.valueOf(0x1001), new SecureRandom(), keySize, 25);
+
+ kpg.init(genParam);
+
+ AsymmetricCipherKeyPair kp = kpg.generateKeyPair();
+
+
+ X500NameBuilder x500NameBld = new X500NameBuilder(RFC4519Style.INSTANCE);
+
+ x500NameBld.addRDN(RFC4519Style.c, "AU");
+ x500NameBld.addRDN(RFC4519Style.o, "The Legion of the Bouncy Castle");
+ x500NameBld.addRDN(RFC4519Style.l, "Melbourne");
+ x500NameBld.addRDN(RFC4519Style.st, "Victoria");
+ x500NameBld.addRDN(PKCSObjectIdentifiers.pkcs_9_at_emailAddress, "feedback-crypto@bouncycastle.org");
+
+ X500Name subject = x500NameBld.build();
+
+ PKCS10CertificationRequestBuilder requestBuilder = new BcPKCS10CertificationRequestBuilder(subject, kp.getPublic());
+
+ DefaultSignatureAlgorithmIdentifierFinder sigAlgFinder = new DefaultSignatureAlgorithmIdentifierFinder();
+ DefaultDigestAlgorithmIdentifierFinder digAlgFinder = new DefaultDigestAlgorithmIdentifierFinder();
+
+ AlgorithmIdentifier sigAlgId = sigAlgFinder.find("SHA1withRSA");
+
+ AlgorithmIdentifier digAlgId = digAlgFinder.find(sigAlgId);
+
+ BcContentSignerBuilder contentSignerBuilder = new BcRSAContentSignerBuilder(sigAlgId, digAlgId);
+
+ PKCS10CertificationRequest req1 = requestBuilder.build(contentSignerBuilder.build(kp.getPrivate()));
+
+ BcPKCS10CertificationRequest req2 = new BcPKCS10CertificationRequest(req1.getEncoded());
+
+ if (!req2.isSignatureValid(new BcRSAContentVerifierProviderBuilder(digAlgFinder).build(kp.getPublic())))
+ {
+ fail(sigName + ": Failed verify check.");
+ }
+
+ if (!Arrays.areEqual(req2.getSubjectPublicKeyInfo().getEncoded(), req1.getSubjectPublicKeyInfo().getEncoded()))
+ {
+ fail(keyName + ": Failed public key check.");
+ }
+ }
+
+ private void createPSSTest(String algorithm)
+ throws Exception
+ {
+ AsymmetricKeyParameter pubKey = new RSAKeyParameters(
+ false,
+ new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+ new BigInteger("010001",16));
+
+ AsymmetricKeyParameter privKey = new RSAPrivateCrtKeyParameters(
+ new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+ new BigInteger("010001",16),
+ new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16),
+ new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16),
+ new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16),
+ new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16),
+ new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16),
+ new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16));
+
+ DefaultSignatureAlgorithmIdentifierFinder sigAlgFinder = new DefaultSignatureAlgorithmIdentifierFinder();
+ DefaultDigestAlgorithmIdentifierFinder digAlgFinder = new DefaultDigestAlgorithmIdentifierFinder();
+
+ AlgorithmIdentifier sigAlgId = sigAlgFinder.find(algorithm);
+ AlgorithmIdentifier digAlgId = digAlgFinder.find(sigAlgId);
+ BcContentSignerBuilder contentSignerBuilder = new BcRSAContentSignerBuilder(sigAlgId, digAlgId);
+
+ PKCS10CertificationRequest req = new BcPKCS10CertificationRequestBuilder(new X500Name("CN=XXX"), pubKey).build(contentSignerBuilder.build(privKey));
+ if (!req.isSignatureValid(new BcRSAContentVerifierProviderBuilder(digAlgFinder).build(pubKey)))
+ {
+ fail("Failed verify check PSS.");
+ }
+
+ BcPKCS10CertificationRequest bcReq = new BcPKCS10CertificationRequest(req.getEncoded());
+ if (!bcReq.isSignatureValid(new BcRSAContentVerifierProviderBuilder(digAlgFinder).build(bcReq.getPublicKey())))
+ {
+ fail("Failed verify check PSS encoded.");
+ }
+
+ if (!bcReq.getSignatureAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ fail("PSS oid incorrect.");
+ }
+
+ if (bcReq.getSignatureAlgorithm().getParameters() == null)
+ {
+ fail("PSS parameters incorrect.");
+ }
+ }
+
+ // previous code found to cause a NullPointerException
+ private void nullPointerTest()
+ throws Exception
+ {
+ AsymmetricCipherKeyPairGenerator kpg = new RSAKeyPairGenerator();
+ RSAKeyGenerationParameters genParam = new RSAKeyGenerationParameters(
+ BigInteger.valueOf(0x1001), new SecureRandom(), 1024, 25);
+
+ kpg.init(genParam);
+
+ AsymmetricCipherKeyPair kp = kpg.generateKeyPair();
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+
+ extGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(true));
+ extGen.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign));
+
+ BcX509ExtensionUtils extUtils = new BcX509ExtensionUtils(new SHA1DigestCalculator());
+
+ SubjectKeyIdentifier subjectKeyIdentifier = extUtils.createSubjectKeyIdentifier(kp.getPublic());
+
+ extGen.addExtension(Extension.subjectKeyIdentifier, false, subjectKeyIdentifier);
+
+ DefaultSignatureAlgorithmIdentifierFinder sigAlgFinder = new DefaultSignatureAlgorithmIdentifierFinder();
+ DefaultDigestAlgorithmIdentifierFinder digAlgFinder = new DefaultDigestAlgorithmIdentifierFinder();
+
+ AlgorithmIdentifier sigAlgId = sigAlgFinder.find("SHA1withRSA");
+
+ AlgorithmIdentifier digAlgId = digAlgFinder.find(sigAlgId);
+
+ BcContentSignerBuilder contentSignerBuilder = new BcRSAContentSignerBuilder(sigAlgId, digAlgId);
+
+ PKCS10CertificationRequest p1 = new BcPKCS10CertificationRequestBuilder(
+ new X500Name("cn=csr"), kp.getPublic())
+ .addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, extGen.generate())
+ .build(contentSignerBuilder.build(kp.getPrivate()));
+ PKCS10CertificationRequest p2 = new BcPKCS10CertificationRequestBuilder(
+ new X500Name("cn=csr"), kp.getPublic())
+ .addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, extGen.generate())
+ .build(contentSignerBuilder.build(kp.getPrivate()));
+
+ if (!p1.equals(p2))
+ {
+ fail("cert request comparison failed");
+ }
+
+ Attribute[] attr1 = p1.getAttributes();
+ Attribute[] attr2 = p1.getAttributes();
+
+ checkAttrs(1, attr1, attr2);
+
+ attr1 = p1.getAttributes(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest);
+ attr2 = p1.getAttributes(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest);
+
+ checkAttrs(1, attr1, attr2);
+ }
+
+ private void checkAttrs(int expectedLength, Attribute[] attr1, Attribute[] attr2)
+ {
+ if (expectedLength != attr1.length)
+ {
+ fail("expected length mismatch");
+ }
+
+ if (attr1.length != attr2.length)
+ {
+ fail("atrribute length mismatch");
+ }
+
+ for (int i = 0; i != attr1.length; i++)
+ {
+ if (!attr1[i].equals(attr2[i]))
+ {
+ fail("atrribute mismatch");
+ }
+ }
+ }
+
+ public void testPKCS10()
+ throws Exception
+ {
+ generationTest(512, "RSA", "SHA1withRSA");
+
+ createPSSTest("SHA1withRSAandMGF1");
+ createPSSTest("SHA224withRSAandMGF1");
+ createPSSTest("SHA256withRSAandMGF1");
+ createPSSTest("SHA384withRSAandMGF1");
+
+ nullPointerTest();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/CertTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/CertTest.java
new file mode 100644
index 000000000..a82d2e415
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/CertTest.java
@@ -0,0 +1,2997 @@
+package org.spongycastle.cert.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Signature;
+import java.security.cert.CRL;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Enumerated;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DEREnumerated;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSAPublicKey;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.X500NameBuilder;
+import org.spongycastle.asn1.x500.style.BCStyle;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.ExtensionsGenerator;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.IssuingDistributionPoint;
+import org.spongycastle.asn1.x509.KeyPurposeId;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509CertificateStructure;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.cert.X509CRLEntryHolder;
+import org.spongycastle.cert.X509CRLHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509v1CertificateBuilder;
+import org.spongycastle.cert.X509v2CRLBuilder;
+import org.spongycastle.cert.X509v3CertificateBuilder;
+import org.spongycastle.cert.jcajce.JcaX509CRLConverter;
+import org.spongycastle.cert.jcajce.JcaX509CRLHolder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.cert.jcajce.JcaX509v1CertificateBuilder;
+import org.spongycastle.cert.jcajce.JcaX509v2CRLBuilder;
+import org.spongycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.spongycastle.jce.X509KeyUsage;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPrivateKeySpec;
+import org.spongycastle.jce.spec.ECPublicKeySpec;
+import org.spongycastle.jce.spec.GOST3410ParameterSpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.bc.BcRSAContentSignerBuilder;
+import org.spongycastle.operator.bc.BcRSAContentVerifierProviderBuilder;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.encoders.Hex;
+import org.spongycastle.util.test.SimpleTest;
+import org.spongycastle.x509.extension.AuthorityKeyIdentifierStructure;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+
+public class CertTest
+ extends SimpleTest
+{
+ private static final String BC = org.spongycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
+
+ // test CA
+ byte[] testCAp12 = Base64.decode(
+ "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"
+ + "HLhcYQcQ1R+RucctAgIEAAAA");
+
+ //
+ // server.crt
+ //
+ byte[] cert1 = Base64.decode(
+ "MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx"
+ + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY"
+ + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB"
+ + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ"
+ + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2"
+ + "MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW"
+ + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM"
+ + "dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l"
+ + "Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv"
+ + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re"
+ + "Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO"
+ + "Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE"
+ + "7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy"
+ + "QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0"
+ + "ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw"
+ + "DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL"
+ + "iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4"
+ + "yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF"
+ + "5/8=");
+
+ //
+ // ca.crt
+ //
+ byte[] cert2 = Base64.decode(
+ "MIIDbDCCAtWgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx"
+ + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY"
+ + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB"
+ + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ"
+ + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU1MzNaFw0wMTA2"
+ + "MDIwNzU1MzNaMIG3MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW"
+ + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM"
+ + "dGQxHjAcBgNVBAsTFUNlcnRpZmljYXRlIEF1dGhvcml0eTEVMBMGA1UEAxMMQ29u"
+ + "bmVjdCA0IENBMSgwJgYJKoZIhvcNAQkBFhl3ZWJtYXN0ZXJAY29ubmVjdDQuY29t"
+ + "LmF1MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgs5ptNG6Qv1ZpCDuUNGmv"
+ + "rhjqMDPd3ri8JzZNRiiFlBA4e6/ReaO1U8ASewDeQMH6i9R6degFdQRLngbuJP0s"
+ + "xcEE+SksEWNvygfzLwV9J/q+TQDyJYK52utb++lS0b48A1KPLwEsyL6kOAgelbur"
+ + "ukwxowprKUIV7Knf1ajetQIDAQABo4GFMIGCMCQGA1UdEQQdMBuBGXdlYm1hc3Rl"
+ + "ckBjb25uZWN0NC5jb20uYXUwDwYDVR0TBAgwBgEB/wIBADA2BglghkgBhvhCAQ0E"
+ + "KRYnbW9kX3NzbCBnZW5lcmF0ZWQgY3VzdG9tIENBIGNlcnRpZmljYXRlMBEGCWCG"
+ + "SAGG+EIBAQQEAwICBDANBgkqhkiG9w0BAQQFAAOBgQCsGvfdghH8pPhlwm1r3pQk"
+ + "msnLAVIBb01EhbXm2861iXZfWqGQjrGAaA0ZpXNk9oo110yxoqEoSJSzniZa7Xtz"
+ + "soTwNUpE0SLHvWf/SlKdFWlzXA+vOZbzEv4UmjeelekTm7lc01EEa5QRVzOxHFtQ"
+ + "DhkaJ8VqOMajkQFma2r9iA==");
+
+ //
+ // testx509.pem
+ //
+ byte[] cert3 = Base64.decode(
+ "MIIBWzCCAQYCARgwDQYJKoZIhvcNAQEEBQAwODELMAkGA1UEBhMCQVUxDDAKBgNV"
+ + "BAgTA1FMRDEbMBkGA1UEAxMSU1NMZWF5L3JzYSB0ZXN0IENBMB4XDTk1MDYxOTIz"
+ + "MzMxMloXDTk1MDcxNzIzMzMxMlowOjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA1FM"
+ + "RDEdMBsGA1UEAxMUU1NMZWF5L3JzYSB0ZXN0IGNlcnQwXDANBgkqhkiG9w0BAQEF"
+ + "AANLADBIAkEAqtt6qS5GTxVxGZYWa0/4u+IwHf7p2LNZbcPBp9/OfIcYAXBQn8hO"
+ + "/Re1uwLKXdCjIoaGs4DLdG88rkzfyK5dPQIDAQABMAwGCCqGSIb3DQIFBQADQQAE"
+ + "Wc7EcF8po2/ZO6kNCwK/ICH6DobgLekA5lSLr5EvuioZniZp5lFzAw4+YzPQ7XKJ"
+ + "zl9HYIMxATFyqSiD9jsx");
+
+ //
+ // v3-cert1.pem
+ //
+ byte[] cert4 = Base64.decode(
+ "MIICjTCCAfigAwIBAgIEMaYgRzALBgkqhkiG9w0BAQQwRTELMAkGA1UEBhMCVVMx"
+ + "NjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFuZCBTcGFjZSBBZG1pbmlz"
+ + "dHJhdGlvbjAmFxE5NjA1MjgxMzQ5MDUrMDgwMBcROTgwNTI4MTM0OTA1KzA4MDAw"
+ + "ZzELMAkGA1UEBhMCVVMxNjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFu"
+ + "ZCBTcGFjZSBBZG1pbmlzdHJhdGlvbjEgMAkGA1UEBRMCMTYwEwYDVQQDEwxTdGV2"
+ + "ZSBTY2hvY2gwWDALBgkqhkiG9w0BAQEDSQAwRgJBALrAwyYdgxmzNP/ts0Uyf6Bp"
+ + "miJYktU/w4NG67ULaN4B5CnEz7k57s9o3YY3LecETgQ5iQHmkwlYDTL2fTgVfw0C"
+ + "AQOjgaswgagwZAYDVR0ZAQH/BFowWDBWMFQxCzAJBgNVBAYTAlVTMTYwNAYDVQQK"
+ + "Ey1OYXRpb25hbCBBZXJvbmF1dGljcyBhbmQgU3BhY2UgQWRtaW5pc3RyYXRpb24x"
+ + "DTALBgNVBAMTBENSTDEwFwYDVR0BAQH/BA0wC4AJODMyOTcwODEwMBgGA1UdAgQR"
+ + "MA8ECTgzMjk3MDgyM4ACBSAwDQYDVR0KBAYwBAMCBkAwCwYJKoZIhvcNAQEEA4GB"
+ + "AH2y1VCEw/A4zaXzSYZJTTUi3uawbbFiS2yxHvgf28+8Js0OHXk1H1w2d6qOHH21"
+ + "X82tZXd/0JtG0g1T9usFFBDvYK8O0ebgz/P5ELJnBL2+atObEuJy1ZZ0pBDWINR3"
+ + "WkDNLCGiTkCKp0F5EWIrVDwh54NNevkCQRZita+z4IBO");
+
+ //
+ // v3-cert2.pem
+ //
+ byte[] cert5 = Base64.decode(
+ "MIICiTCCAfKgAwIBAgIEMeZfHzANBgkqhkiG9w0BAQQFADB9MQswCQYDVQQGEwJD"
+ + "YTEPMA0GA1UEBxMGTmVwZWFuMR4wHAYDVQQLExVObyBMaWFiaWxpdHkgQWNjZXB0"
+ + "ZWQxHzAdBgNVBAoTFkZvciBEZW1vIFB1cnBvc2VzIE9ubHkxHDAaBgNVBAMTE0Vu"
+ + "dHJ1c3QgRGVtbyBXZWIgQ0EwHhcNOTYwNzEyMTQyMDE1WhcNOTYxMDEyMTQyMDE1"
+ + "WjB0MSQwIgYJKoZIhvcNAQkBExVjb29rZUBpc3NsLmF0bC5ocC5jb20xCzAJBgNV"
+ + "BAYTAlVTMScwJQYDVQQLEx5IZXdsZXR0IFBhY2thcmQgQ29tcGFueSAoSVNTTCkx"
+ + "FjAUBgNVBAMTDVBhdWwgQS4gQ29va2UwXDANBgkqhkiG9w0BAQEFAANLADBIAkEA"
+ + "6ceSq9a9AU6g+zBwaL/yVmW1/9EE8s5you1mgjHnj0wAILuoB3L6rm6jmFRy7QZT"
+ + "G43IhVZdDua4e+5/n1ZslwIDAQABo2MwYTARBglghkgBhvhCAQEEBAMCB4AwTAYJ"
+ + "YIZIAYb4QgENBD8WPVRoaXMgY2VydGlmaWNhdGUgaXMgb25seSBpbnRlbmRlZCBm"
+ + "b3IgZGVtb25zdHJhdGlvbiBwdXJwb3Nlcy4wDQYJKoZIhvcNAQEEBQADgYEAi8qc"
+ + "F3zfFqy1sV8NhjwLVwOKuSfhR/Z8mbIEUeSTlnH3QbYt3HWZQ+vXI8mvtZoBc2Fz"
+ + "lexKeIkAZXCesqGbs6z6nCt16P6tmdfbZF3I3AWzLquPcOXjPf4HgstkyvVBn0Ap"
+ + "jAFN418KF/Cx4qyHB4cjdvLrRjjQLnb2+ibo7QU=");
+
+ //
+ // pem encoded pkcs7
+ //
+ byte[] cert6 = Base64.decode(
+ "MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIJbzCCAj0w"
+ + "ggGmAhEAzbp/VvDf5LxU/iKss3KqVTANBgkqhkiG9w0BAQIFADBfMQswCQYDVQQGEwJVUzEXMBUG"
+ + "A1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGljIFByaW1hcnkgQ2Vy"
+ + "dGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNOTYwMTI5MDAwMDAwWhcNMjgwODAxMjM1OTU5WjBfMQsw"
+ + "CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVi"
+ + "bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwgZ8wDQYJKoZIhvcNAQEBBQADgY0A"
+ + "MIGJAoGBAOUZv22jVmEtmUhx9mfeuY3rt56GgAqRDvo4Ja9GiILlc6igmyRdDR/MZW4MsNBWhBiH"
+ + "mgabEKFz37RYOWtuwfYV1aioP6oSBo0xrH+wNNePNGeICc0UEeJORVZpH3gCgNrcR5EpuzbJY1zF"
+ + "4Ncth3uhtzKwezC6Ki8xqu6jZ9rbAgMBAAEwDQYJKoZIhvcNAQECBQADgYEATD+4i8Zo3+5DMw5d"
+ + "6abLB4RNejP/khv0Nq3YlSI2aBFsfELM85wuxAc/FLAPT/+Qknb54rxK6Y/NoIAK98Up8YIiXbix"
+ + "3YEjo3slFUYweRb46gVLlH8dwhzI47f0EEA8E8NfH1PoSOSGtHuhNbB7Jbq4046rPzidADQAmPPR"
+ + "cZQwggMuMIICl6ADAgECAhEA0nYujRQMPX2yqCVdr+4NdTANBgkqhkiG9w0BAQIFADBfMQswCQYD"
+ + "VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGlj"
+ + "IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNOTgwNTEyMDAwMDAwWhcNMDgwNTEy"
+ + "MjM1OTU5WjCBzDEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy"
+ + "dXN0IE5ldHdvcmsxRjBEBgNVBAsTPXd3dy52ZXJpc2lnbi5jb20vcmVwb3NpdG9yeS9SUEEgSW5j"
+ + "b3JwLiBCeSBSZWYuLExJQUIuTFREKGMpOTgxSDBGBgNVBAMTP1ZlcmlTaWduIENsYXNzIDEgQ0Eg"
+ + "SW5kaXZpZHVhbCBTdWJzY3JpYmVyLVBlcnNvbmEgTm90IFZhbGlkYXRlZDCBnzANBgkqhkiG9w0B"
+ + "AQEFAAOBjQAwgYkCgYEAu1pEigQWu1X9A3qKLZRPFXg2uA1Ksm+cVL+86HcqnbnwaLuV2TFBcHqB"
+ + "S7lIE1YtxwjhhEKrwKKSq0RcqkLwgg4C6S/7wju7vsknCl22sDZCM7VuVIhPh0q/Gdr5FegPh7Yc"
+ + "48zGmo5/aiSS4/zgZbqnsX7vyds3ashKyAkG5JkCAwEAAaN8MHowEQYJYIZIAYb4QgEBBAQDAgEG"
+ + "MEcGA1UdIARAMD4wPAYLYIZIAYb4RQEHAQEwLTArBggrBgEFBQcCARYfd3d3LnZlcmlzaWduLmNv"
+ + "bS9yZXBvc2l0b3J5L1JQQTAPBgNVHRMECDAGAQH/AgEAMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0B"
+ + "AQIFAAOBgQCIuDc73dqUNwCtqp/hgQFxHpJqbS/28Z3TymQ43BuYDAeGW4UVag+5SYWklfEXfWe0"
+ + "fy0s3ZpCnsM+tI6q5QsG3vJWKvozx74Z11NMw73I4xe1pElCY+zCphcPXVgaSTyQXFWjZSAA/Rgg"
+ + "5V+CprGoksVYasGNAzzrw80FopCubjCCA/gwggNhoAMCAQICEBbbn/1G1zppD6KsP01bwywwDQYJ"
+ + "KoZIhvcNAQEEBQAwgcwxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln"
+ + "biBUcnVzdCBOZXR3b3JrMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvUlBB"
+ + "IEluY29ycC4gQnkgUmVmLixMSUFCLkxURChjKTk4MUgwRgYDVQQDEz9WZXJpU2lnbiBDbGFzcyAx"
+ + "IENBIEluZGl2aWR1YWwgU3Vic2NyaWJlci1QZXJzb25hIE5vdCBWYWxpZGF0ZWQwHhcNMDAxMDAy"
+ + "MDAwMDAwWhcNMDAxMjAxMjM1OTU5WjCCAQcxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYD"
+ + "VQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3Jl"
+ + "cG9zaXRvcnkvUlBBIEluY29ycC4gYnkgUmVmLixMSUFCLkxURChjKTk4MR4wHAYDVQQLExVQZXJz"
+ + "b25hIE5vdCBWYWxpZGF0ZWQxJzAlBgNVBAsTHkRpZ2l0YWwgSUQgQ2xhc3MgMSAtIE1pY3Jvc29m"
+ + "dDETMBEGA1UEAxQKRGF2aWQgUnlhbjElMCMGCSqGSIb3DQEJARYWZGF2aWRAbGl2ZW1lZGlhLmNv"
+ + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqxBsdeNmSvFqhMNwhQgNzM8mdjX9eSXb"
+ + "DawpHtQHjmh0AKJSa3IwUY0VIsyZHuXWktO/CgaMBVPt6OVf/n0R2sQigMP6Y+PhEiS0vCJBL9aK"
+ + "0+pOo2qXrjVBmq+XuCyPTnc+BOSrU26tJsX0P9BYorwySiEGxGanBNATdVL4NdUCAwEAAaOBnDCB"
+ + "mTAJBgNVHRMEAjAAMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQgwKjAoBggrBgEFBQcCARYcaHR0"
+ + "cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYTARBglghkgBhvhCAQEEBAMCB4AwMwYDVR0fBCwwKjAo"
+ + "oCagJIYiaHR0cDovL2NybC52ZXJpc2lnbi5jb20vY2xhc3MxLmNybDANBgkqhkiG9w0BAQQFAAOB"
+ + "gQBC8yIIdVGpFTf8/YiL14cMzcmL0nIRm4kGR3U59z7UtcXlfNXXJ8MyaeI/BnXwG/gD5OKYqW6R"
+ + "yca9vZOxf1uoTBl82gInk865ED3Tej6msCqFzZffnSUQvOIeqLxxDlqYRQ6PmW2nAnZeyjcnbI5Y"
+ + "syQSM2fmo7n6qJFP+GbFezGCAkUwggJBAgEBMIHhMIHMMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5j"
+ + "LjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazFGMEQGA1UECxM9d3d3LnZlcmlzaWdu"
+ + "LmNvbS9yZXBvc2l0b3J5L1JQQSBJbmNvcnAuIEJ5IFJlZi4sTElBQi5MVEQoYyk5ODFIMEYGA1UE"
+ + "AxM/VmVyaVNpZ24gQ2xhc3MgMSBDQSBJbmRpdmlkdWFsIFN1YnNjcmliZXItUGVyc29uYSBOb3Qg"
+ + "VmFsaWRhdGVkAhAW25/9Rtc6aQ+irD9NW8MsMAkGBSsOAwIaBQCggbowGAYJKoZIhvcNAQkDMQsG"
+ + "CSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMDAxMDAyMTczNTE4WjAjBgkqhkiG9w0BCQQxFgQU"
+ + "gZjSaBEY2oxGvlQUIMnxSXhivK8wWwYJKoZIhvcNAQkPMU4wTDAKBggqhkiG9w0DBzAOBggqhkiG"
+ + "9w0DAgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwBwYFKw4DAh0w"
+ + "DQYJKoZIhvcNAQEBBQAEgYAzk+PU91/ZFfoiuKOECjxEh9fDYE2jfDCheBIgh5gdcCo+sS1WQs8O"
+ + "HreQ9Nop/JdJv1DQMBK6weNBBDoP0EEkRm1XCC144XhXZC82jBZohYmi2WvDbbC//YN58kRMYMyy"
+ + "srrfn4Z9I+6kTriGXkrpGk9Q0LSGjmG2BIsqiF0dvwAAAAAAAA==");
+
+ //
+ // dsaWithSHA1 cert
+ //
+ byte[] cert7 = Base64.decode(
+ "MIIEXAYJKoZIhvcNAQcCoIIETTCCBEkCAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+ + "SIb3DQEHAaCCAsMwggK/MIIB4AIBADCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7"
+ + "d8miwTMN55CUSmo3TO8WGCxgY61TX5k+7NU4XPf1TULjw3GobwaJX13kquPh"
+ + "fVXk+gVy46n4Iw3hAhUBSe/QF4BUj+pJOF9ROBM4u+FEWA8CQQD4mSJbrABj"
+ + "TUWrlnAte8pS22Tq4/FPO7jHSqjijUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/z"
+ + "m8Q12PFp/PjOhh+nMA4xDDAKBgNVBAMTA0lEMzAeFw05NzEwMDEwMDAwMDBa"
+ + "Fw0zODAxMDEwMDAwMDBaMA4xDDAKBgNVBAMTA0lEMzCB8DCBpwYFKw4DAhsw"
+ + "gZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxgY61TX5k+7NU4XPf1TULj"
+ + "w3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/QF4BUj+pJOF9ROBM4u+FE"
+ + "WA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jHSqjijUHfXKTrHL1OEqV3"
+ + "SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nA0QAAkEAkYkXLYMtGVGWj9OnzjPn"
+ + "sB9sefSRPrVegZJCZbpW+Iv0/1RP1u04pHG9vtRpIQLjzUiWvLMU9EKQTThc"
+ + "eNMmWDCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxg"
+ + "Y61TX5k+7NU4XPf1TULjw3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/Q"
+ + "F4BUj+pJOF9ROBM4u+FEWA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jH"
+ + "SqjijUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nAy8AMCwC"
+ + "FBY3dBSdeprGcqpr6wr3xbG+6WW+AhRMm/facKJNxkT3iKgJbp7R8Xd3QTGC"
+ + "AWEwggFdAgEBMBMwDjEMMAoGA1UEAxMDSUQzAgEAMAkGBSsOAwIaBQCgXTAY"
+ + "BgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0wMjA1"
+ + "MjQyMzEzMDdaMCMGCSqGSIb3DQEJBDEWBBS4WMsoJhf7CVbZYCFcjoTRzPkJ"
+ + "xjCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxgY61T"
+ + "X5k+7NU4XPf1TULjw3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/QF4BU"
+ + "j+pJOF9ROBM4u+FEWA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jHSqji"
+ + "jUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nBC8wLQIVALID"
+ + "dt+MHwawrDrwsO1Z6sXBaaJsAhRaKssrpevmLkbygKPV07XiAKBG02Zvb2Jh"
+ + "cg==");
+
+ //
+ // testcrl.pem
+ //
+ byte[] crl1 = Base64.decode(
+ "MIICjTCCAfowDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoT"
+ + "F1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVy"
+ + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5Fw05NTA1MDIwMjEyMjZaFw05NTA2MDEw"
+ + "MDAxNDlaMIIBaDAWAgUCQQAABBcNOTUwMjAxMTcyNDI2WjAWAgUCQQAACRcNOTUw"
+ + "MjEwMDIxNjM5WjAWAgUCQQAADxcNOTUwMjI0MDAxMjQ5WjAWAgUCQQAADBcNOTUw"
+ + "MjI1MDA0NjQ0WjAWAgUCQQAAGxcNOTUwMzEzMTg0MDQ5WjAWAgUCQQAAFhcNOTUw"
+ + "MzE1MTkxNjU0WjAWAgUCQQAAGhcNOTUwMzE1MTk0MDQxWjAWAgUCQQAAHxcNOTUw"
+ + "MzI0MTk0NDMzWjAWAgUCcgAABRcNOTUwMzI5MjAwNzExWjAWAgUCcgAAERcNOTUw"
+ + "MzMwMDIzNDI2WjAWAgUCQQAAIBcNOTUwNDA3MDExMzIxWjAWAgUCcgAAHhcNOTUw"
+ + "NDA4MDAwMjU5WjAWAgUCcgAAQRcNOTUwNDI4MTcxNzI0WjAWAgUCcgAAOBcNOTUw"
+ + "NDI4MTcyNzIxWjAWAgUCcgAATBcNOTUwNTAyMDIxMjI2WjANBgkqhkiG9w0BAQIF"
+ + "AAN+AHqOEJXSDejYy0UwxxrH/9+N2z5xu/if0J6qQmK92W0hW158wpJg+ovV3+wQ"
+ + "wvIEPRL2rocL0tKfAsVq1IawSJzSNgxG0lrcla3MrJBnZ4GaZDu4FutZh72MR3Gt"
+ + "JaAL3iTJHJD55kK2D/VoyY1djlsPuNh6AEgdVwFAyp0v");
+
+ //
+ // ecdsa cert with extra octet string.
+ //
+ byte[] oldEcdsa = Base64.decode(
+ "MIICljCCAkCgAwIBAgIBATALBgcqhkjOPQQBBQAwgY8xCzAJBgNVBAYTAkFVMSgwJ"
+ + "gYDVQQKEx9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIwEAYDVQQHEw"
+ + "lNZWxib3VybmUxETAPBgNVBAgTCFZpY3RvcmlhMS8wLQYJKoZIhvcNAQkBFiBmZWV"
+ + "kYmFjay1jcnlwdG9AYm91bmN5Y2FzdGxlLm9yZzAeFw0wMTEyMDcwMTAwMDRaFw0w"
+ + "MTEyMDcwMTAxNDRaMIGPMQswCQYDVQQGEwJBVTEoMCYGA1UEChMfVGhlIExlZ2lvb"
+ + "iBvZiB0aGUgQm91bmN5IENhc3RsZTESMBAGA1UEBxMJTWVsYm91cm5lMREwDwYDVQ"
+ + "QIEwhWaWN0b3JpYTEvMC0GCSqGSIb3DQEJARYgZmVlZGJhY2stY3J5cHRvQGJvdW5"
+ + "jeWNhc3RsZS5vcmcwgeQwgb0GByqGSM49AgEwgbECAQEwKQYHKoZIzj0BAQIef///"
+ + "////////////f///////gAAAAAAAf///////MEAEHn///////////////3///////"
+ + "4AAAAAAAH///////AQeawFsO9zxiUHQ1lSSFHXKcanbL7J9HTd5YYXClCwKBB8CD/"
+ + "qWPNyogWzMM7hkK+35BcPTWFc9Pyf7vTs8uaqvAh5///////////////9///+eXpq"
+ + "fXZBx+9FSJoiQnQsDIgAEHwJbbcU7xholSP+w9nFHLebJUhqdLSU05lq/y9X+DHAw"
+ + "CwYHKoZIzj0EAQUAA0MAMEACHnz6t4UNoVROp74ma4XNDjjGcjaqiIWPZLK8Bdw3G"
+ + "QIeLZ4j3a6ividZl344UH+UPUE7xJxlYGuy7ejTsqRR");
+
+ byte[] uncompressedPtEC = Base64.decode(
+ "MIIDKzCCAsGgAwIBAgICA+kwCwYHKoZIzj0EAQUAMGYxCzAJBgNVBAYTAkpQ"
+ + "MRUwEwYDVQQKEwxuaXRlY2guYWMuanAxDjAMBgNVBAsTBWFpbGFiMQ8wDQYD"
+ + "VQQDEwZ0ZXN0Y2ExHzAdBgkqhkiG9w0BCQEWEHRlc3RjYUBsb2NhbGhvc3Qw"
+ + "HhcNMDExMDEzMTE1MzE3WhcNMjAxMjEyMTE1MzE3WjBmMQswCQYDVQQGEwJK"
+ + "UDEVMBMGA1UEChMMbml0ZWNoLmFjLmpwMQ4wDAYDVQQLEwVhaWxhYjEPMA0G"
+ + "A1UEAxMGdGVzdGNhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0Y2FAbG9jYWxob3N0"
+ + "MIIBczCCARsGByqGSM49AgEwggEOAgEBMDMGByqGSM49AQECKEdYWnajFmnZ"
+ + "tzrukK2XWdle2v+GsD9l1ZiR6g7ozQDbhFH/bBiMDQcwVAQoJ5EQKrI54/CT"
+ + "xOQ2pMsd/fsXD+EX8YREd8bKHWiLz8lIVdD5cBNeVwQoMKSc6HfI7vKZp8Q2"
+ + "zWgIFOarx1GQoWJbMcSt188xsl30ncJuJT2OoARRBAqJ4fD+q6hbqgNSjTQ7"
+ + "htle1KO3eiaZgcJ8rrnyN8P+5A8+5K+H9aQ/NbBR4Gs7yto5PXIUZEUgodHA"
+ + "TZMSAcSq5ZYt4KbnSYaLY0TtH9CqAigEwZ+hglbT21B7ZTzYX2xj0x+qooJD"
+ + "hVTLtIPaYJK2HrMPxTw6/zfrAgEPA1IABAnvfFcFDgD/JicwBGn6vR3N8MIn"
+ + "mptZf/mnJ1y649uCF60zOgdwIyI7pVSxBFsJ7ohqXEHW0x7LrGVkdSEiipiH"
+ + "LYslqh3xrqbAgPbl93GUo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB"
+ + "/wQEAwIBxjAdBgNVHQ4EFgQUAEo62Xm9H6DcsE0zUDTza4BRG90wCwYHKoZI"
+ + "zj0EAQUAA1cAMFQCKAQsCHHSNOqfJXLgt3bg5+k49hIBGVr/bfG0B9JU3rNt"
+ + "Ycl9Y2zfRPUCKAK2ccOQXByAWfsasDu8zKHxkZv7LVDTFjAIffz3HaCQeVhD"
+ + "z+fauEg=");
+
+ byte[] keyUsage = Base64.decode(
+ "MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UE"
+ + "BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50"
+ + "cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBs"
+ + "aW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExp"
+ + "bWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0"
+ + "aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBa"
+ + "MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNV"
+ + "BAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3Jw"
+ + "LiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50"
+ + "cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50"
+ + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GL"
+ + "ADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSv"
+ + "x1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHV"
+ + "iTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173"
+ + "iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkw"
+ + "ggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50"
+ + "cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0Ff"
+ + "SW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UE"
+ + "CxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50"
+ + "cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYD"
+ + "VQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9D"
+ + "bGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkx"
+ + "MDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW"
+ + "/O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwG"
+ + "A1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI"
+ + "hvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQ"
+ + "OokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkU"
+ + "ODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapE"
+ + "PHayXOw=");
+
+ byte[] nameCert = Base64.decode(
+ "MIIEFjCCA3+gAwIBAgIEdS8BozANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJE"+
+ "RTERMA8GA1UEChQIREFURVYgZUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRQ0Eg"+
+ "REFURVYgRDAzIDE6UE4wIhgPMjAwMTA1MTAxMDIyNDhaGA8yMDA0MDUwOTEwMjI0"+
+ "OFowgYQxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIFAZCYXllcm4xEjAQBgNVBAcUCU7I"+
+ "dXJuYmVyZzERMA8GA1UEChQIREFURVYgZUcxHTAbBgNVBAUTFDAwMDAwMDAwMDA4"+
+ "OTU3NDM2MDAxMR4wHAYDVQQDFBVEaWV0bWFyIFNlbmdlbmxlaXRuZXIwgaEwDQYJ"+
+ "KoZIhvcNAQEBBQADgY8AMIGLAoGBAJLI/LJLKaHoMk8fBECW/od8u5erZi6jI8Ug"+
+ "C0a/LZyQUO/R20vWJs6GrClQtXB+AtfiBSnyZOSYzOdfDI8yEKPEv8qSuUPpOHps"+
+ "uNCFdLZF1vavVYGEEWs2+y+uuPmg8q1oPRyRmUZ+x9HrDvCXJraaDfTEd9olmB/Z"+
+ "AuC/PqpjAgUAwAAAAaOCAcYwggHCMAwGA1UdEwEB/wQCMAAwDwYDVR0PAQH/BAUD"+
+ "AwdAADAxBgNVHSAEKjAoMCYGBSskCAEBMB0wGwYIKwYBBQUHAgEWD3d3dy56cy5k"+
+ "YXRldi5kZTApBgNVHREEIjAggR5kaWV0bWFyLnNlbmdlbmxlaXRuZXJAZGF0ZXYu"+
+ "ZGUwgYQGA1UdIwR9MHuhc6RxMG8xCzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1"+
+ "bGllcnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0"+
+ "MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjVSLUNBIDE6UE6CBACm8LkwDgYHAoIG"+
+ "AQoMAAQDAQEAMEcGA1UdHwRAMD4wPKAUoBKGEHd3dy5jcmwuZGF0ZXYuZGWiJKQi"+
+ "MCAxCzAJBgNVBAYTAkRFMREwDwYDVQQKFAhEQVRFViBlRzAWBgUrJAgDBAQNMAsT"+
+ "A0VVUgIBBQIBATAdBgNVHQ4EFgQUfv6xFP0xk7027folhy+ziZvBJiwwLAYIKwYB"+
+ "BQUHAQEEIDAeMBwGCCsGAQUFBzABhhB3d3cuZGlyLmRhdGV2LmRlMA0GCSqGSIb3"+
+ "DQEBBQUAA4GBAEOVX6uQxbgtKzdgbTi6YLffMftFr2mmNwch7qzpM5gxcynzgVkg"+
+ "pnQcDNlm5AIbS6pO8jTCLfCd5TZ5biQksBErqmesIl3QD+VqtB+RNghxectZ3VEs"+
+ "nCUtcE7tJ8O14qwCb3TxS9dvIUFiVi4DjbxX46TdcTbTaK8/qr6AIf+l");
+
+ byte[] probSelfSignedCert = Base64.decode(
+ "MIICxTCCAi6gAwIBAgIQAQAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQUFADBF"
+ + "MScwJQYDVQQKEx4gRElSRUNUSU9OIEdFTkVSQUxFIERFUyBJTVBPVFMxGjAYBgNV"
+ + "BAMTESBBQyBNSU5FRkkgQiBURVNUMB4XDTA0MDUwNzEyMDAwMFoXDTE0MDUwNzEy"
+ + "MDAwMFowRTEnMCUGA1UEChMeIERJUkVDVElPTiBHRU5FUkFMRSBERVMgSU1QT1RT"
+ + "MRowGAYDVQQDExEgQUMgTUlORUZJIEIgVEVTVDCBnzANBgkqhkiG9w0BAQEFAAOB"
+ + "jQAwgYkCgYEAveoCUOAukZdcFCs2qJk76vSqEX0ZFzHqQ6faBPZWjwkgUNwZ6m6m"
+ + "qWvvyq1cuxhoDvpfC6NXILETawYc6MNwwxsOtVVIjuXlcF17NMejljJafbPximEt"
+ + "DQ4LcQeSp4K7FyFlIAMLyt3BQ77emGzU5fjFTvHSUNb3jblx0sV28c0CAwEAAaOB"
+ + "tTCBsjAfBgNVHSMEGDAWgBSEJ4bLbvEQY8cYMAFKPFD1/fFXlzAdBgNVHQ4EFgQU"
+ + "hCeGy27xEGPHGDABSjxQ9f3xV5cwDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIB"
+ + "AQQEAwIBBjA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vYWRvbmlzLnBrNy5jZXJ0"
+ + "cGx1cy5uZXQvZGdpLXRlc3QuY3JsMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN"
+ + "AQEFBQADgYEAmToHJWjd3+4zknfsP09H6uMbolHNGG0zTS2lrLKpzcmkQfjhQpT9"
+ + "LUTBvfs1jdjo9fGmQLvOG+Sm51Rbjglb8bcikVI5gLbclOlvqLkm77otjl4U4Z2/"
+ + "Y0vP14Aov3Sn3k+17EfReYUZI4liuB95ncobC4e8ZM++LjQcIM0s+Vs=");
+
+
+ byte[] gost34102001base = Base64.decode(
+ "MIIB1DCCAYECEEjpVKXP6Wn1yVz3VeeDQa8wCgYGKoUDAgIDBQAwbTEfMB0G"
+ + "A1UEAwwWR29zdFIzNDEwLTIwMDEgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRv"
+ + "UHJvMQswCQYDVQQGEwJSVTEpMCcGCSqGSIb3DQEJARYaR29zdFIzNDEwLTIw"
+ + "MDFAZXhhbXBsZS5jb20wHhcNMDUwMjAzMTUxNjQ2WhcNMTUwMjAzMTUxNjQ2"
+ + "WjBtMR8wHQYDVQQDDBZHb3N0UjM0MTAtMjAwMSBleGFtcGxlMRIwEAYDVQQK"
+ + "DAlDcnlwdG9Qcm8xCzAJBgNVBAYTAlJVMSkwJwYJKoZIhvcNAQkBFhpHb3N0"
+ + "UjM0MTAtMjAwMUBleGFtcGxlLmNvbTBjMBwGBiqFAwICEzASBgcqhQMCAiQA"
+ + "BgcqhQMCAh4BA0MABECElWh1YAIaQHUIzROMMYks/eUFA3pDXPRtKw/nTzJ+"
+ + "V4/rzBa5lYgD0Jp8ha4P5I3qprt+VsfLsN8PZrzK6hpgMAoGBiqFAwICAwUA"
+ + "A0EAHw5dw/aw/OiNvHyOE65kvyo4Hp0sfz3csM6UUkp10VO247ofNJK3tsLb"
+ + "HOLjUaqzefrlGb11WpHYrvWFg+FcLA==");
+
+ byte[] gost341094base = Base64.decode(
+ "MIICDzCCAbwCEBcxKsIb0ghYvAQeUjfQdFAwCgYGKoUDAgIEBQAwaTEdMBsG"
+ + "A1UEAwwUR29zdFIzNDEwLTk0IGV4YW1wbGUxEjAQBgNVBAoMCUNyeXB0b1By"
+ + "bzELMAkGA1UEBhMCUlUxJzAlBgkqhkiG9w0BCQEWGEdvc3RSMzQxMC05NEBl"
+ + "eGFtcGxlLmNvbTAeFw0wNTAyMDMxNTE2NTFaFw0xNTAyMDMxNTE2NTFaMGkx"
+ + "HTAbBgNVBAMMFEdvc3RSMzQxMC05NCBleGFtcGxlMRIwEAYDVQQKDAlDcnlw"
+ + "dG9Qcm8xCzAJBgNVBAYTAlJVMScwJQYJKoZIhvcNAQkBFhhHb3N0UjM0MTAt"
+ + "OTRAZXhhbXBsZS5jb20wgaUwHAYGKoUDAgIUMBIGByqFAwICIAIGByqFAwIC"
+ + "HgEDgYQABIGAu4Rm4XmeWzTYLIB/E6gZZnFX/oxUJSFHbzALJ3dGmMb7R1W+"
+ + "t7Lzk2w5tUI3JoTiDRCKJA4fDEJNKzsRK6i/ZjkyXJSLwaj+G2MS9gklh8x1"
+ + "G/TliYoJgmjTXHemD7aQEBON4z58nJHWrA0ILD54wbXCtrcaqCqLRYGTMjJ2"
+ + "+nswCgYGKoUDAgIEBQADQQBxKNhOmjgz/i5CEgLOyKyz9pFGkDcaymsWYQWV"
+ + "v7CZ0pTM8IzMzkUBW3GHsUjCFpanFZDfg2zuN+3kT+694n9B");
+
+ byte[] gost341094A = Base64.decode(
+ "MIICSDCCAfWgAwIBAgIBATAKBgYqhQMCAgQFADCBgTEXMBUGA1UEAxMOZGVmYXVsdDM0MTAtOTQx"
+ + "DTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1vbGExDDAKBgNVBAgT"
+ + "A01FTDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAzMjkx"
+ + "MzExNTdaFw0wNjAzMjkxMzExNTdaMIGBMRcwFQYDVQQDEw5kZWZhdWx0MzQxMC05NDENMAsGA1UE"
+ + "ChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLW9sYTEMMAoGA1UECBMDTUVMMQsw"
+ + "CQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MIGlMBwGBiqFAwICFDASBgcq"
+ + "hQMCAiACBgcqhQMCAh4BA4GEAASBgIQACDLEuxSdRDGgdZxHmy30g/DUYkRxO9Mi/uSHX5NjvZ31"
+ + "b7JMEMFqBtyhql1HC5xZfUwZ0aT3UnEFDfFjLP+Bf54gA+LPkQXw4SNNGOj+klnqgKlPvoqMGlwa"
+ + "+hLPKbS561WpvB2XSTgbV+pqqXR3j6j30STmybelEV3RdS2Now8wDTALBgNVHQ8EBAMCB4AwCgYG"
+ + "KoUDAgIEBQADQQBCFy7xWRXtNVXflKvDs0pBdBuPzjCMeZAXVxK8vUxsxxKu76d9CsvhgIFknFRi"
+ + "wWTPiZenvNoJ4R1uzeX+vREm");
+
+ byte[] gost341094B = Base64.decode(
+ "MIICSDCCAfWgAwIBAgIBATAKBgYqhQMCAgQFADCBgTEXMBUGA1UEAxMOcGFyYW0xLTM0MTAtOTQx"
+ + "DTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1PbGExDDAKBgNVBAgT"
+ + "A01lbDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAzMjkx"
+ + "MzEzNTZaFw0wNjAzMjkxMzEzNTZaMIGBMRcwFQYDVQQDEw5wYXJhbTEtMzQxMC05NDENMAsGA1UE"
+ + "ChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLU9sYTEMMAoGA1UECBMDTWVsMQsw"
+ + "CQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MIGlMBwGBiqFAwICFDASBgcq"
+ + "hQMCAiADBgcqhQMCAh4BA4GEAASBgEa+AAcZmijWs1M9x5Pn9efE8D9ztG1NMoIt0/hNZNqln3+j"
+ + "lMZjyqPt+kTLIjtmvz9BRDmIDk6FZz+4LhG2OTL7yGpWfrMxMRr56nxomTN9aLWRqbyWmn3brz9Y"
+ + "AUD3ifnwjjIuW7UM84JNlDTOdxx0XRUfLQIPMCXe9cO02Xskow8wDTALBgNVHQ8EBAMCB4AwCgYG"
+ + "KoUDAgIEBQADQQBzFcnuYc/639OTW+L5Ecjw9KxGr+dwex7lsS9S1BUgKa3m1d5c+cqI0B2XUFi5"
+ + "4iaHHJG0dCyjtQYLJr0OZjRw");
+
+ byte[] gost34102001A = Base64.decode(
+ "MIICCzCCAbigAwIBAgIBATAKBgYqhQMCAgMFADCBhDEaMBgGA1UEAxMRZGVmYXVsdC0zNDEwLTIw"
+ + "MDExDTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1PbGExDDAKBgNV"
+ + "BAgTA01lbDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAz"
+ + "MjkxMzE4MzFaFw0wNjAzMjkxMzE4MzFaMIGEMRowGAYDVQQDExFkZWZhdWx0LTM0MTAtMjAwMTEN"
+ + "MAsGA1UEChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLU9sYTEMMAoGA1UECBMD"
+ + "TWVsMQswCQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MGMwHAYGKoUDAgIT"
+ + "MBIGByqFAwICIwEGByqFAwICHgEDQwAEQG/4c+ZWb10IpeHfmR+vKcbpmSOClJioYmCVgnojw0Xn"
+ + "ned0KTg7TJreRUc+VX7vca4hLQaZ1o/TxVtfEApK/O6jDzANMAsGA1UdDwQEAwIHgDAKBgYqhQMC"
+ + "AgMFAANBAN8y2b6HuIdkD3aWujpfQbS1VIA/7hro4vLgDhjgVmev/PLzFB8oTh3gKhExpDo82IEs"
+ + "ZftGNsbbyp1NFg7zda0=");
+
+ byte[] gostCA1 = Base64.decode(
+ "MIIDNDCCAuGgAwIBAgIQZLcKDcWcQopF+jp4p9jylDAKBgYqhQMCAgQFADBm"
+ + "MQswCQYDVQQGEwJSVTEPMA0GA1UEBxMGTW9zY293MRcwFQYDVQQKEw5PT08g"
+ + "Q3J5cHRvLVBybzEUMBIGA1UECxMLRGV2ZWxvcG1lbnQxFzAVBgNVBAMTDkNQ"
+ + "IENTUCBUZXN0IENBMB4XDTAyMDYwOTE1NTIyM1oXDTA5MDYwOTE1NTkyOVow"
+ + "ZjELMAkGA1UEBhMCUlUxDzANBgNVBAcTBk1vc2NvdzEXMBUGA1UEChMOT09P"
+ + "IENyeXB0by1Qcm8xFDASBgNVBAsTC0RldmVsb3BtZW50MRcwFQYDVQQDEw5D"
+ + "UCBDU1AgVGVzdCBDQTCBpTAcBgYqhQMCAhQwEgYHKoUDAgIgAgYHKoUDAgIe"
+ + "AQOBhAAEgYAYglywKuz1nMc9UiBYOaulKy53jXnrqxZKbCCBSVaJ+aCKbsQm"
+ + "glhRFrw6Mwu8Cdeabo/ojmea7UDMZd0U2xhZFRti5EQ7OP6YpqD0alllo7za"
+ + "4dZNXdX+/ag6fOORSLFdMpVx5ganU0wHMPk67j+audnCPUj/plbeyccgcdcd"
+ + "WaOCASIwggEeMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud"
+ + "DgQWBBTe840gTo4zt2twHilw3PD9wJaX0TCBygYDVR0fBIHCMIG/MDygOqA4"
+ + "hjYtaHR0cDovL2ZpZXdhbGwvQ2VydEVucm9sbC9DUCUyMENTUCUyMFRlc3Ql"
+ + "MjBDQSgzKS5jcmwwRKBCoECGPmh0dHA6Ly93d3cuY3J5cHRvcHJvLnJ1L0Nl"
+ + "cnRFbnJvbGwvQ1AlMjBDU1AlMjBUZXN0JTIwQ0EoMykuY3JsMDmgN6A1hjMt"
+ + "ZmlsZTovL1xcZmlld2FsbFxDZXJ0RW5yb2xsXENQIENTUCBUZXN0IENBKDMp"
+ + "LmNybC8wEgYJKwYBBAGCNxUBBAUCAwMAAzAKBgYqhQMCAgQFAANBAIJi7ni7"
+ + "9rwMR5rRGTFftt2k70GbqyUEfkZYOzrgdOoKiB4IIsIstyBX0/ne6GsL9Xan"
+ + "G2IN96RB7KrowEHeW+k=");
+
+ byte[] gostCA2 = Base64.decode(
+ "MIIC2DCCAoWgAwIBAgIQe9ZCugm42pRKNcHD8466zTAKBgYqhQMCAgMFADB+"
+ + "MRowGAYJKoZIhvcNAQkBFgtzYmFAZGlndC5ydTELMAkGA1UEBhMCUlUxDDAK"
+ + "BgNVBAgTA01FTDEUMBIGA1UEBxMLWW9zaGthci1PbGExDTALBgNVBAoTBERp"
+ + "Z3QxDzANBgNVBAsTBkNyeXB0bzEPMA0GA1UEAxMGc2JhLUNBMB4XDTA0MDgw"
+ + "MzEzMzE1OVoXDTE0MDgwMzEzNDAxMVowfjEaMBgGCSqGSIb3DQEJARYLc2Jh"
+ + "QGRpZ3QucnUxCzAJBgNVBAYTAlJVMQwwCgYDVQQIEwNNRUwxFDASBgNVBAcT"
+ + "C1lvc2hrYXItT2xhMQ0wCwYDVQQKEwREaWd0MQ8wDQYDVQQLEwZDcnlwdG8x"
+ + "DzANBgNVBAMTBnNiYS1DQTBjMBwGBiqFAwICEzASBgcqhQMCAiMBBgcqhQMC"
+ + "Ah4BA0MABEDMSy10CuOH+i8QKG2UWA4XmCt6+BFrNTZQtS6bOalyDY8Lz+G7"
+ + "HybyipE3PqdTB4OIKAAPsEEeZOCZd2UXGQm5o4HaMIHXMBMGCSsGAQQBgjcU"
+ + "AgQGHgQAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud"
+ + "DgQWBBRJJl3LcNMxkZI818STfoi3ng1xoDBxBgNVHR8EajBoMDGgL6Athito"
+ + "dHRwOi8vc2JhLmRpZ3QubG9jYWwvQ2VydEVucm9sbC9zYmEtQ0EuY3JsMDOg"
+ + "MaAvhi1maWxlOi8vXFxzYmEuZGlndC5sb2NhbFxDZXJ0RW5yb2xsXHNiYS1D"
+ + "QS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwCgYGKoUDAgIDBQADQQA+BRJHbc/p"
+ + "q8EYl6iJqXCuR+ozRmH7hPAP3c4KqYSC38TClCgBloLapx/3/WdatctFJW/L"
+ + "mcTovpq088927shE");
+
+ byte[] inDirectCrl = Base64.decode(
+ "MIIdXjCCHMcCAQEwDQYJKoZIhvcNAQEFBQAwdDELMAkGA1UEBhMCREUxHDAaBgNV"
+ +"BAoUE0RldXRzY2hlIFRlbGVrb20gQUcxFzAVBgNVBAsUDlQtVGVsZVNlYyBUZXN0"
+ +"MS4wDAYHAoIGAQoHFBMBMTAeBgNVBAMUF1QtVGVsZVNlYyBUZXN0IERJUiA4OlBO"
+ +"Fw0wNjA4MDQwODQ1MTRaFw0wNjA4MDQxNDQ1MTRaMIIbfzB+AgQvrj/pFw0wMzA3"
+ +"MjIwNTQxMjhaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+ +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+ +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP+oXDTAzMDcyMjA1NDEyOFowZzBlBgNV"
+ +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+ +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+ +"UE4wfgIEL64/5xcNMDQwNDA1MTMxODE3WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+ +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC"
+ +"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/oFw0wNDA0"
+ +"MDUxMzE4MTdaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+ +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+ +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP+UXDTAzMDExMzExMTgxMVowZzBlBgNV"
+ +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+ +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+ +"UE4wfgIEL64/5hcNMDMwMTEzMTExODExWjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+ +"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");
+
+ byte[] directCRL = Base64.decode(
+ "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"
+ +"MQ==");
+
+ private final byte[] pkcs7CrlProblem = Base64.decode(
+ "MIIwSAYJKoZIhvcNAQcCoIIwOTCCMDUCAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+ + "SIb3DQEHAaCCEsAwggP4MIIC4KADAgECAgF1MA0GCSqGSIb3DQEBBQUAMEUx"
+ + "CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR4wHAYDVQQD"
+ + "ExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUwHhcNMDQxMjAyMjEyNTM5WhcNMDYx"
+ + "MjMwMjEyNTM5WjBMMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMR2VvVHJ1c3Qg"
+ + "SW5jMSYwJAYDVQQDEx1HZW9UcnVzdCBBZG9iZSBPQ1NQIFJlc3BvbmRlcjCB"
+ + "nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4gnNYhtw7U6QeVXZODnGhHMj"
+ + "+OgZ0DB393rEk6a2q9kq129IA2e03yKBTfJfQR9aWKc2Qj90dsSqPjvTDHFG"
+ + "Qsagm2FQuhnA3fb1UWhPzeEIdm6bxDsnQ8nWqKqxnWZzELZbdp3I9bBLizIq"
+ + "obZovzt60LNMghn/unvvuhpeVSsCAwEAAaOCAW4wggFqMA4GA1UdDwEB/wQE"
+ + "AwIE8DCB5QYDVR0gAQH/BIHaMIHXMIHUBgkqhkiG9y8BAgEwgcYwgZAGCCsG"
+ + "AQUFBwICMIGDGoGAVGhpcyBjZXJ0aWZpY2F0ZSBoYXMgYmVlbiBpc3N1ZWQg"
+ + "aW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBBY3JvYmF0IENyZWRlbnRpYWxzIENQ"
+ + "UyBsb2NhdGVkIGF0IGh0dHA6Ly93d3cuZ2VvdHJ1c3QuY29tL3Jlc291cmNl"
+ + "cy9jcHMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2VvdHJ1c3QuY29tL3Jl"
+ + "c291cmNlcy9jcHMwEwYDVR0lBAwwCgYIKwYBBQUHAwkwOgYDVR0fBDMwMTAv"
+ + "oC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9hZG9iZWNhMS5j"
+ + "cmwwHwYDVR0jBBgwFoAUq4BZw2WDbR19E70Zw+wajw1HaqMwDQYJKoZIhvcN"
+ + "AQEFBQADggEBAENJf1BD7PX5ivuaawt90q1OGzXpIQL/ClzEeFVmOIxqPc1E"
+ + "TFRq92YuxG5b6+R+k+tGkmCwPLcY8ipg6ZcbJ/AirQhohzjlFuT6YAXsTfEj"
+ + "CqEZfWM2sS7crK2EYxCMmKE3xDfPclYtrAoz7qZvxfQj0TuxHSstHZv39wu2"
+ + "ZiG1BWiEcyDQyTgqTOXBoZmfJtshuAcXmTpgkrYSrS37zNlPTGh+pMYQ0yWD"
+ + "c8OQRJR4OY5ZXfdna01mjtJTOmj6/6XPoLPYTq2gQrc2BCeNJ4bEhLb7sFVB"
+ + "PbwPrpzTE/HRbQHDrzj0YimDxeOUV/UXctgvYwHNtEkcBLsOm/uytMYwggSh"
+ + "MIIDiaADAgECAgQ+HL0oMA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNVBAYTAlVT"
+ + "MSMwIQYDVQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UE"
+ + "CxMUQWRvYmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3Qg"
+ + "Q0EwHhcNMDMwMTA4MjMzNzIzWhcNMjMwMTA5MDAwNzIzWjBpMQswCQYDVQQG"
+ + "EwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQxHTAb"
+ + "BgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYwFAYDVQQDEw1BZG9iZSBS"
+ + "b290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzE9UhPen"
+ + "ouczU38/nBKIayyZR2d+Dx65rRSI+cMQ2B3w8NWfaQovWTWwzGypTJwVoJ/O"
+ + "IL+gz1Ti4CBmRT85hjh+nMSOByLGJPYBErA131XqaZCw24U3HuJOB7JCoWoT"
+ + "aaBm6oCREVkqmwh5WiBELcm9cziLPC/gQxtdswvwrzUaKf7vppLdgUydPVmO"
+ + "rTE8QH6bkTYG/OJcjdGNJtVcRc+vZT+xqtJilvSoOOq6YEL09BxKNRXO+E4i"
+ + "Vg+VGMX4lp+f+7C3eCXpgGu91grwxnSUnfMPUNuad85LcIMjjaDKeCBEXDxU"
+ + "ZPHqojAZn+pMBk0GeEtekt8i0slns3rSAQIDAQABo4IBTzCCAUswEQYJYIZI"
+ + "AYb4QgEBBAQDAgAHMIGOBgNVHR8EgYYwgYMwgYCgfqB8pHoweDELMAkGA1UE"
+ + "BhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMgSW5jb3Jwb3JhdGVkMR0w"
+ + "GwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEWMBQGA1UEAxMNQWRvYmUg"
+ + "Um9vdCBDQTENMAsGA1UEAxMEQ1JMMTArBgNVHRAEJDAigA8yMDAzMDEwODIz"
+ + "MzcyM1qBDzIwMjMwMTA5MDAwNzIzWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgw"
+ + "FoAUgrc4SpOqmxDvgLvZVOLxD/uAnN4wHQYDVR0OBBYEFIK3OEqTqpsQ74C7"
+ + "2VTi8Q/7gJzeMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjYu"
+ + "MDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQAy2p9DdcH6b8lv26sdNjc+"
+ + "vGEZNrcCPB0jWZhsnu5NhedUyCAfp9S74r8Ad30ka3AvXME6dkm10+AjhCpx"
+ + "aiLzwScpmBX2NZDkBEzDjbyfYRzn/SSM0URDjBa6m02l1DUvvBHOvfdRN42f"
+ + "kOQU8Rg/vulZEjX5M5LznuDVa5pxm5lLyHHD4bFhCcTl+pHwQjo3fTT5cujN"
+ + "qmIcIenV9IIQ43sFti1oVgt+fpIsb01yggztVnSynbmrLSsdEF/bJ3Vwj/0d"
+ + "1+ICoHnlHOX/r2RAUS2em0fbQqV8H8KmSLDXvpJpTaT2KVfFeBEY3IdRyhOy"
+ + "Yp1PKzK9MaXB+lKrBYjIMIIEyzCCA7OgAwIBAgIEPhy9tTANBgkqhkiG9w0B"
+ + "AQUFADBpMQswCQYDVQQGEwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJ"
+ + "bmNvcnBvcmF0ZWQxHTAbBgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYw"
+ + "FAYDVQQDEw1BZG9iZSBSb290IENBMB4XDTA0MDExNzAwMDMzOVoXDTE1MDEx"
+ + "NTA4MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu"
+ + "Yy4xHjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTCCASIwDQYJKoZI"
+ + "hvcNAQEBBQADggEPADCCAQoCggEBAKfld+BkeFrnOYW8r9L1WygTDlTdSfrO"
+ + "YvWS/Z6Ye5/l+HrBbOHqQCXBcSeCpz7kB2WdKMh1FOE4e9JlmICsHerBLdWk"
+ + "emU+/PDb69zh8E0cLoDfxukF6oVPXj6WSThdSG7H9aXFzRr6S3XGCuvgl+Qw"
+ + "DTLiLYW+ONF6DXwt3TQQtKReJjOJZk46ZZ0BvMStKyBaeB6DKZsmiIo89qso"
+ + "13VDZINH2w1KvXg0ygDizoNtbvgAPFymwnsINS1klfQlcvn0x0RJm9bYQXK3"
+ + "5GNZAgL3M7Lqrld0jMfIUaWvuHCLyivytRuzq1dJ7E8rmidjDEk/G+27pf13"
+ + "fNZ7vR7M+IkCAwEAAaOCAZ0wggGZMBIGA1UdEwEB/wQIMAYBAf8CAQEwUAYD"
+ + "VR0gBEkwRzBFBgkqhkiG9y8BAgEwODA2BggrBgEFBQcCARYqaHR0cHM6Ly93"
+ + "d3cuYWRvYmUuY29tL21pc2MvcGtpL2Nkc19jcC5odG1sMBQGA1UdJQQNMAsG"
+ + "CSqGSIb3LwEBBTCBsgYDVR0fBIGqMIGnMCKgIKAehhxodHRwOi8vY3JsLmFk"
+ + "b2JlLmNvbS9jZHMuY3JsMIGAoH6gfKR6MHgxCzAJBgNVBAYTAlVTMSMwIQYD"
+ + "VQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRv"
+ + "YmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0ExDTAL"
+ + "BgNVBAMTBENSTDEwCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFIK3OEqTqpsQ"
+ + "74C72VTi8Q/7gJzeMB0GA1UdDgQWBBSrgFnDZYNtHX0TvRnD7BqPDUdqozAZ"
+ + "BgkqhkiG9n0HQQAEDDAKGwRWNi4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA"
+ + "PzlZLqIAjrFeEWEs0uC29YyJhkXOE9mf3YSaFGsITF+Gl1j0pajTjyH4R35Q"
+ + "r3floW2q3HfNzTeZ90Jnr1DhVERD6zEMgJpCtJqVuk0sixuXJHghS/KicKf4"
+ + "YXJJPx9epuIRF1siBRnznnF90svmOJMXApc0jGnYn3nQfk4kaShSnDaYaeYR"
+ + "DJKcsiWhl6S5zfwS7Gg8hDeyckhMQKKWnlG1CQrwlSFisKCduoodwRtWgft8"
+ + "kx13iyKK3sbalm6vnVc+5nufS4vI+TwMXoV63NqYaSroafBWk0nL53zGXPEy"
+ + "+A69QhzEViJKn2Wgqt5gt++jMMNImbRObIqgfgF1VjCCBUwwggQ0oAMCAQIC"
+ + "AgGDMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1H"
+ + "ZW9UcnVzdCBJbmMuMR4wHAYDVQQDExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUw"
+ + "HhcNMDYwMzI0MTU0MjI5WhcNMDkwNDA2MTQ0MjI5WjBzMQswCQYDVQQGEwJV"
+ + "UzELMAkGA1UECBMCTUExETAPBgNVBAoTCEdlb1RydXN0MR0wGwYDVQQDExRN"
+ + "YXJrZXRpbmcgRGVwYXJ0bWVudDElMCMGCSqGSIb3DQEJARYWbWFya2V0aW5n"
+ + "QGdlb3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB"
+ + "ANmvajTO4XJvAU2nVcLmXeCnAQX7RZt+7+ML3InmqQ3LCGo1weop09zV069/"
+ + "1x/Nmieol7laEzeXxd2ghjGzwfXafqQEqHn6+vBCvqdNPoSi63fSWhnuDVWp"
+ + "KVDOYgxOonrXl+Cc43lu4zRSq+Pi5phhrjDWcH74a3/rdljUt4c4GFezFXfa"
+ + "w2oTzWkxj2cTSn0Szhpr17+p66UNt8uknlhmu4q44Speqql2HwmCEnpLYJrK"
+ + "W3fOq5D4qdsvsLR2EABLhrBezamLI3iGV8cRHOUTsbTMhWhv/lKfHAyf4XjA"
+ + "z9orzvPN5jthhIfICOFq/nStTgakyL4Ln+nFAB/SMPkCAwEAAaOCAhYwggIS"
+ + "MA4GA1UdDwEB/wQEAwIF4DCB5QYDVR0gAQH/BIHaMIHXMIHUBgkqhkiG9y8B"
+ + "AgEwgcYwgZAGCCsGAQUFBwICMIGDGoGAVGhpcyBjZXJ0aWZpY2F0ZSBoYXMg"
+ + "YmVlbiBpc3N1ZWQgaW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBBY3JvYmF0IENy"
+ + "ZWRlbnRpYWxzIENQUyBsb2NhdGVkIGF0IGh0dHA6Ly93d3cuZ2VvdHJ1c3Qu"
+ + "Y29tL3Jlc291cmNlcy9jcHMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2Vv"
+ + "dHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwOgYDVR0fBDMwMTAvoC2gK4YpaHR0"
+ + "cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9hZG9iZWNhMS5jcmwwHwYDVR0j"
+ + "BBgwFoAUq4BZw2WDbR19E70Zw+wajw1HaqMwRAYIKwYBBQUHAQEEODA2MDQG"
+ + "CCsGAQUFBzABhihodHRwOi8vYWRvYmUtb2NzcC5nZW90cnVzdC5jb20vcmVz"
+ + "cG9uZGVyMBQGA1UdJQQNMAsGCSqGSIb3LwEBBTA8BgoqhkiG9y8BAQkBBC4w"
+ + "LAIBAYYnaHR0cDovL2Fkb2JlLXRpbWVzdGFtcC5nZW90cnVzdC5jb20vdHNh"
+ + "MBMGCiqGSIb3LwEBCQIEBTADAgEBMAwGA1UdEwQFMAMCAQAwDQYJKoZIhvcN"
+ + "AQEFBQADggEBAAOhy6QxOo+i3h877fvDvTa0plGD2bIqK7wMdNqbMDoSWied"
+ + "FIcgcBOIm2wLxOjZBAVj/3lDq59q2rnVeNnfXM0/N0MHI9TumHRjU7WNk9e4"
+ + "+JfJ4M+c3anrWOG3NE5cICDVgles+UHjXetHWql/LlP04+K2ZOLb6LE2xGnI"
+ + "YyLW9REzCYNAVF+/WkYdmyceHtaBZdbyVAJq0NAJPsfgY1pWcBo31Mr1fpX9"
+ + "WrXNTYDCqMyxMImJTmN3iI68tkXlNrhweQoArKFqBysiBkXzG/sGKYY6tWKU"
+ + "pzjLc3vIp/LrXC5zilROes8BSvwu1w9qQrJNcGwo7O4uijoNtyYil1Exgh1Q"
+ + "MIIdTAIBATBLMEUxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJ"
+ + "bmMuMR4wHAYDVQQDExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUCAgGDMAkGBSsO"
+ + "AwIaBQCgggxMMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwIwYJKoZIhvcN"
+ + "AQkEMRYEFP4R6qIdpQJzWyzrqO8X1ZfJOgChMIIMCQYJKoZIhvcvAQEIMYIL"
+ + "+jCCC/agggZ5MIIGdTCCA6gwggKQMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV"
+ + "BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR4wHAYDVQQDExVHZW9U"
+ + "cnVzdCBDQSBmb3IgQWRvYmUXDTA2MDQwNDE3NDAxMFoXDTA2MDQwNTE3NDAx"
+ + "MFowggIYMBMCAgC5Fw0wNTEwMTEyMDM2MzJaMBICAVsXDTA0MTEwNDE1MDk0"
+ + "MVowEwICALgXDTA1MTIxMjIyMzgzOFowEgIBWhcNMDQxMTA0MTUwOTMzWjAT"
+ + "AgIA5hcNMDUwODI3MDQwOTM4WjATAgIAtxcNMDYwMTE2MTc1NTEzWjATAgIA"
+ + "hhcNMDUxMjEyMjIzODU1WjATAgIAtRcNMDUwNzA2MTgzODQwWjATAgIA4BcN"
+ + "MDYwMzIwMDc0ODM0WjATAgIAgRcNMDUwODAyMjIzMTE1WjATAgIA3xcNMDUx"
+ + "MjEyMjIzNjUwWjASAgFKFw0wNDExMDQxNTA5MTZaMBICAUQXDTA0MTEwNDE1"
+ + "MDg1M1owEgIBQxcNMDQxMDAzMDEwMDQwWjASAgFsFw0wNDEyMDYxOTQ0MzFa"
+ + "MBMCAgEoFw0wNjAzMDkxMjA3MTJaMBMCAgEkFw0wNjAxMTYxNzU1MzRaMBIC"
+ + "AWcXDTA1MDMxODE3NTYxNFowEwICAVEXDTA2MDEzMTExMjcxMVowEgIBZBcN"
+ + "MDQxMTExMjI0ODQxWjATAgIA8RcNMDUwOTE2MTg0ODAxWjATAgIBThcNMDYw"
+ + "MjIxMjAxMDM2WjATAgIAwRcNMDUxMjEyMjIzODE2WjASAgFiFw0wNTAxMTAx"
+ + "NjE5MzRaMBICAWAXDTA1MDExMDE5MDAwNFowEwICAL4XDTA1MDUxNzE0NTYx"
+ + "MFowDQYJKoZIhvcNAQEFBQADggEBAEKhRMS3wVho1U3EvEQJZC8+JlUngmZQ"
+ + "A78KQbHPWNZWFlNvPuf/b0s7Lu16GfNHXh1QAW6Y5Hi1YtYZ3YOPyMd4Xugt"
+ + "gCdumbB6xtKsDyN5RvTht6ByXj+CYlYqsL7RX0izJZ6mJn4fjMkqzPKNOjb8"
+ + "kSn5T6rn93BjlATtCE8tPVOM8dnqGccRE0OV59+nDBXc90UMt5LdEbwaUOap"
+ + "snVB0oLcNm8d/HnlVH6RY5LnDjrT4vwfe/FApZtTecEWsllVUXDjSpwfcfD/"
+ + "476/lpGySB2otALqzImlA9R8Ok3hJ8dnF6hhQ5Oe6OJMnGYgdhkKbxsKkdib"
+ + "tTVl3qmH5QAwggLFMIIBrQIBATANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQG"
+ + "EwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQxHTAb"
+ + "BgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYwFAYDVQQDEw1BZG9iZSBS"
+ + "b290IENBFw0wNjAxMjcxODMzMzFaFw0wNzAxMjcwMDAwMDBaMIHeMCMCBD4c"
+ + "vUAXDTAzMDEyMTIzNDY1NlowDDAKBgNVHRUEAwoBBDAjAgQ+HL1BFw0wMzAx"
+ + "MjEyMzQ3MjJaMAwwCgYDVR0VBAMKAQQwIwIEPhy9YhcNMDMwMTIxMjM0NzQy"
+ + "WjAMMAoGA1UdFQQDCgEEMCMCBD4cvWEXDTA0MDExNzAxMDg0OFowDDAKBgNV"
+ + "HRUEAwoBBDAjAgQ+HL2qFw0wNDAxMTcwMTA5MDVaMAwwCgYDVR0VBAMKAQQw"
+ + "IwIEPhy9qBcNMDQwMTE3MDEzOTI5WjAMMAoGA1UdFQQDCgEEoC8wLTAKBgNV"
+ + "HRQEAwIBDzAfBgNVHSMEGDAWgBSCtzhKk6qbEO+Au9lU4vEP+4Cc3jANBgkq"
+ + "hkiG9w0BAQUFAAOCAQEAwtXF9042wG39icUlsotn5tpE3oCusLb/hBpEONhx"
+ + "OdfEQOq0w5hf/vqaxkcf71etA+KpbEUeSVaHMHRPhx/CmPrO9odE139dJdbt"
+ + "9iqbrC9iZokFK3h/es5kg73xujLKd7C/u5ngJ4mwBtvhMLjFjF2vJhPKHL4C"
+ + "IgMwdaUAhrcNzy16v+mw/VGJy3Fvc6oCESW1K9tvFW58qZSNXrMlsuidgunM"
+ + "hPKG+z0SXVyCqL7pnqKiaGddcgujYGOSY4S938oVcfZeZQEODtSYGlzldojX"
+ + "C1U1hCK5+tHAH0Ox/WqRBIol5VCZQwJftf44oG8oviYq52aaqSejXwmfT6zb"
+ + "76GCBXUwggVxMIIFbQoBAKCCBWYwggViBgkrBgEFBQcwAQEEggVTMIIFTzCB"
+ + "taIWBBS+8EpykfXdl4h3z7m/NZfdkAQQERgPMjAwNjA0MDQyMDIwMTVaMGUw"
+ + "YzA7MAkGBSsOAwIaBQAEFEb4BuZYkbjBjOjT6VeA/00fBvQaBBT3fTSQniOp"
+ + "BbHBSkz4xridlX0bsAICAYOAABgPMjAwNjA0MDQyMDIwMTVaoBEYDzIwMDYw"
+ + "NDA1MDgyMDE1WqEjMCEwHwYJKwYBBQUHMAECBBIEEFqooq/R2WltD7TposkT"
+ + "BhMwDQYJKoZIhvcNAQEFBQADgYEAMig6lty4b0JDsT/oanfQG5x6jVKPACpp"
+ + "1UA9SJ0apJJa7LeIdDFmu5C2S/CYiKZm4A4P9cAu0YzgLHxE4r6Op+HfVlAG"
+ + "6bzUe1P/hi1KCJ8r8wxOZAktQFPSzs85RAZwkHMfB0lP2e/h666Oye+Zf8VH"
+ + "RaE+/xZ7aswE89HXoumgggQAMIID/DCCA/gwggLgoAMCAQICAXUwDQYJKoZI"
+ + "hvcNAQEFBQAwRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu"
+ + "Yy4xHjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTAeFw0wNDEyMDIy"
+ + "MTI1MzlaFw0wNjEyMzAyMTI1MzlaMEwxCzAJBgNVBAYTAlVTMRUwEwYDVQQK"
+ + "EwxHZW9UcnVzdCBJbmMxJjAkBgNVBAMTHUdlb1RydXN0IEFkb2JlIE9DU1Ag"
+ + "UmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDiCc1iG3Dt"
+ + "TpB5Vdk4OcaEcyP46BnQMHf3esSTprar2SrXb0gDZ7TfIoFN8l9BH1pYpzZC"
+ + "P3R2xKo+O9MMcUZCxqCbYVC6GcDd9vVRaE/N4Qh2bpvEOydDydaoqrGdZnMQ"
+ + "tlt2ncj1sEuLMiqhtmi/O3rQs0yCGf+6e++6Gl5VKwIDAQABo4IBbjCCAWow"
+ + "DgYDVR0PAQH/BAQDAgTwMIHlBgNVHSABAf8EgdowgdcwgdQGCSqGSIb3LwEC"
+ + "ATCBxjCBkAYIKwYBBQUHAgIwgYMagYBUaGlzIGNlcnRpZmljYXRlIGhhcyBi"
+ + "ZWVuIGlzc3VlZCBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIEFjcm9iYXQgQ3Jl"
+ + "ZGVudGlhbHMgQ1BTIGxvY2F0ZWQgYXQgaHR0cDovL3d3dy5nZW90cnVzdC5j"
+ + "b20vcmVzb3VyY2VzL2NwczAxBggrBgEFBQcCARYlaHR0cDovL3d3dy5nZW90"
+ + "cnVzdC5jb20vcmVzb3VyY2VzL2NwczATBgNVHSUEDDAKBggrBgEFBQcDCTA6"
+ + "BgNVHR8EMzAxMC+gLaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxz"
+ + "L2Fkb2JlY2ExLmNybDAfBgNVHSMEGDAWgBSrgFnDZYNtHX0TvRnD7BqPDUdq"
+ + "ozANBgkqhkiG9w0BAQUFAAOCAQEAQ0l/UEPs9fmK+5prC33SrU4bNekhAv8K"
+ + "XMR4VWY4jGo9zURMVGr3Zi7Eblvr5H6T60aSYLA8txjyKmDplxsn8CKtCGiH"
+ + "OOUW5PpgBexN8SMKoRl9YzaxLtysrYRjEIyYoTfEN89yVi2sCjPupm/F9CPR"
+ + "O7EdKy0dm/f3C7ZmIbUFaIRzINDJOCpM5cGhmZ8m2yG4BxeZOmCSthKtLfvM"
+ + "2U9MaH6kxhDTJYNzw5BElHg5jlld92drTWaO0lM6aPr/pc+gs9hOraBCtzYE"
+ + "J40nhsSEtvuwVUE9vA+unNMT8dFtAcOvOPRiKYPF45RX9Rdy2C9jAc20SRwE"
+ + "uw6b+7K0xjANBgkqhkiG9w0BAQEFAASCAQC7a4yICFGCEMPlJbydK5qLG3rV"
+ + "sip7Ojjz9TB4nLhC2DgsIHds8jjdq2zguInluH2nLaBCVS+qxDVlTjgbI2cB"
+ + "TaWS8nglC7nNjzkKAsa8vThA8FZUVXTW0pb74jNJJU2AA27bb4g+4WgunCrj"
+ + "fpYp+QjDyMmdrJVqRmt5eQN+dpVxMS9oq+NrhOSEhyIb4/rejgNg9wnVK1ms"
+ + "l5PxQ4x7kpm7+Ua41//owkJVWykRo4T1jo4eHEz1DolPykAaKie2VKH/sMqR"
+ + "Spjh4E5biKJLOV9fKivZWKAXByXfwUbbMsJvz4v/2yVHFy9xP+tqB5ZbRoDK"
+ + "k8PzUyCprozn+/22oYIPijCCD4YGCyqGSIb3DQEJEAIOMYIPdTCCD3EGCSqG"
+ + "SIb3DQEHAqCCD2Iwgg9eAgEDMQswCQYFKw4DAhoFADCB+gYLKoZIhvcNAQkQ"
+ + "AQSggeoEgecwgeQCAQEGAikCMCEwCQYFKw4DAhoFAAQUoT97qeCv3FXYaEcS"
+ + "gY8patCaCA8CAiMHGA8yMDA2MDQwNDIwMjA1N1owAwIBPAEB/wIIO0yRre3L"
+ + "8/6ggZCkgY0wgYoxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNl"
+ + "dHRzMRAwDgYDVQQHEwdOZWVkaGFtMRUwEwYDVQQKEwxHZW9UcnVzdCBJbmMx"
+ + "EzARBgNVBAsTClByb2R1Y3Rpb24xJTAjBgNVBAMTHGFkb2JlLXRpbWVzdGFt"
+ + "cC5nZW90cnVzdC5jb22gggzJMIIDUTCCAjmgAwIBAgICAI8wDQYJKoZIhvcN"
+ + "AQEFBQAwRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4x"
+ + "HjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTAeFw0wNTAxMTAwMTI5"
+ + "MTBaFw0xNTAxMTUwODAwMDBaMIGKMQswCQYDVQQGEwJVUzEWMBQGA1UECBMN"
+ + "TWFzc2FjaHVzZXR0czEQMA4GA1UEBxMHTmVlZGhhbTEVMBMGA1UEChMMR2Vv"
+ + "VHJ1c3QgSW5jMRMwEQYDVQQLEwpQcm9kdWN0aW9uMSUwIwYDVQQDExxhZG9i"
+ + "ZS10aW1lc3RhbXAuZ2VvdHJ1c3QuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GN"
+ + "ADCBiQKBgQDRbxJotLFPWQuuEDhKtOMaBUJepGxIvWxeahMbq1DVmqnk88+j"
+ + "w/5lfPICPzQZ1oHrcTLSAFM7Mrz3pyyQKQKMqUyiemzuG/77ESUNfBNSUfAF"
+ + "PdtHuDMU8Is8ABVnFk63L+wdlvvDIlKkE08+VTKCRdjmuBVltMpQ6QcLFQzm"
+ + "AQIDAQABo4GIMIGFMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly9jcmwuZ2Vv"
+ + "dHJ1c3QuY29tL2NybHMvYWRvYmVjYTEuY3JsMB8GA1UdIwQYMBaAFKuAWcNl"
+ + "g20dfRO9GcPsGo8NR2qjMA4GA1UdDwEB/wQEAwIGwDAWBgNVHSUBAf8EDDAK"
+ + "BggrBgEFBQcDCDANBgkqhkiG9w0BAQUFAAOCAQEAmnyXjdtX+F79Nf0KggTd"
+ + "6YC2MQD9s09IeXTd8TP3rBmizfM+7f3icggeCGakNfPRmIUMLoa0VM5Kt37T"
+ + "2X0TqzBWusfbKx7HnX4v1t/G8NJJlT4SShSHv+8bjjU4lUoCmW2oEcC5vXwP"
+ + "R5JfjCyois16npgcO05ZBT+LLDXyeBijE6qWmwLDfEpLyILzVRmyU4IE7jvm"
+ + "rgb3GXwDUvd3yQXGRRHbPCh3nj9hBGbuzyt7GnlqnEie3wzIyMG2ET/wvTX5"
+ + "4BFXKNe7lDLvZj/MXvd3V7gMTSVW0kAszKao56LfrVTgp1VX3UBQYwmQqaoA"
+ + "UwFezih+jEvjW6cYJo/ErDCCBKEwggOJoAMCAQICBD4cvSgwDQYJKoZIhvcN"
+ + "AQEFBQAwaTELMAkGA1UEBhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMg"
+ + "SW5jb3Jwb3JhdGVkMR0wGwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEW"
+ + "MBQGA1UEAxMNQWRvYmUgUm9vdCBDQTAeFw0wMzAxMDgyMzM3MjNaFw0yMzAx"
+ + "MDkwMDA3MjNaMGkxCzAJBgNVBAYTAlVTMSMwIQYDVQQKExpBZG9iZSBTeXN0"
+ + "ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRvYmUgVHJ1c3QgU2Vydmlj"
+ + "ZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUA"
+ + "A4IBDwAwggEKAoIBAQDMT1SE96ei5zNTfz+cEohrLJlHZ34PHrmtFIj5wxDY"
+ + "HfDw1Z9pCi9ZNbDMbKlMnBWgn84gv6DPVOLgIGZFPzmGOH6cxI4HIsYk9gES"
+ + "sDXfVeppkLDbhTce4k4HskKhahNpoGbqgJERWSqbCHlaIEQtyb1zOIs8L+BD"
+ + "G12zC/CvNRop/u+mkt2BTJ09WY6tMTxAfpuRNgb84lyN0Y0m1VxFz69lP7Gq"
+ + "0mKW9Kg46rpgQvT0HEo1Fc74TiJWD5UYxfiWn5/7sLd4JemAa73WCvDGdJSd"
+ + "8w9Q25p3zktwgyONoMp4IERcPFRk8eqiMBmf6kwGTQZ4S16S3yLSyWezetIB"
+ + "AgMBAAGjggFPMIIBSzARBglghkgBhvhCAQEEBAMCAAcwgY4GA1UdHwSBhjCB"
+ + "gzCBgKB+oHykejB4MQswCQYDVQQGEwJVUzEjMCEGA1UEChMaQWRvYmUgU3lz"
+ + "dGVtcyBJbmNvcnBvcmF0ZWQxHTAbBgNVBAsTFEFkb2JlIFRydXN0IFNlcnZp"
+ + "Y2VzMRYwFAYDVQQDEw1BZG9iZSBSb290IENBMQ0wCwYDVQQDEwRDUkwxMCsG"
+ + "A1UdEAQkMCKADzIwMDMwMTA4MjMzNzIzWoEPMjAyMzAxMDkwMDA3MjNaMAsG"
+ + "A1UdDwQEAwIBBjAfBgNVHSMEGDAWgBSCtzhKk6qbEO+Au9lU4vEP+4Cc3jAd"
+ + "BgNVHQ4EFgQUgrc4SpOqmxDvgLvZVOLxD/uAnN4wDAYDVR0TBAUwAwEB/zAd"
+ + "BgkqhkiG9n0HQQAEEDAOGwhWNi4wOjQuMAMCBJAwDQYJKoZIhvcNAQEFBQAD"
+ + "ggEBADLan0N1wfpvyW/bqx02Nz68YRk2twI8HSNZmGye7k2F51TIIB+n1Lvi"
+ + "vwB3fSRrcC9cwTp2SbXT4COEKnFqIvPBJymYFfY1kOQETMONvJ9hHOf9JIzR"
+ + "REOMFrqbTaXUNS+8Ec6991E3jZ+Q5BTxGD++6VkSNfkzkvOe4NVrmnGbmUvI"
+ + "ccPhsWEJxOX6kfBCOjd9NPly6M2qYhwh6dX0ghDjewW2LWhWC35+kixvTXKC"
+ + "DO1WdLKduastKx0QX9sndXCP/R3X4gKgeeUc5f+vZEBRLZ6bR9tCpXwfwqZI"
+ + "sNe+kmlNpPYpV8V4ERjch1HKE7JinU8rMr0xpcH6UqsFiMgwggTLMIIDs6AD"
+ + "AgECAgQ+HL21MA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNVBAYTAlVTMSMwIQYD"
+ + "VQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRv"
+ + "YmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0EwHhcN"
+ + "MDQwMTE3MDAwMzM5WhcNMTUwMTE1MDgwMDAwWjBFMQswCQYDVQQGEwJVUzEW"
+ + "MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgQ0Eg"
+ + "Zm9yIEFkb2JlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+V3"
+ + "4GR4Wuc5hbyv0vVbKBMOVN1J+s5i9ZL9nph7n+X4esFs4epAJcFxJ4KnPuQH"
+ + "ZZ0oyHUU4Th70mWYgKwd6sEt1aR6ZT788Nvr3OHwTRwugN/G6QXqhU9ePpZJ"
+ + "OF1Ibsf1pcXNGvpLdcYK6+CX5DANMuIthb440XoNfC3dNBC0pF4mM4lmTjpl"
+ + "nQG8xK0rIFp4HoMpmyaIijz2qyjXdUNkg0fbDUq9eDTKAOLOg21u+AA8XKbC"
+ + "ewg1LWSV9CVy+fTHREmb1thBcrfkY1kCAvczsuquV3SMx8hRpa+4cIvKK/K1"
+ + "G7OrV0nsTyuaJ2MMST8b7bul/Xd81nu9Hsz4iQIDAQABo4IBnTCCAZkwEgYD"
+ + "VR0TAQH/BAgwBgEB/wIBATBQBgNVHSAESTBHMEUGCSqGSIb3LwECATA4MDYG"
+ + "CCsGAQUFBwIBFipodHRwczovL3d3dy5hZG9iZS5jb20vbWlzYy9wa2kvY2Rz"
+ + "X2NwLmh0bWwwFAYDVR0lBA0wCwYJKoZIhvcvAQEFMIGyBgNVHR8Egaowgacw"
+ + "IqAgoB6GHGh0dHA6Ly9jcmwuYWRvYmUuY29tL2Nkcy5jcmwwgYCgfqB8pHow"
+ + "eDELMAkGA1UEBhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMgSW5jb3Jw"
+ + "b3JhdGVkMR0wGwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEWMBQGA1UE"
+ + "AxMNQWRvYmUgUm9vdCBDQTENMAsGA1UEAxMEQ1JMMTALBgNVHQ8EBAMCAQYw"
+ + "HwYDVR0jBBgwFoAUgrc4SpOqmxDvgLvZVOLxD/uAnN4wHQYDVR0OBBYEFKuA"
+ + "WcNlg20dfRO9GcPsGo8NR2qjMBkGCSqGSIb2fQdBAAQMMAobBFY2LjADAgSQ"
+ + "MA0GCSqGSIb3DQEBBQUAA4IBAQA/OVkuogCOsV4RYSzS4Lb1jImGRc4T2Z/d"
+ + "hJoUawhMX4aXWPSlqNOPIfhHflCvd+Whbarcd83NN5n3QmevUOFUREPrMQyA"
+ + "mkK0mpW6TSyLG5ckeCFL8qJwp/hhckk/H16m4hEXWyIFGfOecX3Sy+Y4kxcC"
+ + "lzSMadifedB+TiRpKFKcNphp5hEMkpyyJaGXpLnN/BLsaDyEN7JySExAopae"
+ + "UbUJCvCVIWKwoJ26ih3BG1aB+3yTHXeLIorextqWbq+dVz7me59Li8j5PAxe"
+ + "hXrc2phpKuhp8FaTScvnfMZc8TL4Dr1CHMRWIkqfZaCq3mC376Mww0iZtE5s"
+ + "iqB+AXVWMYIBgDCCAXwCAQEwSzBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN"
+ + "R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgQ0EgZm9yIEFkb2Jl"
+ + "AgIAjzAJBgUrDgMCGgUAoIGMMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRAB"
+ + "BDAcBgkqhkiG9w0BCQUxDxcNMDYwNDA0MjAyMDU3WjAjBgkqhkiG9w0BCQQx"
+ + "FgQUp7AnXBqoNcarvO7fMJut1og2U5AwKwYLKoZIhvcNAQkQAgwxHDAaMBgw"
+ + "FgQU1dH4eZTNhgxdiSABrat6zsPdth0wDQYJKoZIhvcNAQEBBQAEgYCinr/F"
+ + "rMiQz/MRm9ZD5YGcC0Qo2dRTPd0Aop8mZ4g1xAhKFLnp7lLsjCbkSDpVLDBh"
+ + "cnCk7CV+3FT5hlvt8OqZlR0CnkSnCswLFhrppiWle6cpxlwGqyAteC8uKtQu"
+ + "wjE5GtBKLcCOAzQYyyuNZZeB6oCZ+3mPhZ62FxrvvEGJCgAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==");
+
+ private final byte[] emptyDNCert = Base64.decode(
+ "MIICfTCCAeagAwIBAgIBajANBgkqhkiG9w0BAQQFADB8MQswCQYDVQQGEwJVUzEMMAoGA1UEChMD"
+ + "Q0RXMQkwBwYDVQQLEwAxCTAHBgNVBAcTADEJMAcGA1UECBMAMRowGAYDVQQDExFUZW1wbGFyIFRl"
+ + "c3QgMTAyNDEiMCAGCSqGSIb3DQEJARYTdGVtcGxhcnRlc3RAY2R3LmNvbTAeFw0wNjA1MjIwNTAw"
+ + "MDBaFw0xMDA1MjIwNTAwMDBaMHwxCzAJBgNVBAYTAlVTMQwwCgYDVQQKEwNDRFcxCTAHBgNVBAsT"
+ + "ADEJMAcGA1UEBxMAMQkwBwYDVQQIEwAxGjAYBgNVBAMTEVRlbXBsYXIgVGVzdCAxMDI0MSIwIAYJ"
+ + "KoZIhvcNAQkBFhN0ZW1wbGFydGVzdEBjZHcuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB"
+ + "gQDH3aJpJBfM+A3d84j5YcU6zEQaQ76u5xO9NSBmHjZykKS2kCcUqPpvVOPDA5WgV22dtKPh+lYV"
+ + "iUp7wyCVwAKibq8HIbihHceFqMKzjwC639rMoDJ7bi/yzQWz1Zg+075a4FGPlUKn7Yfu89wKkjdW"
+ + "wDpRPXc/agqBnrx5pJTXzQIDAQABow8wDTALBgNVHQ8EBAMCALEwDQYJKoZIhvcNAQEEBQADgYEA"
+ + "RRsRsjse3i2/KClFVd6YLZ+7K1BE0WxFyY2bbytkwQJSxvv3vLSuweFUbhNxutb68wl/yW4GLy4b"
+ + "1QdyswNxrNDXTuu5ILKhRDDuWeocz83aG2KGtr3JlFyr3biWGEyn5WUOE6tbONoQDJ0oPYgI6CAc"
+ + "EHdUp0lioOCt6UOw7Cs=");
+
+ private final byte[] gostRFC4491_94 = Base64.decode(
+ "MIICCzCCAboCECMO42BGlSTOxwvklBgufuswCAYGKoUDAgIEMGkxHTAbBgNVBAMM" +
+ "FEdvc3RSMzQxMC05NCBleGFtcGxlMRIwEAYDVQQKDAlDcnlwdG9Qcm8xCzAJBgNV" +
+ "BAYTAlJVMScwJQYJKoZIhvcNAQkBFhhHb3N0UjM0MTAtOTRAZXhhbXBsZS5jb20w" +
+ "HhcNMDUwODE2MTIzMjUwWhcNMTUwODE2MTIzMjUwWjBpMR0wGwYDVQQDDBRHb3N0" +
+ "UjM0MTAtOTQgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRvUHJvMQswCQYDVQQGEwJS" +
+ "VTEnMCUGCSqGSIb3DQEJARYYR29zdFIzNDEwLTk0QGV4YW1wbGUuY29tMIGlMBwG" +
+ "BiqFAwICFDASBgcqhQMCAiACBgcqhQMCAh4BA4GEAASBgLuEZuF5nls02CyAfxOo" +
+ "GWZxV/6MVCUhR28wCyd3RpjG+0dVvrey85NsObVCNyaE4g0QiiQOHwxCTSs7ESuo" +
+ "v2Y5MlyUi8Go/htjEvYJJYfMdRv05YmKCYJo01x3pg+2kBATjeM+fJyR1qwNCCw+" +
+ "eMG1wra3Gqgqi0WBkzIydvp7MAgGBiqFAwICBANBABHHCH4S3ALxAiMpR3aPRyqB" +
+ "g1DjB8zy5DEjiULIc+HeIveF81W9lOxGkZxnrFjXBSqnjLeFKgF1hffXOAP7zUM=");
+
+ private final byte[] gostRFC4491_2001 = Base64.decode(
+ "MIIB0DCCAX8CECv1xh7CEb0Xx9zUYma0LiEwCAYGKoUDAgIDMG0xHzAdBgNVBAMM" +
+ "Fkdvc3RSMzQxMC0yMDAxIGV4YW1wbGUxEjAQBgNVBAoMCUNyeXB0b1BybzELMAkG" +
+ "A1UEBhMCUlUxKTAnBgkqhkiG9w0BCQEWGkdvc3RSMzQxMC0yMDAxQGV4YW1wbGUu" +
+ "Y29tMB4XDTA1MDgxNjE0MTgyMFoXDTE1MDgxNjE0MTgyMFowbTEfMB0GA1UEAwwW" +
+ "R29zdFIzNDEwLTIwMDEgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRvUHJvMQswCQYD" +
+ "VQQGEwJSVTEpMCcGCSqGSIb3DQEJARYaR29zdFIzNDEwLTIwMDFAZXhhbXBsZS5j" +
+ "b20wYzAcBgYqhQMCAhMwEgYHKoUDAgIkAAYHKoUDAgIeAQNDAARAhJVodWACGkB1" +
+ "CM0TjDGJLP3lBQN6Q1z0bSsP508yfleP68wWuZWIA9CafIWuD+SN6qa7flbHy7Df" +
+ "D2a8yuoaYDAIBgYqhQMCAgMDQQA8L8kJRLcnqeyn1en7U23Sw6pkfEQu3u0xFkVP" +
+ "vFQ/3cHeF26NG+xxtZPz3TaTVXdoiYkXYiD02rEx1bUcM97i");
+
+ private PublicKey dudPublicKey = new PublicKey()
+ {
+ public String getAlgorithm()
+ {
+ return null;
+ }
+
+ public String getFormat()
+ {
+ return null;
+ }
+
+ public byte[] getEncoded()
+ {
+ return null;
+ }
+
+ };
+
+ public String getName()
+ {
+ return "CertTest";
+ }
+
+ public void checkCertificate(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+
+ Certificate cert = fact.generateCertificate(bIn);
+
+ PublicKey k = cert.getPublicKey();
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+ public void checkNameCertificate(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+
+ X509Certificate cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ PublicKey k = cert.getPublicKey();
+ if (!cert.getIssuerDN().toString().equals("C=DE,O=DATEV eG,0.2.262.1.10.7.20=1+CN=CA DATEV D03 1:PN"))
+ {
+ fail(id + " failed - name test.");
+ }
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+ public void checkKeyUsage(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+
+ X509Certificate cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ PublicKey k = cert.getPublicKey();
+
+ if (cert.getKeyUsage()[7])
+ {
+ fail("error generating cert - key usage wrong.");
+ }
+
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+
+ public void checkSelfSignedCertificate(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+
+ Certificate cert = fact.generateCertificate(bIn);
+
+ PublicKey k = cert.getPublicKey();
+
+ cert.verify(k);
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+
+ /**
+ * Test a generated certificate with the sun provider
+ */
+ private void sunProviderCheck(byte[] encoding)
+ throws CertificateException
+ {
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509");
+
+ certFact.generateCertificate(new ByteArrayInputStream(encoding));
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - RSA
+ */
+ public void checkCreation1()
+ throws Exception
+ {
+ //
+ // a sample key pair.
+ //
+ 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));
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory fact = KeyFactory.getInstance("RSA", "SC");
+
+ privKey = fact.generatePrivate(privKeySpec);
+ pubKey = fact.generatePublic(pubKeySpec);
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
+
+ builder.addRDN(BCStyle.C, "AU");
+ builder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ builder.addRDN(BCStyle.L, "Melbourne");
+ builder.addRDN(BCStyle.ST, "Victoria");
+ builder.addRDN(BCStyle.E, "feedback-crypto@bouncycastle.org");
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3 - without extensions
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider(BC).build(privKey);
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000),builder.build(), pubKey);
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ cert.verify(cert.getPublicKey());
+
+ Set dummySet = cert.getNonCriticalExtensionOIDs();
+ if (dummySet != null)
+ {
+ fail("non-critical oid set should be null");
+ }
+ dummySet = cert.getCriticalExtensionOIDs();
+ if (dummySet != null)
+ {
+ fail("critical oid set should be null");
+ }
+
+ //
+ // create the certificate - version 3 - with extensions
+ //
+ sigGen = new JcaContentSignerBuilder("MD5WithRSAEncryption").setProvider(BC).build(privKey);
+ certGen = new JcaX509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1)
+ , new Date(System.currentTimeMillis() - 50000)
+ , new Date(System.currentTimeMillis() + 50000)
+ , builder.build()
+ , pubKey)
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true,
+ new X509KeyUsage(X509KeyUsage.encipherOnly))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.37"), true,
+ new DERSequence(KeyPurposeId.anyExtendedKeyUsage))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true,
+ new GeneralNames(new GeneralName[]
+ {
+ new GeneralName(GeneralName.rfc822Name, "test@test.test"),
+ new GeneralName(GeneralName.dNSName, "dom.test.test")
+ }));
+
+ X509CertificateHolder certHolder = certGen.build(sigGen);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certHolder);
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+ cert.verify(cert.getPublicKey());
+
+ ContentVerifierProvider contentVerifierProvider = new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey);
+ if (!certHolder.isSignatureValid(contentVerifierProvider))
+ {
+ fail("signature test failed");
+ }
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", "SC");
+
+ cert = (X509Certificate)certFact.generateCertificate(bIn);
+
+ if (!cert.getKeyUsage()[7])
+ {
+ fail("error generating cert - key usage wrong.");
+ }
+
+ List l = cert.getExtendedKeyUsage();
+ if (!l.get(0).equals(KeyPurposeId.anyExtendedKeyUsage.getId()))
+ {
+ fail("failed extended key usage test");
+ }
+
+ Collection c = cert.getSubjectAlternativeNames();
+ Iterator it = c.iterator();
+ while (it.hasNext())
+ {
+ List gn = (List)it.next();
+ if (!gn.get(1).equals("test@test.test") && !gn.get(1).equals("dom.test.test"))
+ {
+ fail("failed subject alternative names test");
+ }
+ }
+
+ sunProviderCheck(certHolder.getEncoded());
+ sunProviderCheck(cert.getEncoded());
+
+ // System.out.println(cert);
+
+ //
+ // create the certificate - version 1
+ //
+ sigGen = new JcaContentSignerBuilder("MD5WithRSAEncryption").setProvider(BC).build(privKey);
+ X509v1CertificateBuilder certGen1 = new JcaX509v1CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen1.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+ cert.verify(cert.getPublicKey());
+
+ bIn = new ByteArrayInputStream(cert.getEncoded());
+ certFact = CertificateFactory.getInstance("X.509", "SC");
+
+ cert = (X509Certificate)certFact.generateCertificate(bIn);
+
+ // System.out.println(cert);
+ if (!cert.getIssuerDN().equals(cert.getSubjectDN()))
+ {
+ fail("name comparison fails");
+ }
+
+ sunProviderCheck(certHolder.getEncoded());
+ sunProviderCheck(cert.getEncoded());
+//
+ // a lightweight key pair.
+ //
+ RSAKeyParameters lwPubKey = new RSAKeyParameters(
+ false,
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ RSAPrivateCrtKeyParameters lwPrivKey = new RSAPrivateCrtKeyParameters(
+ 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));
+
+ //
+ // distinguished name table.
+ //
+ builder = new X500NameBuilder(BCStyle.INSTANCE);
+
+ builder.addRDN(BCStyle.C, "AU");
+ builder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ builder.addRDN(BCStyle.L, "Melbourne");
+ builder.addRDN(BCStyle.ST, "Victoria");
+ builder.addRDN(BCStyle.E, "feedback-crypto@bouncycastle.org");
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3 - without extensions
+ //
+ AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSAEncryption");
+ AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
+
+ sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(lwPrivKey);
+ SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPublicKey(lwPubKey.getModulus(), lwPubKey.getExponent()));
+ certGen = new X509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000), builder.build(), pubInfo);
+
+ certHolder = certGen.build(sigGen);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certHolder);
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ contentVerifierProvider = new BcRSAContentVerifierProviderBuilder(new DefaultDigestAlgorithmIdentifierFinder()).build(lwPubKey);
+
+ if (!certHolder.isSignatureValid(contentVerifierProvider))
+ {
+ fail("lw sig verification failed");
+ }
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - DSA
+ */
+ public void checkCreation2()
+ throws Exception
+ {
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ try
+ {
+ KeyPairGenerator g = KeyPairGenerator.getInstance("DSA", "SUN");
+
+ g.initialize(512, new SecureRandom());
+
+ KeyPair p = g.generateKeyPair();
+
+ privKey = p.getPrivate();
+ pubKey = p.getPublic();
+ }
+ catch (Exception e)
+ {
+ fail("error setting up keys - " + e.toString());
+ return;
+ }
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3
+ //
+
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA1withDSA").setProvider(BC).build(privKey);
+ JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ // System.out.println(cert);
+
+
+ //
+ // create the certificate - version 1
+ //
+ sigGen = new JcaContentSignerBuilder("SHA1withDSA").setProvider(BC).build(privKey);
+ JcaX509v1CertificateBuilder certGen1 = new JcaX509v1CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen1.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ bIn = new ByteArrayInputStream(cert.getEncoded());
+ fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ //System.out.println(cert);
+
+ //
+ // exception test
+ //
+ try
+ {
+ certGen1 = new JcaX509v1CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),dudPublicKey);
+
+
+ fail("key without encoding not detected in v1");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // expected
+ }
+ }
+
+ private X500NameBuilder createStdBuilder()
+ {
+ X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
+
+ builder.addRDN(BCStyle.C, "AU");
+ builder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ builder.addRDN(BCStyle.L, "Melbourne");
+ builder.addRDN(BCStyle.ST, "Victoria");
+ builder.addRDN(BCStyle.E, "feedback-crypto@bouncycastle.org");
+
+ return builder;
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - ECDSA
+ */
+ public void checkCreation3()
+ {
+ ECCurve curve = new ECCurve.Fp(
+ new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+ new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+ new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+
+ ECParameterSpec spec = new ECParameterSpec(
+ curve,
+ curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+ new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n
+
+
+ ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(
+ new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d
+ spec);
+
+ ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(
+ curve.decodePoint(Hex.decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q
+ spec);
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ try
+ {
+ KeyFactory fact = KeyFactory.getInstance("ECDSA", BC);
+
+ privKey = fact.generatePrivate(privKeySpec);
+ pubKey = fact.generatePublic(pubKeySpec);
+ }
+ catch (Exception e)
+ {
+ fail("error setting up keys - " + e.toString());
+ return;
+ }
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = createStdBuilder();
+
+
+ //
+ // toString test
+ //
+ X500Name p = builder.build();
+ String s = p.toString();
+
+ if (!s.equals("C=AU,O=The Legion of the Bouncy Castle,L=Melbourne,ST=Victoria,E=feedback-crypto@bouncycastle.org"))
+ {
+ fail("ordered X509Principal test failed - s = " + s + ".");
+ }
+
+// p = new X509Principal(attrs);
+// s = p.toString();
+//
+// //
+// // we need two of these as the hash code for strings changed...
+// //
+// if (!s.equals("O=The Legion of the Bouncy Castle,E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU") && !s.equals("ST=Victoria,L=Melbourne,C=AU,E=feedback-crypto@bouncycastle.org,O=The Legion of the Bouncy Castle"))
+// {
+// fail("unordered X509Principal test failed.");
+// }
+
+ //
+ // create the certificate - version 3
+ //
+ try
+ {
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA1withECDSA").setProvider(BC).build(privKey);
+ JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ //
+ // try with point compression turned off
+ //
+ ((ECPointEncoder)pubKey).setPointFormat("UNCOMPRESSED");
+
+ certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ bIn = new ByteArrayInputStream(cert.getEncoded());
+ fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail("error setting generating cert - " + e.toString());
+ }
+
+ X509Principal pr = new X509Principal("O=\"The Bouncy Castle, The Legion of\",E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU");
+
+ if (!pr.toString().equals("O=The Bouncy Castle\\, The Legion of,E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU"))
+ {
+ fail("string based X509Principal test failed.");
+ }
+
+ pr = new X509Principal("O=The Bouncy Castle\\, The Legion of,E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU");
+
+ if (!pr.toString().equals("O=The Bouncy Castle\\, The Legion of,E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU"))
+ {
+ fail("string based X509Principal test failed.");
+ }
+
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - SHA224withECDSA
+ */
+ private void createECCert(String algorithm, DERObjectIdentifier algOid)
+ throws Exception
+ {
+ ECCurve.Fp curve = new ECCurve.Fp(
+ new BigInteger("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"), // q (or p)
+ new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", 16), // a
+ new BigInteger("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", 16)); // b
+
+ ECParameterSpec spec = new ECParameterSpec(
+ curve,
+ curve.decodePoint(Hex.decode("0200C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")), // G
+ new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", 16)); // n
+
+ ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(
+ new BigInteger("5769183828869504557786041598510887460263120754767955773309066354712783118202294874205844512909370791582896372147797293913785865682804434049019366394746072023"), // d
+ spec);
+
+ ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(
+ curve.decodePoint(Hex.decode("02006BFDD2C9278B63C92D6624F151C9D7A822CC75BD983B17D25D74C26740380022D3D8FAF304781E416175EADF4ED6E2B47142D2454A7AC7801DD803CF44A4D1F0AC")), // Q
+ spec);
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory fact = KeyFactory.getInstance("ECDSA", BC);
+
+ privKey = fact.generatePrivate(privKeySpec);
+ pubKey = fact.generatePublic(pubKeySpec);
+
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // create the certificate - version 3
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey);
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)certFact.generateCertificate(bIn);
+
+ //
+ // try with point compression turned off
+ //
+ ((ECPointEncoder)pubKey).setPointFormat("UNCOMPRESSED");
+
+ certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ bIn = new ByteArrayInputStream(cert.getEncoded());
+ certFact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)certFact.generateCertificate(bIn);
+
+ if (!cert.getSigAlgOID().equals(algOid.toString()))
+ {
+ fail("ECDSA oid incorrect.");
+ }
+
+ if (cert.getSigAlgParams() != null)
+ {
+ fail("sig parameters present");
+ }
+
+ Signature sig = Signature.getInstance(algorithm, BC);
+
+ sig.initVerify(pubKey);
+
+ sig.update(cert.getTBSCertificate());
+
+ if (!sig.verify(cert.getSignature()))
+ {
+ fail("EC certificate signature not mapped correctly.");
+ }
+ // System.out.println(cert);
+ }
+
+ private void checkCRL(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
+
+ CRL cert = fact.generateCRL(bIn);
+
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+ public void checkCRLCreation1()
+ throws Exception
+ {
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", BC);
+ Date now = new Date();
+ KeyPair pair = kpGen.generateKeyPair();
+ X509v2CRLBuilder crlGen = new X509v2CRLBuilder(new X500Name("CN=Test CA"), now);
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ crlGen.addCRLEntry(BigInteger.ONE, now, CRLReason.privilegeWithdrawn);
+
+ crlGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.getPublic()));
+
+ X509CRLHolder crl = crlGen.build(new JcaContentSignerBuilder("SHA256withRSAEncryption").setProvider(BC).build(pair.getPrivate()));
+
+ if (!crl.getIssuer().equals(new X500Name("CN=Test CA")))
+ {
+ fail("failed CRL issuer test");
+ }
+
+ Extension authExt = crl.getExtension(Extension.authorityKeyIdentifier);
+
+ if (authExt == null)
+ {
+ fail("failed to find CRL extension");
+ }
+
+ AuthorityKeyIdentifier authId = new AuthorityKeyIdentifierStructure(authExt);
+
+ X509CRLEntryHolder entry = crl.getRevokedCertificate(BigInteger.ONE);
+
+ if (entry == null)
+ {
+ fail("failed to find CRL entry");
+ }
+
+ if (!entry.getSerialNumber().equals(BigInteger.ONE))
+ {
+ fail("CRL cert serial number does not match");
+ }
+
+ if (!entry.hasExtensions())
+ {
+ fail("CRL entry extension not found");
+ }
+
+ Extension ext = entry.getExtension(X509Extension.reasonCode);
+
+ if (ext != null)
+ {
+ ASN1Enumerated reasonCode = (ASN1Enumerated)ASN1Enumerated.getInstance(ext.getParsedValue());
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found");
+ }
+ }
+
+ public void checkCRLCreation2()
+ throws Exception
+ {
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ Date now = new Date();
+ KeyPair pair = kpGen.generateKeyPair();
+ X509v2CRLBuilder crlGen = new JcaX509v2CRLBuilder(new X500Principal("CN=Test CA"), now);
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ Vector extOids = new Vector();
+ Vector extValues = new Vector();
+
+ CRLReason crlReason = CRLReason.lookup(CRLReason.privilegeWithdrawn);
+
+ try
+ {
+ extOids.addElement(X509Extensions.ReasonCode);
+ extValues.addElement(new X509Extension(false, new DEROctetString(crlReason.getEncoded())));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("error encoding reason: " + e);
+ }
+
+ X509Extensions entryExtensions = new X509Extensions(extOids, extValues);
+
+ crlGen.addCRLEntry(BigInteger.ONE, now, entryExtensions);
+
+ crlGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.getPublic()));
+
+ X509CRLHolder crlHolder = crlGen.build(new JcaContentSignerBuilder("SHA256withRSAEncryption").setProvider(BC).build(pair.getPrivate()));
+
+ X509CRL crl = new JcaX509CRLConverter().setProvider(BC).getCRL(crlHolder);
+
+ if (!crl.getIssuerX500Principal().equals(new X500Principal("CN=Test CA")))
+ {
+ fail("failed CRL issuer test");
+ }
+
+ byte[] authExt = crl.getExtensionValue(X509Extensions.AuthorityKeyIdentifier.getId());
+
+ if (authExt == null)
+ {
+ fail("failed to find CRL extension");
+ }
+
+ AuthorityKeyIdentifier authId = new AuthorityKeyIdentifierStructure(authExt);
+
+ X509CRLEntry entry = crl.getRevokedCertificate(BigInteger.ONE);
+
+ if (entry == null)
+ {
+ fail("failed to find CRL entry");
+ }
+
+ if (!entry.getSerialNumber().equals(BigInteger.ONE))
+ {
+ fail("CRL cert serial number does not match");
+ }
+
+ if (!entry.hasExtensions())
+ {
+ fail("CRL entry extension not found");
+ }
+
+ byte[] ext = entry.getExtensionValue(X509Extensions.ReasonCode.getId());
+
+ if (ext != null)
+ {
+ DEREnumerated reasonCode = (DEREnumerated)X509ExtensionUtil.fromExtensionValue(ext);
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found");
+ }
+ }
+
+ public void checkCRLCreation3()
+ throws Exception
+ {
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", BC);
+ Date now = new Date();
+ KeyPair pair = kpGen.generateKeyPair();
+ X509v2CRLBuilder crlGen = new JcaX509v2CRLBuilder(new X500Principal("CN=Test CA"), now);
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ Vector extOids = new Vector();
+ Vector extValues = new Vector();
+
+ CRLReason crlReason = CRLReason.lookup(CRLReason.privilegeWithdrawn);
+
+ try
+ {
+ extOids.addElement(X509Extensions.ReasonCode);
+ extValues.addElement(new X509Extension(false, new DEROctetString(crlReason.getEncoded())));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("error encoding reason: " + e);
+ }
+
+ X509Extensions entryExtensions = new X509Extensions(extOids, extValues);
+
+ crlGen.addCRLEntry(BigInteger.ONE, now, entryExtensions);
+
+ crlGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.getPublic()));
+
+ X509CRLHolder crlHolder = crlGen.build(new JcaContentSignerBuilder("SHA256withRSAEncryption").setProvider(BC).build(pair.getPrivate()));
+
+ X509CRL crl = new JcaX509CRLConverter().setProvider(BC).getCRL(crlHolder);
+
+ if (!crl.getIssuerX500Principal().equals(new X500Principal("CN=Test CA")))
+ {
+ fail("failed CRL issuer test");
+ }
+
+ byte[] authExt = crl.getExtensionValue(X509Extensions.AuthorityKeyIdentifier.getId());
+
+ if (authExt == null)
+ {
+ fail("failed to find CRL extension");
+ }
+
+ AuthorityKeyIdentifier authId = new AuthorityKeyIdentifierStructure(authExt);
+
+ X509CRLEntry entry = crl.getRevokedCertificate(BigInteger.ONE);
+
+ if (entry == null)
+ {
+ fail("failed to find CRL entry");
+ }
+
+ if (!entry.getSerialNumber().equals(BigInteger.ONE))
+ {
+ fail("CRL cert serial number does not match");
+ }
+
+ if (!entry.hasExtensions())
+ {
+ fail("CRL entry extension not found");
+ }
+
+ byte[] ext = entry.getExtensionValue(X509Extensions.ReasonCode.getId());
+
+ if (ext != null)
+ {
+ DEREnumerated reasonCode = (DEREnumerated)X509ExtensionUtil.fromExtensionValue(ext);
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found");
+ }
+
+ //
+ // check loading of existing CRL
+ //
+ now = new Date();
+ crlGen = new X509v2CRLBuilder(new X500Name("CN=Test CA"), now);
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ crlGen.addCRL(new JcaX509CRLHolder(crl));
+
+ crlGen.addCRLEntry(BigInteger.valueOf(2), now, entryExtensions);
+
+ crlGen.addExtension(X509Extension.authorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.getPublic()));
+
+ crlHolder = crlGen.build(new JcaContentSignerBuilder("SHA256withRSAEncryption").setProvider(BC).build(pair.getPrivate()));
+
+ int count = 0;
+ boolean oneFound = false;
+ boolean twoFound = false;
+
+ Iterator it = crlHolder.getRevokedCertificates().iterator();
+ while (it.hasNext())
+ {
+ X509CRLEntryHolder crlEnt = (X509CRLEntryHolder)it.next();
+
+ if (crlEnt.getSerialNumber().intValue() == 1)
+ {
+ oneFound = true;
+ Extension extn = crlEnt.getExtension(X509Extension.reasonCode);
+
+ if (extn != null)
+ {
+ ASN1Enumerated reasonCode = (ASN1Enumerated)ASN1Enumerated.getInstance(extn.getParsedValue());
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found");
+ }
+ }
+ else if (crlEnt.getSerialNumber().intValue() == 2)
+ {
+ twoFound = true;
+ }
+
+ count++;
+ }
+
+ if (count != 2)
+ {
+ fail("wrong number of CRLs found");
+ }
+
+ if (!oneFound || !twoFound)
+ {
+ fail("wrong CRLs found in copied list");
+ }
+
+ //
+ // check factory read back
+ //
+ CertificateFactory cFact = CertificateFactory.getInstance("X.509", BC);
+
+ X509CRL readCrl = (X509CRL)cFact.generateCRL(new ByteArrayInputStream(crlHolder.getEncoded()));
+
+ if (readCrl == null)
+ {
+ fail("crl not returned!");
+ }
+
+ Collection col = cFact.generateCRLs(new ByteArrayInputStream(crlHolder.getEncoded()));
+
+ if (col.size() != 1)
+ {
+ fail("wrong number of CRLs found in collection");
+ }
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - GOST3410
+ */
+ public void checkCreation4()
+ throws Exception
+ {
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyPairGenerator g = KeyPairGenerator.getInstance("GOST3410", BC);
+ GOST3410ParameterSpec gost3410P = new GOST3410ParameterSpec("GostR3410-94-CryptoPro-A");
+
+ g.initialize(gost3410P, new SecureRandom());
+
+ KeyPair p = g.generateKeyPair();
+
+ privKey = p.getPrivate();
+ pubKey = p.getPublic();
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder("GOST3411withGOST3410").setProvider(BC).build(privKey);
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ //
+ // check verifies in general
+ //
+ cert.verify(pubKey);
+
+ //
+ // check verifies with contained key
+ //
+ cert.verify(cert.getPublicKey());
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ //System.out.println(cert);
+
+ //check getEncoded()
+ byte[] bytes = cert.getEncoded();
+ }
+
+ public void checkCreation5()
+ throws Exception
+ {
+ //
+ // a sample key pair.
+ //
+ 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));
+
+ //
+ // set up the keys
+ //
+ SecureRandom rand = new SecureRandom();
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory fact = KeyFactory.getInstance("RSA", BC);
+
+ privKey = fact.generatePrivate(privKeySpec);
+ pubKey = fact.generatePublic(pubKeySpec);
+
+ //
+ // distinguished name table.
+ //
+ Vector ord = new Vector();
+ Vector values = new Vector();
+
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // create base certificate - version 3
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder("MD5WithRSAEncryption").setProvider(BC).build(privKey);
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey)
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true,
+ new X509KeyUsage(X509KeyUsage.encipherOnly))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.37"), true,
+ new DERSequence(KeyPurposeId.anyExtendedKeyUsage))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true,
+ new GeneralNames(new GeneralName(GeneralName.rfc822Name, "test@test.test")));
+
+ X509Certificate baseCert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ //
+ // copy certificate
+ //
+
+ certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey)
+ .copyAndAddExtension(new ASN1ObjectIdentifier("2.5.29.15"), true, baseCert)
+ .copyAndAddExtension(new ASN1ObjectIdentifier("2.5.29.37"), false, baseCert);
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ if (!areEqual(baseCert.getExtensionValue("2.5.29.15"), cert.getExtensionValue("2.5.29.15")))
+ {
+ fail("2.5.29.15 differs");
+ }
+
+ if (!areEqual(baseCert.getExtensionValue("2.5.29.37"), cert.getExtensionValue("2.5.29.37")))
+ {
+ fail("2.5.29.37 differs");
+ }
+
+ //
+ // exception test
+ //
+
+ try
+ {
+ certGen.copyAndAddExtension(new ASN1ObjectIdentifier("2.5.99.99"), true, new JcaX509CertificateHolder(baseCert));
+
+ fail("exception not thrown on dud extension copy");
+ }
+ catch (NullPointerException e)
+ {
+ // expected
+ }
+
+// try
+// {
+// certGen.setPublicKey(dudPublicKey);
+//
+// certGen.generate(privKey, BC);
+//
+// fail("key without encoding not detected in v3");
+// }
+// catch (IllegalArgumentException e)
+// {
+// // expected
+// }
+
+ }
+
+ private void testForgedSignature()
+ throws Exception
+ {
+ String cert = "MIIBsDCCAVoCAQYwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCQVUxEzARBgNV"
+ + "BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMSMwIQYD"
+ + "VQQDExpTZXJ2ZXIgdGVzdCBjZXJ0ICg1MTIgYml0KTAeFw0wNjA5MTEyMzU4NTVa"
+ + "Fw0wNjEwMTEyMzU4NTVaMGMxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpRdWVlbnNs"
+ + "YW5kMRowGAYDVQQKExFDcnlwdFNvZnQgUHR5IEx0ZDEjMCEGA1UEAxMaU2VydmVy"
+ + "IHRlc3QgY2VydCAoNTEyIGJpdCkwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAn7PD"
+ + "hCeV/xIxUg8V70YRxK2A5jZbD92A12GN4PxyRQk0/lVmRUNMaJdq/qigpd9feP/u"
+ + "12S4PwTLb/8q/v657QIDAQABMA0GCSqGSIb3DQEBBQUAA0EAbynCRIlUQgaqyNgU"
+ + "DF6P14yRKUtX8akOP2TwStaSiVf/akYqfLFm3UGka5XbPj4rifrZ0/sOoZEEBvHQ"
+ + "e20sRA==";
+
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", BC);
+
+ X509Certificate x509 = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(Base64.decode(cert)));
+ try
+ {
+ x509.verify(x509.getPublicKey());
+
+ fail("forged RSA signature passed");
+ }
+ catch (Exception e)
+ {
+ // expected
+ }
+ }
+
+
+ private void pemTest()
+ throws Exception
+ {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509", BC);
+
+ Certificate cert = readPEMCert(cf, PEMData.CERTIFICATE_1);
+ if (cert == null)
+ {
+ fail("PEM cert not read");
+ }
+ cert = readPEMCert(cf, "-----BEGIN CERTIFICATE-----" + PEMData.CERTIFICATE_2);
+ if (cert == null)
+ {
+ fail("PEM cert with extraneous header not read");
+ }
+ CRL crl = cf.generateCRL(new ByteArrayInputStream(PEMData.CRL_1.getBytes("US-ASCII")));
+ if (crl == null)
+ {
+ fail("PEM crl not read");
+ }
+ Collection col = cf.generateCertificates(new ByteArrayInputStream(PEMData.CERTIFICATE_2.getBytes("US-ASCII")));
+ if (col.size() != 1 || !col.contains(cert))
+ {
+ fail("PEM cert collection not right");
+ }
+ col = cf.generateCRLs(new ByteArrayInputStream(PEMData.CRL_2.getBytes("US-ASCII")));
+ if (col.size() != 1 || !col.contains(crl))
+ {
+ fail("PEM crl collection not right");
+ }
+ }
+
+ private static Certificate readPEMCert(CertificateFactory cf, String pemData)
+ throws CertificateException, UnsupportedEncodingException
+ {
+ return cf.generateCertificate(new ByteArrayInputStream(pemData.getBytes("US-ASCII")));
+ }
+
+ private void pkcs7Test()
+ throws Exception
+ {
+ /*
+ ASN1EncodableVector certs = new ASN1EncodableVector();
+
+ certs.add(new ASN1InputStream(CertPathTest.rootCertBin).readObject());
+ certs.add(new DERTaggedObject(false, 2, new ASN1InputStream(AttrCertTest.attrCert).readObject()));
+
+ ASN1EncodableVector crls = new ASN1EncodableVector();
+
+ crls.add(new ASN1InputStream(CertPathTest.rootCrlBin).readObject());
+ SignedData sigData = new SignedData(new DERSet(), new ContentInfo(CMSObjectIdentifiers.data, null), new DERSet(certs), new DERSet(crls), new DERSet());
+
+ ContentInfo info = new ContentInfo(CMSObjectIdentifiers.signedData, sigData);
+
+ CertificateFactory cf = CertificateFactory.getInstance("X.509", BC);
+
+ X509Certificate cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(info.getEncoded()));
+ if (cert == null || !areEqual(cert.getEncoded(), certs.get(0).getDERObject().getEncoded()))
+ {
+ fail("PKCS7 cert not read");
+ }
+ X509CRL crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(info.getEncoded()));
+ if (crl == null || !areEqual(crl.getEncoded(), crls.get(0).getDERObject().getEncoded()))
+ {
+ fail("PKCS7 crl not read");
+ }
+ Collection col = cf.generateCertificates(new ByteArrayInputStream(info.getEncoded()));
+ if (col.size() != 1 || !col.contains(cert))
+ {
+ fail("PKCS7 cert collection not right");
+ }
+ col = cf.generateCRLs(new ByteArrayInputStream(info.getEncoded()));
+ if (col.size() != 1 || !col.contains(crl))
+ {
+ fail("PKCS7 crl collection not right");
+ }
+
+ // data with no certificates or CRLs
+
+ sigData = new SignedData(new DERSet(), new ContentInfo(CMSObjectIdentifiers.data, null), new DERSet(), new DERSet(), new DERSet());
+
+ info = new ContentInfo(CMSObjectIdentifiers.signedData, sigData);
+
+ cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(info.getEncoded()));
+ if (cert != null)
+ {
+ fail("PKCS7 cert present");
+ }
+ crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(info.getEncoded()));
+ if (crl != null)
+ {
+ fail("PKCS7 crl present");
+ }
+
+ // data with absent certificates and CRLS
+
+ sigData = new SignedData(new DERSet(), new ContentInfo(CMSObjectIdentifiers.data, null), null, null, new DERSet());
+
+ info = new ContentInfo(CMSObjectIdentifiers.signedData, sigData);
+
+ cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(info.getEncoded()));
+ if (cert != null)
+ {
+ fail("PKCS7 cert present");
+ }
+ crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(info.getEncoded()));
+ if (crl != null)
+ {
+ fail("PKCS7 crl present");
+ }
+
+ //
+ // sample message
+ //
+ InputStream in = new ByteArrayInputStream(pkcs7CrlProblem);
+ Collection certCol = cf.generateCertificates(in);
+ Collection crlCol = cf.generateCRLs(in);
+
+ if (crlCol.size() != 0)
+ {
+ fail("wrong number of CRLs: " + crlCol.size());
+ }
+
+ if (certCol.size() != 4)
+ {
+ fail("wrong number of Certs: " + certCol.size());
+ }
+ */
+ }
+
+ private void createPSSCert(String algorithm)
+ throws Exception
+ {
+ KeyPair pair = generateLongFixedKeys();
+
+ PrivateKey privKey = pair.getPrivate();
+ PublicKey pubKey = pair.getPublic();
+
+ //
+ // distinguished name table.
+ //
+
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // create base certificate - version 3
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey);
+ JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),
+ new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ certGen.addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true,
+ new X509KeyUsage(X509KeyUsage.encipherOnly));
+ certGen.addExtension(new ASN1ObjectIdentifier("2.5.29.37"), true,
+ new DERSequence(KeyPurposeId.anyExtendedKeyUsage));
+ certGen.addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true,
+ new GeneralNames(new GeneralName(GeneralName.rfc822Name, "test@test.test")));
+
+ X509Certificate baseCert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ baseCert.verify(pubKey);
+ }
+
+ private KeyPair generateLongFixedKeys()
+ throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException
+ {
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+ new BigInteger("010001",16));
+
+ RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec(
+ new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+ new BigInteger("010001",16),
+ new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16),
+ new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16),
+ new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16),
+ new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16),
+ new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16),
+ new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16));
+
+ KeyFactory fact = KeyFactory.getInstance("RSA", BC);
+
+ return new KeyPair(fact.generatePublic(pubKeySpec), fact.generatePrivate(privKeySpec));
+ }
+
+ private void rfc4491Test()
+ throws Exception
+ {
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", BC);
+
+ X509Certificate x509 = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(gostRFC4491_94));
+
+ x509.verify(x509.getPublicKey(), BC);
+
+ x509 = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(gostRFC4491_2001));
+
+ x509.verify(x509.getPublicKey(), BC);
+ }
+
+ private void testNullDerNullCert()
+ throws Exception
+ {
+ KeyPair pair = generateLongFixedKeys();
+ PublicKey pubKey = pair.getPublic();
+ PrivateKey privKey = pair.getPrivate();
+
+ ContentSigner sigGen = new JcaContentSignerBuilder("MD5WithRSAEncryption").setProvider(BC).build(privKey);
+ JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(new X500Name("CN=Test"),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),new X500Name("CN=Test"),pubKey);
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ X509CertificateStructure struct = X509CertificateStructure.getInstance(ASN1Primitive.fromByteArray(cert.getEncoded()));
+
+ ASN1Encodable tbsCertificate = struct.getTBSCertificate();
+ AlgorithmIdentifier sig = struct.getSignatureAlgorithm();
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCertificate);
+ v.add(new AlgorithmIdentifier(sig.getAlgorithm()));
+ v.add(struct.getSignature());
+
+ // verify
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(new DERSequence(v).getEncoded());
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ cert.verify(cert.getPublicKey());
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": testNullDerNull failed - exception " + e.toString(), e);
+ }
+ }
+
+ private void testDirect()
+ throws Exception
+ {
+ KeyStore keyStore = KeyStore.getInstance("PKCS12", "SC");
+
+ ByteArrayInputStream input = new ByteArrayInputStream(testCAp12);
+
+ keyStore.load(input, "test".toCharArray());
+
+ X509Certificate certificate = (X509Certificate) keyStore.getCertificate("ca");
+ PrivateKey privateKey = (PrivateKey) keyStore.getKey("ca", null);
+
+ X500Name issuer = X500Name.getInstance(certificate.getIssuerX500Principal().getEncoded());
+
+ X509v2CRLBuilder builder = new X509v2CRLBuilder(issuer, new Date());
+
+ builder.addCRLEntry(certificate.getSerialNumber(), new Date(), CRLReason.cACompromise);
+
+ JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA256WithRSAEncryption");
+
+ contentSignerBuilder.setProvider("SC");
+
+ X509CRLHolder cRLHolder = builder.build(contentSignerBuilder.build(privateKey));
+
+ if (!cRLHolder.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider("SC").build(certificate)))
+ {
+ fail("CRL signature not valid");
+ }
+
+ X509CRLEntryHolder cRLEntryHolder = cRLHolder.getRevokedCertificate(certificate.getSerialNumber());
+
+ if (!cRLEntryHolder.getCertificateIssuer().equals(new GeneralNames(new GeneralName(cRLHolder.getIssuer()))))
+ {
+ fail("certificate issuer incorrect");
+ }
+
+ JcaX509CRLConverter converter = new JcaX509CRLConverter();
+
+ converter.setProvider("SC");
+
+ X509CRL crl = converter.getCRL(cRLHolder);
+
+ crl.verify(certificate.getPublicKey());
+
+ if (!crl.isRevoked(certificate))
+ {
+ fail("Certificate should be revoked");
+ }
+
+ // now encode the CRL and load the CRL with the JCE provider
+
+ CertificateFactory fac = CertificateFactory.getInstance("X.509");
+
+ X509CRL jceCRL = (X509CRL) fac.generateCRL(new ByteArrayInputStream(crl.getEncoded()));
+
+ jceCRL.verify(certificate.getPublicKey());
+
+ if (!jceCRL.isRevoked(certificate))
+ {
+ fail("This certificate should also be revoked");
+ }
+ }
+
+ private void testIndirect()
+ throws Exception
+ {
+ KeyStore keyStore = KeyStore.getInstance("PKCS12", "SC");
+
+ ByteArrayInputStream input = new ByteArrayInputStream(testCAp12);
+
+ keyStore.load(input, "test".toCharArray());
+
+ X509Certificate certificate = (X509Certificate) keyStore.getCertificate("ca");
+ PrivateKey privateKey = (PrivateKey) keyStore.getKey("ca", null);
+
+ X500Name crlIssuer = X500Name.getInstance(certificate.getSubjectX500Principal().getEncoded());
+ X500Name caName = X500Name.getInstance(certificate.getIssuerX500Principal().getEncoded());
+
+ X509v2CRLBuilder builder = new X509v2CRLBuilder(crlIssuer, new Date());
+
+ builder.addExtension(Extension.issuingDistributionPoint, true, new IssuingDistributionPoint(null, true, false));
+
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+
+ extGen.addExtension(Extension.reasonCode, false, CRLReason.lookup(CRLReason.cACompromise));
+ extGen.addExtension(Extension.certificateIssuer, true, new GeneralNames(new GeneralName(caName)));
+
+ builder.addCRLEntry(certificate.getSerialNumber(), new Date(), extGen.generate());
+
+ JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA256WithRSAEncryption");
+
+ contentSignerBuilder.setProvider("SC");
+
+ X509CRLHolder cRLHolder = builder.build(contentSignerBuilder.build(privateKey));
+
+ if (!cRLHolder.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider("SC").build(certificate)))
+ {
+ fail("CRL signature not valid");
+ }
+
+ X509CRLEntryHolder cRLEntryHolder = cRLHolder.getRevokedCertificate(certificate.getSerialNumber());
+
+ if (!cRLEntryHolder.getCertificateIssuer().equals(new GeneralNames(new GeneralName(X500Name.getInstance(certificate.getIssuerX500Principal().getEncoded())))))
+ {
+ fail("certificate issuer incorrect");
+ }
+
+ JcaX509CRLConverter converter = new JcaX509CRLConverter();
+
+ converter.setProvider("SC");
+
+ X509CRL crl = converter.getCRL(cRLHolder);
+
+ crl.verify(certificate.getPublicKey());
+
+ if (!crl.isRevoked(certificate))
+ {
+ fail("Certificate should be revoked");
+ }
+
+ // now encode the CRL and load the CRL with the JCE provider
+
+ CertificateFactory fac = CertificateFactory.getInstance("X.509");
+
+ X509CRL jceCRL = (X509CRL) fac.generateCRL(new ByteArrayInputStream(crl.getEncoded()));
+
+ jceCRL.verify(certificate.getPublicKey());
+
+ if (!jceCRL.isRevoked(certificate))
+ {
+ fail("This certificate should also be revoked");
+ }
+ }
+
+ private void testIndirect2()
+ throws Exception
+ {
+ KeyStore keyStore = KeyStore.getInstance("PKCS12", "SC");
+
+ ByteArrayInputStream input = new ByteArrayInputStream(testCAp12);
+
+ keyStore.load(input, "test".toCharArray());
+
+ X509Certificate certificate = (X509Certificate) keyStore.getCertificate("ca");
+ PrivateKey privateKey = (PrivateKey) keyStore.getKey("ca", null);
+
+ X500Name crlIssuer = X500Name.getInstance(certificate.getSubjectX500Principal().getEncoded());
+ X500Name caName = X500Name.getInstance(certificate.getIssuerX500Principal().getEncoded());
+
+ X509v2CRLBuilder builder = new X509v2CRLBuilder(crlIssuer, new Date());
+
+ builder.addExtension(Extension.issuingDistributionPoint, true, new IssuingDistributionPoint(null, true, false));
+
+ builder.addCRLEntry(BigInteger.valueOf(100), new Date(), CRLReason.cACompromise);
+ builder.addCRLEntry(BigInteger.valueOf(120), new Date(), CRLReason.cACompromise);
+
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+
+ extGen.addExtension(Extension.reasonCode, false, CRLReason.lookup(CRLReason.cACompromise));
+ extGen.addExtension(Extension.certificateIssuer, true, new GeneralNames(new GeneralName(caName)));
+
+ builder.addCRLEntry(certificate.getSerialNumber(), new Date(), extGen.generate());
+
+ builder.addCRLEntry(BigInteger.valueOf(130), new Date(), CRLReason.cACompromise);
+
+ JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA256WithRSAEncryption");
+
+ contentSignerBuilder.setProvider("SC");
+
+ X509CRLHolder cRLHolder = builder.build(contentSignerBuilder.build(privateKey));
+
+ if (!cRLHolder.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider("SC").build(certificate)))
+ {
+ fail("CRL signature not valid");
+ }
+
+ X509CRLEntryHolder cRLEntryHolder = cRLHolder.getRevokedCertificate(certificate.getSerialNumber());
+
+ if (!cRLEntryHolder.getCertificateIssuer().equals(new GeneralNames(new GeneralName(caName))))
+ {
+ fail("certificate issuer incorrect");
+ }
+
+ cRLEntryHolder = cRLHolder.getRevokedCertificate(BigInteger.valueOf(130));
+
+ if (!cRLEntryHolder.getCertificateIssuer().equals(new GeneralNames(new GeneralName(caName))))
+ {
+ fail("certificate issuer incorrect");
+ }
+
+ cRLEntryHolder = cRLHolder.getRevokedCertificate(BigInteger.valueOf(100));
+
+ if (!cRLEntryHolder.getCertificateIssuer().equals(new GeneralNames(new GeneralName(cRLHolder.getIssuer()))))
+ {
+ fail("certificate issuer incorrect");
+ }
+
+ JcaX509CRLConverter converter = new JcaX509CRLConverter();
+
+ converter.setProvider("SC");
+
+ X509CRL crl = converter.getCRL(cRLHolder);
+
+ crl.verify(certificate.getPublicKey());
+
+ X509CRLEntry crlEntry = crl.getRevokedCertificate(BigInteger.valueOf(100));
+
+ if (crlEntry.getCertificateIssuer() != null)
+ {
+ fail("JCA 1 certificate issuer incorrect");
+ }
+
+ crlEntry = crl.getRevokedCertificate(BigInteger.valueOf(130));
+ if (!crlEntry.getCertificateIssuer().equals(new X500Principal(caName.getEncoded())))
+ {
+ fail("JCA 2 certificate issuer incorrect");
+ }
+ }
+
+ // issuing distribution point must be set for an indirect CRL to be recognised
+ private void testMalformedIndirect()
+ throws Exception
+ {
+ KeyStore keyStore = KeyStore.getInstance("PKCS12", "SC");
+
+ ByteArrayInputStream input = new ByteArrayInputStream(testCAp12);
+
+ keyStore.load(input, "test".toCharArray());
+
+ X509Certificate certificate = (X509Certificate) keyStore.getCertificate("ca");
+ PrivateKey privateKey = (PrivateKey) keyStore.getKey("ca", null);
+
+ X500Name crlIssuer = X500Name.getInstance(certificate.getSubjectX500Principal().getEncoded());
+ X500Name caName = X500Name.getInstance(certificate.getIssuerX500Principal().getEncoded());
+
+ X509v2CRLBuilder builder = new X509v2CRLBuilder(crlIssuer, new Date());
+
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+
+ extGen.addExtension(Extension.reasonCode, false, CRLReason.lookup(CRLReason.cACompromise));
+ extGen.addExtension(Extension.certificateIssuer, true, new GeneralNames(new GeneralName(caName)));
+
+ builder.addCRLEntry(certificate.getSerialNumber(), new Date(), extGen.generate());
+
+ JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA256WithRSAEncryption");
+
+ contentSignerBuilder.setProvider("SC");
+
+ X509CRLHolder cRLHolder = builder.build(contentSignerBuilder.build(privateKey));
+
+ if (!cRLHolder.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider("SC").build(certificate)))
+ {
+ fail("CRL signature not valid");
+ }
+
+ X509CRLEntryHolder cRLEntryHolder = cRLHolder.getRevokedCertificate(certificate.getSerialNumber());
+
+ if (!cRLEntryHolder.getCertificateIssuer().equals(new GeneralNames(new GeneralName(cRLHolder.getIssuer()))))
+ {
+ fail("certificate issuer incorrect");
+ }
+
+ JcaX509CRLConverter converter = new JcaX509CRLConverter();
+
+ converter.setProvider("SC");
+
+ X509CRL crl = converter.getCRL(cRLHolder);
+
+ crl.verify(certificate.getPublicKey());
+
+ if (crl.isRevoked(certificate))
+ {
+ throw new Exception("Certificate should not be revoked");
+ }
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ testDirect();
+ testIndirect();
+ testIndirect2();
+ testMalformedIndirect();
+
+ checkCertificate(1, cert1);
+ checkCertificate(2, cert2);
+ checkCertificate(3, cert3);
+ checkCertificate(4, cert4);
+ checkCertificate(5, cert5);
+ checkCertificate(6, oldEcdsa);
+ checkCertificate(7, cert7);
+
+ checkKeyUsage(8, keyUsage);
+ checkSelfSignedCertificate(9, uncompressedPtEC);
+ checkNameCertificate(10, nameCert);
+
+ checkSelfSignedCertificate(11, probSelfSignedCert);
+ checkSelfSignedCertificate(12, gostCA1);
+ checkSelfSignedCertificate(13, gostCA2);
+ checkSelfSignedCertificate(14, gost341094base);
+ checkSelfSignedCertificate(15, gost34102001base);
+ checkSelfSignedCertificate(16, gost341094A);
+ checkSelfSignedCertificate(17, gost341094B);
+ checkSelfSignedCertificate(17, gost34102001A);
+
+ checkCRL(1, crl1);
+
+ checkCreation1();
+ checkCreation2();
+ checkCreation3();
+ checkCreation4();
+ checkCreation5();
+
+ createECCert("SHA1withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ createECCert("SHA224withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ createECCert("SHA256withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ createECCert("SHA384withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ createECCert("SHA512withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+
+ createPSSCert("SHA1withRSAandMGF1");
+ createPSSCert("SHA224withRSAandMGF1");
+ createPSSCert("SHA256withRSAandMGF1");
+ createPSSCert("SHA384withRSAandMGF1");
+
+ checkCRLCreation1();
+ checkCRLCreation2();
+ checkCRLCreation3();
+
+ pemTest();
+ pkcs7Test();
+ rfc4491Test();
+
+ testForgedSignature();
+
+ testNullDerNullCert();
+
+ checkCertificate(18, emptyDNCert);
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new CertTest());
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/ConverterTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/ConverterTest.java
new file mode 100644
index 000000000..0c2f88b8f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/ConverterTest.java
@@ -0,0 +1,66 @@
+package org.spongycastle.cert.test;
+
+import java.math.BigInteger;
+import java.security.cert.X509CertSelector;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cert.selector.X509CertificateHolderSelector;
+import org.spongycastle.cert.selector.jcajce.JcaSelectorConverter;
+import org.spongycastle.cert.selector.jcajce.JcaX509CertSelectorConverter;
+import org.spongycastle.util.Arrays;
+
+public class ConverterTest
+ extends TestCase
+{
+ public void testCertificateSelectorConversion()
+ throws Exception
+ {
+ JcaX509CertSelectorConverter converter = new JcaX509CertSelectorConverter();
+ JcaSelectorConverter toSelector = new JcaSelectorConverter();
+
+ X509CertificateHolderSelector sid1 = new X509CertificateHolderSelector(new X500Name("CN=Test"), BigInteger.valueOf(1), new byte[20]);
+
+ X509CertSelector conv = converter.getCertSelector(sid1);
+
+ assertTrue(conv.getIssuerAsString().equals("CN=Test"));
+ assertTrue(Arrays.areEqual(conv.getSubjectKeyIdentifier(), new DEROctetString(new byte[20]).getEncoded()));
+ assertEquals(conv.getSerialNumber(), sid1.getSerialNumber());
+
+ X509CertificateHolderSelector sid2 = toSelector.getCertificateHolderSelector(conv);
+
+ assertEquals(sid1, sid2);
+
+ sid1 = new X509CertificateHolderSelector(new X500Name("CN=Test"), BigInteger.valueOf(1));
+
+ conv = converter.getCertSelector(sid1);
+
+ assertTrue(conv.getIssuerAsString().equals("CN=Test"));
+ assertNull(conv.getSubjectKeyIdentifier());
+ assertEquals(conv.getSerialNumber(), sid1.getSerialNumber());
+
+ sid2 = toSelector.getCertificateHolderSelector(conv);
+
+ assertEquals(sid1, sid2);
+
+ sid1 = new X509CertificateHolderSelector(new byte[20]);
+
+ conv = converter.getCertSelector(sid1);
+
+ assertNull(conv.getIssuerAsString());
+ assertTrue(Arrays.areEqual(conv.getSubjectKeyIdentifier(), new DEROctetString(new byte[20]).getEncoded()));
+ assertNull(conv.getSerialNumber());
+
+ sid2 = toSelector.getCertificateHolderSelector(conv);
+
+ assertEquals(sid1, sid2);
+ }
+
+ public static Test suite()
+ {
+ return new TestSuite(ConverterTest.class);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/PEMData.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/PEMData.java
new file mode 100644
index 000000000..fff7f9432
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/PEMData.java
@@ -0,0 +1,114 @@
+package org.spongycastle.cert.test;
+
+public class PEMData
+{
+ public static String CERTIFICATE_1 =
+ "-----BEGIN X509 CERTIFICATE-----\r"
+ + "MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx\r"
+ + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY\r"
+ + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB\r"
+ + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ\r"
+ + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2\r"
+ + "MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW\r"
+ + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM\r"
+ + "dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l\r"
+ + "Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv\r"
+ + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re\r"
+ + "Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO\r"
+ + "Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE\r"
+ + "7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy\r"
+ + "QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0\r"
+ + "ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw\r"
+ + "DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL\r"
+ + "iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4\r"
+ + "yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF\r"
+ + "5/8=\r"
+ + "-----END X509 CERTIFICATE-----\r";
+
+ public static String CERTIFICATE_2 =
+ "-----BEGIN CERTIFICATE-----\n"
+ + "MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx\n"
+ + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY\n"
+ + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB\n"
+ + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ\n"
+ + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2\n"
+ + "MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW\n"
+ + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM\n"
+ + "dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l\n"
+ + "Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv\n"
+ + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re\n"
+ + "Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO\n"
+ + "Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE\n"
+ + "7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy\n"
+ + "QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0\n"
+ + "ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw\n"
+ + "DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL\n"
+ + "iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4\n"
+ + "yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF\n"
+ + "5/8=\n"
+ + "-----END CERTIFICATE-----\n";
+
+ public static String CRL_1 =
+ "-----BEGIN X509 CRL-----\r\n"
+ + "MIICjTCCAfowDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoT\r\n"
+ + "F1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVy\r\n"
+ + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5Fw05NTA1MDIwMjEyMjZaFw05NTA2MDEw\r\n"
+ + "MDAxNDlaMIIBaDAWAgUCQQAABBcNOTUwMjAxMTcyNDI2WjAWAgUCQQAACRcNOTUw\r\n"
+ + "MjEwMDIxNjM5WjAWAgUCQQAADxcNOTUwMjI0MDAxMjQ5WjAWAgUCQQAADBcNOTUw\r\n"
+ + "MjI1MDA0NjQ0WjAWAgUCQQAAGxcNOTUwMzEzMTg0MDQ5WjAWAgUCQQAAFhcNOTUw\r\n"
+ + "MzE1MTkxNjU0WjAWAgUCQQAAGhcNOTUwMzE1MTk0MDQxWjAWAgUCQQAAHxcNOTUw\r\n"
+ + "MzI0MTk0NDMzWjAWAgUCcgAABRcNOTUwMzI5MjAwNzExWjAWAgUCcgAAERcNOTUw\r\n"
+ + "MzMwMDIzNDI2WjAWAgUCQQAAIBcNOTUwNDA3MDExMzIxWjAWAgUCcgAAHhcNOTUw\r\n"
+ + "NDA4MDAwMjU5WjAWAgUCcgAAQRcNOTUwNDI4MTcxNzI0WjAWAgUCcgAAOBcNOTUw\r\n"
+ + "NDI4MTcyNzIxWjAWAgUCcgAATBcNOTUwNTAyMDIxMjI2WjANBgkqhkiG9w0BAQIF\r\n"
+ + "AAN+AHqOEJXSDejYy0UwxxrH/9+N2z5xu/if0J6qQmK92W0hW158wpJg+ovV3+wQ\r\n"
+ + "wvIEPRL2rocL0tKfAsVq1IawSJzSNgxG0lrcla3MrJBnZ4GaZDu4FutZh72MR3Gt\r\n"
+ + "JaAL3iTJHJD55kK2D/VoyY1djlsPuNh6AEgdVwFAyp0v\r\n"
+ + "-----END X509 CRL-----\r\n";
+
+ public static String CRL_2 =
+ "-----BEGIN CRL-----\r\n"
+ + "MIICjTCCAfowDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoT\r\n"
+ + "F1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVy\r\n"
+ + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5Fw05NTA1MDIwMjEyMjZaFw05NTA2MDEw\r\n"
+ + "MDAxNDlaMIIBaDAWAgUCQQAABBcNOTUwMjAxMTcyNDI2WjAWAgUCQQAACRcNOTUw\r\n"
+ + "MjEwMDIxNjM5WjAWAgUCQQAADxcNOTUwMjI0MDAxMjQ5WjAWAgUCQQAADBcNOTUw\r\n"
+ + "MjI1MDA0NjQ0WjAWAgUCQQAAGxcNOTUwMzEzMTg0MDQ5WjAWAgUCQQAAFhcNOTUw\r\n"
+ + "MzE1MTkxNjU0WjAWAgUCQQAAGhcNOTUwMzE1MTk0MDQxWjAWAgUCQQAAHxcNOTUw\r\n"
+ + "MzI0MTk0NDMzWjAWAgUCcgAABRcNOTUwMzI5MjAwNzExWjAWAgUCcgAAERcNOTUw\r\n"
+ + "MzMwMDIzNDI2WjAWAgUCQQAAIBcNOTUwNDA3MDExMzIxWjAWAgUCcgAAHhcNOTUw\r\n"
+ + "NDA4MDAwMjU5WjAWAgUCcgAAQRcNOTUwNDI4MTcxNzI0WjAWAgUCcgAAOBcNOTUw\r\n"
+ + "NDI4MTcyNzIxWjAWAgUCcgAATBcNOTUwNTAyMDIxMjI2WjANBgkqhkiG9w0BAQIF\r\n"
+ + "AAN+AHqOEJXSDejYy0UwxxrH/9+N2z5xu/if0J6qQmK92W0hW158wpJg+ovV3+wQ\r\n"
+ + "wvIEPRL2rocL0tKfAsVq1IawSJzSNgxG0lrcla3MrJBnZ4GaZDu4FutZh72MR3Gt\r\n"
+ + "JaAL3iTJHJD55kK2D/VoyY1djlsPuNh6AEgdVwFAyp0v\r\n"
+ + "-----END CRL-----\r\n";
+
+ static String ATTRIBUTE_CERTIFICATE_1 =
+ "-----BEGIN X509 ATTRIBUTE CERTIFICATE-----\r\n"
+ + "MIIBuDCCASECAQEwZ6BlMGCkXjBcMQswCQYDVQQGEwJBVTEoMCYGA1UEChMfVGhl\r\n"
+ + "IExlZ2lvbiBvZiB0aGUgQm91bmN5IENhc3RsZTEjMCEGA1UECxMaQm91bmN5IFBy\r\n"
+ + "aW1hcnkgQ2VydGlmaWNhdGUCARSgYjBgpF4wXDELMAkGA1UEBhMCQVUxKDAmBgNV\r\n"
+ + "BAoTH1RoZSBMZWdpb24gb2YgdGhlIEJvdW5jeSBDYXN0bGUxIzAhBgNVBAsTGkJv\r\n"
+ + "dW5jeSBQcmltYXJ5IENlcnRpZmljYXRlMA0GCSqGSIb3DQEBBQUAAgEBMCIYDzIw\r\n"
+ + "MDUwNjEwMDI0MTMzWhgPMjAwNTA2MTAwMjQzMTNaMBkwFwYDVRhIMRAwDoEMREFV\r\n"
+ + "MTIzNDU2Nzg5MA0GCSqGSIb3DQEBBQUAA4GBALAYXT9zdxSR5zdPLAon1xIPehgI\r\n"
+ + "NZhjM7w0uu3OdzSV5sC31X1Kx9vi5RIWiM9VimRTwbQIod9POttD5QMXCwQb/fm7\r\n"
+ + "eiJqL2YBIXOeClB19VrQe8xQtMFbyuFpDiM7QdvIam9ShZZMEMGjv9QHI64M4b0G\r\n"
+ + "odUBlSsJwPPQjZSU\r\n"
+ + "-----END X509 ATTRIBUTE CERTIFICATE-----\r\n";
+
+ static String ATTRIBUTE_CERTIFICATE_2 =
+ "-----BEGIN ATTRIBUTE CERTIFICATE-----\r\n"
+ + "MIIBuDCCASECAQEwZ6BlMGCkXjBcMQswCQYDVQQGEwJBVTEoMCYGA1UEChMfVGhl\r\n"
+ + "IExlZ2lvbiBvZiB0aGUgQm91bmN5IENhc3RsZTEjMCEGA1UECxMaQm91bmN5IFBy\r\n"
+ + "aW1hcnkgQ2VydGlmaWNhdGUCARSgYjBgpF4wXDELMAkGA1UEBhMCQVUxKDAmBgNV\r\n"
+ + "BAoTH1RoZSBMZWdpb24gb2YgdGhlIEJvdW5jeSBDYXN0bGUxIzAhBgNVBAsTGkJv\r\n"
+ + "dW5jeSBQcmltYXJ5IENlcnRpZmljYXRlMA0GCSqGSIb3DQEBBQUAAgEBMCIYDzIw\r\n"
+ + "MDUwNjEwMDI0MTMzWhgPMjAwNTA2MTAwMjQzMTNaMBkwFwYDVRhIMRAwDoEMREFV\r\n"
+ + "MTIzNDU2Nzg5MA0GCSqGSIb3DQEBBQUAA4GBALAYXT9zdxSR5zdPLAon1xIPehgI\r\n"
+ + "NZhjM7w0uu3OdzSV5sC31X1Kx9vi5RIWiM9VimRTwbQIod9POttD5QMXCwQb/fm7\r\n"
+ + "eiJqL2YBIXOeClB19VrQe8xQtMFbyuFpDiM7QdvIam9ShZZMEMGjv9QHI64M4b0G\r\n"
+ + "odUBlSsJwPPQjZSU\r\n"
+ + "-----END ATTRIBUTE CERTIFICATE-----\r\n";
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/PKCS10Test.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/PKCS10Test.java
new file mode 100644
index 000000000..e130fa4d0
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/PKCS10Test.java
@@ -0,0 +1,616 @@
+package org.spongycastle.cert.test;
+
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Signature;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.Attribute;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.X500NameBuilder;
+import org.spongycastle.asn1.x500.style.BCStyle;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.KeyUsage;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.cert.jcajce.JcaX509ExtensionUtils;
+import org.spongycastle.jce.ECGOST3410NamedCurveTable;
+import org.spongycastle.jce.ECNamedCurveTable;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+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.jce.spec.ECPublicKeySpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+import org.spongycastle.pkcs.PKCS10CertificationRequest;
+import org.spongycastle.pkcs.PKCS10CertificationRequestBuilder;
+import org.spongycastle.pkcs.jcajce.JcaPKCS10CertificationRequest;
+import org.spongycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.encoders.Hex;
+import org.spongycastle.util.test.SimpleTest;
+
+/**
+ **/
+public class PKCS10Test
+ extends SimpleTest
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ private byte[] gost3410EC_A = Base64.decode(
+ "MIIBOzCB6wIBADB/MQ0wCwYDVQQDEwR0ZXN0MRUwEwYDVQQKEwxEZW1vcyBDbyBMdGQxHjAcBgNV"
+ +"BAsTFUNyeXB0b2dyYXBoeSBkaXZpc2lvbjEPMA0GA1UEBxMGTW9zY293MQswCQYDVQQGEwJydTEZ"
+ +"MBcGCSqGSIb3DQEJARYKc2RiQGRvbC5ydTBjMBwGBiqFAwICEzASBgcqhQMCAiMBBgcqhQMCAh4B"
+ +"A0MABEBYx0P2D7YuuZo5HgdIAUKAXcLBDZ+4LYFgbKjrfStVfH59lc40BQ2FZ7M703hLpXK8GiBQ"
+ +"GEYpKaAuQZnMIpByoAAwCAYGKoUDAgIDA0EAgXMcTrhdOY2Er2tHOSAgnMezqrYxocZTWhxmW5Rl"
+ +"JY6lbXH5rndCn4swFzXU+YhgAsJv1wQBaoZEWRl5WV4/nA==");
+
+ private byte[] gost3410EC_B = Base64.decode(
+ "MIIBPTCB7QIBADCBgDENMAsGA1UEAxMEdGVzdDEWMBQGA1UEChMNRGVtb3MgQ28gTHRkLjEeMBwG"
+ +"A1UECxMVQ3J5cHRvZ3JhcGh5IGRpdmlzaW9uMQ8wDQYDVQQHEwZNb3Njb3cxCzAJBgNVBAYTAnJ1"
+ +"MRkwFwYJKoZIhvcNAQkBFgpzZGJAZG9sLnJ1MGMwHAYGKoUDAgITMBIGByqFAwICIwIGByqFAwIC"
+ +"HgEDQwAEQI5SLoWT7dZVilbV9j5B/fyIDuDs6x4pjqNC2TtFYbpRHrk/Wc5g/mcHvD80tsm5o1C7"
+ +"7cizNzkvAVUM4VT4Dz6gADAIBgYqhQMCAgMDQQAoT5TwJ8o+bSrxckymyo3diwG7ZbSytX4sRiKy"
+ +"wXPWRS9LlBvPO2NqwpS2HUnxSU8rzfL9fJcybATf7Yt1OEVq");
+
+ private byte[] gost3410EC_C = Base64.decode(
+ "MIIBRDCB9AIBADCBhzEVMBMGA1UEAxMMdGVzdCByZXF1ZXN0MRUwEwYDVQQKEwxEZW1vcyBDbyBM"
+ +"dGQxHjAcBgNVBAsTFUNyeXB0b2dyYXBoeSBkaXZpc2lvbjEPMA0GA1UEBxMGTW9zY293MQswCQYD"
+ +"VQQGEwJydTEZMBcGCSqGSIb3DQEJARYKc2RiQGRvbC5ydTBjMBwGBiqFAwICEzASBgcqhQMCAiMD"
+ +"BgcqhQMCAh4BA0MABEBcmGh7OmR4iqqj+ycYo1S1fS7r5PhisSQU2Ezuz8wmmmR2zeTZkdMYCOBa"
+ +"UTMNms0msW3wuYDho7nTDNscHTB5oAAwCAYGKoUDAgIDA0EAVoOMbfyo1Un4Ss7WQrUjHJoiaYW8"
+ +"Ime5LeGGU2iW3ieAv6es/FdMrwTKkqn5dhd3aL/itFg5oQbhyfXw5yw/QQ==");
+
+ private byte[] gost3410EC_ExA = Base64.decode(
+ "MIIBOzCB6wIBADB/MQ0wCwYDVQQDEwR0ZXN0MRUwEwYDVQQKEwxEZW1vcyBDbyBMdGQxHjAcBgNV"
+ + "BAsTFUNyeXB0b2dyYXBoeSBkaXZpc2lvbjEPMA0GA1UEBxMGTW9zY293MQswCQYDVQQGEwJydTEZ"
+ + "MBcGCSqGSIb3DQEJARYKc2RiQGRvbC5ydTBjMBwGBiqFAwICEzASBgcqhQMCAiQABgcqhQMCAh4B"
+ + "A0MABEDkqNT/3f8NHj6EUiWnK4JbVZBh31bEpkwq9z3jf0u8ZndG56Vt+K1ZB6EpFxLT7hSIos0w"
+ + "weZ2YuTZ4w43OgodoAAwCAYGKoUDAgIDA0EASk/IUXWxoi6NtcUGVF23VRV1L3undB4sRZLp4Vho"
+ + "gQ7m3CMbZFfJ2cPu6QyarseXGYHmazoirH5lGjEo535c1g==");
+
+ private byte[] gost3410EC_ExB = Base64.decode(
+ "MIIBPTCB7QIBADCBgDENMAsGA1UEAxMEdGVzdDEWMBQGA1UEChMNRGVtb3MgQ28gTHRkLjEeMBwG"
+ + "A1UECxMVQ3J5cHRvZ3JhcGh5IGRpdmlzaW9uMQ8wDQYDVQQHEwZNb3Njb3cxCzAJBgNVBAYTAnJ1"
+ + "MRkwFwYJKoZIhvcNAQkBFgpzZGJAZG9sLnJ1MGMwHAYGKoUDAgITMBIGByqFAwICJAEGByqFAwIC"
+ + "HgEDQwAEQMBWYUKPy/1Kxad9ChAmgoSWSYOQxRnXo7KEGLU5RNSXA4qMUvArWzvhav+EYUfTbWLh"
+ + "09nELDyHt2XQcvgQHnSgADAIBgYqhQMCAgMDQQAdaNhgH/ElHp64mbMaEo1tPCg9Q22McxpH8rCz"
+ + "E0QBpF4H5mSSQVGI5OAXHToetnNuh7gHHSynyCupYDEHTbkZ");
+
+ public String getName()
+ {
+ return "PKCS10CertRequest";
+ }
+
+ private void generationTest(int keySize, String keyName, String sigName, String provider)
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyName, "SC");
+
+ kpg.initialize(keySize);
+
+ KeyPair kp = kpg.genKeyPair();
+
+
+ X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE);
+
+ x500NameBld.addRDN(BCStyle.C, "AU");
+ x500NameBld.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ x500NameBld.addRDN(BCStyle.L, "Melbourne");
+ x500NameBld.addRDN(BCStyle.ST, "Victoria");
+ x500NameBld.addRDN(BCStyle.EmailAddress, "feedback-crypto@bouncycastle.org");
+
+ X500Name subject = x500NameBld.build();
+
+ PKCS10CertificationRequestBuilder requestBuilder = new JcaPKCS10CertificationRequestBuilder(subject, kp.getPublic());
+
+ PKCS10CertificationRequest req1 = requestBuilder.build(new JcaContentSignerBuilder(sigName).setProvider(provider).build(kp.getPrivate()));
+
+ JcaPKCS10CertificationRequest req2 = new JcaPKCS10CertificationRequest(req1.getEncoded()).setProvider(provider);
+
+ if (!req2.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(provider).build(kp.getPublic())))
+ {
+ fail(sigName + ": Failed verify check.");
+ }
+
+ if (!Arrays.areEqual(req2.getPublicKey().getEncoded(), req1.getSubjectPublicKeyInfo().getEncoded()))
+ {
+ fail(keyName + ": Failed public key check.");
+ }
+ }
+
+ private void generationTestX500Principal(int keySize, String keyName, String sigName, String provider)
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyName, "SC");
+
+ kpg.initialize(keySize);
+
+ KeyPair kp = kpg.genKeyPair();
+
+
+ X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE);
+
+ x500NameBld.addRDN(BCStyle.C, "AU");
+ x500NameBld.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ x500NameBld.addRDN(BCStyle.L, "Melbourne");
+ x500NameBld.addRDN(BCStyle.ST, "Victoria");
+ x500NameBld.addRDN(BCStyle.EmailAddress, "feedback-crypto@bouncycastle.org");
+
+ X500Name subject = x500NameBld.build();
+
+ PKCS10CertificationRequestBuilder requestBuilder = new JcaPKCS10CertificationRequestBuilder(new X500Principal(subject.getEncoded()), kp.getPublic());
+
+ PKCS10CertificationRequest req1 = requestBuilder.build(new JcaContentSignerBuilder(sigName).setProvider(provider).build(kp.getPrivate()));
+
+ JcaPKCS10CertificationRequest req2 = new JcaPKCS10CertificationRequest(req1.getEncoded()).setProvider(provider);
+
+ if (!req2.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(provider).build(kp.getPublic())))
+ {
+ fail(sigName + ": Failed verify check.");
+ }
+
+ if (!Arrays.areEqual(req2.getPublicKey().getEncoded(), req1.getSubjectPublicKeyInfo().getEncoded()))
+ {
+ fail(keyName + ": Failed public key check.");
+ }
+
+ if (!Arrays.areEqual(req2.getSubject().getEncoded(), req1.getSubject().getEncoded()))
+ {
+ fail(keyName + ": Failed subject key check.");
+ }
+ }
+
+ /*
+ * we generate a self signed certificate for the sake of testing - SHA224withECDSA
+ */
+ private void createECRequest(String algorithm, DERObjectIdentifier algOid, DERObjectIdentifier curveOid)
+ throws Exception
+ {
+ ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(curveOid.getId());
+ KeyPairGenerator ecGen = KeyPairGenerator.getInstance("ECDSA", "SC");
+
+ ecGen.initialize(spec);
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyPair pair = ecGen.generateKeyPair();
+
+ privKey = pair.getPrivate();
+ pubKey = pair.getPublic();
+
+ ContentSigner signer = new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey);
+
+ PKCS10CertificationRequestBuilder reqBuilder = new JcaPKCS10CertificationRequestBuilder(new X500Name("CN=XXX"), pubKey);
+ PKCS10CertificationRequest req = reqBuilder.build(signer);
+
+ ContentVerifierProvider verifier = new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey);
+
+ if (!req.isSignatureValid(verifier))
+ {
+ fail("Failed verify check EC.");
+ }
+
+ req = new PKCS10CertificationRequest(req.getEncoded());
+ if (!req.isSignatureValid(verifier))
+ {
+ fail("Failed verify check EC encoded.");
+ }
+
+ //
+ // try with point compression turned off
+ //
+ ((ECPointEncoder)pubKey).setPointFormat("UNCOMPRESSED");
+
+ reqBuilder = new JcaPKCS10CertificationRequestBuilder(new X500Name("CN=XXX"), pubKey);
+ req = reqBuilder.build(signer);
+
+ if (!req.isSignatureValid(verifier))
+ {
+ fail("Failed verify check EC uncompressed.");
+ }
+
+ req = new PKCS10CertificationRequest(req.getEncoded());
+ if (!req.isSignatureValid(verifier))
+ {
+ fail("Failed verify check EC uncompressed encoded.");
+ }
+
+ if (!req.toASN1Structure().getSignatureAlgorithm().getAlgorithm().equals(algOid))
+ {
+ fail("ECDSA oid incorrect.");
+ }
+
+ if (req.toASN1Structure().getSignatureAlgorithm().getParameters() != null)
+ {
+ fail("ECDSA parameters incorrect.");
+ }
+
+ Signature sig = Signature.getInstance(algorithm, "SC");
+
+ sig.initVerify(pubKey);
+
+ sig.update(req.toASN1Structure().getCertificationRequestInfo().getEncoded());
+
+ if (!sig.verify(req.toASN1Structure().getSignature().getBytes()))
+ {
+ fail("signature not mapped correctly.");
+ }
+ }
+
+ private void createECRequest(String algorithm, DERObjectIdentifier algOid)
+ throws Exception
+ {
+ ECCurve.Fp curve = new ECCurve.Fp(
+ new BigInteger("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"), // q (or p)
+ new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", 16), // a
+ new BigInteger("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", 16)); // b
+
+ ECParameterSpec spec = new ECParameterSpec(
+ curve,
+ curve.decodePoint(Hex.decode("0200C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")), // G
+ new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", 16)); // n
+
+ ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(
+ new BigInteger("5769183828869504557786041598510887460263120754767955773309066354712783118202294874205844512909370791582896372147797293913785865682804434049019366394746072023"), // d
+ spec);
+
+ ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(
+ curve.decodePoint(Hex.decode("02006BFDD2C9278B63C92D6624F151C9D7A822CC75BD983B17D25D74C26740380022D3D8FAF304781E416175EADF4ED6E2B47142D2454A7AC7801DD803CF44A4D1F0AC")), // Q
+ spec);
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory fact = KeyFactory.getInstance("ECDSA", "SC");
+
+ privKey = fact.generatePrivate(privKeySpec);
+ pubKey = fact.generatePublic(pubKeySpec);
+
+ PKCS10CertificationRequest req = new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("CN=XXX"), pubKey).build(new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey));
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("Failed verify check EC.");
+ }
+
+ req = new PKCS10CertificationRequest(req.getEncoded());
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("Failed verify check EC encoded.");
+ }
+
+ //
+ // try with point compression turned off
+ //
+ ((ECPointEncoder)pubKey).setPointFormat("UNCOMPRESSED");
+
+ req = new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("CN=XXX"), pubKey).build(new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey));
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("Failed verify check EC uncompressed.");
+ }
+
+ JcaPKCS10CertificationRequest jcaReq = new JcaPKCS10CertificationRequest(new PKCS10CertificationRequest(req.getEncoded()));
+ if (!jcaReq.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(jcaReq.getPublicKey())))
+ {
+ fail("Failed verify check EC uncompressed encoded.");
+ }
+
+ if (!jcaReq.getSignatureAlgorithm().getAlgorithm().equals(algOid))
+ {
+ fail("ECDSA oid incorrect.");
+ }
+
+ if (jcaReq.getSignatureAlgorithm().getParameters() != null)
+ {
+ fail("ECDSA parameters incorrect.");
+ }
+
+ Signature sig = Signature.getInstance(algorithm, BC);
+
+ sig.initVerify(pubKey);
+
+ sig.update(req.toASN1Structure().getCertificationRequestInfo().getEncoded());
+
+ if (!sig.verify(req.getSignature()))
+ {
+ fail("signature not mapped correctly.");
+ }
+ }
+
+ private void createECGOSTRequest()
+ throws Exception
+ {
+ String algorithm = "GOST3411withECGOST3410";
+ KeyPairGenerator ecGostKpg = KeyPairGenerator.getInstance("ECGOST3410", "SC");
+
+ ecGostKpg.initialize(ECGOST3410NamedCurveTable.getParameterSpec("GostR3410-2001-CryptoPro-A"), new SecureRandom());
+
+ //
+ // set up the keys
+ //
+ KeyPair pair = ecGostKpg.generateKeyPair();
+ PrivateKey privKey = pair.getPrivate();
+ PublicKey pubKey = pair.getPublic();
+
+ PKCS10CertificationRequest req = new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("CN=XXX"), pubKey).build(new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey));
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("Failed verify check EC.");
+ }
+
+ req = new PKCS10CertificationRequest(req.getEncoded());
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("Failed verify check EC encoded.");
+ }
+
+ if (!req.getSignatureAlgorithm().getAlgorithm().equals(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001))
+ {
+ fail("ECGOST oid incorrect.");
+ }
+
+ if (req.getSignatureAlgorithm().getParameters() != null)
+ {
+ fail("ECGOST parameters incorrect.");
+ }
+
+ Signature sig = Signature.getInstance(algorithm, "SC");
+
+ sig.initVerify(pubKey);
+
+ sig.update(req.toASN1Structure().getCertificationRequestInfo().getEncoded());
+
+ if (!sig.verify(req.getSignature()))
+ {
+ fail("signature not mapped correctly.");
+ }
+ }
+
+ private void createPSSTest(String algorithm)
+ throws Exception
+ {
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+ new BigInteger("010001",16));
+
+ RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec(
+ new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+ new BigInteger("010001",16),
+ new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16),
+ new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16),
+ new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16),
+ new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16),
+ new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16),
+ new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16));
+
+ KeyFactory fact = KeyFactory.getInstance("RSA", "SC");
+
+ PrivateKey privKey = fact.generatePrivate(privKeySpec);
+ PublicKey pubKey = fact.generatePublic(pubKeySpec);
+
+ PKCS10CertificationRequest req = new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("CN=XXX"), pubKey).build(new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey));
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("Failed verify check PSS.");
+ }
+
+ JcaPKCS10CertificationRequest jcaReq = new JcaPKCS10CertificationRequest(req.getEncoded()).setProvider(BC);
+ if (!jcaReq.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(jcaReq.getPublicKey())))
+ {
+ fail("Failed verify check PSS encoded.");
+ }
+
+ if (!jcaReq.getSignatureAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ fail("PSS oid incorrect.");
+ }
+
+ if (jcaReq.getSignatureAlgorithm().getParameters() == null)
+ {
+ fail("PSS parameters incorrect.");
+ }
+
+ Signature sig = Signature.getInstance(algorithm, "SC");
+
+ sig.initVerify(pubKey);
+
+ sig.update(jcaReq.toASN1Structure().getCertificationRequestInfo().getEncoded());
+
+ if (!sig.verify(req.getSignature()))
+ {
+ fail("signature not mapped correctly.");
+ }
+ }
+
+ // previous code found to cause a NullPointerException
+ private void nullPointerTest()
+ throws Exception
+ {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA", "SC");
+ keyGen.initialize(1024, new SecureRandom());
+ KeyPair pair = keyGen.generateKeyPair();
+ JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
+
+ Extension[] ext = new Extension[] {
+ new Extension(Extension.basicConstraints, true, new DEROctetString(new BasicConstraints(true))),
+ new Extension(Extension.keyUsage, true, new DEROctetString(new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign))),
+ new Extension(Extension.subjectKeyIdentifier, false, new DEROctetString(extUtils.createSubjectKeyIdentifier(pair.getPublic())))
+ };
+
+ PKCS10CertificationRequest p1 = new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("cn=csr"),
+ pair.getPublic())
+ .addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, new Extensions(ext))
+ .build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(pair.getPrivate()));
+ PKCS10CertificationRequest p2 = new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("cn=csr"),
+ pair.getPublic())
+ .addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, new Extensions(ext))
+ .build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(pair.getPrivate()));
+
+ if (!p1.equals(p2))
+ {
+ fail("cert request comparison failed");
+ }
+
+ Attribute[] attr1 = p1.getAttributes();
+ Attribute[] attr2 = p1.getAttributes();
+
+ checkAttrs(1, attr1, attr2);
+
+ attr1 = p1.getAttributes(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest);
+ attr2 = p1.getAttributes(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest);
+
+ checkAttrs(1, attr1, attr2);
+ }
+
+ private void checkAttrs(int expectedLength, Attribute[] attr1, Attribute[] attr2)
+ {
+ if (expectedLength != attr1.length)
+ {
+ fail("expected length mismatch");
+ }
+
+ if (attr1.length != attr2.length)
+ {
+ fail("atrribute length mismatch");
+ }
+
+ for (int i = 0; i != attr1.length; i++)
+ {
+ if (!attr1[i].equals(attr2[i]))
+ {
+ fail("atrribute mismatch");
+ }
+ }
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ generationTest(512, "RSA", "SHA1withRSA", "SC");
+ generationTestX500Principal(512, "RSA", "SHA1withRSA", "SC");
+ generationTest(512, "GOST3410", "GOST3411withGOST3410", "SC");
+
+ if (Security.getProvider("SunRsaSign") != null)
+ {
+ generationTest(512, "RSA", "SHA1withRSA", "SunRsaSign");
+ }
+
+ // elliptic curve GOST A parameter set
+ JcaPKCS10CertificationRequest req = new JcaPKCS10CertificationRequest(gost3410EC_A).setProvider(BC);
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(req.getPublicKey())))
+ {
+ fail("Failed verify check gost3410EC_A.");
+ }
+
+ // elliptic curve GOST B parameter set
+ req = new JcaPKCS10CertificationRequest(gost3410EC_B).setProvider(BC);
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(req.getPublicKey())))
+ {
+ fail("Failed verify check gost3410EC_B.");
+ }
+
+ // elliptic curve GOST C parameter set
+ req = new JcaPKCS10CertificationRequest(gost3410EC_C).setProvider(BC);
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(req.getPublicKey())))
+ {
+ fail("Failed verify check gost3410EC_C.");
+ }
+
+ // elliptic curve GOST ExA parameter set
+ req = new JcaPKCS10CertificationRequest(gost3410EC_ExA).setProvider(BC);
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(req.getPublicKey())))
+ {
+ fail("Failed verify check gost3410EC_ExA.");
+ }
+
+ // elliptic curve GOST ExB parameter set
+ req = new JcaPKCS10CertificationRequest(gost3410EC_ExB).setProvider(BC);
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(req.getPublicKey())))
+ {
+ fail("Failed verify check gost3410EC_ExA.");
+ }
+
+ // elliptic curve openSSL
+ KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "SC");
+
+ ECCurve curve = new ECCurve.Fp(
+ new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+ new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+ new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+
+ ECParameterSpec ecSpec = new ECParameterSpec(
+ curve,
+ curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+ new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n
+
+ g.initialize(ecSpec, new SecureRandom());
+
+ KeyPair kp = g.generateKeyPair();
+
+ req = new JcaPKCS10CertificationRequest(new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("CN=XXX"), kp.getPublic()).build(new JcaContentSignerBuilder( "ECDSAWITHSHA1").setProvider(BC).build(kp.getPrivate())));
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(req.getPublicKey())))
+ {
+ fail("Failed verify check EC.");
+ }
+
+ createECRequest("SHA1withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ createECRequest("SHA224withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ createECRequest("SHA256withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ createECRequest("SHA384withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ createECRequest("SHA512withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+
+ createECRequest("SHA1withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1, new DERObjectIdentifier("1.3.132.0.34"));
+
+ createECGOSTRequest();
+
+ createPSSTest("SHA1withRSAandMGF1");
+ createPSSTest("SHA224withRSAandMGF1");
+ createPSSTest("SHA256withRSAandMGF1");
+ createPSSTest("SHA384withRSAandMGF1");
+
+ nullPointerTest();
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new PKCS10Test());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/SHA1DigestCalculator.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/SHA1DigestCalculator.java
new file mode 100644
index 000000000..61bfe6e61
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/SHA1DigestCalculator.java
@@ -0,0 +1,44 @@
+package org.spongycastle.cert.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.operator.DigestCalculator;
+
+
+class SHA1DigestCalculator
+ implements DigestCalculator
+{
+ private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1);
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return bOut;
+ }
+
+ public byte[] getDigest()
+ {
+ byte[] bytes = bOut.toByteArray();
+
+ bOut.reset();
+
+ Digest sha1 = new SHA1Digest();
+
+ sha1.update(bytes, 0, bytes.length);
+
+ byte[] digest = new byte[sha1.getDigestSize()];
+
+ sha1.doFinal(digest, 0);
+
+ return digest;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/X509ExtensionUtilsTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/X509ExtensionUtilsTest.java
new file mode 100644
index 000000000..0b0730099
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cert/test/X509ExtensionUtilsTest.java
@@ -0,0 +1,55 @@
+package org.spongycastle.cert.test;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.X509ExtensionUtils;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.encoders.Hex;
+import org.spongycastle.util.test.SimpleTest;
+
+public class X509ExtensionUtilsTest
+ extends SimpleTest
+{
+ private static byte[] pubKeyInfo = Base64.decode(
+ "MFgwCwYJKoZIhvcNAQEBA0kAMEYCQQC6wMMmHYMZszT/7bNFMn+gaZoiWJLVP8ODRuu1C2jeAe" +
+ "QpxM+5Oe7PaN2GNy3nBE4EOYkB5pMJWA0y9n04FX8NAgED");
+
+ private static byte[] shaID = Hex.decode("d8128a06d6c2feb0865994a2936e7b75b836a021");
+ private static byte[] shaTruncID = Hex.decode("436e7b75b836a021");
+ private X509ExtensionUtils x509ExtensionUtils = new X509ExtensionUtils(new SHA1DigestCalculator());
+
+ public String getName()
+ {
+ return "X509ExtensionUtilsTest";
+ }
+
+ public void performTest()
+ throws IOException
+ {
+ SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pubKeyInfo));
+
+ SubjectKeyIdentifier ski = x509ExtensionUtils.createSubjectKeyIdentifier(pubInfo);
+
+ if (!Arrays.areEqual(shaID, ski.getKeyIdentifier()))
+ {
+ fail("SHA-1 ID does not match");
+ }
+
+ ski = x509ExtensionUtils.createTruncatedSubjectKeyIdentifier(pubInfo);
+
+ if (!Arrays.areEqual(shaTruncID, ski.getKeyIdentifier()))
+ {
+ fail("truncated SHA-1 ID does not match");
+ }
+ }
+
+ public static void main(
+ String[] args)
+ {
+ runTest(new X509ExtensionUtilsTest());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/AllTests.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/AllTests.java
new file mode 100644
index 000000000..7ef73a69f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/AllTests.java
@@ -0,0 +1,51 @@
+package org.spongycastle.cms.test;
+
+import javax.crypto.Cipher;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AllTests
+{
+ public static void main (String[] args)
+ throws Exception
+ {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ TestSuite suite = new TestSuite("CMS tests");
+
+ suite.addTest(NewCompressedDataTest.suite());
+ suite.addTest(NewSignedDataTest.suite());
+ suite.addTest(NewEnvelopedDataTest.suite());
+ suite.addTest(NewAuthenticatedDataTest.suite());
+ suite.addTest(NewAuthenticatedDataStreamTest.suite());
+ suite.addTest(NewCompressedDataStreamTest.suite());
+ suite.addTest(NewSignedDataStreamTest.suite());
+ suite.addTest(NewEnvelopedDataStreamTest.suite());
+
+ suite.addTest(MiscDataStreamTest.suite());
+ suite.addTest(Rfc4134Test.suite());
+ suite.addTest(ConverterTest.suite());
+
+ suite.addTest(BcEnvelopedDataTest.suite());
+ suite.addTest(BcSignedDataTest.suite());
+
+ try
+ {
+ Cipher.getInstance("RSA", "SunJCE");
+
+ suite.addTest(SunProviderTest.suite());
+ suite.addTest(NullProviderTest.suite());
+ }
+ catch (Exception e)
+ {
+ // ignore
+ }
+
+ return suite;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/BcEnvelopedDataTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/BcEnvelopedDataTest.java
new file mode 100644
index 000000000..c7dd42f5b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/BcEnvelopedDataTest.java
@@ -0,0 +1,969 @@
+package org.spongycastle.cms.test;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import javax.crypto.SecretKey;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.DERUTF8String;
+import org.spongycastle.asn1.cms.Attribute;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSEnvelopedData;
+import org.spongycastle.cms.CMSEnvelopedDataGenerator;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.KeyTransRecipientInformation;
+import org.spongycastle.cms.PasswordRecipient;
+import org.spongycastle.cms.PasswordRecipientInformation;
+import org.spongycastle.cms.RecipientId;
+import org.spongycastle.cms.RecipientInformation;
+import org.spongycastle.cms.RecipientInformationStore;
+import org.spongycastle.cms.SimpleAttributeTableGenerator;
+import org.spongycastle.cms.bc.BcCMSContentEncryptorBuilder;
+import org.spongycastle.cms.bc.BcKEKEnvelopedRecipient;
+import org.spongycastle.cms.bc.BcKEKRecipientInfoGenerator;
+import org.spongycastle.cms.bc.BcPasswordEnvelopedRecipient;
+import org.spongycastle.cms.bc.BcPasswordRecipientInfoGenerator;
+import org.spongycastle.cms.bc.BcRSAKeyTransEnvelopedRecipient;
+import org.spongycastle.cms.bc.BcRSAKeyTransRecipientInfoGenerator;
+import org.spongycastle.cms.jcajce.JceKeyAgreeEnvelopedRecipient;
+import org.spongycastle.cms.jcajce.JceKeyAgreeRecipientId;
+import org.spongycastle.cms.jcajce.JceKeyAgreeRecipientInfoGenerator;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.util.PrivateKeyFactory;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.OutputEncryptor;
+import org.spongycastle.operator.bc.BcAESSymmetricKeyUnwrapper;
+import org.spongycastle.operator.bc.BcAESSymmetricKeyWrapper;
+import org.spongycastle.operator.bc.BcSymmetricKeyUnwrapper;
+import org.spongycastle.operator.bc.BcSymmetricKeyWrapper;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.encoders.Hex;
+
+public class BcEnvelopedDataTest
+ extends TestCase
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ private static String _signDN;
+ private static KeyPair _signKP;
+ private static X509Certificate _signCert;
+
+ private static String _origDN;
+ private static KeyPair _origKP;
+ private static X509Certificate _origCert;
+
+ private static String _reciDN;
+ private static String _reciDN2;
+ private static KeyPair _reciKP;
+ private static X509Certificate _reciCert;
+
+ private static KeyPair _origEcKP;
+ private static KeyPair _reciEcKP;
+ private static X509Certificate _reciEcCert;
+ private static KeyPair _reciEcKP2;
+ private static X509Certificate _reciEcCert2;
+
+ private static boolean _initialised = false;
+
+ private byte[] oldKEK = Base64.decode(
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxQaI/MD0CAQQwBwQFAQIDBAUwDQYJYIZIAWUDBAEFBQAEI"
+ + "Fi2eHTPM4bQSjP4DUeDzJZLpfemW2gF1SPq7ZPHJi1mMIAGCSqGSIb3DQEHATAUBggqhkiG9w"
+ + "0DBwQImtdGyUdGGt6ggAQYk9X9z01YFBkU7IlS3wmsKpm/zpZClTceAAAAAAAAAAAAAA==");
+
+ private byte[] ecKeyAgreeMsgAES256 = Base64.decode(
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxgcShgcECAQOgQ6FBMAsGByqGSM49AgEF"
+ + "AAMyAAPdXlSTpub+qqno9hUGkUDl+S3/ABhPziIB5yGU4678tgOgU5CiKG9Z"
+ + "kfnabIJ3nZYwGgYJK4EFEIZIPwACMA0GCWCGSAFlAwQBLQUAMFswWTAtMCgx"
+ + "EzARBgNVBAMTCkFkbWluLU1EU0UxETAPBgNVBAoTCDRCQ1QtMklEAgEBBCi/"
+ + "rJRLbFwEVW6PcLLmojjW9lI/xGD7CfZzXrqXFw8iHaf3hTRau1gYMIAGCSqG"
+ + "SIb3DQEHATAdBglghkgBZQMEASoEEMtCnKKPwccmyrbgeSIlA3qggAQQDLw8"
+ + "pNJR97bPpj6baG99bQQQwhEDsoj5Xg1oOxojHVcYzAAAAAAAAAAAAAA=");
+
+ private byte[] ecKeyAgreeMsgAES128 = Base64.decode(
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxgbShgbECAQOgQ6FBMAsGByqGSM49AgEF"
+ + "AAMyAAL01JLEgKvKh5rbxI/hOxs/9WEezMIsAbUaZM4l5tn3CzXAN505nr5d"
+ + "LhrcurMK+tAwGgYJK4EFEIZIPwACMA0GCWCGSAFlAwQBBQUAMEswSTAtMCgx"
+ + "EzARBgNVBAMTCkFkbWluLU1EU0UxETAPBgNVBAoTCDRCQ1QtMklEAgEBBBhi"
+ + "FLjc5g6aqDT3f8LomljOwl1WTrplUT8wgAYJKoZIhvcNAQcBMB0GCWCGSAFl"
+ + "AwQBAgQQzXjms16Y69S/rB0EbHqRMaCABBAFmc/QdVW6LTKdEy97kaZzBBBa"
+ + "fQuviUS03NycpojELx0bAAAAAAAAAAAAAA==");
+
+ private byte[] ecKeyAgreeMsgDESEDE = Base64.decode(
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxgcahgcMCAQOgQ6FBMAsGByqGSM49AgEF"
+ + "AAMyAALIici6Nx1WN5f0ThH2A8ht9ovm0thpC5JK54t73E1RDzCifePaoQo0"
+ + "xd6sUqoyGaYwHAYJK4EFEIZIPwACMA8GCyqGSIb3DQEJEAMGBQAwWzBZMC0w"
+ + "KDETMBEGA1UEAxMKQWRtaW4tTURTRTERMA8GA1UEChMINEJDVC0ySUQCAQEE"
+ + "KJuqZQ1NB1vXrKPOnb4TCpYOsdm6GscWdwAAZlm2EHMp444j0s55J9wwgAYJ"
+ + "KoZIhvcNAQcBMBQGCCqGSIb3DQMHBAjwnsDMsafCrKCABBjyPvqFOVMKxxut"
+ + "VfTx4fQlNGJN8S2ATRgECMcTQ/dsmeViAAAAAAAAAAAAAA==");
+
+ private byte[] ecMQVKeyAgreeMsgAES128 = Base64.decode(
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxgf2hgfoCAQOgQ6FBMAsGByqGSM49AgEF"
+ + "AAMyAAPDKU+0H58tsjpoYmYCInMr/FayvCCkupebgsnpaGEB7qS9vzcNVUj6"
+ + "mrnmiC2grpmhRwRFMEMwQTALBgcqhkjOPQIBBQADMgACZpD13z9c7DzRWx6S"
+ + "0xdbq3S+EJ7vWO+YcHVjTD8NcQDcZcWASW899l1PkL936zsuMBoGCSuBBRCG"
+ + "SD8AEDANBglghkgBZQMEAQUFADBLMEkwLTAoMRMwEQYDVQQDEwpBZG1pbi1N"
+ + "RFNFMREwDwYDVQQKEwg0QkNULTJJRAIBAQQYFq58L71nyMK/70w3nc6zkkRy"
+ + "RL7DHmpZMIAGCSqGSIb3DQEHATAdBglghkgBZQMEAQIEEDzRUpreBsZXWHBe"
+ + "onxOtSmggAQQ7csAZXwT1lHUqoazoy8bhAQQq+9Zjj8iGdOWgyebbfj67QAA"
+ + "AAAAAAAAAAA=");
+
+
+ private byte[] ecKeyAgreeKey = Base64.decode(
+ "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDC8vp7xVTbKSgYVU5Wc"
+ + "hGkWbzaj+yUFETIWP1Dt7+WSpq3ikSPdl7PpHPqnPVZfoIWhZANiAgSYHTgxf+Dd"
+ + "Tt84dUvuSKkFy3RhjxJmjwIscK6zbEUzKhcPQG2GHzXhWK5x1kov0I74XpGhVkya"
+ + "ElH5K6SaOXiXAzcyNGggTOk4+ZFnz5Xl0pBje3zKxPhYu0SnCw7Pcqw=");
+
+ private byte[] bobPrivRsaEncrypt = Base64.decode(
+ "MIIChQIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKnhZ5g/OdVf"
+ + "8qCTQV6meYmFyDVdmpFb+x0B2hlwJhcPvaUi0DWFbXqYZhRBXM+3twg7CcmR"
+ + "uBlpN235ZR572akzJKN/O7uvRgGGNjQyywcDWVL8hYsxBLjMGAgUSOZPHPtd"
+ + "YMTgXB9T039T2GkB8QX4enDRvoPGXzjPHCyqaqfrAgMBAAECgYBnzUhMmg2P"
+ + "mMIbZf8ig5xt8KYGHbztpwOIlPIcaw+LNd4Ogngwy+e6alatd8brUXlweQqg"
+ + "9P5F4Kmy9Bnah5jWMIR05PxZbMHGd9ypkdB8MKCixQheIXFD/A0HPfD6bRSe"
+ + "TmPwF1h5HEuYHD09sBvf+iU7o8AsmAX2EAnYh9sDGQJBANDDIsbeopkYdo+N"
+ + "vKZ11mY/1I1FUox29XLE6/BGmvE+XKpVC5va3Wtt+Pw7PAhDk7Vb/s7q/WiE"
+ + "I2Kv8zHCueUCQQDQUfweIrdb7bWOAcjXq/JY1PeClPNTqBlFy2bKKBlf4hAr"
+ + "84/sajB0+E0R9KfEILVHIdxJAfkKICnwJAiEYH2PAkA0umTJSChXdNdVUN5q"
+ + "SO8bKlocSHseIVnDYDubl6nA7xhmqU5iUjiEzuUJiEiUacUgFJlaV/4jbOSn"
+ + "I3vQgLeFAkEAni+zN5r7CwZdV+EJBqRd2ZCWBgVfJAZAcpw6iIWchw+dYhKI"
+ + "FmioNRobQ+g4wJhprwMKSDIETukPj3d9NDAlBwJAVxhn1grStavCunrnVNqc"
+ + "BU+B1O8BiR4yPWnLMcRSyFRVJQA7HCp8JlDV6abXd8vPFfXuC9WN7rOvTKF8"
+ + "Y0ZB9qANMAsGA1UdDzEEAwIAEA==");
+
+ private byte[] rfc4134ex5_1 = Base64.decode(
+ "MIIBHgYJKoZIhvcNAQcDoIIBDzCCAQsCAQAxgcAwgb0CAQAwJjASMRAwDgYD"
+ + "VQQDEwdDYXJsUlNBAhBGNGvHgABWvBHTbi7NXXHQMA0GCSqGSIb3DQEBAQUA"
+ + "BIGAC3EN5nGIiJi2lsGPcP2iJ97a4e8kbKQz36zg6Z2i0yx6zYC4mZ7mX7FB"
+ + "s3IWg+f6KgCLx3M1eCbWx8+MDFbbpXadCDgO8/nUkUNYeNxJtuzubGgzoyEd"
+ + "8Ch4H/dd9gdzTd+taTEgS0ipdSJuNnkVY4/M652jKKHRLFf02hosdR8wQwYJ"
+ + "KoZIhvcNAQcBMBQGCCqGSIb3DQMHBAgtaMXpRwZRNYAgDsiSf8Z9P43LrY4O"
+ + "xUk660cu1lXeCSFOSOpOJ7FuVyU=");
+
+ private byte[] rfc4134ex5_2 = Base64.decode(
+ "MIIBZQYJKoZIhvcNAQcDoIIBVjCCAVICAQIxggEAMIG9AgEAMCYwEjEQMA4G"
+ + "A1UEAxMHQ2FybFJTQQIQRjRrx4AAVrwR024uzV1x0DANBgkqhkiG9w0BAQEF"
+ + "AASBgJQmQojGi7Z4IP+CVypBmNFoCDoEp87khtgyff2N4SmqD3RxPx+8hbLQ"
+ + "t9i3YcMwcap+aiOkyqjMalT03VUC0XBOGv+HYI3HBZm/aFzxoq+YOXAWs5xl"
+ + "GerZwTOc9j6AYlK4qXvnztR5SQ8TBjlzytm4V7zg+TGrnGVNQBNw47Ewoj4C"
+ + "AQQwDQQLTWFpbExpc3RSQzIwEAYLKoZIhvcNAQkQAwcCAToEGHcUr5MSJ/g9"
+ + "HnJVHsQ6X56VcwYb+OfojTBJBgkqhkiG9w0BBwEwGgYIKoZIhvcNAwIwDgIC"
+ + "AKAECJwE0hkuKlWhgCBeKNXhojuej3org9Lt7n+wWxOhnky5V50vSpoYRfRR"
+ + "yw==");
+
+ public BcEnvelopedDataTest()
+ {
+ }
+
+ private static void init()
+ throws Exception
+ {
+ if (!_initialised)
+ {
+ _initialised = true;
+
+ if (Security.getProvider(BC) == null)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ _signDN = "O=Bouncy Castle, C=AU";
+ _signKP = CMSTestUtil.makeKeyPair();
+ _signCert = CMSTestUtil.makeCertificate(_signKP, _signDN, _signKP, _signDN);
+
+ _origDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+ _origKP = CMSTestUtil.makeKeyPair();
+ _origCert = CMSTestUtil.makeCertificate(_origKP, _origDN, _signKP, _signDN);
+
+ _reciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+ _reciDN2 = "CN=Fred, OU=Sales, O=Bouncy Castle, C=AU";
+ _reciKP = CMSTestUtil.makeKeyPair();
+ _reciCert = CMSTestUtil.makeCertificate(_reciKP, _reciDN, _signKP, _signDN);
+
+ _origEcKP = CMSTestUtil.makeEcDsaKeyPair();
+ _reciEcKP = CMSTestUtil.makeEcDsaKeyPair();
+ _reciEcCert = CMSTestUtil.makeCertificate(_reciEcKP, _reciDN, _signKP, _signDN);
+ _reciEcKP2 = CMSTestUtil.makeEcDsaKeyPair();
+ _reciEcCert2 = CMSTestUtil.makeCertificate(_reciEcKP2, _reciDN2, _signKP, _signDN);
+ }
+ }
+
+ public static void main(
+ String args[])
+ throws Exception
+ {
+ junit.textui.TestRunner.run(BcEnvelopedDataTest.suite());
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ init();
+
+ return new CMSTestSetup(new TestSuite(BcEnvelopedDataTest.class));
+ }
+
+ public void testUnprotectedAttributes()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new BcRSAKeyTransRecipientInfoGenerator(new JcaX509CertificateHolder(_reciCert)));
+
+ Hashtable attrs = new Hashtable();
+
+ attrs.put(PKCSObjectIdentifiers.id_aa_contentHint, new Attribute(PKCSObjectIdentifiers.id_aa_contentHint, new DERSet(new DERUTF8String("Hint"))));
+ attrs.put(PKCSObjectIdentifiers.id_aa_receiptRequest, new Attribute(PKCSObjectIdentifiers.id_aa_receiptRequest, new DERSet(new DERUTF8String("Request"))));
+
+ AttributeTable attrTable = new AttributeTable(attrs);
+
+ edGen.setUnprotectedAttributeGenerator(new SimpleAttributeTableGenerator(attrTable));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new BcCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSAlgorithm.DES_EDE3_CBC.getId());
+
+ attrTable = ed.getUnprotectedAttributes();
+
+ assertEquals(attrs.size(), 2);
+
+ assertEquals(new DERUTF8String("Hint"), attrTable.get(PKCSObjectIdentifiers.id_aa_contentHint).getAttrValues().getObjectAt(0));
+ assertEquals(new DERUTF8String("Request"), attrTable.get(PKCSObjectIdentifiers.id_aa_receiptRequest).getAttrValues().getObjectAt(0));
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new BcRSAKeyTransEnvelopedRecipient(PrivateKeyFactory.createKey(_reciKP.getPrivate().getEncoded())));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ }
+
+ public void testKeyTrans()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new BcRSAKeyTransRecipientInfoGenerator(new JcaX509CertificateHolder(_reciCert)));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new BcCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSAlgorithm.DES_EDE3_CBC.getId());
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new BcRSAKeyTransEnvelopedRecipient(PrivateKeyFactory.createKey(PrivateKeyInfo.getInstance(_reciKP.getPrivate().getEncoded()))));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ }
+
+ public void testKeyTransRC4()
+ throws Exception
+ {
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new BcRSAKeyTransRecipientInfoGenerator(new JcaX509CertificateHolder(_reciCert)));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new BcCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.2.840.113549.3.4")).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), new ASN1ObjectIdentifier("1.2.840.113549.3.4").getId());
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new BcRSAKeyTransEnvelopedRecipient(PrivateKeyFactory.createKey(PrivateKeyInfo.getInstance(_reciKP.getPrivate().getEncoded()))));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ }
+
+ public void testKeyTrans128RC4()
+ throws Exception
+ {
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new BcRSAKeyTransRecipientInfoGenerator(new JcaX509CertificateHolder(_reciCert)));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new BcCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.2.840.113549.3.4"), 128).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), "1.2.840.113549.3.4");
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new BcRSAKeyTransEnvelopedRecipient(PrivateKeyFactory.createKey(PrivateKeyInfo.getInstance(_reciKP.getPrivate().getEncoded()))));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testKeyTransLight128RC4()
+ throws Exception
+ {
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new BcRSAKeyTransRecipientInfoGenerator(new JcaX509CertificateHolder(_reciCert)));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new BcCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.2.840.113549.3.4"), 128).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), "1.2.840.113549.3.4");
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new BcRSAKeyTransEnvelopedRecipient(PrivateKeyFactory.createKey(PrivateKeyInfo.getInstance(_reciKP.getPrivate().getEncoded()))));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testKeyTransODES()
+ throws Exception
+ {
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new BcRSAKeyTransRecipientInfoGenerator(new JcaX509CertificateHolder(_reciCert)));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new BcCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.3.14.3.2.7")).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), "1.3.14.3.2.7");
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new BcRSAKeyTransEnvelopedRecipient(PrivateKeyFactory.createKey(PrivateKeyInfo.getInstance(_reciKP.getPrivate().getEncoded()))));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testKeyTransSmallAES()
+ throws Exception
+ {
+ byte[] data = new byte[] { 0, 1, 2, 3 };
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new BcRSAKeyTransRecipientInfoGenerator(new JcaX509CertificateHolder(_reciCert)));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new BcCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(),
+ CMSAlgorithm.AES128_CBC.getId());
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new BcRSAKeyTransEnvelopedRecipient(PrivateKeyFactory.createKey(PrivateKeyInfo.getInstance(_reciKP.getPrivate().getEncoded()))));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testKeyTransAES128()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.AES128_CBC, NISTObjectIdentifiers.id_aes128_CBC, 16, DEROctetString.class);
+ }
+
+ public void testKeyTransAES192()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.AES192_CBC, NISTObjectIdentifiers.id_aes192_CBC, 24, DEROctetString.class);
+ }
+
+ public void testKeyTransAES256()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.AES256_CBC, NISTObjectIdentifiers.id_aes256_CBC, 32, DEROctetString.class);
+ }
+
+ private void tryKeyTrans(ASN1ObjectIdentifier generatorOID, ASN1ObjectIdentifier checkOID, int keySize, Class asn1Params)
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new BcRSAKeyTransRecipientInfoGenerator(new JcaX509CertificateHolder(_reciCert)));
+
+ OutputEncryptor encryptor = new BcCMSContentEncryptorBuilder(generatorOID).build();
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data), encryptor);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(checkOID.getId(), ed.getEncryptionAlgOID());
+ assertEquals(keySize, ((byte[])encryptor.getKey().getRepresentation()).length);
+
+ if (asn1Params != null)
+ {
+ assertTrue(asn1Params.isAssignableFrom(ed.getContentEncryptionAlgorithm().getParameters().toASN1Primitive().getClass()));
+ }
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ if (!it.hasNext())
+ {
+ fail("no recipients found");
+ }
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new BcRSAKeyTransEnvelopedRecipient(PrivateKeyFactory.createKey(PrivateKeyInfo.getInstance(_reciKP.getPrivate().getEncoded()))));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ }
+
+ public void testAES128KEK()
+ throws Exception
+ {
+ SecretKey key = CMSTestUtil.makeAESKey(128);
+
+ tryKekAlgorithm(new BcAESSymmetricKeyWrapper(new KeyParameter(key.getEncoded())), new BcAESSymmetricKeyUnwrapper(new KeyParameter(key.getEncoded())), NISTObjectIdentifiers.id_aes128_wrap);
+ }
+
+ public void testAES192KEK()
+ throws Exception
+ {
+ SecretKey key = CMSTestUtil.makeAESKey(192);
+
+ tryKekAlgorithm(new BcAESSymmetricKeyWrapper(new KeyParameter(key.getEncoded())), new BcAESSymmetricKeyUnwrapper(new KeyParameter(key.getEncoded())), NISTObjectIdentifiers.id_aes192_wrap);
+ }
+
+ public void testAES256KEK()
+ throws Exception
+ {
+ SecretKey key = CMSTestUtil.makeAESKey(256);
+
+ tryKekAlgorithm(new BcAESSymmetricKeyWrapper(new KeyParameter(key.getEncoded())), new BcAESSymmetricKeyUnwrapper(new KeyParameter(key.getEncoded())), NISTObjectIdentifiers.id_aes256_wrap);
+ }
+
+ private void tryKekAlgorithm(BcSymmetricKeyWrapper kekWrapper, BcSymmetricKeyUnwrapper kekUnwrapper, ASN1ObjectIdentifier algOid)
+ throws NoSuchAlgorithmException, NoSuchProviderException, CMSException
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ byte[] kekId = new byte[] { 1, 2, 3, 4, 5 };
+
+ edGen.addRecipientInfoGenerator(new BcKEKRecipientInfoGenerator(kekId, kekWrapper));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new BcCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSAlgorithm.DES_EDE3_CBC.getId());
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(algOid.getId(), recipient.getKeyEncryptionAlgOID());
+
+ byte[] recData = recipient.getContent(new BcKEKEnvelopedRecipient(kekUnwrapper));
+
+ assertTrue(Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testECKeyAgree()
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyAgreeRecipientInfoGenerator(CMSAlgorithm.ECDH_SHA1KDF,
+ _origEcKP.getPrivate(), _origEcKP.getPublic(),
+ CMSAlgorithm.AES128_WRAP).addRecipient(_reciEcCert).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new BcCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).build());
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSAlgorithm.AES128_CBC.getId());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ confirmDataReceived(recipients, data, _reciEcCert, _reciEcKP.getPrivate(), BC);
+ confirmNumberRecipients(recipients, 1);
+ }
+
+ public void testECMQVKeyAgree()
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyAgreeRecipientInfoGenerator(CMSAlgorithm.ECMQV_SHA1KDF,
+ _origEcKP.getPrivate(), _origEcKP.getPublic(),
+ CMSAlgorithm.AES128_WRAP).addRecipient(_reciEcCert).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new BcCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).build());
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSAlgorithm.AES128_CBC.getId());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ confirmDataReceived(recipients, data, _reciEcCert, _reciEcKP.getPrivate(), BC);
+ confirmNumberRecipients(recipients, 1);
+ }
+
+ public void testECMQVKeyAgreeMultiple()
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ JceKeyAgreeRecipientInfoGenerator recipientGenerator = new JceKeyAgreeRecipientInfoGenerator(CMSAlgorithm.ECMQV_SHA1KDF,
+ _origEcKP.getPrivate(), _origEcKP.getPublic(), CMSAlgorithm.AES128_WRAP).setProvider(BC);
+
+ recipientGenerator.addRecipient(_reciEcCert);
+ recipientGenerator.addRecipient(_reciEcCert2);
+
+ edGen.addRecipientInfoGenerator(recipientGenerator);
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new BcCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).build());
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSAlgorithm.AES128_CBC.getId());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ confirmDataReceived(recipients, data, _reciEcCert, _reciEcKP.getPrivate(), BC);
+ confirmDataReceived(recipients, data, _reciEcCert2, _reciEcKP2.getPrivate(), BC);
+ confirmNumberRecipients(recipients, 2);
+ }
+
+ private static void confirmDataReceived(RecipientInformationStore recipients,
+ byte[] expectedData, X509Certificate reciCert, PrivateKey reciPrivKey, String provider)
+ throws CMSException, NoSuchProviderException, CertificateEncodingException, IOException
+ {
+ RecipientId rid = new JceKeyAgreeRecipientId(reciCert);
+
+ RecipientInformation recipient = recipients.get(rid);
+ assertNotNull(recipient);
+
+ byte[] actualData = recipient.getContent(new JceKeyAgreeEnvelopedRecipient(reciPrivKey).setProvider(provider));
+ assertEquals(true, Arrays.equals(expectedData, actualData));
+ }
+
+ private static void confirmNumberRecipients(RecipientInformationStore recipients, int count)
+ {
+ assertEquals(count, recipients.getRecipients().size());
+ }
+
+ public void testECKeyAgreeVectors()
+ throws Exception
+ {
+ PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(ecKeyAgreeKey);
+ KeyFactory fact = KeyFactory.getInstance("ECDH", BC);
+ PrivateKey privKey = fact.generatePrivate(privSpec);
+
+ verifyECKeyAgreeVectors(privKey, "2.16.840.1.101.3.4.1.42", ecKeyAgreeMsgAES256);
+ verifyECKeyAgreeVectors(privKey, "2.16.840.1.101.3.4.1.2", ecKeyAgreeMsgAES128);
+ verifyECKeyAgreeVectors(privKey, "1.2.840.113549.3.7", ecKeyAgreeMsgDESEDE);
+ }
+
+ public void testECMQVKeyAgreeVectors()
+ throws Exception
+ {
+ PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(ecKeyAgreeKey);
+ KeyFactory fact = KeyFactory.getInstance("ECDH", BC);
+ PrivateKey privKey = fact.generatePrivate(privSpec);
+
+ verifyECMQVKeyAgreeVectors(privKey, "2.16.840.1.101.3.4.1.2", ecMQVKeyAgreeMsgAES128);
+ }
+
+ public void testPasswordAES256()
+ throws Exception
+ {
+ passwordTest(CMSAlgorithm.AES256_CBC);
+ passwordUTF8Test(CMSAlgorithm.AES256_CBC);
+ }
+
+ public void testPasswordDESEDE()
+ throws Exception
+ {
+ passwordTest(CMSAlgorithm.DES_EDE3_CBC);
+ passwordUTF8Test(CMSAlgorithm.DES_EDE3_CBC);
+ }
+
+ public void testRFC4134ex5_1()
+ throws Exception
+ {
+ byte[] data = Hex.decode("5468697320697320736f6d652073616d706c6520636f6e74656e742e");
+
+ KeyFactory kFact = KeyFactory.getInstance("RSA", BC);
+ Key key = kFact.generatePrivate(new PKCS8EncodedKeySpec(bobPrivRsaEncrypt));
+
+ CMSEnvelopedData ed = new CMSEnvelopedData(rfc4134ex5_1);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals("1.2.840.113549.3.7", ed.getEncryptionAlgOID());
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new BcRSAKeyTransEnvelopedRecipient(PrivateKeyFactory.createKey(PrivateKeyInfo.getInstance(key.getEncoded()))));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testRFC4134ex5_2()
+ throws Exception
+ {
+ byte[] data = Hex.decode("5468697320697320736f6d652073616d706c6520636f6e74656e742e");
+
+ KeyFactory kFact = KeyFactory.getInstance("RSA", BC);
+ PrivateKey key = kFact.generatePrivate(new PKCS8EncodedKeySpec(bobPrivRsaEncrypt));
+
+ CMSEnvelopedData ed = new CMSEnvelopedData(rfc4134ex5_2);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals("1.2.840.113549.3.2", ed.getEncryptionAlgOID());
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+ byte[] recData;
+
+ if (recipient instanceof KeyTransRecipientInformation)
+ {
+ recData = recipient.getContent(new BcRSAKeyTransEnvelopedRecipient(PrivateKeyFactory.createKey(PrivateKeyInfo.getInstance(key.getEncoded()))));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ }
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testOriginatorInfo()
+ throws Exception
+ {
+ CMSEnvelopedData env = new CMSEnvelopedData(CMSSampleMessages.originatorMessage);
+
+ RecipientInformationStore recipients = env.getRecipientInfos();
+
+ assertEquals(CMSAlgorithm.DES_EDE3_CBC.getId(), env.getEncryptionAlgOID());
+ }
+
+ private void passwordTest(ASN1ObjectIdentifier algorithm)
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new BcPasswordRecipientInfoGenerator(algorithm, "password".toCharArray()).setPasswordConversionScheme(PasswordRecipient.PKCS5_SCHEME2).setSaltAndIterationCount(new byte[20], 5));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new BcCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(),
+ CMSAlgorithm.AES128_CBC.getId());
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ PasswordRecipientInformation recipient = (PasswordRecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new BcPasswordEnvelopedRecipient("password".toCharArray()).setPasswordConversionScheme(PasswordRecipient.PKCS5_SCHEME2));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+
+ //
+ // try algorithm parameters constructor
+ //
+ it = c.iterator();
+
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new BcPasswordEnvelopedRecipient("password".toCharArray()).setPasswordConversionScheme(PasswordRecipient.PKCS5_SCHEME2));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+
+ private void passwordUTF8Test(ASN1ObjectIdentifier algorithm)
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new BcPasswordRecipientInfoGenerator(algorithm, "abc\u5639\u563b".toCharArray()).setSaltAndIterationCount(new byte[20], 5));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new BcCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(),
+ CMSAlgorithm.AES128_CBC.getId());
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new BcPasswordEnvelopedRecipient("abc\u5639\u563b".toCharArray()));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+
+ //
+ // try algorithm parameters constructor
+ //
+ it = c.iterator();
+
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new BcPasswordEnvelopedRecipient("abc\u5639\u563b".toCharArray()));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+
+ private void verifyECKeyAgreeVectors(PrivateKey privKey, String wrapAlg, byte[] message)
+ throws CMSException, GeneralSecurityException
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedData ed = new CMSEnvelopedData(message);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ assertEquals(wrapAlg, ed.getEncryptionAlgOID());
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals("1.3.133.16.840.63.0.2", recipient.getKeyEncryptionAlgOID());
+
+ byte[] recData = recipient.getContent(new JceKeyAgreeEnvelopedRecipient(privKey).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ private void verifyECMQVKeyAgreeVectors(PrivateKey privKey, String wrapAlg, byte[] message)
+ throws CMSException, GeneralSecurityException
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedData ed = new CMSEnvelopedData(message);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ assertEquals(wrapAlg, ed.getEncryptionAlgOID());
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals("1.3.133.16.840.63.0.16", recipient.getKeyEncryptionAlgOID());
+
+ byte[] recData = recipient.getContent(new JceKeyAgreeEnvelopedRecipient(privKey).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/BcSignedDataTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/BcSignedDataTest.java
new file mode 100644
index 000000000..e2782ba6a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/BcSignedDataTest.java
@@ -0,0 +1,1835 @@
+package org.spongycastle.cms.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.MessageDigest;
+import java.security.Security;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.cms.Attribute;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSAttributes;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.jcajce.JcaCRLStore;
+import org.spongycastle.cert.jcajce.JcaCertStore;
+import org.spongycastle.cert.jcajce.JcaX509CRLHolder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.cms.CMSAbsentContent;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.CMSSignedData;
+import org.spongycastle.cms.CMSSignedDataGenerator;
+import org.spongycastle.cms.CMSSignedDataParser;
+import org.spongycastle.cms.CMSTypedData;
+import org.spongycastle.cms.DefaultCMSSignatureAlgorithmNameGenerator;
+import org.spongycastle.cms.DefaultSignedAttributeTableGenerator;
+import org.spongycastle.cms.SignerId;
+import org.spongycastle.cms.SignerInfoGeneratorBuilder;
+import org.spongycastle.cms.SignerInformation;
+import org.spongycastle.cms.SignerInformationStore;
+import org.spongycastle.cms.bc.BcRSASignerInfoVerifierBuilder;
+import org.spongycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
+import org.spongycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder;
+import org.spongycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.util.PrivateKeyFactory;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.BufferingContentSigner;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.bc.BcContentSignerBuilder;
+import org.spongycastle.operator.bc.BcDigestCalculatorProvider;
+import org.spongycastle.operator.bc.BcRSAContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.spongycastle.util.CollectionStore;
+import org.spongycastle.util.Store;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.io.Streams;
+
+public class BcSignedDataTest
+ extends TestCase
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ boolean DEBUG = true;
+
+ private static String _origDN;
+ private static KeyPair _origKP;
+ private static X509Certificate _origCert;
+
+ private static String _signDN;
+ private static KeyPair _signKP;
+ private static X509Certificate _signCert;
+
+ private static KeyPair _signEcDsaKP;
+ private static X509Certificate _signEcDsaCert;
+
+ private static KeyPair _signEcGostKP;
+ private static X509Certificate _signEcGostCert;
+
+ private static KeyPair _signDsaKP;
+ private static X509Certificate _signDsaCert;
+
+ private static String _reciDN;
+ private static KeyPair _reciKP;
+ private static X509Certificate _reciCert;
+
+ private static X509CRL _signCrl;
+
+ private static boolean _initialised = false;
+
+ private byte[] disorderedMessage = Base64.decode(
+ "SU9fc3RkaW5fdXNlZABfX2xpYmNfc3RhcnRfbWFpbgBnZXRob3N0aWQAX19n"
+ + "bW9uX3M=");
+
+ private byte[] disorderedSet = Base64.decode(
+ "MIIYXQYJKoZIhvcNAQcCoIIYTjCCGEoCAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+ + "SIb3DQEHAaCCFqswggJUMIIBwKADAgECAgMMg6wwCgYGKyQDAwECBQAwbzEL"
+ + "MAkGA1UEBhMCREUxPTA7BgNVBAoUNFJlZ3VsaWVydW5nc2JlaMhvcmRlIGbI"
+ + "dXIgVGVsZWtvbW11bmlrYXRpb24gdW5kIFBvc3QxITAMBgcCggYBCgcUEwEx"
+ + "MBEGA1UEAxQKNFItQ0EgMTpQTjAiGA8yMDAwMDMyMjA5NDM1MFoYDzIwMDQw"
+ + "MTIxMTYwNDUzWjBvMQswCQYDVQQGEwJERTE9MDsGA1UEChQ0UmVndWxpZXJ1"
+ + "bmdzYmVoyG9yZGUgZsh1ciBUZWxla29tbXVuaWthdGlvbiB1bmQgUG9zdDEh"
+ + "MAwGBwKCBgEKBxQTATEwEQYDVQQDFAo1Ui1DQSAxOlBOMIGhMA0GCSqGSIb3"
+ + "DQEBAQUAA4GPADCBiwKBgQCKHkFTJx8GmoqFTxEOxpK9XkC3NZ5dBEKiUv0I"
+ + "fe3QMqeGMoCUnyJxwW0k2/53duHxtv2yHSZpFKjrjvE/uGwdOMqBMTjMzkFg"
+ + "19e9JPv061wyADOucOIaNAgha/zFt9XUyrHF21knKCvDNExv2MYIAagkTKaj"
+ + "LMAw0bu1J0FadQIFAMAAAAEwCgYGKyQDAwECBQADgYEAgFauXpoTLh3Z3pT/"
+ + "3bhgrxO/2gKGZopWGSWSJPNwq/U3x2EuctOJurj+y2inTcJjespThflpN+7Q"
+ + "nvsUhXU+jL2MtPlObU0GmLvWbi47cBShJ7KElcZAaxgWMBzdRGqTOdtMv+ev"
+ + "2t4igGF/q71xf6J2c3pTLWr6P8s6tzLfOCMwggJDMIIBr6ADAgECAgQAuzyu"
+ + "MAoGBiskAwMBAgUAMG8xCzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1bGll"
+ + "cnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0"
+ + "MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjVSLUNBIDE6UE4wIhgPMjAwMTA4"
+ + "MjAwODA4MjBaGA8yMDA1MDgyMDA4MDgyMFowSzELMAkGA1UEBhMCREUxEjAQ"
+ + "BgNVBAoUCVNpZ250cnVzdDEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFDQSBT"
+ + "SUdOVFJVU1QgMTpQTjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAhV12"
+ + "N2WhlR6f+3CXP57GrBM9la5Vnsu2b92zv5MZqQOPeEsYbZqDCFkYg1bSwsDE"
+ + "XsGVQqXdQNAGUaapr/EUVVN+hNZ07GcmC1sPeQECgUkxDYjGi4ihbvzxlahj"
+ + "L4nX+UTzJVBfJwXoIvJ+lMHOSpnOLIuEL3SRhBItvRECxN0CAwEAAaMSMBAw"
+ + "DgYDVR0PAQH/BAQDAgEGMAoGBiskAwMBAgUAA4GBACDc9Pc6X8sK1cerphiV"
+ + "LfFv4kpZb9ev4WPy/C6987Qw1SOTElhZAmxaJQBqmDHWlQ63wj1DEqswk7hG"
+ + "LrvQk/iX6KXIn8e64uit7kx6DHGRKNvNGofPjr1WelGeGW/T2ZJKgmPDjCkf"
+ + "sIKt2c3gwa2pDn4mmCz/DStUIqcPDbqLMIICVTCCAcGgAwIBAgIEAJ16STAK"
+ + "BgYrJAMDAQIFADBvMQswCQYDVQQGEwJERTE9MDsGA1UEChQ0UmVndWxpZXJ1"
+ + "bmdzYmVoyG9yZGUgZsh1ciBUZWxla29tbXVuaWthdGlvbiB1bmQgUG9zdDEh"
+ + "MAwGBwKCBgEKBxQTATEwEQYDVQQDFAo1Ui1DQSAxOlBOMCIYDzIwMDEwMjAx"
+ + "MTM0NDI1WhgPMjAwNTAzMjIwODU1NTFaMG8xCzAJBgNVBAYTAkRFMT0wOwYD"
+ + "VQQKFDRSZWd1bGllcnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5pa2F0"
+ + "aW9uIHVuZCBQb3N0MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjZSLUNhIDE6"
+ + "UE4wgaEwDQYJKoZIhvcNAQEBBQADgY8AMIGLAoGBAIOiqxUkzVyqnvthihnl"
+ + "tsE5m1Xn5TZKeR/2MQPStc5hJ+V4yptEtIx+Fn5rOoqT5VEVWhcE35wdbPvg"
+ + "JyQFn5msmhPQT/6XSGOlrWRoFummXN9lQzAjCj1sgTcmoLCVQ5s5WpCAOXFw"
+ + "VWu16qndz3sPItn3jJ0F3Kh3w79NglvPAgUAwAAAATAKBgYrJAMDAQIFAAOB"
+ + "gQBpSRdnDb6AcNVaXSmGo6+kVPIBhot1LzJOGaPyDNpGXxd7LV4tMBF1U7gr"
+ + "4k1g9BO6YiMWvw9uiTZmn0CfV8+k4fWEuG/nmafRoGIuay2f+ILuT+C0rnp1"
+ + "4FgMsEhuVNJJAmb12QV0PZII+UneyhAneZuQQzVUkTcVgYxogxdSOzCCAlUw"
+ + "ggHBoAMCAQICBACdekowCgYGKyQDAwECBQAwbzELMAkGA1UEBhMCREUxPTA7"
+ + "BgNVBAoUNFJlZ3VsaWVydW5nc2JlaMhvcmRlIGbIdXIgVGVsZWtvbW11bmlr"
+ + "YXRpb24gdW5kIFBvc3QxITAMBgcCggYBCgcUEwExMBEGA1UEAxQKNlItQ2Eg"
+ + "MTpQTjAiGA8yMDAxMDIwMTEzNDcwN1oYDzIwMDUwMzIyMDg1NTUxWjBvMQsw"
+ + "CQYDVQQGEwJERTE9MDsGA1UEChQ0UmVndWxpZXJ1bmdzYmVoyG9yZGUgZsh1"
+ + "ciBUZWxla29tbXVuaWthdGlvbiB1bmQgUG9zdDEhMAwGBwKCBgEKBxQTATEw"
+ + "EQYDVQQDFAo1Ui1DQSAxOlBOMIGhMA0GCSqGSIb3DQEBAQUAA4GPADCBiwKB"
+ + "gQCKHkFTJx8GmoqFTxEOxpK9XkC3NZ5dBEKiUv0Ife3QMqeGMoCUnyJxwW0k"
+ + "2/53duHxtv2yHSZpFKjrjvE/uGwdOMqBMTjMzkFg19e9JPv061wyADOucOIa"
+ + "NAgha/zFt9XUyrHF21knKCvDNExv2MYIAagkTKajLMAw0bu1J0FadQIFAMAA"
+ + "AAEwCgYGKyQDAwECBQADgYEAV1yTi+2gyB7sUhn4PXmi/tmBxAfe5oBjDW8m"
+ + "gxtfudxKGZ6l/FUPNcrSc5oqBYxKWtLmf3XX87LcblYsch617jtNTkMzhx9e"
+ + "qxiD02ufcrxz2EVt0Akdqiz8mdVeqp3oLcNU/IttpSrcA91CAnoUXtDZYwb/"
+ + "gdQ4FI9l3+qo/0UwggJVMIIBwaADAgECAgQAxIymMAoGBiskAwMBAgUAMG8x"
+ + "CzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1bGllcnVuZ3NiZWjIb3JkZSBm"
+ + "yHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0MSEwDAYHAoIGAQoHFBMB"
+ + "MTARBgNVBAMUCjZSLUNhIDE6UE4wIhgPMjAwMTEwMTUxMzMxNThaGA8yMDA1"
+ + "MDYwMTA5NTIxN1owbzELMAkGA1UEBhMCREUxPTA7BgNVBAoUNFJlZ3VsaWVy"
+ + "dW5nc2JlaMhvcmRlIGbIdXIgVGVsZWtvbW11bmlrYXRpb24gdW5kIFBvc3Qx"
+ + "ITAMBgcCggYBCgcUEwExMBEGA1UEAxQKN1ItQ0EgMTpQTjCBoTANBgkqhkiG"
+ + "9w0BAQEFAAOBjwAwgYsCgYEAiokD/j6lEP4FexF356OpU5teUpGGfUKjIrFX"
+ + "BHc79G0TUzgVxqMoN1PWnWktQvKo8ETaugxLkP9/zfX3aAQzDW4Zki6x6GDq"
+ + "fy09Agk+RJvhfbbIzRkV4sBBco0n73x7TfG/9NTgVr/96U+I+z/1j30aboM6"
+ + "9OkLEhjxAr0/GbsCBQDAAAABMAoGBiskAwMBAgUAA4GBAHWRqRixt+EuqHhR"
+ + "K1kIxKGZL2vZuakYV0R24Gv/0ZR52FE4ECr+I49o8FP1qiGSwnXB0SwjuH2S"
+ + "iGiSJi+iH/MeY85IHwW1P5e+bOMvEOFhZhQXQixOD7totIoFtdyaj1XGYRef"
+ + "0f2cPOjNJorXHGV8wuBk+/j++sxbd/Net3FtMIICVTCCAcGgAwIBAgIEAMSM"
+ + "pzAKBgYrJAMDAQIFADBvMQswCQYDVQQGEwJERTE9MDsGA1UEChQ0UmVndWxp"
+ + "ZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxla29tbXVuaWthdGlvbiB1bmQgUG9z"
+ + "dDEhMAwGBwKCBgEKBxQTATEwEQYDVQQDFAo3Ui1DQSAxOlBOMCIYDzIwMDEx"
+ + "MDE1MTMzNDE0WhgPMjAwNTA2MDEwOTUyMTdaMG8xCzAJBgNVBAYTAkRFMT0w"
+ + "OwYDVQQKFDRSZWd1bGllcnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5p"
+ + "a2F0aW9uIHVuZCBQb3N0MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjZSLUNh"
+ + "IDE6UE4wgaEwDQYJKoZIhvcNAQEBBQADgY8AMIGLAoGBAIOiqxUkzVyqnvth"
+ + "ihnltsE5m1Xn5TZKeR/2MQPStc5hJ+V4yptEtIx+Fn5rOoqT5VEVWhcE35wd"
+ + "bPvgJyQFn5msmhPQT/6XSGOlrWRoFummXN9lQzAjCj1sgTcmoLCVQ5s5WpCA"
+ + "OXFwVWu16qndz3sPItn3jJ0F3Kh3w79NglvPAgUAwAAAATAKBgYrJAMDAQIF"
+ + "AAOBgQBi5W96UVDoNIRkCncqr1LLG9vF9SGBIkvFpLDIIbcvp+CXhlvsdCJl"
+ + "0pt2QEPSDl4cmpOet+CxJTdTuMeBNXxhb7Dvualog69w/+K2JbPhZYxuVFZs"
+ + "Zh5BkPn2FnbNu3YbJhE60aIkikr72J4XZsI5DxpZCGh6xyV/YPRdKSljFjCC"
+ + "AlQwggHAoAMCAQICAwyDqzAKBgYrJAMDAQIFADBvMQswCQYDVQQGEwJERTE9"
+ + "MDsGA1UEChQ0UmVndWxpZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxla29tbXVu"
+ + "aWthdGlvbiB1bmQgUG9zdDEhMAwGBwKCBgEKBxQTATEwEQYDVQQDFAo1Ui1D"
+ + "QSAxOlBOMCIYDzIwMDAwMzIyMDk0MTI3WhgPMjAwNDAxMjExNjA0NTNaMG8x"
+ + "CzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1bGllcnVuZ3NiZWjIb3JkZSBm"
+ + "yHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0MSEwDAYHAoIGAQoHFBMB"
+ + "MTARBgNVBAMUCjRSLUNBIDE6UE4wgaEwDQYJKoZIhvcNAQEBBQADgY8AMIGL"
+ + "AoGBAI8x26tmrFJanlm100B7KGlRemCD1R93PwdnG7svRyf5ZxOsdGrDszNg"
+ + "xg6ouO8ZHQMT3NC2dH8TvO65Js+8bIyTm51azF6clEg0qeWNMKiiXbBXa+ph"
+ + "hTkGbXiLYvACZ6/MTJMJ1lcrjpRF7BXtYeYMcEF6znD4pxOqrtbf9z5hAgUA"
+ + "wAAAATAKBgYrJAMDAQIFAAOBgQB99BjSKlGPbMLQAgXlvA9jUsDNhpnVm3a1"
+ + "YkfxSqS/dbQlYkbOKvCxkPGA9NBxisBM8l1zFynVjJoy++aysRmcnLY/sHaz"
+ + "23BF2iU7WERy18H3lMBfYB6sXkfYiZtvQZcWaO48m73ZBySuiV3iXpb2wgs/"
+ + "Cs20iqroAWxwq/W/9jCCAlMwggG/oAMCAQICBDsFZ9UwCgYGKyQDAwECBQAw"
+ + "bzELMAkGA1UEBhMCREUxITAMBgcCggYBCgcUEwExMBEGA1UEAxQKNFItQ0Eg"
+ + "MTpQTjE9MDsGA1UEChQ0UmVndWxpZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxl"
+ + "a29tbXVuaWthdGlvbiB1bmQgUG9zdDAiGA8xOTk5MDEyMTE3MzUzNFoYDzIw"
+ + "MDQwMTIxMTYwMDAyWjBvMQswCQYDVQQGEwJERTE9MDsGA1UEChQ0UmVndWxp"
+ + "ZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxla29tbXVuaWthdGlvbiB1bmQgUG9z"
+ + "dDEhMAwGBwKCBgEKBxQTATEwEQYDVQQDFAozUi1DQSAxOlBOMIGfMA0GCSqG"
+ + "SIb3DQEBAQUAA4GNADCBiQKBgI4B557mbKQg/AqWBXNJhaT/6lwV93HUl4U8"
+ + "u35udLq2+u9phns1WZkdM3gDfEpL002PeLfHr1ID/96dDYf04lAXQfombils"
+ + "of1C1k32xOvxjlcrDOuPEMxz9/HDAQZA5MjmmYHAIulGI8Qg4Tc7ERRtg/hd"
+ + "0QX0/zoOeXoDSEOBAgTAAAABMAoGBiskAwMBAgUAA4GBAIyzwfT3keHI/n2P"
+ + "LrarRJv96mCohmDZNpUQdZTVjGu5VQjVJwk3hpagU0o/t/FkdzAjOdfEw8Ql"
+ + "3WXhfIbNLv1YafMm2eWSdeYbLcbB5yJ1od+SYyf9+tm7cwfDAcr22jNRBqx8"
+ + "wkWKtKDjWKkevaSdy99sAI8jebHtWz7jzydKMIID9TCCA16gAwIBAgICbMcw"
+ + "DQYJKoZIhvcNAQEFBQAwSzELMAkGA1UEBhMCREUxEjAQBgNVBAoUCVNpZ250"
+ + "cnVzdDEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFDQSBTSUdOVFJVU1QgMTpQ"
+ + "TjAeFw0wNDA3MzAxMzAyNDZaFw0wNzA3MzAxMzAyNDZaMDwxETAPBgNVBAMM"
+ + "CFlhY29tOlBOMQ4wDAYDVQRBDAVZYWNvbTELMAkGA1UEBhMCREUxCjAIBgNV"
+ + "BAUTATEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAIWzLlYLQApocXIp"
+ + "pgCCpkkOUVLgcLYKeOd6/bXAnI2dTHQqT2bv7qzfUnYvOqiNgYdF13pOYtKg"
+ + "XwXMTNFL4ZOI6GoBdNs9TQiZ7KEWnqnr2945HYx7UpgTBclbOK/wGHuCdcwO"
+ + "x7juZs1ZQPFG0Lv8RoiV9s6HP7POqh1sO0P/AgMBAAGjggH1MIIB8TCBnAYD"
+ + "VR0jBIGUMIGRgBQcZzNghfnXoXRm8h1+VITC5caNRqFzpHEwbzELMAkGA1UE"
+ + "BhMCREUxPTA7BgNVBAoUNFJlZ3VsaWVydW5nc2JlaMhvcmRlIGbIdXIgVGVs"
+ + "ZWtvbW11bmlrYXRpb24gdW5kIFBvc3QxITAMBgcCggYBCgcUEwExMBEGA1UE"
+ + "AxQKNVItQ0EgMTpQToIEALs8rjAdBgNVHQ4EFgQU2e5KAzkVuKaM9I5heXkz"
+ + "bcAIuR8wDgYDVR0PAQH/BAQDAgZAMBIGA1UdIAQLMAkwBwYFKyQIAQEwfwYD"
+ + "VR0fBHgwdjB0oCygKoYobGRhcDovL2Rpci5zaWdudHJ1c3QuZGUvbz1TaWdu"
+ + "dHJ1c3QsYz1kZaJEpEIwQDEdMBsGA1UEAxMUQ1JMU2lnblNpZ250cnVzdDE6"
+ + "UE4xEjAQBgNVBAoTCVNpZ250cnVzdDELMAkGA1UEBhMCREUwYgYIKwYBBQUH"
+ + "AQEEVjBUMFIGCCsGAQUFBzABhkZodHRwOi8vZGlyLnNpZ250cnVzdC5kZS9T"
+ + "aWdudHJ1c3QvT0NTUC9zZXJ2bGV0L2h0dHBHYXRld2F5LlBvc3RIYW5kbGVy"
+ + "MBgGCCsGAQUFBwEDBAwwCjAIBgYEAI5GAQEwDgYHAoIGAQoMAAQDAQH/MA0G"
+ + "CSqGSIb3DQEBBQUAA4GBAHn1m3GcoyD5GBkKUY/OdtD6Sj38LYqYCF+qDbJR"
+ + "6pqUBjY2wsvXepUppEler+stH8mwpDDSJXrJyuzf7xroDs4dkLl+Rs2x+2tg"
+ + "BjU+ABkBDMsym2WpwgA8LCdymmXmjdv9tULxY+ec2pjSEzql6nEZNEfrU8nt"
+ + "ZCSCavgqW4TtMYIBejCCAXYCAQEwUTBLMQswCQYDVQQGEwJERTESMBAGA1UE"
+ + "ChQJU2lnbnRydXN0MSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEUNBIFNJR05U"
+ + "UlVTVCAxOlBOAgJsxzAJBgUrDgMCGgUAoIGAMBgGCSqGSIb3DQEJAzELBgkq"
+ + "hkiG9w0BBwEwIwYJKoZIhvcNAQkEMRYEFIYfhPoyfGzkLWWSSLjaHb4HQmaK"
+ + "MBwGCSqGSIb3DQEJBTEPFw0wNTAzMjQwNzM4MzVaMCEGBSskCAYFMRgWFi92"
+ + "YXIvZmlsZXMvdG1wXzEvdGVzdDEwDQYJKoZIhvcNAQEFBQAEgYA2IvA8lhVz"
+ + "VD5e/itUxbFboKxeKnqJ5n/KuO/uBCl1N14+7Z2vtw1sfkIG+bJdp3OY2Cmn"
+ + "mrQcwsN99Vjal4cXVj8t+DJzFG9tK9dSLvD3q9zT/GQ0kJXfimLVwCa4NaSf"
+ + "Qsu4xtG0Rav6bCcnzabAkKuNNvKtH8amSRzk870DBg==");
+
+ public static byte[] xtraCounterSig = Base64.decode(
+ "MIIR/AYJKoZIhvcNAQcCoIIR7TCCEekCAQExCzAJBgUrDgMCGgUAMBoGCSqG"
+ + "SIb3DQEHAaANBAtIZWxsbyB3b3JsZKCCDnkwggTPMIIDt6ADAgECAgRDnYD3"
+ + "MA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNVBAYTAklUMRowGAYDVQQKExFJbi5U"
+ + "ZS5TLkEuIFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5BLiAtIENlcnRpZmlj"
+ + "YXRpb24gQXV0aG9yaXR5MB4XDTA4MDkxMjExNDMxMloXDTEwMDkxMjExNDMx"
+ + "MlowgdgxCzAJBgNVBAYTAklUMSIwIAYDVQQKDBlJbnRlc2EgUy5wLkEuLzA1"
+ + "MjYyODkwMDE0MSowKAYDVQQLDCFCdXNpbmVzcyBDb2xsYWJvcmF0aW9uICYg"
+ + "U2VjdXJpdHkxHjAcBgNVBAMMFU1BU1NJTUlMSUFOTyBaSUNDQVJESTERMA8G"
+ + "A1UEBAwIWklDQ0FSREkxFTATBgNVBCoMDE1BU1NJTUlMSUFOTzEcMBoGA1UE"
+ + "BRMTSVQ6WkNDTVNNNzZIMTRMMjE5WTERMA8GA1UELhMIMDAwMDI1ODUwgaAw"
+ + "DQYJKoZIhvcNAQEBBQADgY4AMIGKAoGBALeJTjmyFgx1SIP6c2AuB/kuyHo5"
+ + "j/prKELTALsFDimre/Hxr3wOSet1TdQfFzU8Lu+EJqgfV9cV+cI1yeH1rZs7"
+ + "lei7L3tX/VR565IywnguX5xwvteASgWZr537Fkws50bvTEMyYOj1Tf3FZvZU"
+ + "z4n4OD39KI4mfR9i1eEVIxR3AgQAizpNo4IBoTCCAZ0wHQYDVR0RBBYwFIES"
+ + "emljY2FyZGlAaW50ZXNhLml0MC8GCCsGAQUFBwEDBCMwITAIBgYEAI5GAQEw"
+ + "CwYGBACORgEDAgEUMAgGBgQAjkYBBDBZBgNVHSAEUjBQME4GBgQAizABATBE"
+ + "MEIGCCsGAQUFBwIBFjZodHRwOi8vZS10cnVzdGNvbS5pbnRlc2EuaXQvY2Ff"
+ + "cHViYmxpY2EvQ1BTX0lOVEVTQS5odG0wDgYDVR0PAQH/BAQDAgZAMIGDBgNV"
+ + "HSMEfDB6gBQZCQOW0bjFWBt+EORuxPagEgkQqKFcpFowWDELMAkGA1UEBhMC"
+ + "SVQxGjAYBgNVBAoTEUluLlRlLlMuQS4gUy5wLkEuMS0wKwYDVQQDEyRJbi5U"
+ + "ZS5TLkEuIC0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHmCBDzRARMwOwYDVR0f"
+ + "BDQwMjAwoC6gLIYqaHR0cDovL2UtdHJ1c3Rjb20uaW50ZXNhLml0L0NSTC9J"
+ + "TlRFU0EuY3JsMB0GA1UdDgQWBBTf5ItL8KmQh541Dxt7YxcWI1254TANBgkq"
+ + "hkiG9w0BAQUFAAOCAQEAgW+uL1CVWQepbC/wfCmR6PN37Sueb4xiKQj2mTD5"
+ + "UZ5KQjpivy/Hbuf0NrfKNiDEhAvoHSPC31ebGiKuTMFNyZPHfPEUnyYGSxea"
+ + "2w837aXJFr6utPNQGBRi89kH90sZDlXtOSrZI+AzJJn5QK3F9gjcayU2NZXQ"
+ + "MJgRwYmFyn2w4jtox+CwXPQ9E5XgxiMZ4WDL03cWVXDLX00EOJwnDDMUNTRI"
+ + "m9Zv+4SKTNlfFbi9UTBqWBySkDzAelsfB2U61oqc2h1xKmCtkGMmN9iZT+Qz"
+ + "ZC/vaaT+hLEBFGAH2gwFrYc4/jTBKyBYeU1vsAxsibIoTs1Apgl6MH75qPDL"
+ + "BzCCBM8wggO3oAMCAQICBEOdgPcwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UE"
+ + "BhMCSVQxGjAYBgNVBAoTEUluLlRlLlMuQS4gUy5wLkEuMS0wKwYDVQQDEyRJ"
+ + "bi5UZS5TLkEuIC0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwOTEy"
+ + "MTE0MzEyWhcNMTAwOTEyMTE0MzEyWjCB2DELMAkGA1UEBhMCSVQxIjAgBgNV"
+ + "BAoMGUludGVzYSBTLnAuQS4vMDUyNjI4OTAwMTQxKjAoBgNVBAsMIUJ1c2lu"
+ + "ZXNzIENvbGxhYm9yYXRpb24gJiBTZWN1cml0eTEeMBwGA1UEAwwVTUFTU0lN"
+ + "SUxJQU5PIFpJQ0NBUkRJMREwDwYDVQQEDAhaSUNDQVJESTEVMBMGA1UEKgwM"
+ + "TUFTU0lNSUxJQU5PMRwwGgYDVQQFExNJVDpaQ0NNU003NkgxNEwyMTlZMREw"
+ + "DwYDVQQuEwgwMDAwMjU4NTCBoDANBgkqhkiG9w0BAQEFAAOBjgAwgYoCgYEA"
+ + "t4lOObIWDHVIg/pzYC4H+S7IejmP+msoQtMAuwUOKat78fGvfA5J63VN1B8X"
+ + "NTwu74QmqB9X1xX5wjXJ4fWtmzuV6Lsve1f9VHnrkjLCeC5fnHC+14BKBZmv"
+ + "nfsWTCznRu9MQzJg6PVN/cVm9lTPifg4Pf0ojiZ9H2LV4RUjFHcCBACLOk2j"
+ + "ggGhMIIBnTAdBgNVHREEFjAUgRJ6aWNjYXJkaUBpbnRlc2EuaXQwLwYIKwYB"
+ + "BQUHAQMEIzAhMAgGBgQAjkYBATALBgYEAI5GAQMCARQwCAYGBACORgEEMFkG"
+ + "A1UdIARSMFAwTgYGBACLMAEBMEQwQgYIKwYBBQUHAgEWNmh0dHA6Ly9lLXRy"
+ + "dXN0Y29tLmludGVzYS5pdC9jYV9wdWJibGljYS9DUFNfSU5URVNBLmh0bTAO"
+ + "BgNVHQ8BAf8EBAMCBkAwgYMGA1UdIwR8MHqAFBkJA5bRuMVYG34Q5G7E9qAS"
+ + "CRCooVykWjBYMQswCQYDVQQGEwJJVDEaMBgGA1UEChMRSW4uVGUuUy5BLiBT"
+ + "LnAuQS4xLTArBgNVBAMTJEluLlRlLlMuQS4gLSBDZXJ0aWZpY2F0aW9uIEF1"
+ + "dGhvcml0eYIEPNEBEzA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vZS10cnVz"
+ + "dGNvbS5pbnRlc2EuaXQvQ1JML0lOVEVTQS5jcmwwHQYDVR0OBBYEFN/ki0vw"
+ + "qZCHnjUPG3tjFxYjXbnhMA0GCSqGSIb3DQEBBQUAA4IBAQCBb64vUJVZB6ls"
+ + "L/B8KZHo83ftK55vjGIpCPaZMPlRnkpCOmK/L8du5/Q2t8o2IMSEC+gdI8Lf"
+ + "V5saIq5MwU3Jk8d88RSfJgZLF5rbDzftpckWvq6081AYFGLz2Qf3SxkOVe05"
+ + "Ktkj4DMkmflArcX2CNxrJTY1ldAwmBHBiYXKfbDiO2jH4LBc9D0TleDGIxnh"
+ + "YMvTdxZVcMtfTQQ4nCcMMxQ1NEib1m/7hIpM2V8VuL1RMGpYHJKQPMB6Wx8H"
+ + "ZTrWipzaHXEqYK2QYyY32JlP5DNkL+9ppP6EsQEUYAfaDAWthzj+NMErIFh5"
+ + "TW+wDGyJsihOzUCmCXowfvmo8MsHMIIEzzCCA7egAwIBAgIEQ52A9zANBgkq"
+ + "hkiG9w0BAQUFADBYMQswCQYDVQQGEwJJVDEaMBgGA1UEChMRSW4uVGUuUy5B"
+ + "LiBTLnAuQS4xLTArBgNVBAMTJEluLlRlLlMuQS4gLSBDZXJ0aWZpY2F0aW9u"
+ + "IEF1dGhvcml0eTAeFw0wODA5MTIxMTQzMTJaFw0xMDA5MTIxMTQzMTJaMIHY"
+ + "MQswCQYDVQQGEwJJVDEiMCAGA1UECgwZSW50ZXNhIFMucC5BLi8wNTI2Mjg5"
+ + "MDAxNDEqMCgGA1UECwwhQnVzaW5lc3MgQ29sbGFib3JhdGlvbiAmIFNlY3Vy"
+ + "aXR5MR4wHAYDVQQDDBVNQVNTSU1JTElBTk8gWklDQ0FSREkxETAPBgNVBAQM"
+ + "CFpJQ0NBUkRJMRUwEwYDVQQqDAxNQVNTSU1JTElBTk8xHDAaBgNVBAUTE0lU"
+ + "OlpDQ01TTTc2SDE0TDIxOVkxETAPBgNVBC4TCDAwMDAyNTg1MIGgMA0GCSqG"
+ + "SIb3DQEBAQUAA4GOADCBigKBgQC3iU45shYMdUiD+nNgLgf5Lsh6OY/6ayhC"
+ + "0wC7BQ4pq3vx8a98DknrdU3UHxc1PC7vhCaoH1fXFfnCNcnh9a2bO5Xouy97"
+ + "V/1UeeuSMsJ4Ll+ccL7XgEoFma+d+xZMLOdG70xDMmDo9U39xWb2VM+J+Dg9"
+ + "/SiOJn0fYtXhFSMUdwIEAIs6TaOCAaEwggGdMB0GA1UdEQQWMBSBEnppY2Nh"
+ + "cmRpQGludGVzYS5pdDAvBggrBgEFBQcBAwQjMCEwCAYGBACORgEBMAsGBgQA"
+ + "jkYBAwIBFDAIBgYEAI5GAQQwWQYDVR0gBFIwUDBOBgYEAIswAQEwRDBCBggr"
+ + "BgEFBQcCARY2aHR0cDovL2UtdHJ1c3Rjb20uaW50ZXNhLml0L2NhX3B1YmJs"
+ + "aWNhL0NQU19JTlRFU0EuaHRtMA4GA1UdDwEB/wQEAwIGQDCBgwYDVR0jBHww"
+ + "eoAUGQkDltG4xVgbfhDkbsT2oBIJEKihXKRaMFgxCzAJBgNVBAYTAklUMRow"
+ + "GAYDVQQKExFJbi5UZS5TLkEuIFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5B"
+ + "LiAtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ80QETMDsGA1UdHwQ0MDIw"
+ + "MKAuoCyGKmh0dHA6Ly9lLXRydXN0Y29tLmludGVzYS5pdC9DUkwvSU5URVNB"
+ + "LmNybDAdBgNVHQ4EFgQU3+SLS/CpkIeeNQ8be2MXFiNdueEwDQYJKoZIhvcN"
+ + "AQEFBQADggEBAIFvri9QlVkHqWwv8Hwpkejzd+0rnm+MYikI9pkw+VGeSkI6"
+ + "Yr8vx27n9Da3yjYgxIQL6B0jwt9XmxoirkzBTcmTx3zxFJ8mBksXmtsPN+2l"
+ + "yRa+rrTzUBgUYvPZB/dLGQ5V7Tkq2SPgMySZ+UCtxfYI3GslNjWV0DCYEcGJ"
+ + "hcp9sOI7aMfgsFz0PROV4MYjGeFgy9N3FlVwy19NBDicJwwzFDU0SJvWb/uE"
+ + "ikzZXxW4vVEwalgckpA8wHpbHwdlOtaKnNodcSpgrZBjJjfYmU/kM2Qv72mk"
+ + "/oSxARRgB9oMBa2HOP40wSsgWHlNb7AMbImyKE7NQKYJejB++ajwywcxggM8"
+ + "MIIDOAIBATBgMFgxCzAJBgNVBAYTAklUMRowGAYDVQQKExFJbi5UZS5TLkEu"
+ + "IFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5BLiAtIENlcnRpZmljYXRpb24g"
+ + "QXV0aG9yaXR5AgRDnYD3MAkGBSsOAwIaBQAwDQYJKoZIhvcNAQEBBQAEgYB+"
+ + "lH2cwLqc91mP8prvgSV+RRzk13dJdZvdoVjgQoFrPhBiZCNIEoHvIhMMA/sM"
+ + "X6euSRZk7EjD24FasCEGYyd0mJVLEy6TSPmuW+wWz/28w3a6IWXBGrbb/ild"
+ + "/CJMkPgLPGgOVD1WDwiNKwfasiQSFtySf5DPn3jFevdLeMmEY6GCAjIwggEV"
+ + "BgkqhkiG9w0BCQYxggEGMIIBAgIBATBgMFgxCzAJBgNVBAYTAklUMRowGAYD"
+ + "VQQKExFJbi5UZS5TLkEuIFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5BLiAt"
+ + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5AgRDnYD3MAkGBSsOAwIaBQAwDQYJ"
+ + "KoZIhvcNAQEBBQAEgYBHlOULfT5GDigIvxP0qZOy8VbpntmzaPF55VV4buKV"
+ + "35J+uHp98gXKp0LrHM69V5IRKuyuQzHHFBqsXxsRI9o6KoOfgliD9Xc+BeMg"
+ + "dKzQhBhBYoFREq8hQM0nSbqDNHYAQyNHMzUA/ZQUO5dlFuH8Dw3iDYAhNtfd"
+ + "PrlchKJthDCCARUGCSqGSIb3DQEJBjGCAQYwggECAgEBMGAwWDELMAkGA1UE"
+ + "BhMCSVQxGjAYBgNVBAoTEUluLlRlLlMuQS4gUy5wLkEuMS0wKwYDVQQDEyRJ"
+ + "bi5UZS5TLkEuIC0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkCBEOdgPcwCQYF"
+ + "Kw4DAhoFADANBgkqhkiG9w0BAQEFAASBgEeU5Qt9PkYOKAi/E/Spk7LxVume"
+ + "2bNo8XnlVXhu4pXfkn64en3yBcqnQusczr1XkhEq7K5DMccUGqxfGxEj2joq"
+ + "g5+CWIP1dz4F4yB0rNCEGEFigVESryFAzSdJuoM0dgBDI0czNQD9lBQ7l2UW"
+ + "4fwPDeINgCE2190+uVyEom2E");
+
+ byte[] noSignedAttrSample2 = Base64.decode(
+ "MIIIlAYJKoZIhvcNAQcCoIIIhTCCCIECAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+ + "SIb3DQEHAaCCB3UwggOtMIIDa6ADAgECAgEzMAsGByqGSM44BAMFADCBkDEL"
+ + "MAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlQYWxvIEFsdG8x"
+ + "HTAbBgNVBAoTFFN1biBNaWNyb3N5c3RlbXMgSW5jMSMwIQYDVQQLExpKYXZh"
+ + "IFNvZnR3YXJlIENvZGUgU2lnbmluZzEcMBoGA1UEAxMTSkNFIENvZGUgU2ln"
+ + "bmluZyBDQTAeFw0wMTA1MjkxNjQ3MTFaFw0wNjA1MjgxNjQ3MTFaMG4xHTAb"
+ + "BgNVBAoTFFN1biBNaWNyb3N5c3RlbXMgSW5jMSMwIQYDVQQLExpKYXZhIFNv"
+ + "ZnR3YXJlIENvZGUgU2lnbmluZzEoMCYGA1UEAxMfVGhlIExlZ2lvbiBvZiB0"
+ + "aGUgQm91bmN5IENhc3RsZTCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OB"
+ + "HXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2"
+ + "y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58aophUP"
+ + "BPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvM"
+ + "spK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9"
+ + "B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCj"
+ + "rh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtV"
+ + "JWQBTDv+z0kqA4GEAAKBgBWry/FCAZ6miyy39+ftsa+h9lxoL+JtV0MJcUyQ"
+ + "E4VAhpAwWb8vyjba9AwOylYQTktHX5sAkFvjBiU0LOYDbFSTVZSHMRJgfjxB"
+ + "SHtICjOEvr1BJrrOrdzqdxcOUge5n7El124BCrv91x5Ol8UTwtiO9LrRXF/d"
+ + "SyK+RT5n1klRo3YwdDARBglghkgBhvhCAQEEBAMCAIcwDgYDVR0PAQH/BAQD"
+ + "AgHGMB0GA1UdDgQWBBQwMY4NRcco1AO3w1YsokfDLVseEjAPBgNVHRMBAf8E"
+ + "BTADAQH/MB8GA1UdIwQYMBaAFGXi9IbJ007wkU5Yomr12HhamsGmMAsGByqG"
+ + "SM44BAMFAAMvADAsAhRmigTu6QV0sTfEkVljgij/hhdVfAIUQZvMxAnIHc30"
+ + "y/u0C1T5UEG9glUwggPAMIIDfqADAgECAgEQMAsGByqGSM44BAMFADCBkDEL"
+ + "MAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlQYWxvIEFsdG8x"
+ + "HTAbBgNVBAoTFFN1biBNaWNyb3N5c3RlbXMgSW5jMSMwIQYDVQQLExpKYXZh"
+ + "IFNvZnR3YXJlIENvZGUgU2lnbmluZzEcMBoGA1UEAxMTSkNFIENvZGUgU2ln"
+ + "bmluZyBDQTAeFw0wMTA0MjUwNzAwMDBaFw0yMDA0MjUwNzAwMDBaMIGQMQsw"
+ + "CQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVBhbG8gQWx0bzEd"
+ + "MBsGA1UEChMUU3VuIE1pY3Jvc3lzdGVtcyBJbmMxIzAhBgNVBAsTGkphdmEg"
+ + "U29mdHdhcmUgQ29kZSBTaWduaW5nMRwwGgYDVQQDExNKQ0UgQ29kZSBTaWdu"
+ + "aW5nIENBMIIBtzCCASwGByqGSM44BAEwggEfAoGBAOuvNwQeylEeaV2w8o/2"
+ + "tUkfxqSZBdcpv3S3avUZ2B7kG/gKAZqY/3Cr4kpWhmxTs/zhyIGMMfDE87CL"
+ + "5nAG7PdpaNuDTHIpiSk2F1w7SgegIAIqRpdRHXDICBgLzgxum3b3BePn+9Nh"
+ + "eeFgmiSNBpWDPFEg4TDPOFeCphpyDc7TAhUAhCVF4bq5qWKreehbMLiJaxv/"
+ + "e3UCgYEAq8l0e3Tv7kK1alNNO92QBnJokQ8LpCl2LlU71a5NZVx+KjoEpmem"
+ + "0HGqpde34sFyDaTRqh6SVEwgAAmisAlBGTMAssNcrkL4sYvKfJbYEH83RFuq"
+ + "zHjI13J2N2tAmahVZvqoAx6LShECactMuCUGHKB30sms0j3pChD6dnC3+9wD"
+ + "gYQAAoGALQmYXKy4nMeZfu4gGSo0kPnXq6uu3WtylQ1m+O8nj0Sy7ShEx/6v"
+ + "sKYnbwBnRYJbB6hWVjvSKVFhXmk51y50dxLPGUr1LcjLcmHETm/6R0M/FLv6"
+ + "vBhmKMLZZot6LS/CYJJLFP5YPiF/aGK+bEhJ+aBLXoWdGRD5FUVRG3HU9wuj"
+ + "ZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1Ud"
+ + "IwQYMBaAFGXi9IbJ007wkU5Yomr12HhamsGmMB0GA1UdDgQWBBRl4vSGydNO"
+ + "8JFOWKJq9dh4WprBpjALBgcqhkjOOAQDBQADLwAwLAIUKvfPPJdd+Xi2CNdB"
+ + "tNkNRUzktJwCFEXNdWkOIfod1rMpsun3Mx0z/fxJMYHoMIHlAgEBMIGWMIGQ"
+ + "MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVBhbG8gQWx0"
+ + "bzEdMBsGA1UEChMUU3VuIE1pY3Jvc3lzdGVtcyBJbmMxIzAhBgNVBAsTGkph"
+ + "dmEgU29mdHdhcmUgQ29kZSBTaWduaW5nMRwwGgYDVQQDExNKQ0UgQ29kZSBT"
+ + "aWduaW5nIENBAgEzMAkGBSsOAwIaBQAwCwYHKoZIzjgEAQUABC8wLQIVAIGV"
+ + "khm+kbV4a/+EP45PHcq0hIViAhR4M9os6IrJnoEDS3Y3l7O6zrSosA==");
+
+ /*
+ *
+ * INFRASTRUCTURE
+ *
+ */
+
+ public BcSignedDataTest(String name)
+ {
+ super(name);
+ }
+
+ public static void main(String args[])
+ {
+
+ junit.textui.TestRunner.run(BcSignedDataTest.class);
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ init();
+
+ return new CMSTestSetup(new TestSuite(BcSignedDataTest.class));
+ }
+
+ private static void init()
+ throws Exception
+ {
+ if (!_initialised)
+ {
+ _initialised = true;
+
+ if (Security.getProvider(BC) == null)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ _origDN = "O=Bouncy Castle, C=AU";
+ _origKP = CMSTestUtil.makeKeyPair();
+ _origCert = CMSTestUtil.makeCertificate(_origKP, _origDN, _origKP, _origDN);
+
+ _signDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+ _signKP = CMSTestUtil.makeKeyPair();
+ _signCert = CMSTestUtil.makeCertificate(_signKP, _signDN, _origKP, _origDN);
+
+ _signDsaKP = CMSTestUtil.makeDsaKeyPair();
+ _signDsaCert = CMSTestUtil.makeCertificate(_signDsaKP, _signDN, _origKP, _origDN);
+
+ _signEcDsaKP = CMSTestUtil.makeEcDsaKeyPair();
+ _signEcDsaCert = CMSTestUtil.makeCertificate(_signEcDsaKP, _signDN, _origKP, _origDN);
+
+ _reciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+ _reciKP = CMSTestUtil.makeKeyPair();
+ _reciCert = CMSTestUtil.makeCertificate(_reciKP, _reciDN, _signKP, _signDN);
+
+ _signCrl = CMSTestUtil.makeCrl(_signKP);
+ }
+ }
+
+ private void verifyRSASignatures(CMSSignedData s, byte[] contentDigest)
+ throws Exception
+ {
+ Store certStore = s.getCertificates();
+ SignerInformationStore signers = s.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certStore.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new BcRSASignerInfoVerifierBuilder(new DefaultCMSSignatureAlgorithmNameGenerator(), new DefaultSignatureAlgorithmIdentifierFinder(), new DefaultDigestAlgorithmIdentifierFinder(), new BcDigestCalculatorProvider()).build(cert)));
+
+ if (contentDigest != null)
+ {
+ assertTrue(MessageDigest.isEqual(contentDigest, signer.getContentDigest()));
+ }
+ }
+ }
+
+ private void verifySignatures(CMSSignedData s, byte[] contentDigest)
+ throws Exception
+ {
+ Store certStore = s.getCertificates();
+ Store crlStore = s.getCRLs();
+ SignerInformationStore signers = s.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certStore.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+
+ if (contentDigest != null)
+ {
+ assertTrue(MessageDigest.isEqual(contentDigest, signer.getContentDigest()));
+ }
+ }
+
+ Collection certColl = certStore.getMatches(null);
+ Collection crlColl = crlStore.getMatches(null);
+
+ assertEquals(certColl.size(), s.getCertificates().getMatches(null).size());
+ assertEquals(crlColl.size(), s.getCRLs().getMatches(null).size());
+ }
+
+ private void verifySignatures(CMSSignedData s)
+ throws Exception
+ {
+ verifySignatures(s, null);
+ }
+
+ public void testDetachedVerification()
+ throws Exception
+ {
+ byte[] data = "Hello World!".getBytes();
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray(data);
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ DigestCalculatorProvider digProvider = new JcaDigestCalculatorProviderBuilder().setProvider(BC).build();
+ JcaSignerInfoGeneratorBuilder signerInfoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(digProvider);
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+ ContentSigner md5Signer = new JcaContentSignerBuilder("MD5withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(signerInfoGeneratorBuilder.build(sha1Signer, _origCert));
+ gen.addSignerInfoGenerator(signerInfoGeneratorBuilder.build(md5Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(msg);
+
+ MessageDigest sha1 = MessageDigest.getInstance("SHA1", BC);
+ MessageDigest md5 = MessageDigest.getInstance("MD5", BC);
+ Map hashes = new HashMap();
+ byte[] sha1Hash = sha1.digest(data);
+ byte[] md5Hash = md5.digest(data);
+
+ hashes.put(CMSAlgorithm.SHA1, sha1Hash);
+ hashes.put(CMSAlgorithm.MD5, md5Hash);
+
+ s = new CMSSignedData(hashes, s.getEncoded());
+
+ verifySignatures(s, null);
+ }
+
+ public void testDetachedVerificationWithBufferingContentSigner()
+ throws Exception
+ {
+ byte[] data = "Hello World!".getBytes();
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray(data);
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ DigestCalculatorProvider digProvider = new JcaDigestCalculatorProviderBuilder().setProvider(BC).build();
+ JcaSignerInfoGeneratorBuilder signerInfoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(digProvider);
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+ ContentSigner md5Signer = new JcaContentSignerBuilder("MD5withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(signerInfoGeneratorBuilder.build(new BufferingContentSigner(sha1Signer), _origCert));
+ gen.addSignerInfoGenerator(signerInfoGeneratorBuilder.build(new BufferingContentSigner(md5Signer), _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(msg);
+
+ MessageDigest sha1 = MessageDigest.getInstance("SHA1", BC);
+ MessageDigest md5 = MessageDigest.getInstance("MD5", BC);
+ Map hashes = new HashMap();
+ byte[] sha1Hash = sha1.digest(data);
+ byte[] md5Hash = md5.digest(data);
+
+ hashes.put(CMSAlgorithm.SHA1, sha1Hash);
+ hashes.put(CMSAlgorithm.MD5, md5Hash);
+
+ s = new CMSSignedData(hashes, s.getEncoded());
+
+ verifySignatures(s, null);
+ }
+
+ public void testSHA1AndMD5WithRSAEncapsulatedRepeated()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ DigestCalculatorProvider digCalcProv = new JcaDigestCalculatorProviderBuilder().setProvider(BC).build();
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(digCalcProv).build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate()), _origCert));
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(digCalcProv).build(new JcaContentSignerBuilder("MD5withRSA").setProvider(BC).build(_origKP.getPrivate()), _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(msg, true);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded());
+ ASN1InputStream aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ certs = s.getCertificates();
+
+ SignerInformationStore signers = s.getSignerInfos();
+
+ assertEquals(2, signers.size());
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+ SignerId sid = null;
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ sid = signer.getSID();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+
+ //
+ // check content digest
+ //
+
+ byte[] contentDigest = (byte[])gen.getGeneratedDigests().get(signer.getDigestAlgOID());
+
+ AttributeTable table = signer.getSignedAttributes();
+ Attribute hash = table.get(CMSAttributes.messageDigest);
+
+ assertTrue(MessageDigest.isEqual(contentDigest, ((ASN1OctetString)hash.getAttrValues().getObjectAt(0)).getOctets()));
+ }
+
+ c = signers.getSigners(sid);
+
+ assertEquals(2, c.size());
+
+
+ //
+ // try using existing signer
+ //
+
+ gen = new CMSSignedDataGenerator();
+
+ gen.addSigners(s.getSignerInfos());
+
+ gen.addCertificates(s.getCertificates());
+
+ s = gen.generate(msg, true);
+
+ bIn = new ByteArrayInputStream(s.getEncoded());
+ aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ certs = s.getCertificates();
+
+ signers = s.getSignerInfos();
+ c = signers.getSigners();
+ it = c.iterator();
+
+ assertEquals(2, c.size());
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+
+ checkSignerStoreReplacement(s, signers);
+ }
+
+ public void testSHA1WithRSANoAttributes()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ JcaSignerInfoGeneratorBuilder builder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ builder.setDirectSignature(true);
+
+ gen.addSignerInfoGenerator(builder.build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(msg, false);
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+
+ verifySignatures(s, md.digest("Hello world!".getBytes()));
+ }
+
+ public void testSHA1WithRSANoAttributesSimple()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ JcaSimpleSignerInfoGeneratorBuilder builder = new JcaSimpleSignerInfoGeneratorBuilder().setProvider(BC).setDirectSignature(true);
+
+ gen.addSignerInfoGenerator(builder.build("SHA1withRSA", _origKP.getPrivate(), _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(msg, false);
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+
+ verifySignatures(s, md.digest("Hello world!".getBytes()));
+ }
+
+ public void testSHA1WithRSAViaConfig()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ // set some bogus mappings.
+ TestCMSSignatureAlgorithmNameGenerator sigAlgNameGen = new TestCMSSignatureAlgorithmNameGenerator();
+
+ sigAlgNameGen.setEncryptionAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "XXXX");
+ sigAlgNameGen.setDigestAlgorithmMapping(OIWObjectIdentifiers.idSHA1, "YYYY");
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s;
+
+ try
+ {
+ // try the bogus mappings
+ s = gen.generate(msg, false);
+ }
+ catch (CMSException e)
+ {
+ if (!e.getMessage().startsWith("no such algorithm: YYYYwithXXXX"))
+ {
+ throw e;
+ }
+ }
+ finally
+ {
+ // reset to the real ones
+ sigAlgNameGen.setEncryptionAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ sigAlgNameGen.setDigestAlgorithmMapping(OIWObjectIdentifiers.idSHA1, "SHA1");
+ }
+
+ s = gen.generate(msg, false);
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+
+ verifySignatures(s, md.digest("Hello world!".getBytes()));
+ }
+
+ public void testSHA1WithRSAAndAttributeTableSimple()
+ throws Exception
+ {
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ Attribute attr = new Attribute(CMSAttributes.messageDigest,
+ new DERSet(
+ new DEROctetString(
+ md.digest("Hello world!".getBytes()))));
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(attr);
+
+ SignerInfoGeneratorBuilder builder = new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider()).setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)));
+
+ AlgorithmIdentifier sha1withRSA = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA");
+ gen.addSignerInfoGenerator(builder.build(new BcRSAContentSignerBuilder(sha1withRSA, new DefaultDigestAlgorithmIdentifierFinder().find(sha1withRSA)).build(PrivateKeyFactory.createKey(_origKP.getPrivate().getEncoded())), new JcaX509CertificateHolder(_origCert)));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(new CMSAbsentContent(), false);
+
+ //
+ // the signature is detached, so need to add msg before passing on
+ //
+ s = new CMSSignedData(msg, s.getEncoded());
+ //
+ // compute expected content digest
+ //
+
+ verifySignatures(s, md.digest("Hello world!".getBytes()));
+ verifyRSASignatures(s, md.digest("Hello world!".getBytes()));
+ }
+
+ public void testSHA1WithRSAAndAttributeTable()
+ throws Exception
+ {
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ Attribute attr = new Attribute(CMSAttributes.messageDigest,
+ new DERSet(
+ new DEROctetString(
+ md.digest("Hello world!".getBytes()))));
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(attr);
+
+ JcaSignerInfoGeneratorBuilder builder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ builder.setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)));
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(builder.build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(new CMSAbsentContent(), false);
+
+ //
+ // the signature is detached, so need to add msg before passing on
+ //
+ s = new CMSSignedData(msg, s.getEncoded());
+ //
+ // compute expected content digest
+ //
+
+ verifySignatures(s, md.digest("Hello world!".getBytes()));
+ verifyRSASignatures(s, md.digest("Hello world!".getBytes()));
+ }
+
+ public void testLwSHA1WithRSAAndAttributeTable()
+ throws Exception
+ {
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ Attribute attr = new Attribute(CMSAttributes.messageDigest,
+ new DERSet(
+ new DEROctetString(
+ md.digest("Hello world!".getBytes()))));
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(attr);
+
+ AsymmetricKeyParameter privKey = PrivateKeyFactory.createKey(_origKP.getPrivate().getEncoded());
+
+ AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA");
+ AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
+
+ BcContentSignerBuilder contentSignerBuilder = new BcRSAContentSignerBuilder(sigAlgId, digAlgId);
+
+ gen.addSignerInfoGenerator(
+ new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider())
+ .setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)))
+ .build(contentSignerBuilder.build(privKey), new JcaX509CertificateHolder(_origCert)));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(new CMSAbsentContent(), false);
+
+ //
+ // the signature is detached, so need to add msg before passing on
+ //
+ s = new CMSSignedData(msg, s.getEncoded());
+ //
+ // compute expected content digest
+ //
+
+ verifySignatures(s, md.digest("Hello world!".getBytes()));
+ verifyRSASignatures(s, md.digest("Hello world!".getBytes()));
+ }
+
+ public void testSHA1WithRSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signKP, _signCert, "SHA1withRSA");
+ }
+
+ public void testSHA1WithRSAEncapsulatedSubjectKeyID()
+ throws Exception
+ {
+ subjectKeyIDTest(_signKP, _signCert, "SHA1withRSA");
+ }
+
+ public void testSHA1WithRSAPSS()
+ throws Exception
+ {
+ rsaPSSTest("SHA1withRSAandMGF1");
+ }
+
+ public void testSHA224WithRSAPSS()
+ throws Exception
+ {
+ rsaPSSTest("SHA224withRSAandMGF1");
+ }
+
+ public void testSHA256WithRSAPSS()
+ throws Exception
+ {
+ rsaPSSTest("SHA256withRSAandMGF1");
+ }
+
+ public void testSHA384WithRSAPSS()
+ throws Exception
+ {
+ rsaPSSTest("SHA384withRSAandMGF1");
+ }
+
+ public void testSHA224WithRSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signKP, _signCert, "SHA224withRSA");
+ }
+
+ public void testSHA256WithRSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signKP, _signCert, "SHA256withRSA");
+ }
+
+ public void testRIPEMD128WithRSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signKP, _signCert, "RIPEMD128withRSA");
+ }
+
+ public void testRIPEMD160WithRSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signKP, _signCert, "RIPEMD160withRSA");
+ }
+
+ public void testRIPEMD256WithRSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signKP, _signCert, "RIPEMD256withRSA");
+ }
+
+ public void testECDSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signEcDsaKP, _signEcDsaCert, "SHA1withECDSA");
+ }
+
+ public void testECDSAEncapsulatedSubjectKeyID()
+ throws Exception
+ {
+ subjectKeyIDTest(_signEcDsaKP, _signEcDsaCert, "SHA1withECDSA");
+ }
+
+ public void testECDSASHA224Encapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signEcDsaKP, _signEcDsaCert, "SHA224withECDSA");
+ }
+
+ public void testECDSASHA256Encapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signEcDsaKP, _signEcDsaCert, "SHA256withECDSA");
+ }
+
+ public void testECDSASHA384Encapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signEcDsaKP, _signEcDsaCert, "SHA384withECDSA");
+ }
+
+ public void testECDSASHA512Encapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signEcDsaKP, _signEcDsaCert, "SHA512withECDSA");
+ }
+
+ public void testECDSASHA512EncapsulatedWithKeyFactoryAsEC()
+ throws Exception
+ {
+ X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(_signEcDsaKP.getPublic().getEncoded());
+ PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(_signEcDsaKP.getPrivate().getEncoded());
+ KeyFactory keyFact = KeyFactory.getInstance("EC", BC);
+ KeyPair kp = new KeyPair(keyFact.generatePublic(pubSpec), keyFact.generatePrivate(privSpec));
+
+ encapsulatedTest(kp, _signEcDsaCert, "SHA512withECDSA");
+ }
+
+ public void testDSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signDsaKP, _signDsaCert, "SHA1withDSA");
+ }
+
+ public void testDSAEncapsulatedSubjectKeyID()
+ throws Exception
+ {
+ subjectKeyIDTest(_signDsaKP, _signDsaCert, "SHA1withDSA");
+ }
+
+ public void testSHA1WithRSACounterSignature()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ List crlList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(_signCert);
+ certList.add(_origCert);
+
+ crlList.add(_signCrl);
+
+ Store certStore = new JcaCertStore(certList);
+ Store crlStore = new JcaCRLStore(crlList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_signKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _signCert));
+
+ gen.addCertificates(certStore);
+ gen.addCRLs(crlStore);
+
+ CMSSignedData s = gen.generate(msg, true);
+ SignerInformation origSigner = (SignerInformation)s.getSignerInfos().getSigners().toArray()[0];
+ SignerInformationStore counterSigners1 = gen.generateCounterSigners(origSigner);
+ SignerInformationStore counterSigners2 = gen.generateCounterSigners(origSigner);
+
+ SignerInformation signer1 = SignerInformation.addCounterSigners(origSigner, counterSigners1);
+ SignerInformation signer2 = SignerInformation.addCounterSigners(signer1, counterSigners2);
+
+ SignerInformationStore cs = signer2.getCounterSignatures();
+ Collection csSigners = cs.getSigners();
+ assertEquals(2, csSigners.size());
+
+ Iterator it = csSigners.iterator();
+ while (it.hasNext())
+ {
+ SignerInformation cSigner = (SignerInformation)it.next();
+ Collection certCollection = certStore.getMatches(cSigner.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertTrue(cSigner.isCounterSignature());
+ assertNull(cSigner.getSignedAttributes().get(PKCSObjectIdentifiers.pkcs_9_at_contentType));
+ assertEquals(true, cSigner.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+ }
+
+ private void rsaPSSTest(String signatureAlgorithmName)
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithmName).setProvider(BC).build(_origKP.getPrivate());
+
+ JcaSignerInfoGeneratorBuilder siBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ siBuilder.setDirectSignature(true);
+
+ gen.addSignerInfoGenerator(siBuilder.build(contentSigner, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(msg, false);
+
+ //
+ // compute expected content digest
+ //
+ String digestName = signatureAlgorithmName.substring(0, signatureAlgorithmName.indexOf('w'));
+ MessageDigest md = MessageDigest.getInstance(digestName, BC);
+
+ verifySignatures(s, md.digest("Hello world!".getBytes()));
+ }
+
+ private void subjectKeyIDTest(
+ KeyPair signaturePair,
+ X509Certificate signatureCert,
+ String signatureAlgorithm)
+ throws Exception
+ {
+ List certList = new ArrayList();
+ List crlList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(signatureCert);
+ certList.add(_origCert);
+
+ crlList.add(_signCrl);
+
+ Store certStore = new JcaCertStore(certList);
+ Store crlStore = new JcaCRLStore(crlList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).setProvider(BC).build(signaturePair.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(contentSigner, CMSTestUtil.createSubjectKeyId(signatureCert.getPublicKey()).getKeyIdentifier()));
+
+ gen.addCertificates(certStore);
+ gen.addCRLs(crlStore);
+
+ CMSSignedData s = gen.generate(msg, true);
+
+ assertEquals(3, s.getVersion());
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded());
+ ASN1InputStream aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ certStore = s.getCertificates();
+
+ SignerInformationStore signers = s.getSignerInfos();
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certStore.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+
+ //
+ // check for CRLs
+ //
+ Collection crls = crlStore.getMatches(null);
+
+ assertEquals(1, crls.size());
+
+ assertTrue(crls.contains(new JcaX509CRLHolder(_signCrl)));
+
+ //
+ // try using existing signer
+ //
+
+ gen = new CMSSignedDataGenerator();
+
+ gen.addSigners(s.getSignerInfos());
+
+ gen.addCertificates(s.getCertificates());
+
+ s = gen.generate(msg, true);
+
+ bIn = new ByteArrayInputStream(s.getEncoded());
+ aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ certStore = s.getCertificates();
+
+ signers = s.getSignerInfos();
+ c = signers.getSigners();
+ it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certStore.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+
+ checkSignerStoreReplacement(s, signers);
+ }
+
+ private void encapsulatedTest(
+ KeyPair signaturePair,
+ X509Certificate signatureCert,
+ String signatureAlgorithm)
+ throws Exception
+ {
+ ConfigurableProvider provider = (ConfigurableProvider)Security.getProvider(BC);
+
+ if (!provider.hasAlgorithm("Signature", signatureAlgorithm))
+ {
+ return;
+ }
+
+ List certList = new ArrayList();
+ List crlList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(signatureCert);
+ certList.add(_origCert);
+
+ crlList.add(_signCrl);
+
+ Store certs = new JcaCertStore(certList);
+ Store crlStore = new JcaCRLStore(crlList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).setProvider(BC).build(signaturePair.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(contentSigner, signatureCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(msg, true);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded());
+ ASN1InputStream aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ certs = s.getCertificates();
+
+ SignerInformationStore signers = s.getSignerInfos();
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+
+ //
+ // check for CRLs
+ //
+ Collection crls = crlStore.getMatches(null);
+
+ assertEquals(1, crls.size());
+
+ assertTrue(crls.contains(new JcaX509CRLHolder(_signCrl)));
+
+ //
+ // try using existing signer
+ //
+
+ gen = new CMSSignedDataGenerator();
+
+ gen.addSigners(s.getSignerInfos());
+
+ gen.addCertificates(s.getCertificates());
+
+ s = gen.generate(msg, true);
+
+ bIn = new ByteArrayInputStream(s.getEncoded());
+ aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ certs = s.getCertificates();
+
+ signers = s.getSignerInfos();
+ c = signers.getSigners();
+ it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+
+ checkSignerStoreReplacement(s, signers);
+ }
+
+ //
+ // signerInformation store replacement test.
+ //
+ private void checkSignerStoreReplacement(
+ CMSSignedData orig,
+ SignerInformationStore signers)
+ throws Exception
+ {
+ CMSSignedData s = CMSSignedData.replaceSigners(orig, signers);
+
+ Store certs = s.getCertificates();
+
+ signers = s.getSignerInfos();
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+ }
+
+ public void testUnsortedAttributes()
+ throws Exception
+ {
+ CMSSignedData s = new CMSSignedData(new CMSProcessableByteArray(disorderedMessage), disorderedSet);
+
+ Store certs = s.getCertificates();
+
+ SignerInformationStore signers = s.getSignerInfos();
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getMatches(signer.getSID());
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+ }
+
+ public void testNullContentWithSigner()
+ throws Exception
+ {
+ List certList = new ArrayList();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(new CMSAbsentContent(), false);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded());
+ ASN1InputStream aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ verifySignatures(s);
+ }
+
+ public void testWithAttributeCertificate()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+
+ certList.add(_signDsaCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ JcaSignerInfoGeneratorBuilder builder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(builder.build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ X509AttributeCertificateHolder attrCert = new X509AttributeCertificateHolder(CMSTestUtil.getAttributeCertificate().getEncoded());
+ List attrList = new ArrayList();
+
+ attrList.add(new X509AttributeCertificateHolder(attrCert.getEncoded()));
+
+ Store store = new CollectionStore(attrList);
+
+ gen.addAttributeCertificates(store);
+
+ CMSSignedData sd = gen.generate(msg);
+
+ assertEquals(4, sd.getVersion());
+
+ store = sd.getAttributeCertificates();
+
+ Collection coll = store.getMatches(null);
+
+ assertEquals(1, coll.size());
+
+ assertTrue(coll.contains(new X509AttributeCertificateHolder(attrCert.getEncoded())));
+
+ //
+ // create new certstore
+ //
+ certList = new ArrayList();
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ certs = new JcaCertStore(certList);
+
+
+ //
+ // replace certs
+ //
+ sd = CMSSignedData.replaceCertificatesAndCRLs(sd, certs, null, null);
+
+ verifySignatures(sd);
+ }
+
+ public void testCertStoreReplacement()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+
+ certList.add(_signDsaCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData sd = gen.generate(msg);
+
+ //
+ // create new certstore
+ //
+ certList = new ArrayList();
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ certs = new JcaCertStore(certList);
+
+ //
+ // replace certs
+ //
+ sd = CMSSignedData.replaceCertificatesAndCRLs(sd, certs, null, null);
+
+ verifySignatures(sd);
+ }
+
+ public void testEncapsulatedCertStoreReplacement()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+
+ certList.add(_signDsaCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData sd = gen.generate(msg, true);
+
+ //
+ // create new certstore
+ //
+ certList = new ArrayList();
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ certs = new JcaCertStore(certList);
+
+
+ //
+ // replace certs
+ //
+ sd = CMSSignedData.replaceCertificatesAndCRLs(sd, certs, null, null);
+
+ verifySignatures(sd);
+ }
+
+ public void testCertOrdering1()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+ certList.add(_signDsaCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData sd = gen.generate(msg, true);
+
+ certs = sd.getCertificates();
+ Iterator it = certs.getMatches(null).iterator();
+
+ assertEquals(new JcaX509CertificateHolder(_origCert), it.next());
+ assertEquals(new JcaX509CertificateHolder(_signCert), it.next());
+ assertEquals(new JcaX509CertificateHolder(_signDsaCert), it.next());
+ }
+
+ public void testCertOrdering2()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(_signCert);
+ certList.add(_signDsaCert);
+ certList.add(_origCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData sd = gen.generate(msg, true);
+
+ certs = sd.getCertificates();
+ Iterator it = certs.getMatches(null).iterator();
+
+ assertEquals(new JcaX509CertificateHolder(_signCert), it.next());
+ assertEquals(new JcaX509CertificateHolder(_signDsaCert), it.next());
+ assertEquals(new JcaX509CertificateHolder(_origCert), it.next());
+ }
+
+ public void testSignerStoreReplacement()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData original = gen.generate(msg, true);
+
+ //
+ // create new Signer
+ //
+ gen = new CMSSignedDataGenerator();
+
+ ContentSigner sha224Signer = new JcaContentSignerBuilder("SHA224withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha224Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData newSD = gen.generate(msg, true);
+
+ //
+ // replace signer
+ //
+ CMSSignedData sd = CMSSignedData.replaceSigners(original, newSD.getSignerInfos());
+
+ SignerInformation signer = (SignerInformation)sd.getSignerInfos().getSigners().iterator().next();
+
+ assertEquals(CMSAlgorithm.SHA224.getId(), signer.getDigestAlgOID());
+
+ // we use a parser here as it requires the digests to be correct in the digest set, if it
+ // isn't we'll get a NullPointerException
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), sd.getEncoded());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+ }
+
+ public void testEncapsulatedSamples()
+ throws Exception
+ {
+ testSample("PSSSignDataSHA1Enc.sig");
+ testSample("PSSSignDataSHA256Enc.sig");
+ testSample("PSSSignDataSHA512Enc.sig");
+ }
+
+ public void testSamples()
+ throws Exception
+ {
+ testSample("PSSSignData.data", "PSSSignDataSHA1.sig");
+ testSample("PSSSignData.data", "PSSSignDataSHA256.sig");
+ testSample("PSSSignData.data", "PSSSignDataSHA512.sig");
+ }
+
+ public void testCounterSig()
+ throws Exception
+ {
+ CMSSignedData sig = new CMSSignedData(getInput("counterSig.p7m"));
+
+ SignerInformationStore ss = sig.getSignerInfos();
+ Collection signers = ss.getSigners();
+
+ SignerInformationStore cs = ((SignerInformation)signers.iterator().next()).getCounterSignatures();
+ Collection csSigners = cs.getSigners();
+ assertEquals(1, csSigners.size());
+
+ Iterator it = csSigners.iterator();
+ while (it.hasNext())
+ {
+ SignerInformation cSigner = (SignerInformation)it.next();
+ Collection certCollection = sig.getCertificates().getMatches(cSigner.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertTrue(cSigner.isCounterSignature());
+ assertNull(cSigner.getSignedAttributes().get(PKCSObjectIdentifiers.pkcs_9_at_contentType));
+ assertEquals(true, cSigner.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+
+ verifySignatures(sig);
+ }
+
+ private void testSample(String sigName)
+ throws Exception
+ {
+ CMSSignedData sig = new CMSSignedData(getInput(sigName));
+
+ verifySignatures(sig);
+ }
+
+ private void testSample(String messageName, String sigName)
+ throws Exception
+ {
+ CMSSignedData sig = new CMSSignedData(new CMSProcessableByteArray(getInput(messageName)), getInput(sigName));
+
+ verifySignatures(sig);
+ }
+
+ private byte[] getInput(String name)
+ throws IOException
+ {
+ return Streams.readAll(getClass().getResourceAsStream(name));
+ }
+
+ public void testForMultipleCounterSignatures()
+ throws Exception
+ {
+ CMSSignedData sd = new CMSSignedData(xtraCounterSig);
+
+ for (Iterator sI = sd.getSignerInfos().getSigners().iterator(); sI.hasNext();)
+ {
+ SignerInformation sigI = (SignerInformation)sI.next();
+
+ SignerInformationStore counter = sigI.getCounterSignatures();
+ List sigs = new ArrayList(counter.getSigners());
+
+ assertEquals(2, sigs.size());
+ }
+ }
+
+ private void verifySignatures(CMSSignedDataParser sp)
+ throws Exception
+ {
+ Store certs = sp.getCertificates();
+ SignerInformationStore signers = sp.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+ }
+
+ private class TestCMSSignatureAlgorithmNameGenerator
+ extends DefaultCMSSignatureAlgorithmNameGenerator
+ {
+ void setDigestAlgorithmMapping(ASN1ObjectIdentifier oid, String algName)
+ {
+ super.setSigningDigestAlgorithmMapping(oid, algName);
+ }
+
+ void setEncryptionAlgorithmMapping(ASN1ObjectIdentifier oid, String algName)
+ {
+ super.setSigningEncryptionAlgorithmMapping(oid, algName);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/CMSSampleMessages.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/CMSSampleMessages.java
new file mode 100644
index 000000000..a9609df77
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/CMSSampleMessages.java
@@ -0,0 +1,147 @@
+package org.spongycastle.cms.test;
+
+import org.spongycastle.util.encoders.Base64;
+
+public class CMSSampleMessages
+{
+ static byte[] originatorMessage = Base64.decode(
+ "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"
+ + "k9HhGwwsgiR+");
+
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/CMSTestSetup.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/CMSTestSetup.java
new file mode 100644
index 000000000..644d3d3be
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/CMSTestSetup.java
@@ -0,0 +1,24 @@
+package org.spongycastle.cms.test;
+
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+
+import java.security.Security;
+
+class CMSTestSetup extends TestSetup
+{
+ public CMSTestSetup(Test test)
+ {
+ super(test);
+ }
+
+ protected void setUp()
+ {
+ Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider());
+ }
+
+ protected void tearDown()
+ {
+ Security.removeProvider("SC");
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/CMSTestUtil.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/CMSTestUtil.java
new file mode 100644
index 000000000..90c42e743
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/CMSTestUtil.java
@@ -0,0 +1,503 @@
+package org.spongycastle.cms.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.DSAParameterSpec;
+import java.util.Date;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSAESOAEPparams;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.cert.X509ExtensionUtils;
+import org.spongycastle.cert.X509v1CertificateBuilder;
+import org.spongycastle.cert.X509v2CRLBuilder;
+import org.spongycastle.cert.X509v3CertificateBuilder;
+import org.spongycastle.cert.jcajce.JcaX509CRLConverter;
+import org.spongycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.spongycastle.cert.jcajce.JcaX509ExtensionUtils;
+import org.spongycastle.cert.jcajce.JcaX509v1CertificateBuilder;
+import org.spongycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.spongycastle.jce.ECGOST3410NamedCurveTable;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.GOST3410ParameterSpec;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.util.encoders.Base64;
+
+public class CMSTestUtil
+{
+ public static SecureRandom rand;
+ public static KeyPairGenerator kpg;
+
+ public static KeyPairGenerator gostKpg;
+ public static KeyPairGenerator dsaKpg;
+ public static KeyPairGenerator ecGostKpg;
+ public static KeyPairGenerator ecDsaKpg;
+ public static KeyGenerator aes192kg;
+ public static KeyGenerator desede128kg;
+ public static KeyGenerator desede192kg;
+ public static KeyGenerator rc240kg;
+ public static KeyGenerator rc264kg;
+ public static KeyGenerator rc2128kg;
+ public static KeyGenerator aesKg;
+ public static KeyGenerator seedKg;
+ public static KeyGenerator camelliaKg;
+ public static BigInteger serialNumber;
+
+ public static final boolean DEBUG = true;
+
+ private static byte[] attrCert = Base64.decode(
+ "MIIHQDCCBqkCAQEwgZChgY2kgYowgYcxHDAaBgkqhkiG9w0BCQEWDW1sb3JjaEB2"
+ + "dC5lZHUxHjAcBgNVBAMTFU1hcmt1cyBMb3JjaCAobWxvcmNoKTEbMBkGA1UECxMS"
+ + "VmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAyMQswCQYDVQQKEwJ2"
+ + "dDELMAkGA1UEBhMCVVMwgYmkgYYwgYMxGzAZBgkqhkiG9w0BCQEWDHNzaGFoQHZ0"
+ + "LmVkdTEbMBkGA1UEAxMSU3VtaXQgU2hhaCAoc3NoYWgpMRswGQYDVQQLExJWaXJn"
+ + "aW5pYSBUZWNoIFVzZXIxEDAOBgNVBAsTB0NsYXNzIDExCzAJBgNVBAoTAnZ0MQsw"
+ + "CQYDVQQGEwJVUzANBgkqhkiG9w0BAQQFAAIBBTAiGA8yMDAzMDcxODE2MDgwMloY"
+ + "DzIwMDMwNzI1MTYwODAyWjCCBU0wggVJBgorBgEEAbRoCAEBMYIFORaCBTU8UnVs"
+ + "ZSBSdWxlSWQ9IkZpbGUtUHJpdmlsZWdlLVJ1bGUiIEVmZmVjdD0iUGVybWl0Ij4K"
+ + "IDxUYXJnZXQ+CiAgPFN1YmplY3RzPgogICA8U3ViamVjdD4KICAgIDxTdWJqZWN0"
+ + "TWF0Y2ggTWF0Y2hJZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5j"
+ + "dGlvbjpzdHJpbmctZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlw"
+ + "ZT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjc3RyaW5nIj4KICAg"
+ + "ICAgIENOPU1hcmt1cyBMb3JjaDwvQXR0cmlidXRlVmFsdWU+CiAgICAgPFN1Ympl"
+ + "Y3RBdHRyaWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFt"
+ + "ZXM6dGM6eGFjbWw6MS4wOnN1YmplY3Q6c3ViamVjdC1pZCIgRGF0YVR5cGU9Imh0"
+ + "dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hI3N0cmluZyIgLz4gCiAgICA8"
+ + "L1N1YmplY3RNYXRjaD4KICAgPC9TdWJqZWN0PgogIDwvU3ViamVjdHM+CiAgPFJl"
+ + "c291cmNlcz4KICAgPFJlc291cmNlPgogICAgPFJlc291cmNlTWF0Y2ggTWF0Y2hJ"
+ + "ZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5jdGlvbjpzdHJpbmct"
+ + "ZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlwZT0iaHR0cDovL3d3"
+ + "dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIj4KICAgICAgaHR0cDovL3p1"
+ + "bmkuY3MudnQuZWR1PC9BdHRyaWJ1dGVWYWx1ZT4KICAgICA8UmVzb3VyY2VBdHRy"
+ + "aWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6"
+ + "eGFjbWw6MS4wOnJlc291cmNlOnJlc291cmNlLWlkIiBEYXRhVHlwZT0iaHR0cDov"
+ + "L3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIiAvPiAKICAgIDwvUmVz"
+ + "b3VyY2VNYXRjaD4KICAgPC9SZXNvdXJjZT4KICA8L1Jlc291cmNlcz4KICA8QWN0"
+ + "aW9ucz4KICAgPEFjdGlvbj4KICAgIDxBY3Rpb25NYXRjaCBNYXRjaElkPSJ1cm46"
+ + "b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmZ1bmN0aW9uOnN0cmluZy1lcXVhbCI+"
+ + "CiAgICAgPEF0dHJpYnV0ZVZhbHVlIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9y"
+ + "Zy8yMDAxL1hNTFNjaGVtYSNzdHJpbmciPgpEZWxlZ2F0ZSBBY2Nlc3MgICAgIDwv"
+ + "QXR0cmlidXRlVmFsdWU+CgkgIDxBY3Rpb25BdHRyaWJ1dGVEZXNpZ25hdG9yIEF0"
+ + "dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmFjdGlvbjph"
+ + "Y3Rpb24taWQiIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNj"
+ + "aGVtYSNzdHJpbmciIC8+IAogICAgPC9BY3Rpb25NYXRjaD4KICAgPC9BY3Rpb24+"
+ + "CiAgPC9BY3Rpb25zPgogPC9UYXJnZXQ+CjwvUnVsZT4KMA0GCSqGSIb3DQEBBAUA"
+ + "A4GBAGiJSM48XsY90HlYxGmGVSmNR6ZW2As+bot3KAfiCIkUIOAqhcphBS23egTr"
+ + "6asYwy151HshbPNYz+Cgeqs45KkVzh7bL/0e1r8sDVIaaGIkjHK3CqBABnfSayr3"
+ + "Rd1yBoDdEv8Qb+3eEPH6ab9021AsLEnJ6LWTmybbOpMNZ3tv");
+
+ static
+ {
+ try
+ {
+ java.security.Security.addProvider(new BouncyCastleProvider());
+
+ rand = new SecureRandom();
+
+ kpg = KeyPairGenerator.getInstance("RSA", "SC");
+ kpg.initialize(1024, rand);
+
+ kpg = KeyPairGenerator.getInstance("RSA", "SC");
+ kpg.initialize(1024, rand);
+
+ gostKpg = KeyPairGenerator.getInstance("GOST3410", "SC");
+ GOST3410ParameterSpec gost3410P = new GOST3410ParameterSpec(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_A.getId());
+
+ gostKpg.initialize(gost3410P, new SecureRandom());
+
+ dsaKpg = KeyPairGenerator.getInstance("DSA", "SC");
+ DSAParameterSpec dsaSpec = new DSAParameterSpec(
+ new BigInteger("7434410770759874867539421675728577177024889699586189000788950934679315164676852047058354758883833299702695428196962057871264685291775577130504050839126673"),
+ new BigInteger("1138656671590261728308283492178581223478058193247"),
+ new BigInteger("4182906737723181805517018315469082619513954319976782448649747742951189003482834321192692620856488639629011570381138542789803819092529658402611668375788410"));
+
+ dsaKpg.initialize(dsaSpec, new SecureRandom());
+
+ ecGostKpg = KeyPairGenerator.getInstance("ECGOST3410", "SC");
+ ecGostKpg.initialize(ECGOST3410NamedCurveTable.getParameterSpec("GostR3410-2001-CryptoPro-A"), new SecureRandom());
+
+ ecDsaKpg = KeyPairGenerator.getInstance("ECDSA", "SC");
+ ecDsaKpg.initialize(239, new SecureRandom());
+
+ aes192kg = KeyGenerator.getInstance("AES", "SC");
+ aes192kg.init(192, rand);
+
+ desede128kg = KeyGenerator.getInstance("DESEDE", "SC");
+ desede128kg.init(112, rand);
+
+ desede192kg = KeyGenerator.getInstance("DESEDE", "SC");
+ desede192kg.init(168, rand);
+
+ rc240kg = KeyGenerator.getInstance("RC2", "SC");
+ rc240kg.init(40, rand);
+
+ rc264kg = KeyGenerator.getInstance("RC2", "SC");
+ rc264kg.init(64, rand);
+
+ rc2128kg = KeyGenerator.getInstance("RC2", "SC");
+ rc2128kg.init(128, rand);
+
+ aesKg = KeyGenerator.getInstance("AES", "SC");
+
+ seedKg = KeyGenerator.getInstance("SEED", "SC");
+
+ camelliaKg = KeyGenerator.getInstance("Camellia", "SC");
+
+ serialNumber = new BigInteger("1");
+ }
+ catch (Exception ex)
+ {
+ throw new RuntimeException(ex.toString());
+ }
+ }
+
+ public static String dumpBase64(
+ byte[] data)
+ {
+ StringBuffer buf = new StringBuffer();
+
+ data = Base64.encode(data);
+
+ for (int i = 0; i < data.length; i += 64)
+ {
+ if (i + 64 < data.length)
+ {
+ buf.append(new String(data, i, 64));
+ }
+ else
+ {
+ buf.append(new String(data, i, data.length - i));
+ }
+ buf.append('\n');
+ }
+
+ return buf.toString();
+ }
+
+ public static X509AttributeCertificateHolder getAttributeCertificate()
+ throws Exception
+ {
+ return new X509AttributeCertificateHolder(CMSTestUtil.attrCert);
+ }
+
+ public static KeyPair makeKeyPair()
+ {
+ return kpg.generateKeyPair();
+ }
+
+ public static KeyPair makeGostKeyPair()
+ {
+ return gostKpg.generateKeyPair();
+ }
+
+ public static KeyPair makeDsaKeyPair()
+ {
+ return dsaKpg.generateKeyPair();
+ }
+
+ public static KeyPair makeEcDsaKeyPair()
+ {
+ return ecDsaKpg.generateKeyPair();
+ }
+
+ public static KeyPair makeEcGostKeyPair()
+ {
+ return ecGostKpg.generateKeyPair();
+ }
+
+ public static SecretKey makeDesede128Key()
+ {
+ return desede128kg.generateKey();
+ }
+
+ public static SecretKey makeAES192Key()
+ {
+ return aes192kg.generateKey();
+ }
+
+ public static SecretKey makeDesede192Key()
+ {
+ return desede192kg.generateKey();
+ }
+
+ public static SecretKey makeRC240Key()
+ {
+ return rc240kg.generateKey();
+ }
+
+ public static SecretKey makeRC264Key()
+ {
+ return rc264kg.generateKey();
+ }
+
+ public static SecretKey makeRC2128Key()
+ {
+ return rc2128kg.generateKey();
+ }
+
+ public static SecretKey makeSEEDKey()
+ {
+ return seedKg.generateKey();
+ }
+
+ public static SecretKey makeAESKey(int keySize)
+ {
+ aesKg.init(keySize);
+ return aesKg.generateKey();
+ }
+
+ public static SecretKey makeCamelliaKey(int keySize)
+ {
+ camelliaKg.init(keySize);
+ return camelliaKg.generateKey();
+ }
+
+ public static X509Certificate makeCertificate(KeyPair _subKP,
+ String _subDN, KeyPair _issKP, String _issDN)
+ throws GeneralSecurityException, IOException, OperatorCreationException
+ {
+ return makeCertificate(_subKP, _subDN, _issKP, _issDN, false);
+ }
+
+ public static X509Certificate makeOaepCertificate(KeyPair _subKP,
+ String _subDN, KeyPair _issKP, String _issDN)
+ throws GeneralSecurityException, IOException, OperatorCreationException
+ {
+ return makeOaepCertificate(_subKP, _subDN, _issKP, _issDN, false);
+ }
+
+ public static X509Certificate makeCACertificate(KeyPair _subKP,
+ String _subDN, KeyPair _issKP, String _issDN)
+ throws GeneralSecurityException, IOException, OperatorCreationException
+ {
+ return makeCertificate(_subKP, _subDN, _issKP, _issDN, true);
+ }
+
+ public static X509Certificate makeV1Certificate(KeyPair subKP, String _subDN, KeyPair issKP, String _issDN)
+ throws GeneralSecurityException, IOException, OperatorCreationException
+ {
+
+ PublicKey subPub = subKP.getPublic();
+ PrivateKey issPriv = issKP.getPrivate();
+ PublicKey issPub = issKP.getPublic();
+
+ X509v1CertificateBuilder v1CertGen = new JcaX509v1CertificateBuilder(
+ new X500Name(_issDN),
+ allocateSerialNumber(),
+ new Date(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)),
+ new X500Name(_subDN),
+ subPub);
+
+ JcaContentSignerBuilder contentSignerBuilder = makeContentSignerBuilder(issPub);
+
+ X509Certificate _cert = new JcaX509CertificateConverter().setProvider("SC").getCertificate(v1CertGen.build(contentSignerBuilder.build(issPriv)));
+
+ _cert.checkValidity(new Date());
+ _cert.verify(issPub);
+
+ return _cert;
+ }
+
+ public static X509Certificate makeCertificate(KeyPair subKP, String _subDN, KeyPair issKP, String _issDN, boolean _ca)
+ throws GeneralSecurityException, IOException, OperatorCreationException
+ {
+
+ PublicKey subPub = subKP.getPublic();
+ PrivateKey issPriv = issKP.getPrivate();
+ PublicKey issPub = issKP.getPublic();
+
+ X509v3CertificateBuilder v3CertGen = new JcaX509v3CertificateBuilder(
+ new X500Name(_issDN),
+ allocateSerialNumber(),
+ new Date(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)),
+ new X500Name(_subDN),
+ subPub);
+
+ JcaContentSignerBuilder contentSignerBuilder = makeContentSignerBuilder(issPub);
+
+ v3CertGen.addExtension(
+ Extension.subjectKeyIdentifier,
+ false,
+ createSubjectKeyId(subPub));
+
+ v3CertGen.addExtension(
+ Extension.authorityKeyIdentifier,
+ false,
+ createAuthorityKeyId(issPub));
+
+ v3CertGen.addExtension(
+ Extension.basicConstraints,
+ false,
+ new BasicConstraints(_ca));
+
+ X509Certificate _cert = new JcaX509CertificateConverter().setProvider("SC").getCertificate(v3CertGen.build(contentSignerBuilder.build(issPriv)));
+
+ _cert.checkValidity(new Date());
+ _cert.verify(issPub);
+
+ return _cert;
+ }
+
+ public static X509Certificate makeOaepCertificate(KeyPair subKP, String _subDN, KeyPair issKP, String _issDN, boolean _ca)
+ throws GeneralSecurityException, IOException, OperatorCreationException
+ {
+
+ SubjectPublicKeyInfo subPub = SubjectPublicKeyInfo.getInstance(subKP.getPublic().getEncoded());
+ PrivateKey issPriv = issKP.getPrivate();
+ PublicKey issPub = issKP.getPublic();
+
+ X509v3CertificateBuilder v3CertGen = new X509v3CertificateBuilder(
+ new X500Name(_issDN),
+ allocateSerialNumber(),
+ new Date(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)),
+ new X500Name(_subDN),
+ new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP, new RSAESOAEPparams()), subPub.parsePublicKey()));
+
+ JcaContentSignerBuilder contentSignerBuilder = makeContentSignerBuilder(issPub);
+
+ v3CertGen.addExtension(
+ Extension.subjectKeyIdentifier,
+ false,
+ createSubjectKeyId(subPub));
+
+ v3CertGen.addExtension(
+ Extension.authorityKeyIdentifier,
+ false,
+ createAuthorityKeyId(issPub));
+
+ v3CertGen.addExtension(
+ Extension.basicConstraints,
+ false,
+ new BasicConstraints(_ca));
+
+ X509Certificate _cert = new JcaX509CertificateConverter().setProvider("SC").getCertificate(v3CertGen.build(contentSignerBuilder.build(issPriv)));
+
+ _cert.checkValidity(new Date());
+ _cert.verify(issPub);
+
+ return _cert;
+ }
+
+ private static JcaContentSignerBuilder makeContentSignerBuilder(PublicKey issPub)
+ {
+ JcaContentSignerBuilder contentSignerBuilder;
+ if (issPub instanceof RSAPublicKey)
+ {
+ contentSignerBuilder = new JcaContentSignerBuilder("SHA1WithRSA");
+ }
+ else if (issPub.getAlgorithm().equals("DSA"))
+ {
+ contentSignerBuilder = new JcaContentSignerBuilder("SHA1withDSA");
+ }
+ else if (issPub.getAlgorithm().equals("ECDSA"))
+ {
+ contentSignerBuilder = new JcaContentSignerBuilder("SHA1withECDSA");
+ }
+ else if (issPub.getAlgorithm().equals("ECGOST3410"))
+ {
+ contentSignerBuilder = new JcaContentSignerBuilder("GOST3411withECGOST3410");
+ }
+ else
+ {
+ contentSignerBuilder = new JcaContentSignerBuilder("GOST3411WithGOST3410");
+ }
+
+ contentSignerBuilder.setProvider(BouncyCastleProvider.PROVIDER_NAME);
+
+ return contentSignerBuilder;
+ }
+
+ public static X509CRL makeCrl(KeyPair pair)
+ throws Exception
+ {
+ Date now = new Date();
+ X509v2CRLBuilder crlGen = new X509v2CRLBuilder(new X500Name("CN=Test CA"), now);
+ JcaX509ExtensionUtils extensionUtils = new JcaX509ExtensionUtils();
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ crlGen.addCRLEntry(BigInteger.ONE, now, CRLReason.privilegeWithdrawn);
+
+ crlGen.addExtension(Extension.authorityKeyIdentifier, false, extensionUtils.createAuthorityKeyIdentifier(pair.getPublic()));
+
+ return new JcaX509CRLConverter().setProvider("SC").getCRL(crlGen.build(new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider("SC").build(pair.getPrivate())));
+ }
+
+ /*
+ *
+ * INTERNAL METHODS
+ *
+ */
+
+ private static final X509ExtensionUtils extUtils = new X509ExtensionUtils(new SHA1DigestCalculator());
+
+ private static AuthorityKeyIdentifier createAuthorityKeyId(
+ PublicKey _pubKey)
+ throws IOException
+ {
+ return extUtils.createAuthorityKeyIdentifier(SubjectPublicKeyInfo.getInstance(_pubKey.getEncoded()));
+ }
+
+ static SubjectKeyIdentifier createSubjectKeyId(
+ SubjectPublicKeyInfo _pubKey)
+ throws IOException
+ {
+ return extUtils.createSubjectKeyIdentifier(_pubKey);
+ }
+
+ static SubjectKeyIdentifier createSubjectKeyId(
+ PublicKey _pubKey)
+ throws IOException
+ {
+ return extUtils.createSubjectKeyIdentifier(SubjectPublicKeyInfo.getInstance(_pubKey.getEncoded()));
+ }
+
+ private static BigInteger allocateSerialNumber()
+ {
+ BigInteger _tmp = serialNumber;
+ serialNumber = serialNumber.add(BigInteger.ONE);
+ return _tmp;
+ }
+
+ public static byte[] streamToByteArray(
+ InputStream in)
+ throws IOException
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ int ch;
+
+ while ((ch = in.read()) >= 0)
+ {
+ bOut.write(ch);
+ }
+
+ return bOut.toByteArray();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/ConverterTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/ConverterTest.java
new file mode 100644
index 000000000..cf08054d4
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/ConverterTest.java
@@ -0,0 +1,111 @@
+package org.spongycastle.cms.test;
+
+import java.math.BigInteger;
+import java.security.cert.X509CertSelector;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cms.KeyTransRecipientId;
+import org.spongycastle.cms.SignerId;
+import org.spongycastle.cms.jcajce.JcaSelectorConverter;
+import org.spongycastle.cms.jcajce.JcaX509CertSelectorConverter;
+import org.spongycastle.util.Arrays;
+
+public class ConverterTest
+ extends TestCase
+{
+ public void testSignerIdConversion()
+ throws Exception
+ {
+ JcaX509CertSelectorConverter converter = new JcaX509CertSelectorConverter();
+ JcaSelectorConverter toSelector = new JcaSelectorConverter();
+
+ SignerId sid1 = new SignerId(new X500Name("CN=Test"), BigInteger.valueOf(1), new byte[20]);
+
+ X509CertSelector conv = converter.getCertSelector(sid1);
+
+ assertTrue(conv.getIssuerAsString().equals("CN=Test"));
+ assertTrue(Arrays.areEqual(conv.getSubjectKeyIdentifier(), new DEROctetString(new byte[20]).getEncoded()));
+ assertEquals(conv.getSerialNumber(), sid1.getSerialNumber());
+
+ SignerId sid2 = toSelector.getSignerId(conv);
+
+ assertEquals(sid1, sid2);
+
+ sid1 = new SignerId(new X500Name("CN=Test"), BigInteger.valueOf(1));
+
+ conv = converter.getCertSelector(sid1);
+
+ assertTrue(conv.getIssuerAsString().equals("CN=Test"));
+ assertNull(conv.getSubjectKeyIdentifier());
+ assertEquals(conv.getSerialNumber(), sid1.getSerialNumber());
+
+ sid2 = toSelector.getSignerId(conv);
+
+ assertEquals(sid1, sid2);
+
+ sid1 = new SignerId(new byte[20]);
+
+ conv = converter.getCertSelector(sid1);
+
+ assertNull(conv.getIssuerAsString());
+ assertTrue(Arrays.areEqual(conv.getSubjectKeyIdentifier(), new DEROctetString(new byte[20]).getEncoded()));
+ assertNull(conv.getSerialNumber());
+
+ sid2 = toSelector.getSignerId(conv);
+
+ assertEquals(sid1, sid2);
+ }
+
+ public void testRecipientIdConversion()
+ throws Exception
+ {
+ JcaX509CertSelectorConverter converter = new JcaX509CertSelectorConverter();
+ JcaSelectorConverter toSelector = new JcaSelectorConverter();
+
+ KeyTransRecipientId ktid1 = new KeyTransRecipientId(new X500Name("CN=Test"), BigInteger.valueOf(1), new byte[20]);
+
+ X509CertSelector conv = converter.getCertSelector(ktid1);
+
+ assertTrue(conv.getIssuerAsString().equals("CN=Test"));
+ assertTrue(Arrays.areEqual(conv.getSubjectKeyIdentifier(), new DEROctetString(new byte[20]).getEncoded()));
+ assertEquals(conv.getSerialNumber(), ktid1.getSerialNumber());
+
+ KeyTransRecipientId ktid2 = toSelector.getKeyTransRecipientId(conv);
+
+ assertEquals(ktid1, ktid2);
+
+ ktid1 = new KeyTransRecipientId(new X500Name("CN=Test"), BigInteger.valueOf(1));
+
+ conv = converter.getCertSelector(ktid1);
+
+ assertTrue(conv.getIssuerAsString().equals("CN=Test"));
+ assertNull(conv.getSubjectKeyIdentifier());
+ assertEquals(conv.getSerialNumber(), ktid1.getSerialNumber());
+
+ ktid2 = toSelector.getKeyTransRecipientId(conv);
+
+ assertEquals(ktid1, ktid2);
+
+ ktid1 = new KeyTransRecipientId(new byte[20]);
+
+ conv = converter.getCertSelector(ktid1);
+
+ assertNull(conv.getIssuerAsString());
+ assertTrue(Arrays.areEqual(conv.getSubjectKeyIdentifier(), new DEROctetString(new byte[20]).getEncoded()));
+ assertNull(conv.getSerialNumber());
+
+ ktid2 = toSelector.getKeyTransRecipientId(conv);
+
+ assertEquals(ktid1, ktid2);
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ return new TestSuite(ConverterTest.class);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/MiscDataStreamTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/MiscDataStreamTest.java
new file mode 100644
index 000000000..d01b68e3d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/MiscDataStreamTest.java
@@ -0,0 +1,265 @@
+package org.spongycastle.cms.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.security.KeyPair;
+import java.security.MessageDigest;
+import java.security.Security;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.jcajce.JcaCRLStore;
+import org.spongycastle.cert.jcajce.JcaCertStore;
+import org.spongycastle.cms.CMSCompressedDataStreamGenerator;
+import org.spongycastle.cms.CMSDigestedData;
+import org.spongycastle.cms.CMSSignedDataParser;
+import org.spongycastle.cms.CMSSignedDataStreamGenerator;
+import org.spongycastle.cms.CMSTypedStream;
+import org.spongycastle.cms.SignerInformation;
+import org.spongycastle.cms.SignerInformationStore;
+import org.spongycastle.cms.jcajce.JcaSignerInfoVerifierBuilder;
+import org.spongycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder;
+import org.spongycastle.cms.jcajce.JcaX509CertSelectorConverter;
+import org.spongycastle.cms.jcajce.ZlibCompressor;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Store;
+import org.spongycastle.util.encoders.Base64;
+
+public class MiscDataStreamTest
+ extends TestCase
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ private static byte[] data = Base64.decode(
+ "TUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi9v" +
+ "Y3RldC1zdHJlYW0KQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogYmluYXJ5" +
+ "CkNvbnRlbnQtRGlzcG9zaXRpb246IGF0dGFjaG1lbnQ7IGZpbGVuYW1lPWRv" +
+ "Yy5iaW4KClRoaXMgaXMgYSB2ZXJ5IGh1Z2Ugc2VjcmV0LCBtYWRlIHdpdGgg" +
+ "b3BlbnNzbAoKCgo=");
+
+ private static byte[] digestedData = Base64.decode(
+ "MIIBGAYJKoZIhvcNAQcFoIIBCTCCAQUCAQAwCwYJYIZIAWUDBAIBMIHQBgkq"
+ + "hkiG9w0BBwGggcIEgb9NSU1FLVZlcnNpb246IDEuMApDb250ZW50LVR5cGU6"
+ + "IGFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbQpDb250ZW50LVRyYW5zZmVyLUVu"
+ + "Y29kaW5nOiBiaW5hcnkKQ29udGVudC1EaXNwb3NpdGlvbjogYXR0YWNobWVu"
+ + "dDsgZmlsZW5hbWU9ZG9jLmJpbgoKVGhpcyBpcyBhIHZlcnkgaHVnZSBzZWNy"
+ + "ZXQsIG1hZGUgd2l0aCBvcGVuc3NsCgoKCgQgHLG72tSYW0LgcxOA474iwdCv"
+ + "KyhnaV4RloWTAvkq+do=");
+
+ private static final String TEST_MESSAGE = "Hello World!";
+ private static String _signDN;
+ private static KeyPair _signKP;
+ private static X509Certificate _signCert;
+
+ private static String _origDN;
+ private static KeyPair _origKP;
+ private static X509Certificate _origCert;
+
+ private static String _reciDN;
+ private static KeyPair _reciKP;
+ private static X509Certificate _reciCert;
+
+ private static KeyPair _origDsaKP;
+ private static X509Certificate _origDsaCert;
+
+ private static X509CRL _signCrl;
+ private static X509CRL _origCrl;
+
+ private static boolean _initialised = false;
+
+ private static final JcaX509CertSelectorConverter selectorConverter = new JcaX509CertSelectorConverter();
+
+ private static final DigestCalculatorProvider digCalcProv;
+
+ static
+ {
+ try
+ {
+ digCalcProv = new JcaDigestCalculatorProviderBuilder().build();
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new IllegalStateException("can't create default provider!!!");
+ }
+ }
+
+ public MiscDataStreamTest(String name)
+ {
+ super(name);
+ }
+
+ private static void init()
+ throws Exception
+ {
+ if (!_initialised)
+ {
+ _initialised = true;
+ Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider());
+
+ _signDN = "O=Bouncy Castle, C=AU";
+ _signKP = CMSTestUtil.makeKeyPair();
+ _signCert = CMSTestUtil.makeCertificate(_signKP, _signDN, _signKP, _signDN);
+
+ _origDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+ _origKP = CMSTestUtil.makeKeyPair();
+ _origCert = CMSTestUtil.makeCertificate(_origKP, _origDN, _signKP, _signDN);
+
+ _origDsaKP = CMSTestUtil.makeDsaKeyPair();
+ _origDsaCert = CMSTestUtil.makeCertificate(_origDsaKP, _origDN, _signKP, _signDN);
+
+ _reciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+ _reciKP = CMSTestUtil.makeKeyPair();
+ _reciCert = CMSTestUtil.makeCertificate(_reciKP, _reciDN, _signKP, _signDN);
+
+ _signCrl = CMSTestUtil.makeCrl(_signKP);
+ _origCrl = CMSTestUtil.makeCrl(_origKP);
+ }
+ }
+
+ private void verifySignatures(CMSSignedDataParser sp, byte[] contentDigest)
+ throws Exception
+ {
+ Store certStore = sp.getCertificates();
+ SignerInformationStore signers = sp.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certStore.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSignerInfoVerifierBuilder(digCalcProv).setProvider(BC).build(cert)));
+
+ if (contentDigest != null)
+ {
+ assertTrue(MessageDigest.isEqual(contentDigest, signer.getContentDigest()));
+ }
+ }
+ }
+
+ private void verifySignatures(CMSSignedDataParser sp)
+ throws Exception
+ {
+ verifySignatures(sp, null);
+ }
+
+ private void verifyEncodedData(ByteArrayOutputStream bOut)
+ throws Exception
+ {
+ CMSSignedDataParser sp;
+ sp = new CMSSignedDataParser(digCalcProv, bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+
+ sp.close();
+ }
+
+ private void checkSigParseable(byte[] sig)
+ throws Exception
+ {
+ CMSSignedDataParser sp = new CMSSignedDataParser(digCalcProv, sig);
+ sp.getVersion();
+ CMSTypedStream sc = sp.getSignedContent();
+ if (sc != null)
+ {
+ sc.drain();
+ }
+ sp.getCertificates();
+ sp.getSignerInfos();
+ sp.close();
+ }
+
+ public void testSHA1WithRSA()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ List crlList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ crlList.add(_signCrl);
+ crlList.add(_origCrl);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder().setProvider(BC).build("SHA1withRSA", _origKP.getPrivate(), _origCert));
+
+ gen.addCertificates(new JcaCertStore(certList));
+ gen.addCRLs(new JcaCRLStore(crlList));
+
+ OutputStream sigOut = gen.open(bOut);
+
+ CMSCompressedDataStreamGenerator cGen = new CMSCompressedDataStreamGenerator();
+
+ OutputStream cOut = cGen.open(sigOut, new ZlibCompressor());
+
+ cOut.write(TEST_MESSAGE.getBytes());
+
+ cOut.close();
+
+ sigOut.close();
+
+ checkSigParseable(bOut.toByteArray());
+
+ // generate compressed stream
+ ByteArrayOutputStream cDataOut = new ByteArrayOutputStream();
+
+ cOut = cGen.open(cDataOut, new ZlibCompressor());
+
+ cOut.write(TEST_MESSAGE.getBytes());
+
+ cOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(digCalcProv,
+ new CMSTypedStream(new ByteArrayInputStream(cDataOut.toByteArray())), bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+
+ verifySignatures(sp, md.digest(cDataOut.toByteArray()));
+ }
+
+ public void testDigestedData()
+ throws Exception
+ {
+ CMSDigestedData digData = new CMSDigestedData(digestedData);
+
+ assertTrue(Arrays.areEqual(data, (byte[])digData.getDigestedContent().getContent()));
+
+ assertTrue(digData.verify(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()));
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ init();
+
+ return new CMSTestSetup(new TestSuite(MiscDataStreamTest.class));
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewAuthenticatedDataStreamTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewAuthenticatedDataStreamTest.java
new file mode 100644
index 000000000..589c64e4a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewAuthenticatedDataStreamTest.java
@@ -0,0 +1,251 @@
+package org.spongycastle.cms.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.security.KeyPair;
+import java.security.Security;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSAuthenticatedDataParser;
+import org.spongycastle.cms.CMSAuthenticatedDataStreamGenerator;
+import org.spongycastle.cms.OriginatorInfoGenerator;
+import org.spongycastle.cms.RecipientInformation;
+import org.spongycastle.cms.RecipientInformationStore;
+import org.spongycastle.cms.jcajce.JceCMSMacCalculatorBuilder;
+import org.spongycastle.cms.jcajce.JceKeyTransAuthenticatedRecipient;
+import org.spongycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+
+public class NewAuthenticatedDataStreamTest
+ extends TestCase
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ private static String _signDN;
+ private static KeyPair _signKP;
+ private static X509Certificate _signCert;
+
+ private static String _origDN;
+ private static KeyPair _origKP;
+ private static X509Certificate _origCert;
+
+ private static String _reciDN;
+ private static KeyPair _reciKP;
+ private static X509Certificate _reciCert;
+
+ private static KeyPair _origEcKP;
+ private static KeyPair _reciEcKP;
+ private static X509Certificate _reciEcCert;
+
+ private static boolean _initialised = false;
+
+ public boolean DEBUG = true;
+
+ private static void init()
+ throws Exception
+ {
+ if (!_initialised)
+ {
+ _initialised = true;
+ Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider());
+
+ _signDN = "O=Bouncy Castle, C=AU";
+ _signKP = CMSTestUtil.makeKeyPair();
+ _signCert = CMSTestUtil.makeCertificate(_signKP, _signDN, _signKP, _signDN);
+
+ _origDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+ _origKP = CMSTestUtil.makeKeyPair();
+ _origCert = CMSTestUtil.makeCertificate(_origKP, _origDN, _signKP, _signDN);
+
+ _reciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+ _reciKP = CMSTestUtil.makeKeyPair();
+ _reciCert = CMSTestUtil.makeCertificate(_reciKP, _reciDN, _signKP, _signDN);
+
+ _origEcKP = CMSTestUtil.makeEcDsaKeyPair();
+ _reciEcKP = CMSTestUtil.makeEcDsaKeyPair();
+ _reciEcCert = CMSTestUtil.makeCertificate(_reciEcKP, _reciDN, _signKP, _signDN);
+ }
+ }
+
+ public void setUp()
+ throws Exception
+ {
+ init();
+ }
+
+ public NewAuthenticatedDataStreamTest(String name)
+ {
+ super(name);
+ }
+
+ public static void main(String args[])
+ {
+ junit.textui.TestRunner.run(NewAuthenticatedDataStreamTest.class);
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ init();
+
+ return new CMSTestSetup(new TestSuite(NewAuthenticatedDataStreamTest.class));
+ }
+
+ public void testKeyTransDESede()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.DES_EDE3_CBC);
+ }
+
+ public void testKeyTransDESedeWithDigest()
+ throws Exception
+ {
+ tryKeyTransWithDigest(CMSAlgorithm.DES_EDE3_CBC);
+ }
+
+ public void testOriginatorInfo()
+ throws Exception
+ {
+ ASN1ObjectIdentifier macAlg = CMSAlgorithm.DES_EDE3_CBC;
+ byte[] data = "Eric H. Echidna".getBytes();
+
+ CMSAuthenticatedDataStreamGenerator adGen = new CMSAuthenticatedDataStreamGenerator();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ X509CertificateHolder origCert = new X509CertificateHolder(_origCert.getEncoded());
+
+ adGen.setOriginatorInfo(new OriginatorInfoGenerator(origCert).generate());
+
+ adGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ OutputStream aOut = adGen.open(bOut, new JceCMSMacCalculatorBuilder(macAlg).setProvider(BC).build());
+
+ aOut.write(data);
+
+ aOut.close();
+
+ CMSAuthenticatedDataParser ad = new CMSAuthenticatedDataParser(bOut.toByteArray());
+
+ assertTrue(ad.getOriginatorInfo().getCertificates().getMatches(null).contains(origCert));
+
+ RecipientInformationStore recipients = ad.getRecipientInfos();
+
+ assertEquals(ad.getMacAlgOID(), macAlg.getId());
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransAuthenticatedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ assertTrue(Arrays.equals(ad.getMac(), recipient.getMac()));
+ }
+ }
+
+ private void tryKeyTrans(ASN1ObjectIdentifier macAlg)
+ throws Exception
+ {
+ byte[] data = "Eric H. Echidna".getBytes();
+
+ CMSAuthenticatedDataStreamGenerator adGen = new CMSAuthenticatedDataStreamGenerator();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ adGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ OutputStream aOut = adGen.open(bOut, new JceCMSMacCalculatorBuilder(macAlg).setProvider(BC).build());
+
+ aOut.write(data);
+
+ aOut.close();
+
+ CMSAuthenticatedDataParser ad = new CMSAuthenticatedDataParser(bOut.toByteArray());
+
+ RecipientInformationStore recipients = ad.getRecipientInfos();
+
+ assertEquals(ad.getMacAlgOID(), macAlg.getId());
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransAuthenticatedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ assertTrue(Arrays.equals(ad.getMac(), recipient.getMac()));
+ }
+ }
+
+ private void tryKeyTransWithDigest(ASN1ObjectIdentifier macAlg)
+ throws Exception
+ {
+ byte[] data = "Eric H. Echidna".getBytes();
+
+ CMSAuthenticatedDataStreamGenerator adGen = new CMSAuthenticatedDataStreamGenerator();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DigestCalculatorProvider calcProvider = new JcaDigestCalculatorProviderBuilder().setProvider(BC).build();
+
+ adGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ OutputStream aOut = adGen.open(bOut, new JceCMSMacCalculatorBuilder(macAlg).setProvider(BC).build(), calcProvider.get(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1)));
+
+ aOut.write(data);
+
+ aOut.close();
+
+ CMSAuthenticatedDataParser ad = new CMSAuthenticatedDataParser(bOut.toByteArray(), calcProvider);
+
+ RecipientInformationStore recipients = ad.getRecipientInfos();
+
+ assertEquals(ad.getMacAlgOID(), macAlg.getId());
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransAuthenticatedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ assertTrue(Arrays.equals(ad.getMac(), recipient.getMac()));
+ assertTrue(Arrays.equals(ad.getContentDigest(), recipient.getContentDigest()));
+ }
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewAuthenticatedDataTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewAuthenticatedDataTest.java
new file mode 100644
index 000000000..523662cc9
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewAuthenticatedDataTest.java
@@ -0,0 +1,473 @@
+package org.spongycastle.cms.test;
+
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Security;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+
+import javax.crypto.SecretKey;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSAuthenticatedData;
+import org.spongycastle.cms.CMSAuthenticatedDataGenerator;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.OriginatorInfoGenerator;
+import org.spongycastle.cms.PasswordRecipient;
+import org.spongycastle.cms.PasswordRecipientInformation;
+import org.spongycastle.cms.RecipientInformation;
+import org.spongycastle.cms.RecipientInformationStore;
+import org.spongycastle.cms.jcajce.JceCMSMacCalculatorBuilder;
+import org.spongycastle.cms.jcajce.JceKEKAuthenticatedRecipient;
+import org.spongycastle.cms.jcajce.JceKEKRecipientInfoGenerator;
+import org.spongycastle.cms.jcajce.JceKeyAgreeAuthenticatedRecipient;
+import org.spongycastle.cms.jcajce.JceKeyAgreeRecipientInfoGenerator;
+import org.spongycastle.cms.jcajce.JceKeyTransAuthenticatedRecipient;
+import org.spongycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
+import org.spongycastle.cms.jcajce.JcePasswordAuthenticatedRecipient;
+import org.spongycastle.cms.jcajce.JcePasswordRecipientInfoGenerator;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.spongycastle.util.encoders.Hex;
+
+public class NewAuthenticatedDataTest
+ extends TestCase
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ private static String _signDN;
+ private static KeyPair _signKP;
+ private static X509Certificate _signCert;
+
+ private static String _origDN;
+ private static KeyPair _origKP;
+ private static X509Certificate _origCert;
+
+ private static String _reciDN;
+ private static KeyPair _reciKP;
+ private static X509Certificate _reciCert;
+
+ private static KeyPair _origEcKP;
+ private static KeyPair _reciEcKP;
+ private static X509Certificate _reciEcCert;
+
+ private static boolean _initialised = false;
+
+ public boolean DEBUG = true;
+
+ private static void init()
+ throws Exception
+ {
+ if (!_initialised)
+ {
+ _initialised = true;
+ Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider());
+
+ _signDN = "O=Bouncy Castle, C=AU";
+ _signKP = CMSTestUtil.makeKeyPair();
+ _signCert = CMSTestUtil.makeCertificate(_signKP, _signDN, _signKP, _signDN);
+
+ _origDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+ _origKP = CMSTestUtil.makeKeyPair();
+ _origCert = CMSTestUtil.makeCertificate(_origKP, _origDN, _signKP, _signDN);
+
+ _reciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+ _reciKP = CMSTestUtil.makeKeyPair();
+ _reciCert = CMSTestUtil.makeCertificate(_reciKP, _reciDN, _signKP, _signDN);
+
+ _origEcKP = CMSTestUtil.makeEcDsaKeyPair();
+ _reciEcKP = CMSTestUtil.makeEcDsaKeyPair();
+ _reciEcCert = CMSTestUtil.makeCertificate(_reciEcKP, _reciDN, _signKP, _signDN);
+ }
+ }
+
+ public void setUp()
+ throws Exception
+ {
+ init();
+ }
+
+ public NewAuthenticatedDataTest(String name)
+ {
+ super(name);
+ }
+
+ public static void main(String args[])
+ {
+ junit.textui.TestRunner.run(NewAuthenticatedDataTest.class);
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ init();
+
+ return new CMSTestSetup(new TestSuite(NewAuthenticatedDataTest.class));
+ }
+
+ public void testKeyTransDESede()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.DES_EDE3_CBC);
+ }
+
+ public void testKeyTransDESedeWithDigest()
+ throws Exception
+ {
+ tryKeyTransWithDigest(CMSAlgorithm.DES_EDE3_CBC);
+ }
+
+ public void testKeyTransRC2()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.RC2_CBC);
+ }
+
+ public void testKEKDESede()
+ throws Exception
+ {
+ tryKekAlgorithm(CMSTestUtil.makeDesede192Key(), new DERObjectIdentifier("1.2.840.113549.1.9.16.3.6"));
+ }
+
+ public void testKEKDESedeWithDigest()
+ throws Exception
+ {
+ tryKekAlgorithmWithDigest(CMSTestUtil.makeDesede192Key(), new DERObjectIdentifier("1.2.840.113549.1.9.16.3.6"));
+ }
+
+ public void testPasswordAES256()
+ throws Exception
+ {
+ passwordTest(CMSAuthenticatedDataGenerator.AES256_CBC);
+ }
+
+ public void testECKeyAgree()
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSAuthenticatedDataGenerator adGen = new CMSAuthenticatedDataGenerator();
+
+ JceKeyAgreeRecipientInfoGenerator recipientGenerator = new JceKeyAgreeRecipientInfoGenerator(CMSAlgorithm.ECDH_SHA1KDF, _origEcKP.getPrivate(), _origEcKP.getPublic(), CMSAlgorithm.AES128_WRAP).setProvider(BC);
+
+ recipientGenerator.addRecipient(_reciEcCert);
+
+ adGen.addRecipientInfoGenerator(recipientGenerator);
+
+ CMSAuthenticatedData ad = adGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSMacCalculatorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ad.getRecipientInfos();
+
+ assertEquals(ad.getMacAlgOID(),
+ CMSAuthenticatedDataGenerator.DES_EDE3_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JceKeyAgreeAuthenticatedRecipient(_reciEcKP.getPrivate()).setProvider(BC));
+ assertTrue(Arrays.equals(data, recData));
+ assertTrue(Arrays.equals(ad.getMac(), recipient.getMac()));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testEncoding()
+ throws Exception
+ {
+ byte[] data = "Eric H. Echidna".getBytes();
+
+ CMSAuthenticatedDataGenerator adGen = new CMSAuthenticatedDataGenerator();
+
+ adGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ CMSAuthenticatedData ad = adGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSMacCalculatorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+
+ ad = new CMSAuthenticatedData(ad.getEncoded());
+
+ RecipientInformationStore recipients = ad.getRecipientInfos();
+
+ assertEquals(CMSAuthenticatedDataGenerator.DES_EDE3_CBC, ad.getMacAlgOID());
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransAuthenticatedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ assertTrue(Arrays.equals(ad.getMac(), recipient.getMac()));
+ }
+ }
+
+ public void testOriginatorInfo()
+ throws Exception
+ {
+ byte[] data = "Eric H. Echidna".getBytes();
+ ASN1ObjectIdentifier macAlg = CMSAlgorithm.DES_EDE3_CBC;
+
+ CMSAuthenticatedDataGenerator adGen = new CMSAuthenticatedDataGenerator();
+
+ X509CertificateHolder origCert = new X509CertificateHolder(_origCert.getEncoded());
+
+ adGen.setOriginatorInfo(new OriginatorInfoGenerator(origCert).generate());
+
+ adGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ CMSAuthenticatedData ad = adGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSMacCalculatorBuilder(macAlg).setProvider(BC).build());
+
+ assertTrue(ad.getOriginatorInfo().getCertificates().getMatches(null).contains(origCert));
+
+ RecipientInformationStore recipients = ad.getRecipientInfos();
+
+ assertEquals(ad.getMacAlgOID(), macAlg.getId());
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransAuthenticatedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ assertTrue(Arrays.equals(ad.getMac(), recipient.getMac()));
+ }
+ }
+
+ private void tryKeyTrans(ASN1ObjectIdentifier macAlg)
+ throws Exception
+ {
+ byte[] data = "Eric H. Echidna".getBytes();
+
+ CMSAuthenticatedDataGenerator adGen = new CMSAuthenticatedDataGenerator();
+
+ adGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ CMSAuthenticatedData ad = adGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSMacCalculatorBuilder(macAlg).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ad.getRecipientInfos();
+
+ assertEquals(ad.getMacAlgOID(), macAlg.getId());
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransAuthenticatedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ assertTrue(Arrays.equals(ad.getMac(), recipient.getMac()));
+ }
+ }
+
+ private void tryKeyTransWithDigest(ASN1ObjectIdentifier macAlg)
+ throws Exception
+ {
+ byte[] data = "Eric H. Echidna".getBytes();
+
+ CMSAuthenticatedDataGenerator adGen = new CMSAuthenticatedDataGenerator();
+ DigestCalculatorProvider calcProvider = new JcaDigestCalculatorProviderBuilder().setProvider(BC).build();
+
+ adGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ CMSAuthenticatedData ad = adGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSMacCalculatorBuilder(macAlg).setProvider(BC).build(),
+ calcProvider.get(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1)));
+
+ RecipientInformationStore recipients = ad.getRecipientInfos();
+
+ assertEquals(ad.getMacAlgOID(), macAlg.getId());
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransAuthenticatedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ assertTrue(Arrays.equals(ad.getMac(), recipient.getMac()));
+ assertTrue(Arrays.equals(ad.getContentDigest(), recipient.getContentDigest()));
+ }
+ }
+
+ private void tryKekAlgorithm(SecretKey kek, DERObjectIdentifier algOid)
+ throws NoSuchAlgorithmException, NoSuchProviderException, CMSException, OperatorCreationException
+ {
+ byte[] data = "Eric H. Echidna".getBytes();
+
+ CMSAuthenticatedDataGenerator adGen = new CMSAuthenticatedDataGenerator();
+
+ byte[] kekId = new byte[] { 1, 2, 3, 4, 5 };
+
+ adGen.addRecipientInfoGenerator(new JceKEKRecipientInfoGenerator(kekId, kek).setProvider(BC));
+
+ CMSAuthenticatedData ad = adGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSMacCalculatorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ad.getRecipientInfos();
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ assertEquals(ad.getMacAlgOID(), CMSAuthenticatedDataGenerator.DES_EDE3_CBC);
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), algOid.getId());
+
+ byte[] recData = recipient.getContent(new JceKEKAuthenticatedRecipient(kek).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ assertTrue(Arrays.equals(ad.getMac(), recipient.getMac()));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ private void tryKekAlgorithmWithDigest(SecretKey kek, DERObjectIdentifier algOid)
+ throws NoSuchAlgorithmException, NoSuchProviderException, CMSException, OperatorCreationException
+ {
+ byte[] data = "Eric H. Echidna".getBytes();
+
+ CMSAuthenticatedDataGenerator adGen = new CMSAuthenticatedDataGenerator();
+ DigestCalculatorProvider calcProvider = new JcaDigestCalculatorProviderBuilder().setProvider(BC).build();
+
+ byte[] kekId = new byte[] { 1, 2, 3, 4, 5 };
+
+ adGen.addRecipientInfoGenerator(new JceKEKRecipientInfoGenerator(kekId, kek).setProvider(BC));
+
+ CMSAuthenticatedData ad = adGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSMacCalculatorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build(),
+ calcProvider.get(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1)));
+
+ RecipientInformationStore recipients = ad.getRecipientInfos();
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ assertEquals(ad.getMacAlgOID(), CMSAuthenticatedDataGenerator.DES_EDE3_CBC);
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), algOid.getId());
+
+ byte[] recData = recipient.getContent(new JceKEKAuthenticatedRecipient(kek).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ assertTrue(Arrays.equals(ad.getMac(), recipient.getMac()));
+ assertTrue(Arrays.equals(ad.getContentDigest(), recipient.getContentDigest()));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+
+ private void passwordTest(String algorithm)
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSAuthenticatedDataGenerator adGen = new CMSAuthenticatedDataGenerator();
+
+ adGen.addRecipientInfoGenerator(new JcePasswordRecipientInfoGenerator(new ASN1ObjectIdentifier(algorithm), "password".toCharArray()).setProvider(BC).setSaltAndIterationCount(new byte[20], 5));
+
+ CMSAuthenticatedData ad = adGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSMacCalculatorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ad.getRecipientInfos();
+
+ assertEquals(ad.getMacAlgOID(),
+ CMSAuthenticatedDataGenerator.DES_EDE3_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ PasswordRecipientInformation recipient = (PasswordRecipientInformation)it.next();
+
+ PasswordRecipient pbeRep = new JcePasswordAuthenticatedRecipient("password".toCharArray()).setProvider(BC);
+
+ byte[] recData = recipient.getContent(pbeRep);
+
+ assertTrue(Arrays.equals(data, recData));
+ assertTrue(Arrays.equals(ad.getMac(), recipient.getMac()));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewCompressedDataStreamTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewCompressedDataStreamTest.java
new file mode 100644
index 000000000..f2edfbe9b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewCompressedDataStreamTest.java
@@ -0,0 +1,127 @@
+package org.spongycastle.cms.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Random;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.cms.CMSCompressedDataParser;
+import org.spongycastle.cms.CMSCompressedDataStreamGenerator;
+import org.spongycastle.cms.jcajce.ZlibCompressor;
+import org.spongycastle.cms.jcajce.ZlibExpanderProvider;
+import org.spongycastle.util.encoders.Base64;
+
+public class NewCompressedDataStreamTest
+ extends TestCase
+{
+ public NewCompressedDataStreamTest(String name)
+ {
+ super(name);
+ }
+
+ public void testWorkingData()
+ throws Exception
+ {
+ byte[] compData = Base64.decode(
+ "MIAGCyqGSIb3DQEJEAEJoIAwgAIBADANBgsqhkiG9w0BCRADCDCABgkqhkiG9w0BBwGggCSABIIC"
+ + "Hnic7ZRdb9owFIbvK/k/5PqVYPFXGK12YYyboVFASSp1vQtZGiLRACZE49/XHoUW7S/0tXP8Efux"
+ + "fU5ivWnasml72XFb3gb5druui7ytN803M570nii7C5r8tfwR281hy/p/KSM3+jzH5s3+pbQ90xSb"
+ + "P3VT3QbLusnt8WPIuN5vN/vaA2+DulnXTXkXvNTr8j8ouZmkCmGI/UW+ZS/C8zP0bz2dz0zwLt+1"
+ + "UEk2M8mlaxjRMByAhZTj0RGYg4TvogiRASROsZgjpVcJCb1KV6QzQeDJ1XkoQ5Jm+C5PbOHZZGRi"
+ + "v+ORAcshOGeCcdFJyfgFxdtCdEcmOrbinc/+BBMzRThEYpwl+jEBpciSGWQkI0TSlREmD/eOHb2D"
+ + "SGLuESm/iKUFt1y4XHBO2a5oq0IKJKWLS9kUZTA7vC5LSxYmgVL46SIWxIfWBQd6AdrnjLmH94UT"
+ + "vGxVibLqRCtIpp4g2qpdtqK1LiOeolpVK5wVQ5P7+QjZAlrh0cePYTx/gNZuB9Vhndtgujl9T/tg"
+ + "W9ogK+3rnmg3YWygnTuF5GDS+Q/jIVLnCcYZFc6Kk/+c80wKwZjwdZIqDYWRH68MuBQSXLgXYXj2"
+ + "3CAaYOBNJMliTl0X7eV5DnoKIFSKYdj3cRpD/cK/JWTHJRe76MUXnfBW8m7Hd5zhQ4ri2NrVF/WL"
+ + "+kV1/3AGSlJ32bFPd2BsQD8uSzIx6lObkjdz95c0AAAAAAAAAAAAAAAA");
+
+ byte[] uncompData = Base64.decode(
+ "Q29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi9FREktWDEyOyBuYW1lPUdyb3VwMi54MTINCkNvbnRl"
+ + "bnQtVHJhbnNmZXItRW5jb2Rpbmc6IGJpbmFyeQ0KQ29udGVudC1EaXNwb3NpdGlvbjogaW5saW5l"
+ + "OyBmaWxlbmFtZT1Hcm91cDIueDEyDQoNCklTQSowMCpzc3Nzc3Nzc3NzKjAwKnJycnJycnJycnIqW"
+ + "loqQ1lDTE9ORSAgICAgICAgKlpaKlBBUlRORVIgICAgICAgICo5NjEwMDcqMjAxMypVKjAwMjAwKj"
+ + "AwMDAwMDAwMSowKlQqKg1HUypQTypTMVMxUzFTMVMxUzFTMVMqUjFSMVIxUjFSMVIxUjFSKjk2MTA"
+ + "wNyoyMDEzKjAwMDAwMDAwNCpYKjAwMzA1MA1TVCo4NTAqMDAwMDQwMDAxDUJFRyowMCpCRSoyYSo0"
+ + "MzMyNDIzNHY1NTIzKjk2MTAwNyoyM3RjNHZ5MjR2MmgzdmgzdmgqWloqSUVMKjA5KlJFKjA5DUNVU"
+ + "ioxMSpUUk4qNTY1Nio2NSo1NjYqSU1GKjAwNio5NjEwMDcNUkVGKjZBKjQzM3IxYzNyMzRyMzRjMz"
+ + "MxMnFjdGdjNTQqUmVmZXJlbmNlIE51bWJlcg1QRVIqQUEqSGFucyBHdXR0ZW4qQ1AqMS4zMjIuMzI"
+ + "zLjQ0NDQqKioqKnJnZzRlZ3Y0dDQNVEFYKjR0Z3RidDR0cjR0cipHTCpnaGdoKioqKioqKioqRypD"
+ + "DUZPQipUUCpDQSpVU0EqMDIqRE9NKkNDKlJlZ3VsYXIgTG9jYXRpb25zIHBlciBUZXJtcw1DVFAqR"
+ + "EUqQzA0KjQ1MyoyNTAwMCpEOSpTRUwqMjMyMTQqMjM0MzI0MjM0MjMqRVMqNDIyNDM0MjMNU0FDKk"
+ + "EqQjAwMCpBRSozNTQ1KjM0NDIzMDANQ1VSKjExKjc2Nyo3NzY3KjY1DVBPMSoxMTEtYWFhKjEwMDA"
+ + "wMDAqQVMqOTAuMDAqQkQqQUsqMjM0MjM1djM1MzRxNmYzNTM0djQzNTM0NTN2cTNxMzIqKioqKioq"
+ + "KioqKkExKnl0cmgNUE8xKjExMS1hYWEqMTAwMDAwMCpBUyo5MC4wMCpCRCpBSyoyMzQyMzV2MzUzN"
+ + "HE2ZjM1MzR2NDM1MzQ1M3ZxM3EzMioqKioqKioqKioqQTEqeXRyaA1QTzEqMTExLWFhYSoxMDAwMD"
+ + "AwKkFTKjkwLjAwKkJEKkFLKjIzNDIzNXYzNTM0cTZmMzUzNHY0MzUzNDUzdnEzcTMyKioqKioqKio"
+ + "qKipBMSp5dHJoDVBPMSoxMTEtYWFhKjEwMDAwMDAqQVMqOTAuMDAqQkQqQUsqMjM0MjM1djM1MzRx"
+ + "NmYzNTM0djQzNTM0NTN2cTNxMzIqKioqKioqKioqKkExKnl0cmgNUE8xKjExMS1hYWEqMTAwMDAwM"
+ + "CpBUyo5MC4wMCpCRCpBSyoyMzQyMzV2MzUzNHE2ZjM1MzR2NDM1MzQ1M3ZxM3EzMioqKioqKioqKi"
+ + "oqQTEqeXRyaA1QTzEqMTExLWFhYSoxMDAwMDAwKkFTKjkwLjAwKkJEKkFLKjIzNDIzNXYzNTM0cTZ"
+ + "mMzUzNHY0MzUzNDUzdnEzcTMyKioqKioqKioqKipBMSp5dHJoDVBPMSoxMTEtYWFhKjEwMDAwMDAq"
+ + "QVMqOTAuMDAqQkQqQUsqMjM0MjM1djM1MzRxNmYzNTM0djQzNTM0NTN2cTNxMzIqKioqKioqKioqK"
+ + "kExKnl0cmgNUE8xKjExMS1hYWEqMTAwMDAwMCpBUyo5MC4wMCpCRCpBSyoyMzQyMzV2MzUzNHE2Zj"
+ + "M1MzR2NDM1MzQ1M3ZxM3EzMioqKioqKioqKioqQTEqeXRyaA1QTzEqMTExLWFhYSoxMDAwMDAwKkF"
+ + "TKjkwLjAwKkJEKkFLKjIzNDIzNXYzNTM0cTZmMzUzNHY0MzUzNDUzdnEzcTMyKioqKioqKioqKipB"
+ + "MSp5dHJoDVBPMSoxMTEtYWFhKjEwMDAwMDAqQVMqOTAuMDAqQkQqQUsqMjM0MjM1djM1MzRxNmYzN"
+ + "TM0djQzNTM0NTN2cTNxMzIqKioqKioqKioqKkExKnl0cmgNQ1RUKjENU0UqMjIqMDAwMDQwMDAxDU"
+ + "dFKjEqMDAwMDAwMDA0DUlFQSoxKjAwMDAwMDAwMQ0=");
+
+ CMSCompressedDataParser ed = new CMSCompressedDataParser(compData);
+
+ assertEquals(true, Arrays.equals(uncompData, CMSTestUtil.streamToByteArray(ed.getContent(new ZlibExpanderProvider()).getContentStream())));
+ }
+
+ public void testEach()
+ throws Exception
+ {
+ byte[] testData = "Hello world!".getBytes();
+
+ CMSCompressedDataStreamGenerator gen = new CMSCompressedDataStreamGenerator();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ OutputStream cOut = gen.open(bOut, new ZlibCompressor());
+
+ cOut.write(testData);
+
+ cOut.close();
+
+ CMSCompressedDataParser ed = new CMSCompressedDataParser(bOut.toByteArray());
+
+ assertEquals(true, Arrays.equals(testData, CMSTestUtil.streamToByteArray(ed.getContent(new ZlibExpanderProvider()).getContentStream())));
+ }
+
+ public void test1000()
+ throws Exception
+ {
+ byte[] testData = new byte[10000];
+ Random rand = new Random();
+
+ rand.setSeed(0);
+
+ for (int i = 0; i != 10; i++)
+ {
+ CMSCompressedDataStreamGenerator gen = new CMSCompressedDataStreamGenerator();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ OutputStream cOut = gen.open(bOut, new ZlibCompressor());
+
+ rand.nextBytes(testData);
+
+ cOut.write(testData);
+
+ cOut.close();
+
+ CMSCompressedDataParser ed = new CMSCompressedDataParser(bOut.toByteArray());
+
+ assertEquals(true, Arrays.equals(testData, CMSTestUtil.streamToByteArray(ed.getContent(new ZlibExpanderProvider()).getContentStream())));
+ }
+ }
+
+ public static Test suite()
+ {
+ return new TestSuite(NewCompressedDataStreamTest.class);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewCompressedDataTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewCompressedDataTest.java
new file mode 100644
index 000000000..13600e725
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewCompressedDataTest.java
@@ -0,0 +1,151 @@
+package org.spongycastle.cms.test;
+
+import java.util.Arrays;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.cms.CMSCompressedData;
+import org.spongycastle.cms.CMSCompressedDataGenerator;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.jcajce.ZlibCompressor;
+import org.spongycastle.cms.jcajce.ZlibExpanderProvider;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.io.StreamOverflowException;
+
+public class NewCompressedDataTest
+ extends TestCase
+{
+ private static final byte[] TEST_DATA = "Hello world!".getBytes();
+
+ /*
+ *
+ * INFRASTRUCTURE
+ *
+ */
+
+ public NewCompressedDataTest(String name)
+ {
+ super(name);
+ }
+
+ public static void main(String args[])
+ {
+ junit.textui.TestRunner.run(NewCompressedDataTest.class);
+ }
+
+ public static Test suite()
+ {
+ return new CMSTestSetup(new TestSuite(NewCompressedDataTest.class));
+ }
+
+ public void setUp()
+ {
+
+ }
+
+ public void tearDown()
+ {
+
+ }
+
+ public void testWorkingData()
+ throws Exception
+ {
+ byte[] compData = Base64
+ .decode("MIAGCyqGSIb3DQEJEAEJoIAwgAIBADANBgsqhkiG9w0BCRADCDCABgkqhkiG9w0BBwGggCSABIIC"
+ + "Hnic7ZRdb9owFIbvK/k/5PqVYPFXGK12YYyboVFASSp1vQtZGiLRACZE49/XHoUW7S/0tXP8Efux"
+ + "fU5ivWnasml72XFb3gb5druui7ytN803M570nii7C5r8tfwR281hy/p/KSM3+jzH5s3+pbQ90xSb"
+ + "P3VT3QbLusnt8WPIuN5vN/vaA2+DulnXTXkXvNTr8j8ouZmkCmGI/UW+ZS/C8zP0bz2dz0zwLt+1"
+ + "UEk2M8mlaxjRMByAhZTj0RGYg4TvogiRASROsZgjpVcJCb1KV6QzQeDJ1XkoQ5Jm+C5PbOHZZGRi"
+ + "v+ORAcshOGeCcdFJyfgFxdtCdEcmOrbinc/+BBMzRThEYpwl+jEBpciSGWQkI0TSlREmD/eOHb2D"
+ + "SGLuESm/iKUFt1y4XHBO2a5oq0IKJKWLS9kUZTA7vC5LSxYmgVL46SIWxIfWBQd6AdrnjLmH94UT"
+ + "vGxVibLqRCtIpp4g2qpdtqK1LiOeolpVK5wVQ5P7+QjZAlrh0cePYTx/gNZuB9Vhndtgujl9T/tg"
+ + "W9ogK+3rnmg3YWygnTuF5GDS+Q/jIVLnCcYZFc6Kk/+c80wKwZjwdZIqDYWRH68MuBQSXLgXYXj2"
+ + "3CAaYOBNJMliTl0X7eV5DnoKIFSKYdj3cRpD/cK/JWTHJRe76MUXnfBW8m7Hd5zhQ4ri2NrVF/WL"
+ + "+kV1/3AGSlJ32bFPd2BsQD8uSzIx6lObkjdz95c0AAAAAAAAAAAAAAAA");
+
+ byte[] uncompData = Base64
+ .decode("Q29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi9FREktWDEyOyBuYW1lPUdyb3VwMi54MTINCkNvbnRl"
+ + "bnQtVHJhbnNmZXItRW5jb2Rpbmc6IGJpbmFyeQ0KQ29udGVudC1EaXNwb3NpdGlvbjogaW5saW5l"
+ + "OyBmaWxlbmFtZT1Hcm91cDIueDEyDQoNCklTQSowMCpzc3Nzc3Nzc3NzKjAwKnJycnJycnJycnIqW"
+ + "loqQ1lDTE9ORSAgICAgICAgKlpaKlBBUlRORVIgICAgICAgICo5NjEwMDcqMjAxMypVKjAwMjAwKj"
+ + "AwMDAwMDAwMSowKlQqKg1HUypQTypTMVMxUzFTMVMxUzFTMVMqUjFSMVIxUjFSMVIxUjFSKjk2MTA"
+ + "wNyoyMDEzKjAwMDAwMDAwNCpYKjAwMzA1MA1TVCo4NTAqMDAwMDQwMDAxDUJFRyowMCpCRSoyYSo0"
+ + "MzMyNDIzNHY1NTIzKjk2MTAwNyoyM3RjNHZ5MjR2MmgzdmgzdmgqWloqSUVMKjA5KlJFKjA5DUNVU"
+ + "ioxMSpUUk4qNTY1Nio2NSo1NjYqSU1GKjAwNio5NjEwMDcNUkVGKjZBKjQzM3IxYzNyMzRyMzRjMz"
+ + "MxMnFjdGdjNTQqUmVmZXJlbmNlIE51bWJlcg1QRVIqQUEqSGFucyBHdXR0ZW4qQ1AqMS4zMjIuMzI"
+ + "zLjQ0NDQqKioqKnJnZzRlZ3Y0dDQNVEFYKjR0Z3RidDR0cjR0cipHTCpnaGdoKioqKioqKioqRypD"
+ + "DUZPQipUUCpDQSpVU0EqMDIqRE9NKkNDKlJlZ3VsYXIgTG9jYXRpb25zIHBlciBUZXJtcw1DVFAqR"
+ + "EUqQzA0KjQ1MyoyNTAwMCpEOSpTRUwqMjMyMTQqMjM0MzI0MjM0MjMqRVMqNDIyNDM0MjMNU0FDKk"
+ + "EqQjAwMCpBRSozNTQ1KjM0NDIzMDANQ1VSKjExKjc2Nyo3NzY3KjY1DVBPMSoxMTEtYWFhKjEwMDA"
+ + "wMDAqQVMqOTAuMDAqQkQqQUsqMjM0MjM1djM1MzRxNmYzNTM0djQzNTM0NTN2cTNxMzIqKioqKioq"
+ + "KioqKkExKnl0cmgNUE8xKjExMS1hYWEqMTAwMDAwMCpBUyo5MC4wMCpCRCpBSyoyMzQyMzV2MzUzN"
+ + "HE2ZjM1MzR2NDM1MzQ1M3ZxM3EzMioqKioqKioqKioqQTEqeXRyaA1QTzEqMTExLWFhYSoxMDAwMD"
+ + "AwKkFTKjkwLjAwKkJEKkFLKjIzNDIzNXYzNTM0cTZmMzUzNHY0MzUzNDUzdnEzcTMyKioqKioqKio"
+ + "qKipBMSp5dHJoDVBPMSoxMTEtYWFhKjEwMDAwMDAqQVMqOTAuMDAqQkQqQUsqMjM0MjM1djM1MzRx"
+ + "NmYzNTM0djQzNTM0NTN2cTNxMzIqKioqKioqKioqKkExKnl0cmgNUE8xKjExMS1hYWEqMTAwMDAwM"
+ + "CpBUyo5MC4wMCpCRCpBSyoyMzQyMzV2MzUzNHE2ZjM1MzR2NDM1MzQ1M3ZxM3EzMioqKioqKioqKi"
+ + "oqQTEqeXRyaA1QTzEqMTExLWFhYSoxMDAwMDAwKkFTKjkwLjAwKkJEKkFLKjIzNDIzNXYzNTM0cTZ"
+ + "mMzUzNHY0MzUzNDUzdnEzcTMyKioqKioqKioqKipBMSp5dHJoDVBPMSoxMTEtYWFhKjEwMDAwMDAq"
+ + "QVMqOTAuMDAqQkQqQUsqMjM0MjM1djM1MzRxNmYzNTM0djQzNTM0NTN2cTNxMzIqKioqKioqKioqK"
+ + "kExKnl0cmgNUE8xKjExMS1hYWEqMTAwMDAwMCpBUyo5MC4wMCpCRCpBSyoyMzQyMzV2MzUzNHE2Zj"
+ + "M1MzR2NDM1MzQ1M3ZxM3EzMioqKioqKioqKioqQTEqeXRyaA1QTzEqMTExLWFhYSoxMDAwMDAwKkF"
+ + "TKjkwLjAwKkJEKkFLKjIzNDIzNXYzNTM0cTZmMzUzNHY0MzUzNDUzdnEzcTMyKioqKioqKioqKipB"
+ + "MSp5dHJoDVBPMSoxMTEtYWFhKjEwMDAwMDAqQVMqOTAuMDAqQkQqQUsqMjM0MjM1djM1MzRxNmYzN"
+ + "TM0djQzNTM0NTN2cTNxMzIqKioqKioqKioqKkExKnl0cmgNQ1RUKjENU0UqMjIqMDAwMDQwMDAxDUdFKjEqMDAwMDAwMDA0DUlFQSoxKjAwMDAwMDAwMQ0=");
+
+ CMSCompressedData ed = new CMSCompressedData(compData);
+
+ assertEquals(true, Arrays.equals(uncompData, ed.getContent(new ZlibExpanderProvider())));
+ }
+
+ public void testEach()
+ throws Exception
+ {
+ CMSCompressedData cd = getStdData();
+
+ assertEquals(true, Arrays.equals(TEST_DATA, cd.getContent(new ZlibExpanderProvider())));
+ }
+
+ public void testLimitUnder()
+ throws Exception
+ {
+ CMSCompressedData cd = getStdData();
+
+ try
+ {
+ cd.getContent(new ZlibExpanderProvider(TEST_DATA.length / 2));
+ }
+ catch (CMSException e)
+ {
+ assertEquals(true, e.getCause() instanceof StreamOverflowException);
+ }
+ }
+
+ public void testLimitOver()
+ throws Exception
+ {
+ CMSCompressedData cd = getStdData();
+
+ assertEquals(true, Arrays.equals(TEST_DATA, cd.getContent(new ZlibExpanderProvider(TEST_DATA.length * 2))));
+ }
+
+ public void testLimitEqual()
+ throws Exception
+ {
+ CMSCompressedData cd = getStdData();
+
+ assertEquals(true, Arrays.equals(TEST_DATA, cd.getContent(new ZlibExpanderProvider(TEST_DATA.length))));
+ }
+
+ private CMSCompressedData getStdData()
+ throws CMSException
+ {
+ CMSProcessableByteArray testData = new CMSProcessableByteArray(TEST_DATA);
+ CMSCompressedDataGenerator gen = new CMSCompressedDataGenerator();
+
+ return gen.generate(testData, new ZlibCompressor());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewEnvelopedDataStreamTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewEnvelopedDataStreamTest.java
new file mode 100644
index 000000000..3a86a67a6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewEnvelopedDataStreamTest.java
@@ -0,0 +1,760 @@
+package org.spongycastle.cms.test;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.cert.X509Certificate;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import javax.crypto.SecretKey;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.DERUTF8String;
+import org.spongycastle.asn1.cms.Attribute;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSEnvelopedDataGenerator;
+import org.spongycastle.cms.CMSEnvelopedDataParser;
+import org.spongycastle.cms.CMSEnvelopedDataStreamGenerator;
+import org.spongycastle.cms.CMSTypedStream;
+import org.spongycastle.cms.KEKRecipientId;
+import org.spongycastle.cms.OriginatorInfoGenerator;
+import org.spongycastle.cms.OriginatorInformation;
+import org.spongycastle.cms.RecipientId;
+import org.spongycastle.cms.RecipientInformation;
+import org.spongycastle.cms.RecipientInformationStore;
+import org.spongycastle.cms.SimpleAttributeTableGenerator;
+import org.spongycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
+import org.spongycastle.cms.jcajce.JceKEKEnvelopedRecipient;
+import org.spongycastle.cms.jcajce.JceKEKRecipientInfoGenerator;
+import org.spongycastle.cms.jcajce.JceKeyAgreeEnvelopedRecipient;
+import org.spongycastle.cms.jcajce.JceKeyAgreeRecipientId;
+import org.spongycastle.cms.jcajce.JceKeyAgreeRecipientInfoGenerator;
+import org.spongycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
+import org.spongycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.encoders.Hex;
+
+public class NewEnvelopedDataStreamTest
+ extends TestCase
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ private static final int BUFFER_SIZE = 4000;
+ private static String _signDN;
+ private static KeyPair _signKP;
+ private static X509Certificate _signCert;
+
+ private static String _origDN;
+ private static KeyPair _origKP;
+ private static X509Certificate _origCert;
+
+ private static String _reciDN;
+ private static KeyPair _reciKP;
+ private static X509Certificate _reciCert;
+
+ private static KeyPair _origEcKP;
+ private static KeyPair _reciEcKP;
+ private static X509Certificate _reciEcCert;
+
+ private static boolean _initialised = false;
+
+ public NewEnvelopedDataStreamTest()
+ {
+ }
+
+ private static void init()
+ throws Exception
+ {
+ if (!_initialised)
+ {
+ _initialised = true;
+
+ _signDN = "O=Bouncy Castle, C=AU";
+ _signKP = CMSTestUtil.makeKeyPair();
+ _signCert = CMSTestUtil.makeCertificate(_signKP, _signDN, _signKP, _signDN);
+
+ _origDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+ _origKP = CMSTestUtil.makeKeyPair();
+ _origCert = CMSTestUtil.makeCertificate(_origKP, _origDN, _signKP, _signDN);
+
+ _reciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+ _reciKP = CMSTestUtil.makeKeyPair();
+ _reciCert = CMSTestUtil.makeCertificate(_reciKP, _reciDN, _signKP, _signDN);
+
+ _origEcKP = CMSTestUtil.makeEcDsaKeyPair();
+ _reciEcKP = CMSTestUtil.makeEcDsaKeyPair();
+ _reciEcCert = CMSTestUtil.makeCertificate(_reciEcKP, _reciDN, _signKP, _signDN);
+ }
+ }
+
+ public void setUp()
+ throws Exception
+ {
+ init();
+ }
+
+ public void testWorkingData()
+ throws Exception
+ {
+ byte[] keyData = Base64.decode(
+ "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKrAz/SQKrcQ" +
+ "nj9IxHIfKDbuXsMqUpI06s2gps6fp7RDNvtUDDMOciWGFhD45YSy8GO0mPx3" +
+ "Nkc7vKBqX4TLcqLUz7kXGOHGOwiPZoNF+9jBMPNROe/B0My0PkWg9tuq+nxN" +
+ "64oD47+JvDwrpNOS5wsYavXeAW8Anv9ZzHLU7KwZAgMBAAECgYA/fqdVt+5K" +
+ "WKGfwr1Z+oAHvSf7xtchiw/tGtosZ24DOCNP3fcTXUHQ9kVqVkNyzt9ZFCT3" +
+ "bJUAdBQ2SpfuV4DusVeQZVzcROKeA09nPkxBpTefWbSDQGhb+eZq9L8JDRSW" +
+ "HyYqs+MBoUpLw7GKtZiJkZyY6CsYkAnQ+uYVWq/TIQJBAP5zafO4HUV/w4KD" +
+ "VJi+ua+GYF1Sg1t/dYL1kXO9GP1p75YAmtm6LdnOCas7wj70/G1YlPGkOP0V" +
+ "GFzeG5KAmAUCQQCryvKU9nwWA+kypcQT9Yr1P4vGS0APYoBThnZq7jEPc5Cm" +
+ "ZI82yseSxSeea0+8KQbZ5mvh1p3qImDLEH/iNSQFAkAghS+tboKPN10NeSt+" +
+ "uiGRRWNbiggv0YJ7Uldcq3ZeLQPp7/naiekCRUsHD4Qr97OrZf7jQ1HlRqTu" +
+ "eZScjMLhAkBNUMZCQnhwFAyEzdPkQ7LpU1MdyEopYmRssuxijZao5JLqQAGw" +
+ "YCzXokGFa7hz72b09F4DQurJL/WuDlvvu4jdAkEAxwT9lylvfSfEQw4/qQgZ" +
+ "MFB26gqB6Gqs1pHIZCzdliKx5BO3VDeUGfXMI8yOkbXoWbYx5xPid/+N8R//" +
+ "+sxLBw==");
+
+ byte[] envData = Base64.decode(
+ "MIAGCSqGSIb3DQEHA6CAMIACAQAxgcQwgcECAQAwKjAlMRYwFAYDVQQKEw1C" +
+ "b3VuY3kgQ2FzdGxlMQswCQYDVQQGEwJBVQIBHjANBgkqhkiG9w0BAQEFAASB" +
+ "gDmnaDZ0vDJNlaUSYyEXsgbaUH+itNTjCOgv77QTX2ImXj+kTctM19PQF2I1" +
+ "0/NL0fjakvCgBTHKmk13a7jqB6cX3bysenHNrglHsgNGgeXQ7ggAq5fV/JQQ" +
+ "T7rSxEtuwpbuHQnoVUZahOHVKy/a0uLr9iIh1A3y+yZTZaG505ZJMIAGCSqG" +
+ "SIb3DQEHATAdBglghkgBZQMEAQIEENmkYNbDXiZxJWtq82qIRZKggAQgkOGr" +
+ "1JcTsADStez1eY4+rO4DtyBIyUYQ3pilnbirfPkAAAAAAAAAAAAA");
+
+
+ CMSEnvelopedDataParser ep = new CMSEnvelopedDataParser(envData);
+
+ RecipientInformationStore recipients = ep.getRecipientInfos();
+
+ assertEquals(ep.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.AES128_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyData);
+ KeyFactory keyFact = KeyFactory.getInstance("RSA", BC);
+ PrivateKey priKey = keyFact.generatePrivate(keySpec);
+ byte[] data = Hex.decode("57616c6c6157616c6c6157617368696e67746f6e");
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ CMSTypedStream recData = recipient.getContentStream(new JceKeyTransEnvelopedRecipient(priKey).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, CMSTestUtil.streamToByteArray(recData.getContentStream())));
+ }
+ }
+
+ private void verifyData(
+ ByteArrayOutputStream encodedStream,
+ String expectedOid,
+ byte[] expectedData)
+ throws Exception
+ {
+ CMSEnvelopedDataParser ep = new CMSEnvelopedDataParser(encodedStream.toByteArray());
+ RecipientInformationStore recipients = ep.getRecipientInfos();
+
+ assertEquals(ep.getEncryptionAlgOID(), expectedOid);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ CMSTypedStream recData = recipient.getContentStream(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(expectedData, CMSTestUtil.streamToByteArray(recData.getContentStream())));
+ }
+ }
+
+ public void testUnprotectedAttributes()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataStreamGenerator edGen = new CMSEnvelopedDataStreamGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ Hashtable attrs = new Hashtable();
+
+ attrs.put(PKCSObjectIdentifiers.id_aa_contentHint, new Attribute(PKCSObjectIdentifiers.id_aa_contentHint, new DERSet(new DERUTF8String("Hint"))));
+ attrs.put(PKCSObjectIdentifiers.id_aa_receiptRequest, new Attribute(PKCSObjectIdentifiers.id_aa_receiptRequest, new DERSet(new DERUTF8String("Request"))));
+
+ AttributeTable attrTable = new AttributeTable(attrs);
+
+ edGen.setUnprotectedAttributeGenerator(new SimpleAttributeTableGenerator(attrTable));
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ OutputStream out = edGen.open(
+ bOut, new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ out.write(data);
+
+ out.close();
+
+ CMSEnvelopedDataParser ed = new CMSEnvelopedDataParser(bOut.toByteArray());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+
+ attrTable = ed.getUnprotectedAttributes();
+
+ assertEquals(attrs.size(), 2);
+
+ assertEquals(new DERUTF8String("Hint"), attrTable.get(PKCSObjectIdentifiers.id_aa_contentHint).getAttrValues().getObjectAt(0));
+ assertEquals(new DERUTF8String("Request"), attrTable.get(PKCSObjectIdentifiers.id_aa_receiptRequest).getAttrValues().getObjectAt(0));
+
+ }
+
+ public void testKeyTransAES128BufferedStream()
+ throws Exception
+ {
+ byte[] data = new byte[2000];
+
+ for (int i = 0; i != 2000; i++)
+ {
+ data[i] = (byte)(i & 0xff);
+ }
+
+ //
+ // unbuffered
+ //
+ CMSEnvelopedDataStreamGenerator edGen = new CMSEnvelopedDataStreamGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ OutputStream out = edGen.open(
+ bOut, new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ for (int i = 0; i != 2000; i++)
+ {
+ out.write(data[i]);
+ }
+
+ out.close();
+
+ verifyData(bOut, CMSEnvelopedDataGenerator.AES128_CBC, data);
+
+ int unbufferedLength = bOut.toByteArray().length;
+
+ //
+ // Using buffered output - should be == to unbuffered
+ //
+ edGen = new CMSEnvelopedDataStreamGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ bOut = new ByteArrayOutputStream();
+
+ out = edGen.open(bOut, new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ BufferedOutputStream bfOut = new BufferedOutputStream(out, 300);
+
+ for (int i = 0; i != 2000; i++)
+ {
+ bfOut.write(data[i]);
+ }
+
+ bfOut.close();
+
+ verifyData(bOut, CMSEnvelopedDataGenerator.AES128_CBC, data);
+
+ assertTrue(bOut.toByteArray().length == unbufferedLength);
+ }
+
+ public void testKeyTransAES128Buffered()
+ throws Exception
+ {
+ byte[] data = new byte[2000];
+
+ for (int i = 0; i != 2000; i++)
+ {
+ data[i] = (byte)(i & 0xff);
+ }
+
+ //
+ // unbuffered
+ //
+ CMSEnvelopedDataStreamGenerator edGen = new CMSEnvelopedDataStreamGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ OutputStream out = edGen.open(
+ bOut, new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ for (int i = 0; i != 2000; i++)
+ {
+ out.write(data[i]);
+ }
+
+ out.close();
+
+ verifyData(bOut, CMSEnvelopedDataGenerator.AES128_CBC, data);
+
+ int unbufferedLength = bOut.toByteArray().length;
+
+ //
+ // buffered - less than default of 1000
+ //
+ edGen = new CMSEnvelopedDataStreamGenerator();
+
+ edGen.setBufferSize(300);
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ bOut = new ByteArrayOutputStream();
+
+ out = edGen.open(bOut, new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ for (int i = 0; i != 2000; i++)
+ {
+ out.write(data[i]);
+ }
+
+ out.close();
+
+ verifyData(bOut, CMSEnvelopedDataGenerator.AES128_CBC, data);
+
+ assertTrue(bOut.toByteArray().length > unbufferedLength);
+ }
+
+ public void testKeyTransAES128Der()
+ throws Exception
+ {
+ byte[] data = new byte[2000];
+
+ for (int i = 0; i != 2000; i++)
+ {
+ data[i] = (byte)(i & 0xff);
+ }
+
+ CMSEnvelopedDataStreamGenerator edGen = new CMSEnvelopedDataStreamGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ OutputStream out = edGen.open(
+ bOut, new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ for (int i = 0; i != 2000; i++)
+ {
+ out.write(data[i]);
+ }
+
+ out.close();
+
+ // convert to DER
+ ASN1InputStream aIn = new ASN1InputStream(bOut.toByteArray());
+
+ bOut.reset();
+
+ DEROutputStream dOut = new DEROutputStream(bOut);
+
+ dOut.writeObject(aIn.readObject());
+
+ verifyData(bOut, CMSEnvelopedDataGenerator.AES128_CBC, data);
+ }
+
+ public void testKeyTransAES128Throughput()
+ throws Exception
+ {
+ byte[] data = new byte[40001];
+
+ for (int i = 0; i != data.length; i++)
+ {
+ data[i] = (byte)(i & 0xff);
+ }
+
+ //
+ // buffered
+ //
+ CMSEnvelopedDataStreamGenerator edGen = new CMSEnvelopedDataStreamGenerator();
+
+ edGen.setBufferSize(BUFFER_SIZE);
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ OutputStream out = edGen.open(bOut, new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ for (int i = 0; i != data.length; i++)
+ {
+ out.write(data[i]);
+ }
+
+ out.close();
+
+ CMSEnvelopedDataParser ep = new CMSEnvelopedDataParser(bOut.toByteArray());
+ RecipientInformationStore recipients = ep.getRecipientInfos();
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ CMSTypedStream recData = recipient.getContentStream(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ InputStream dataStream = recData.getContentStream();
+ ByteArrayOutputStream dataOut = new ByteArrayOutputStream();
+ int len;
+ byte[] buf = new byte[BUFFER_SIZE];
+ int count = 0;
+
+ while (count != 10 && (len = dataStream.read(buf)) > 0)
+ {
+ assertEquals(buf.length, len);
+
+ dataOut.write(buf);
+ count++;
+ }
+
+ len = dataStream.read(buf);
+ dataOut.write(buf, 0, len);
+
+ assertEquals(true, Arrays.equals(data, dataOut.toByteArray()));
+ }
+ else
+ {
+ fail("recipient not found.");
+ }
+ }
+
+ public void testKeyTransAES128AndOriginatorInfo()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataStreamGenerator edGen = new CMSEnvelopedDataStreamGenerator();
+
+ X509CertificateHolder origCert = new X509CertificateHolder(_origCert.getEncoded());
+
+ edGen.setOriginatorInfo(new OriginatorInfoGenerator(origCert).generate());
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ OutputStream out = edGen.open(
+ bOut, new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ out.write(data);
+
+ out.close();
+
+ CMSEnvelopedDataParser ep = new CMSEnvelopedDataParser(bOut.toByteArray());
+
+ assertTrue(ep.getOriginatorInfo().getCertificates().getMatches(null).contains(origCert));
+
+ RecipientInformationStore recipients = ep.getRecipientInfos();
+
+ assertEquals(ep.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.AES128_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ CMSTypedStream recData = recipient.getContentStream(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, CMSTestUtil.streamToByteArray(recData.getContentStream())));
+ }
+
+ ep.close();
+ }
+
+ public void testKeyTransAES128()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataStreamGenerator edGen = new CMSEnvelopedDataStreamGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ OutputStream out = edGen.open(
+ bOut, new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ out.write(data);
+
+ out.close();
+
+ CMSEnvelopedDataParser ep = new CMSEnvelopedDataParser(bOut.toByteArray());
+
+ RecipientInformationStore recipients = ep.getRecipientInfos();
+
+ assertEquals(ep.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.AES128_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ CMSTypedStream recData = recipient.getContentStream(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, CMSTestUtil.streamToByteArray(recData.getContentStream())));
+ }
+
+ ep.close();
+ }
+
+ public void testKeyTransCAST5SunJCE()
+ throws Exception
+ {
+ if (Security.getProvider("SunJCE") == null)
+ {
+ return;
+ }
+
+ String version = System.getProperty("java.version");
+ if (version.startsWith("1.4") || version.startsWith("1.3"))
+ {
+ return;
+ }
+
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataStreamGenerator edGen = new CMSEnvelopedDataStreamGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider("SunJCE"));
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ OutputStream out = edGen.open(
+ bOut, new JceCMSContentEncryptorBuilder(CMSAlgorithm.CAST5_CBC).setProvider(BC).build());
+
+ out.write(data);
+
+ out.close();
+
+ CMSEnvelopedDataParser ep = new CMSEnvelopedDataParser(bOut.toByteArray());
+
+ RecipientInformationStore recipients = ep.getRecipientInfos();
+
+ assertEquals(ep.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.CAST5_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ CMSTypedStream recData = recipient.getContentStream(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider("SunJCE").setContentProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, CMSTestUtil.streamToByteArray(recData.getContentStream())));
+ }
+
+ ep.close();
+ }
+
+ public void testAESKEK()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+ SecretKey kek = CMSTestUtil.makeAES192Key();
+
+ CMSEnvelopedDataStreamGenerator edGen = new CMSEnvelopedDataStreamGenerator();
+
+ byte[] kekId = new byte[] { 1, 2, 3, 4, 5 };
+
+ edGen.addRecipientInfoGenerator(new JceKEKRecipientInfoGenerator(kekId, kek).setProvider(BC));
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ OutputStream out = edGen.open(
+ bOut,
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+ out.write(data);
+
+ out.close();
+
+ CMSEnvelopedDataParser ep = new CMSEnvelopedDataParser(bOut.toByteArray());
+
+ RecipientInformationStore recipients = ep.getRecipientInfos();
+
+ assertEquals(ep.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), "2.16.840.1.101.3.4.1.25");
+
+ CMSTypedStream recData = recipient.getContentStream(new JceKEKEnvelopedRecipient(kek).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, CMSTestUtil.streamToByteArray(recData.getContentStream())));
+ }
+
+ ep.close();
+ }
+
+ public void testTwoAESKEK()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+ SecretKey kek1 = CMSTestUtil.makeAES192Key();
+ SecretKey kek2 = CMSTestUtil.makeAES192Key();
+
+ CMSEnvelopedDataStreamGenerator edGen = new CMSEnvelopedDataStreamGenerator();
+
+ byte[] kekId1 = new byte[] { 1, 2, 3, 4, 5 };
+ byte[] kekId2 = new byte[] { 5, 4, 3, 2, 1 };
+
+ edGen.addRecipientInfoGenerator(new JceKEKRecipientInfoGenerator(kekId1, kek1).setProvider(BC));
+ edGen.addRecipientInfoGenerator(new JceKEKRecipientInfoGenerator(kekId2, kek2).setProvider(BC));
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ OutputStream out = edGen.open(
+ bOut,
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+ out.write(data);
+
+ out.close();
+
+ CMSEnvelopedDataParser ep = new CMSEnvelopedDataParser(bOut.toByteArray());
+
+ RecipientInformationStore recipients = ep.getRecipientInfos();
+
+ assertEquals(ep.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ RecipientId recSel = new KEKRecipientId(kekId2);
+
+ RecipientInformation recipient = recipients.get(recSel);
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), "2.16.840.1.101.3.4.1.25");
+
+ CMSTypedStream recData = recipient.getContentStream(new JceKEKEnvelopedRecipient(kek2).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, CMSTestUtil.streamToByteArray(recData.getContentStream())));
+
+ ep.close();
+ }
+
+ public void testECKeyAgree()
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedDataStreamGenerator edGen = new CMSEnvelopedDataStreamGenerator();
+
+ JceKeyAgreeRecipientInfoGenerator recipientGenerator = new JceKeyAgreeRecipientInfoGenerator(CMSAlgorithm.ECDH_SHA1KDF, _origEcKP.getPrivate(), _origEcKP.getPublic(), CMSAlgorithm.AES128_WRAP).setProvider(BC);
+
+ recipientGenerator.addRecipient(_reciEcCert);
+
+ edGen.addRecipientInfoGenerator(recipientGenerator);
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ OutputStream out = edGen.open(
+ bOut,
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+ out.write(data);
+
+ out.close();
+
+ CMSEnvelopedDataParser ep = new CMSEnvelopedDataParser(bOut.toByteArray());
+
+ RecipientInformationStore recipients = ep.getRecipientInfos();
+
+ assertEquals(ep.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.AES128_CBC);
+
+ RecipientId recSel = new JceKeyAgreeRecipientId(_reciEcCert);
+
+ RecipientInformation recipient = recipients.get(recSel);
+
+ CMSTypedStream recData = recipient.getContentStream(new JceKeyAgreeEnvelopedRecipient(_reciEcKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, CMSTestUtil.streamToByteArray(recData.getContentStream())));
+
+ ep.close();
+ }
+
+ public void testOriginatorInfo()
+ throws Exception
+ {
+ CMSEnvelopedDataParser env = new CMSEnvelopedDataParser(CMSSampleMessages.originatorMessage);
+
+ OriginatorInformation origInfo = env.getOriginatorInfo();
+
+ RecipientInformationStore recipients = env.getRecipientInfos();
+
+ assertEquals(new X500Name("C=US,O=U.S. Government,OU=HSPD12Lab,OU=Agents,CN=user1"), ((X509CertificateHolder)origInfo.getCertificates().getMatches(null).iterator().next()).getSubject());
+ assertEquals(CMSEnvelopedDataGenerator.DES_EDE3_CBC, env.getEncryptionAlgOID());
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ return new CMSTestSetup(new TestSuite(NewEnvelopedDataStreamTest.class));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewEnvelopedDataTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewEnvelopedDataTest.java
new file mode 100644
index 000000000..f68ed3838
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewEnvelopedDataTest.java
@@ -0,0 +1,1488 @@
+package org.spongycastle.cms.test;
+
+import java.io.IOException;
+import java.security.*;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+import javax.crypto.spec.SecretKeySpec;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.DERUTF8String;
+import org.spongycastle.asn1.cms.Attribute;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.kisa.KISAObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.ntt.NTTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RC2CBCParameter;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSEnvelopedData;
+import org.spongycastle.cms.CMSEnvelopedDataGenerator;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.KeyTransRecipientInformation;
+import org.spongycastle.cms.OriginatorInfoGenerator;
+import org.spongycastle.cms.OriginatorInformation;
+import org.spongycastle.cms.PasswordRecipient;
+import org.spongycastle.cms.PasswordRecipientInformation;
+import org.spongycastle.cms.RecipientId;
+import org.spongycastle.cms.RecipientInformation;
+import org.spongycastle.cms.RecipientInformationStore;
+import org.spongycastle.cms.SimpleAttributeTableGenerator;
+import org.spongycastle.cms.bc.BcCMSContentEncryptorBuilder;
+import org.spongycastle.cms.bc.BcRSAKeyTransRecipientInfoGenerator;
+import org.spongycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
+import org.spongycastle.cms.jcajce.JceKEKEnvelopedRecipient;
+import org.spongycastle.cms.jcajce.JceKEKRecipientInfoGenerator;
+import org.spongycastle.cms.jcajce.JceKeyAgreeEnvelopedRecipient;
+import org.spongycastle.cms.jcajce.JceKeyAgreeRecipientId;
+import org.spongycastle.cms.jcajce.JceKeyAgreeRecipientInfoGenerator;
+import org.spongycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
+import org.spongycastle.cms.jcajce.JceKeyTransRecipientId;
+import org.spongycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
+import org.spongycastle.cms.jcajce.JcePasswordEnvelopedRecipient;
+import org.spongycastle.cms.jcajce.JcePasswordRecipientInfoGenerator;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.OutputEncryptor;
+import org.spongycastle.operator.jcajce.JcaAlgorithmParametersConverter;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.encoders.Hex;
+
+public class NewEnvelopedDataTest
+ extends TestCase
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ private static String _signDN;
+ private static KeyPair _signKP;
+ private static X509Certificate _signCert;
+
+ private static String _origDN;
+ private static KeyPair _origKP;
+ private static X509Certificate _origCert;
+
+ private static String _reciDN;
+ private static String _reciDN2;
+ private static KeyPair _reciKP;
+ private static KeyPair _reciOaepKP;
+ private static X509Certificate _reciCert;
+ private static X509Certificate _reciCertOaep;
+
+ private static KeyPair _origEcKP;
+ private static KeyPair _reciEcKP;
+ private static X509Certificate _reciEcCert;
+ private static KeyPair _reciEcKP2;
+ private static X509Certificate _reciEcCert2;
+
+ private static boolean _initialised = false;
+
+ private byte[] oldKEK = Base64.decode(
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxQaI/MD0CAQQwBwQFAQIDBAUwDQYJYIZIAWUDBAEFBQAEI"
+ + "Fi2eHTPM4bQSjP4DUeDzJZLpfemW2gF1SPq7ZPHJi1mMIAGCSqGSIb3DQEHATAUBggqhkiG9w"
+ + "0DBwQImtdGyUdGGt6ggAQYk9X9z01YFBkU7IlS3wmsKpm/zpZClTceAAAAAAAAAAAAAA==");
+
+ private byte[] ecKeyAgreeMsgAES256 = Base64.decode(
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxgcShgcECAQOgQ6FBMAsGByqGSM49AgEF"
+ + "AAMyAAPdXlSTpub+qqno9hUGkUDl+S3/ABhPziIB5yGU4678tgOgU5CiKG9Z"
+ + "kfnabIJ3nZYwGgYJK4EFEIZIPwACMA0GCWCGSAFlAwQBLQUAMFswWTAtMCgx"
+ + "EzARBgNVBAMTCkFkbWluLU1EU0UxETAPBgNVBAoTCDRCQ1QtMklEAgEBBCi/"
+ + "rJRLbFwEVW6PcLLmojjW9lI/xGD7CfZzXrqXFw8iHaf3hTRau1gYMIAGCSqG"
+ + "SIb3DQEHATAdBglghkgBZQMEASoEEMtCnKKPwccmyrbgeSIlA3qggAQQDLw8"
+ + "pNJR97bPpj6baG99bQQQwhEDsoj5Xg1oOxojHVcYzAAAAAAAAAAAAAA=");
+
+ private byte[] ecKeyAgreeMsgAES128 = Base64.decode(
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxgbShgbECAQOgQ6FBMAsGByqGSM49AgEF"
+ + "AAMyAAL01JLEgKvKh5rbxI/hOxs/9WEezMIsAbUaZM4l5tn3CzXAN505nr5d"
+ + "LhrcurMK+tAwGgYJK4EFEIZIPwACMA0GCWCGSAFlAwQBBQUAMEswSTAtMCgx"
+ + "EzARBgNVBAMTCkFkbWluLU1EU0UxETAPBgNVBAoTCDRCQ1QtMklEAgEBBBhi"
+ + "FLjc5g6aqDT3f8LomljOwl1WTrplUT8wgAYJKoZIhvcNAQcBMB0GCWCGSAFl"
+ + "AwQBAgQQzXjms16Y69S/rB0EbHqRMaCABBAFmc/QdVW6LTKdEy97kaZzBBBa"
+ + "fQuviUS03NycpojELx0bAAAAAAAAAAAAAA==");
+
+ private byte[] ecKeyAgreeMsgDESEDE = Base64.decode(
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxgcahgcMCAQOgQ6FBMAsGByqGSM49AgEF"
+ + "AAMyAALIici6Nx1WN5f0ThH2A8ht9ovm0thpC5JK54t73E1RDzCifePaoQo0"
+ + "xd6sUqoyGaYwHAYJK4EFEIZIPwACMA8GCyqGSIb3DQEJEAMGBQAwWzBZMC0w"
+ + "KDETMBEGA1UEAxMKQWRtaW4tTURTRTERMA8GA1UEChMINEJDVC0ySUQCAQEE"
+ + "KJuqZQ1NB1vXrKPOnb4TCpYOsdm6GscWdwAAZlm2EHMp444j0s55J9wwgAYJ"
+ + "KoZIhvcNAQcBMBQGCCqGSIb3DQMHBAjwnsDMsafCrKCABBjyPvqFOVMKxxut"
+ + "VfTx4fQlNGJN8S2ATRgECMcTQ/dsmeViAAAAAAAAAAAAAA==");
+
+ private byte[] ecMQVKeyAgreeMsgAES128 = Base64.decode(
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxgf2hgfoCAQOgQ6FBMAsGByqGSM49AgEF"
+ + "AAMyAAPDKU+0H58tsjpoYmYCInMr/FayvCCkupebgsnpaGEB7qS9vzcNVUj6"
+ + "mrnmiC2grpmhRwRFMEMwQTALBgcqhkjOPQIBBQADMgACZpD13z9c7DzRWx6S"
+ + "0xdbq3S+EJ7vWO+YcHVjTD8NcQDcZcWASW899l1PkL936zsuMBoGCSuBBRCG"
+ + "SD8AEDANBglghkgBZQMEAQUFADBLMEkwLTAoMRMwEQYDVQQDEwpBZG1pbi1N"
+ + "RFNFMREwDwYDVQQKEwg0QkNULTJJRAIBAQQYFq58L71nyMK/70w3nc6zkkRy"
+ + "RL7DHmpZMIAGCSqGSIb3DQEHATAdBglghkgBZQMEAQIEEDzRUpreBsZXWHBe"
+ + "onxOtSmggAQQ7csAZXwT1lHUqoazoy8bhAQQq+9Zjj8iGdOWgyebbfj67QAA"
+ + "AAAAAAAAAAA=");
+
+
+ private byte[] ecKeyAgreeKey = Base64.decode(
+ "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDC8vp7xVTbKSgYVU5Wc"
+ + "hGkWbzaj+yUFETIWP1Dt7+WSpq3ikSPdl7PpHPqnPVZfoIWhZANiAgSYHTgxf+Dd"
+ + "Tt84dUvuSKkFy3RhjxJmjwIscK6zbEUzKhcPQG2GHzXhWK5x1kov0I74XpGhVkya"
+ + "ElH5K6SaOXiXAzcyNGggTOk4+ZFnz5Xl0pBje3zKxPhYu0SnCw7Pcqw=");
+
+ private byte[] bobPrivRsaEncrypt = Base64.decode(
+ "MIIChQIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKnhZ5g/OdVf"
+ + "8qCTQV6meYmFyDVdmpFb+x0B2hlwJhcPvaUi0DWFbXqYZhRBXM+3twg7CcmR"
+ + "uBlpN235ZR572akzJKN/O7uvRgGGNjQyywcDWVL8hYsxBLjMGAgUSOZPHPtd"
+ + "YMTgXB9T039T2GkB8QX4enDRvoPGXzjPHCyqaqfrAgMBAAECgYBnzUhMmg2P"
+ + "mMIbZf8ig5xt8KYGHbztpwOIlPIcaw+LNd4Ogngwy+e6alatd8brUXlweQqg"
+ + "9P5F4Kmy9Bnah5jWMIR05PxZbMHGd9ypkdB8MKCixQheIXFD/A0HPfD6bRSe"
+ + "TmPwF1h5HEuYHD09sBvf+iU7o8AsmAX2EAnYh9sDGQJBANDDIsbeopkYdo+N"
+ + "vKZ11mY/1I1FUox29XLE6/BGmvE+XKpVC5va3Wtt+Pw7PAhDk7Vb/s7q/WiE"
+ + "I2Kv8zHCueUCQQDQUfweIrdb7bWOAcjXq/JY1PeClPNTqBlFy2bKKBlf4hAr"
+ + "84/sajB0+E0R9KfEILVHIdxJAfkKICnwJAiEYH2PAkA0umTJSChXdNdVUN5q"
+ + "SO8bKlocSHseIVnDYDubl6nA7xhmqU5iUjiEzuUJiEiUacUgFJlaV/4jbOSn"
+ + "I3vQgLeFAkEAni+zN5r7CwZdV+EJBqRd2ZCWBgVfJAZAcpw6iIWchw+dYhKI"
+ + "FmioNRobQ+g4wJhprwMKSDIETukPj3d9NDAlBwJAVxhn1grStavCunrnVNqc"
+ + "BU+B1O8BiR4yPWnLMcRSyFRVJQA7HCp8JlDV6abXd8vPFfXuC9WN7rOvTKF8"
+ + "Y0ZB9qANMAsGA1UdDzEEAwIAEA==");
+
+ private byte[] rfc4134ex5_1 = Base64.decode(
+ "MIIBHgYJKoZIhvcNAQcDoIIBDzCCAQsCAQAxgcAwgb0CAQAwJjASMRAwDgYD"
+ + "VQQDEwdDYXJsUlNBAhBGNGvHgABWvBHTbi7NXXHQMA0GCSqGSIb3DQEBAQUA"
+ + "BIGAC3EN5nGIiJi2lsGPcP2iJ97a4e8kbKQz36zg6Z2i0yx6zYC4mZ7mX7FB"
+ + "s3IWg+f6KgCLx3M1eCbWx8+MDFbbpXadCDgO8/nUkUNYeNxJtuzubGgzoyEd"
+ + "8Ch4H/dd9gdzTd+taTEgS0ipdSJuNnkVY4/M652jKKHRLFf02hosdR8wQwYJ"
+ + "KoZIhvcNAQcBMBQGCCqGSIb3DQMHBAgtaMXpRwZRNYAgDsiSf8Z9P43LrY4O"
+ + "xUk660cu1lXeCSFOSOpOJ7FuVyU=");
+
+ private byte[] rfc4134ex5_2 = Base64.decode(
+ "MIIBZQYJKoZIhvcNAQcDoIIBVjCCAVICAQIxggEAMIG9AgEAMCYwEjEQMA4G"
+ + "A1UEAxMHQ2FybFJTQQIQRjRrx4AAVrwR024uzV1x0DANBgkqhkiG9w0BAQEF"
+ + "AASBgJQmQojGi7Z4IP+CVypBmNFoCDoEp87khtgyff2N4SmqD3RxPx+8hbLQ"
+ + "t9i3YcMwcap+aiOkyqjMalT03VUC0XBOGv+HYI3HBZm/aFzxoq+YOXAWs5xl"
+ + "GerZwTOc9j6AYlK4qXvnztR5SQ8TBjlzytm4V7zg+TGrnGVNQBNw47Ewoj4C"
+ + "AQQwDQQLTWFpbExpc3RSQzIwEAYLKoZIhvcNAQkQAwcCAToEGHcUr5MSJ/g9"
+ + "HnJVHsQ6X56VcwYb+OfojTBJBgkqhkiG9w0BBwEwGgYIKoZIhvcNAwIwDgIC"
+ + "AKAECJwE0hkuKlWhgCBeKNXhojuej3org9Lt7n+wWxOhnky5V50vSpoYRfRR"
+ + "yw==");
+
+ private byte[] tooShort3DES = Base64.decode(
+ "MIAGCSqGSIb3DQEHA6CAMIACAQAxgcQwgcECAQAwKjAlMRYwFAYDVQQKDA1C" +
+ "b3VuY3kgQ2FzdGxlMQswCQYDVQQGEwJBVQIBCjANBgkqhkiG9w0BAQEFAASB" +
+ "gJIM2QN0o6iv8Ux018pVCJ8js+ROV4t6+KoMwLJ4DzRKLU8XCAb9BS+crP+F" +
+ "ghNTxTpTX8TaxPrO4wV0USgVHu2SvFnxNaWZjBDVIyZI2HR4QkSTqFMhsUB2" +
+ "6CuZIWBZkhqQ6ruDfvn9UuBWVnfsBD4iryZ1idr713sDeVo5TyvTMIAGCSqG" +
+ "SIb3DQEHATAUBggqhkiG9w0DBwQIQq9e4+WB3CqggAQIwU4cOlmkWUcAAAAA" +
+ "AAAAAAAA");
+
+ private byte[] tooShort3DESKey = Base64.decode(
+ "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAODZDCj0nQdV" +
+ "f0GGeFsPjjvPx1Vem0V6IkJ4SzazGKfddk0pX58ZDCnG+S+OPiXmPDqValiu" +
+ "9FtNy2/r9rrf/6qtcVQJkfSJv9E5Y7HgI98L/Y9lKxZWsfRqu/SlYO5zx0Dc" +
+ "2rzDvvZRtrtaq0uuHXWJlbWda2L9S65sv/Le/zvjAgMBAAECgYEAnn+iGMTG" +
+ "ZMMaH6Cg+t/uTa9cPougPMuplt2hd3+sY7izihUeONK5RkHiqmlE2gaAcnOd" +
+ "McKysiIWxGC73mPEnsOObPkaFlneVb5CtjTaTMdptuLNEQkwvtKhuW2HnMra" +
+ "4afEgFZdll3FyRpvW/CDooe4Bppjd4aGn/Sr/o9nOzECQQD4QKLwZssuclji" +
+ "nD/8gU1CqGMMnGNogTMpHm1269HUOE7r1y3MuapUqSWsVhpuEQ8P/Tko0haJ" +
+ "jeZn2eWTbZu/AkEA591snui8FMeGvkRgvyMFNvXZWDEjsh+N74XEL1lykTgZ" +
+ "FQJ+cmThnrdM/8yj1dKkdASYrk5kFJ4PVE6CzDI43QJAFS22eNncJZc9u/9m" +
+ "eg0x4SjqYk4JMQYsripZXlbZ7Mfs+7O8xYVlYZmYjC5ATPmJlmyc7r2VjKCd" +
+ "cmilbEFikwJBAMh7yf8BaBdjitubzjeW9VxXaa37F01eQWD5PfBfHFP6uJ1V" +
+ "AbayCfAtuHN6I7OwJih3DPmyqJC3NrQECs67IjUCQAb4TfVE/2G1s66SGnb4" +
+ "no34BspoV/i4f0uLhJap84bTHcF/ZRSXCmQOCRGdSvQkXHeNPI5Lus6lOHuU" +
+ "vUDbQC8=");
+
+ public NewEnvelopedDataTest()
+ {
+ }
+
+ private static void init()
+ throws Exception
+ {
+ if (!_initialised)
+ {
+ _initialised = true;
+ Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider());
+
+ _signDN = "O=Bouncy Castle, C=AU";
+ _signKP = CMSTestUtil.makeKeyPair();
+ _signCert = CMSTestUtil.makeCertificate(_signKP, _signDN, _signKP, _signDN);
+
+ _origDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+ _origKP = CMSTestUtil.makeKeyPair();
+ _origCert = CMSTestUtil.makeCertificate(_origKP, _origDN, _signKP, _signDN);
+
+ _reciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+ _reciDN2 = "CN=Fred, OU=Sales, O=Bouncy Castle, C=AU";
+ _reciKP = CMSTestUtil.makeKeyPair();
+ _reciCert = CMSTestUtil.makeCertificate(_reciKP, _reciDN, _signKP, _signDN);
+ _reciCertOaep = CMSTestUtil.makeOaepCertificate(_reciKP, _reciDN, _signKP, _signDN);
+
+ _origEcKP = CMSTestUtil.makeEcDsaKeyPair();
+ _reciEcKP = CMSTestUtil.makeEcDsaKeyPair();
+ _reciEcCert = CMSTestUtil.makeCertificate(_reciEcKP, _reciDN, _signKP, _signDN);
+ _reciEcKP2 = CMSTestUtil.makeEcDsaKeyPair();
+ _reciEcCert2 = CMSTestUtil.makeCertificate(_reciEcKP2, _reciDN2, _signKP, _signDN);
+ }
+ }
+
+ public static void main(
+ String args[])
+ throws Exception
+ {
+ junit.textui.TestRunner.run(NewEnvelopedDataTest.suite());
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ init();
+
+ return new CMSTestSetup(new TestSuite(NewEnvelopedDataTest.class));
+ }
+
+ public void testUnprotectedAttributes()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ Hashtable attrs = new Hashtable();
+
+ attrs.put(PKCSObjectIdentifiers.id_aa_contentHint, new Attribute(PKCSObjectIdentifiers.id_aa_contentHint, new DERSet(new DERUTF8String("Hint"))));
+ attrs.put(PKCSObjectIdentifiers.id_aa_receiptRequest, new Attribute(PKCSObjectIdentifiers.id_aa_receiptRequest, new DERSet(new DERUTF8String("Request"))));
+
+ AttributeTable attrTable = new AttributeTable(attrs);
+
+ edGen.setUnprotectedAttributeGenerator(new SimpleAttributeTableGenerator(attrTable));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ attrTable = ed.getUnprotectedAttributes();
+
+ assertEquals(attrs.size(), 2);
+
+ assertEquals(new DERUTF8String("Hint"), attrTable.get(PKCSObjectIdentifiers.id_aa_contentHint).getAttrValues().getObjectAt(0));
+ assertEquals(new DERUTF8String("Request"), attrTable.get(PKCSObjectIdentifiers.id_aa_receiptRequest).getAttrValues().getObjectAt(0));
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ }
+
+ public void testKeyTrans()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(ASN1OctetString.getInstance(ASN1OctetString.getInstance(_reciCert.getExtensionValue(Extension.subjectKeyIdentifier.getId())).getOctets()).getOctets(), _reciCert.getPublicKey()).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(2, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+
+ RecipientId id = new JceKeyTransRecipientId(_reciCert);
+
+ Collection collection = recipients.getRecipients(id);
+ if (collection.size() != 2)
+ {
+ fail("recipients not matched using general recipient ID.");
+ }
+ assertTrue(collection.iterator().next() instanceof RecipientInformation);
+ }
+
+ public void testKeyTransOAEPDefault()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+ JcaAlgorithmParametersConverter paramsConverter = new JcaAlgorithmParametersConverter();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert, paramsConverter.getAlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP, OAEPParameterSpec.DEFAULT)).setProvider(BC));
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(ASN1OctetString.getInstance(ASN1OctetString.getInstance(_reciCert.getExtensionValue(Extension.subjectKeyIdentifier.getId())).getOctets()).getOctets(), paramsConverter.getAlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP, OAEPParameterSpec.DEFAULT), _reciCert.getPublicKey()).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(2, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(PKCSObjectIdentifiers.id_RSAES_OAEP, recipient.getKeyEncryptionAlgorithm().getAlgorithm());
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+
+ RecipientId id = new JceKeyTransRecipientId(_reciCert);
+
+ Collection collection = recipients.getRecipients(id);
+ if (collection.size() != 2)
+ {
+ fail("recipients not matched using general recipient ID.");
+ }
+ assertTrue(collection.iterator().next() instanceof RecipientInformation);
+ }
+
+ public void testKeyTransOAEPSHA1()
+ throws Exception
+ {
+ doTestKeyTransOAEPDefaultNamed("SHA-1");
+ }
+
+ public void testKeyTransOAEPSHA224()
+ throws Exception
+ {
+ doTestKeyTransOAEPDefaultNamed("SHA-224");
+ }
+
+ public void testKeyTransOAEPSHA256()
+ throws Exception
+ {
+ doTestKeyTransOAEPDefaultNamed("SHA-256");
+ }
+
+ public void testKeyTransOAEPSHA1AndSHA256()
+ throws Exception
+ {
+ doTestKeyTransOAEPDefaultNamed("SHA-1", "SHA-256");
+ }
+
+ private void doTestKeyTransOAEPDefaultNamed(String digest)
+ throws Exception
+ {
+ doTestKeyTransOAEPDefaultNamed(digest, digest);
+ }
+
+ private void doTestKeyTransOAEPDefaultNamed(String digest, String mgfDigest)
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+ JcaAlgorithmParametersConverter paramsConverter = new JcaAlgorithmParametersConverter();
+
+ OAEPParameterSpec oaepSpec = new OAEPParameterSpec(digest, "MGF1", new MGF1ParameterSpec(mgfDigest), new PSource.PSpecified(new byte[]{1, 2, 3, 4, 5}));
+ AlgorithmIdentifier oaepAlgId = paramsConverter.getAlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP, oaepSpec);
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert, oaepAlgId).setProvider(BC));
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(ASN1OctetString.getInstance(ASN1OctetString.getInstance(_reciCert.getExtensionValue(Extension.subjectKeyIdentifier.getId())).getOctets()).getOctets(), oaepAlgId, _reciCert.getPublicKey()).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(2, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(PKCSObjectIdentifiers.id_RSAES_OAEP, recipient.getKeyEncryptionAlgorithm().getAlgorithm());
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+
+ RecipientId id = new JceKeyTransRecipientId(_reciCert);
+
+ Collection collection = recipients.getRecipients(id);
+ if (collection.size() != 2)
+ {
+ fail("recipients not matched using general recipient ID.");
+ }
+ assertTrue(collection.iterator().next() instanceof RecipientInformation);
+ }
+
+ public void testKeyTransOAEPInCert()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCertOaep).setProvider(BC));
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(ASN1OctetString.getInstance(ASN1OctetString.getInstance(_reciCertOaep.getExtensionValue(Extension.subjectKeyIdentifier.getId())).getOctets()).getOctets(), _reciCertOaep.getPublicKey()).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(2, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(PKCSObjectIdentifiers.id_RSAES_OAEP, recipient.getKeyEncryptionAlgorithm().getAlgorithm());
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+
+ RecipientId id = new JceKeyTransRecipientId(_reciCertOaep);
+
+ Collection collection = recipients.getRecipients(id);
+ if (collection.size() != 2)
+ {
+ fail("recipients not matched using general recipient ID.");
+ }
+ assertTrue(collection.iterator().next() instanceof RecipientInformation);
+ }
+
+ public void testKeyTransWithAlgMapping()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA/2/PKCS1Padding").setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA/2/PKCS1Padding").setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+
+ RecipientId id = new JceKeyTransRecipientId(_reciCert);
+
+ Collection collection = recipients.getRecipients(id);
+ if (collection.size() != 1)
+ {
+ fail("recipients not matched using general recipient ID.");
+ }
+ assertTrue(collection.iterator().next() instanceof RecipientInformation);
+ }
+
+ public void testOriginatorInfoGeneration()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ X509CertificateHolder origCert = new X509CertificateHolder(_origCert.getEncoded());
+
+ edGen.setOriginatorInfo(new OriginatorInfoGenerator(origCert).generate());
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(ASN1OctetString.getInstance(ASN1OctetString.getInstance(_reciCert.getExtensionValue(Extension.subjectKeyIdentifier.getId())).getOctets()).getOctets(), _reciCert.getPublicKey()).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ assertTrue(ed.getOriginatorInfo().getCertificates().getMatches(null).contains(origCert));
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(2, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+
+ RecipientId id = new JceKeyTransRecipientId(_reciCert);
+
+ Collection collection = recipients.getRecipients(id);
+ if (collection.size() != 2)
+ {
+ fail("recipients not matched using general recipient ID.");
+ }
+ assertTrue(collection.iterator().next() instanceof RecipientInformation);
+ }
+
+ public void testKeyTransRC2bit40()
+ throws Exception
+ {
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.RC2_CBC, 40).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getContentEncryptionAlgorithm().getAlgorithm(), CMSAlgorithm.RC2_CBC);
+
+ RC2CBCParameter rc2P = RC2CBCParameter.getInstance(ed.getContentEncryptionAlgorithm().getParameters());
+ assertEquals(160, rc2P.getRC2ParameterVersion().intValue());
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ }
+
+ public void testKeyTransRC4()
+ throws Exception
+ {
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.2.840.113549.3.4")).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), "1.2.840.113549.3.4");
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ }
+
+ public void testKeyTrans128RC4()
+ throws Exception
+ {
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.2.840.113549.3.4"), 128).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), "1.2.840.113549.3.4");
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testKeyTransLight128RC4()
+ throws Exception
+ {
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new BcRSAKeyTransRecipientInfoGenerator(new JcaX509CertificateHolder(_reciCert)));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.2.840.113549.3.4"), 128).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), "1.2.840.113549.3.4");
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testKeyTransODES()
+ throws Exception
+ {
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.3.14.3.2.7")).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), "1.3.14.3.2.7");
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testKeyTransSmallAES()
+ throws Exception
+ {
+ byte[] data = new byte[] { 0, 1, 2, 3 };
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(),
+ CMSEnvelopedDataGenerator.AES128_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testKeyTransDESEDE3Short()
+ throws Exception
+ {
+ byte[] data = new byte[] { 0, 1, 2, 3 };
+ KeyFactory kf = KeyFactory.getInstance("RSA", BC);
+ PrivateKey kPriv = kf.generatePrivate(new PKCS8EncodedKeySpec(tooShort3DESKey));
+
+ CMSEnvelopedData ed = new CMSEnvelopedData(tooShort3DES);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+ try
+ {
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(kPriv).setKeySizeValidation(true).setProvider(BC));
+ fail("invalid 3DES-EDE key not picked up");
+ }
+ catch (CMSException e)
+ {
+ assertEquals("Expected key size for algorithm OID not found in recipient.", e.getMessage());
+ }
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(kPriv).setKeySizeValidation(false).setProvider(BC));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testKeyTransDESEDE3Light()
+ throws Exception
+ {
+ byte[] data = new byte[] { 0, 1, 2, 3 };
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new BcRSAKeyTransRecipientInfoGenerator(new JcaX509CertificateHolder(_reciCert)));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new BcCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC, 192).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setKeySizeValidation(true).setProvider(BC));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testKeyTransDES()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.DES_CBC, CMSAlgorithm.DES_CBC, 8, DEROctetString.class);
+ }
+
+ public void testKeyTransCAST5()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.CAST5_CBC, CMSAlgorithm.CAST5_CBC, 16, ASN1Sequence.class);
+ }
+
+ public void testKeyTransAES128()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.AES128_CBC, NISTObjectIdentifiers.id_aes128_CBC, 16, DEROctetString.class);
+ }
+
+ public void testKeyTransAES192()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.AES192_CBC, NISTObjectIdentifiers.id_aes192_CBC, 24, DEROctetString.class);
+ }
+
+ public void testKeyTransAES256()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.AES256_CBC, NISTObjectIdentifiers.id_aes256_CBC, 32, DEROctetString.class);
+ }
+
+ public void testKeyTransSEED()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.SEED_CBC, KISAObjectIdentifiers.id_seedCBC, 16, DEROctetString.class);
+ }
+
+ public void testKeyTransCamellia128()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.CAMELLIA128_CBC, NTTObjectIdentifiers.id_camellia128_cbc, 16, DEROctetString.class);
+ }
+
+ public void testKeyTransCamellia192()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.CAMELLIA192_CBC, NTTObjectIdentifiers.id_camellia192_cbc, 24, DEROctetString.class);
+ }
+
+ public void testKeyTransCamellia256()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.CAMELLIA256_CBC, NTTObjectIdentifiers.id_camellia256_cbc, 32, DEROctetString.class);
+ }
+
+ private void tryKeyTrans(ASN1ObjectIdentifier generatorOID, ASN1ObjectIdentifier checkOID, int keySize, Class asn1Params)
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ OutputEncryptor encryptor = new JceCMSContentEncryptorBuilder(generatorOID).setProvider(BC).build();
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ encryptor);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(checkOID.getId(), ed.getEncryptionAlgOID());
+ assertEquals(keySize, ((byte[])encryptor.getKey().getRepresentation()).length);
+
+ if (asn1Params != null)
+ {
+ ASN1InputStream aIn = new ASN1InputStream(ed.getEncryptionAlgParams());
+
+ assertTrue(asn1Params.isAssignableFrom(aIn.readObject().getClass()));
+ }
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ if (!it.hasNext())
+ {
+ fail("no recipients found");
+ }
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setKeySizeValidation(true).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ }
+
+ public void testErroneousKEK()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+ SecretKey kek = new SecretKeySpec(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, "AES");
+
+ CMSEnvelopedData ed = new CMSEnvelopedData(oldKEK);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), NISTObjectIdentifiers.id_aes128_wrap.getId());
+
+ byte[] recData = recipient.getContent(new JceKEKEnvelopedRecipient(kek).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testDESKEK()
+ throws Exception
+ {
+ tryKekAlgorithm(CMSTestUtil.makeDesede192Key(), new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.6"));
+ }
+ public void testRC2128KEK()
+ throws Exception
+ {
+ tryKekAlgorithm(CMSTestUtil.makeRC2128Key(), new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.7"));
+ }
+
+ public void testAES128KEK()
+ throws Exception
+ {
+ tryKekAlgorithm(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap);
+ }
+
+ public void testAES192KEK()
+ throws Exception
+ {
+ tryKekAlgorithm(CMSTestUtil.makeAESKey(192), NISTObjectIdentifiers.id_aes192_wrap);
+ }
+
+ public void testAES256KEK()
+ throws Exception
+ {
+ tryKekAlgorithm(CMSTestUtil.makeAESKey(256), NISTObjectIdentifiers.id_aes256_wrap);
+ }
+
+ public void testSEED128KEK()
+ throws Exception
+ {
+ tryKekAlgorithm(CMSTestUtil.makeSEEDKey(), KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap);
+ }
+
+ public void testCamellia128KEK()
+ throws Exception
+ {
+ tryKekAlgorithm(CMSTestUtil.makeCamelliaKey(128), NTTObjectIdentifiers.id_camellia128_wrap);
+ }
+
+ public void testCamellia192KEK()
+ throws Exception
+ {
+ tryKekAlgorithm(CMSTestUtil.makeCamelliaKey(192), NTTObjectIdentifiers.id_camellia192_wrap);
+ }
+
+ public void testCamellia256KEK()
+ throws Exception
+ {
+ tryKekAlgorithm(CMSTestUtil.makeCamelliaKey(256), NTTObjectIdentifiers.id_camellia256_wrap);
+ }
+
+ private void tryKekAlgorithm(SecretKey kek, ASN1ObjectIdentifier algOid)
+ throws NoSuchAlgorithmException, NoSuchProviderException, CMSException
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ byte[] kekId = new byte[] { 1, 2, 3, 4, 5 };
+
+ edGen.addRecipientInfoGenerator(new JceKEKRecipientInfoGenerator(kekId, kek).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(algOid.getId(), recipient.getKeyEncryptionAlgOID());
+
+ byte[] recData = recipient.getContent(new JceKEKEnvelopedRecipient(kek).setKeySizeValidation(true).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testECKeyAgree()
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyAgreeRecipientInfoGenerator(CMSAlgorithm.ECDH_SHA1KDF,
+ _origEcKP.getPrivate(), _origEcKP.getPublic(),
+ CMSAlgorithm.AES128_WRAP).addRecipient(_reciEcCert).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.AES128_CBC);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ confirmDataReceived(recipients, data, _reciEcCert, _reciEcKP.getPrivate(), BC);
+ confirmNumberRecipients(recipients, 1);
+ }
+
+ public void testECMQVKeyAgree()
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyAgreeRecipientInfoGenerator(CMSAlgorithm.ECMQV_SHA1KDF,
+ _origEcKP.getPrivate(), _origEcKP.getPublic(),
+ CMSAlgorithm.AES128_WRAP).addRecipient(_reciEcCert).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.AES128_CBC);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ confirmDataReceived(recipients, data, _reciEcCert, _reciEcKP.getPrivate(), BC);
+ confirmNumberRecipients(recipients, 1);
+ }
+
+ public void testECMQVKeyAgreeMultiple()
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ JceKeyAgreeRecipientInfoGenerator recipientGenerator = new JceKeyAgreeRecipientInfoGenerator(CMSAlgorithm.ECMQV_SHA1KDF,
+ _origEcKP.getPrivate(), _origEcKP.getPublic(), CMSAlgorithm.AES128_WRAP).setProvider(BC);
+
+ recipientGenerator.addRecipient(_reciEcCert);
+ recipientGenerator.addRecipient(_reciEcCert2);
+
+ edGen.addRecipientInfoGenerator(recipientGenerator);
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.AES128_CBC);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ confirmDataReceived(recipients, data, _reciEcCert, _reciEcKP.getPrivate(), BC);
+ confirmDataReceived(recipients, data, _reciEcCert2, _reciEcKP2.getPrivate(), BC);
+ confirmNumberRecipients(recipients, 2);
+ }
+
+ private static void confirmDataReceived(RecipientInformationStore recipients,
+ byte[] expectedData, X509Certificate reciCert, PrivateKey reciPrivKey, String provider)
+ throws CMSException, NoSuchProviderException, CertificateEncodingException, IOException
+ {
+ RecipientId rid = new JceKeyAgreeRecipientId(reciCert);
+
+ RecipientInformation recipient = recipients.get(rid);
+ assertNotNull(recipient);
+
+ byte[] actualData = recipient.getContent(new JceKeyAgreeEnvelopedRecipient(reciPrivKey).setProvider(provider));
+ assertEquals(true, Arrays.equals(expectedData, actualData));
+ }
+
+ private static void confirmNumberRecipients(RecipientInformationStore recipients, int count)
+ {
+ assertEquals(count, recipients.getRecipients().size());
+ }
+
+ public void testECKeyAgreeVectors()
+ throws Exception
+ {
+ PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(ecKeyAgreeKey);
+ KeyFactory fact = KeyFactory.getInstance("ECDH", BC);
+ PrivateKey privKey = fact.generatePrivate(privSpec);
+
+ verifyECKeyAgreeVectors(privKey, "2.16.840.1.101.3.4.1.42", ecKeyAgreeMsgAES256);
+ verifyECKeyAgreeVectors(privKey, "2.16.840.1.101.3.4.1.2", ecKeyAgreeMsgAES128);
+ verifyECKeyAgreeVectors(privKey, "1.2.840.113549.3.7", ecKeyAgreeMsgDESEDE);
+ }
+
+ public void testECMQVKeyAgreeVectors()
+ throws Exception
+ {
+ PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(ecKeyAgreeKey);
+ KeyFactory fact = KeyFactory.getInstance("ECDH", BC);
+ PrivateKey privKey = fact.generatePrivate(privSpec);
+
+ verifyECMQVKeyAgreeVectors(privKey, "2.16.840.1.101.3.4.1.2", ecMQVKeyAgreeMsgAES128);
+ }
+
+ public void testPasswordAES256()
+ throws Exception
+ {
+ passwordTest(CMSEnvelopedDataGenerator.AES256_CBC);
+ passwordUTF8Test(CMSEnvelopedDataGenerator.AES256_CBC);
+ }
+
+ public void testPasswordDESEDE()
+ throws Exception
+ {
+ passwordTest(CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+ passwordUTF8Test(CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+ }
+
+ public void testRFC4134ex5_1()
+ throws Exception
+ {
+ byte[] data = Hex.decode("5468697320697320736f6d652073616d706c6520636f6e74656e742e");
+
+ KeyFactory kFact = KeyFactory.getInstance("RSA", BC);
+ Key key = kFact.generatePrivate(new PKCS8EncodedKeySpec(bobPrivRsaEncrypt));
+
+ CMSEnvelopedData ed = new CMSEnvelopedData(rfc4134ex5_1);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals("1.2.840.113549.3.7", ed.getEncryptionAlgOID());
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient((PrivateKey)key).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testRFC4134ex5_2()
+ throws Exception
+ {
+ byte[] data = Hex.decode("5468697320697320736f6d652073616d706c6520636f6e74656e742e");
+
+ KeyFactory kFact = KeyFactory.getInstance("RSA", BC);
+ PrivateKey key = kFact.generatePrivate(new PKCS8EncodedKeySpec(bobPrivRsaEncrypt));
+
+ CMSEnvelopedData ed = new CMSEnvelopedData(rfc4134ex5_2);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals("1.2.840.113549.3.2", ed.getEncryptionAlgOID());
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+ byte[] recData;
+
+ if (recipient instanceof KeyTransRecipientInformation)
+ {
+ recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(key).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ }
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testOriginatorInfo()
+ throws Exception
+ {
+ CMSEnvelopedData env = new CMSEnvelopedData(CMSSampleMessages.originatorMessage);
+
+ RecipientInformationStore recipients = env.getRecipientInfos();
+
+ OriginatorInformation origInfo = env.getOriginatorInfo();
+
+ assertEquals(new X500Name("C=US,O=U.S. Government,OU=HSPD12Lab,OU=Agents,CN=user1"), ((X509CertificateHolder)origInfo.getCertificates().getMatches(null).iterator().next()).getSubject());
+ assertEquals(CMSEnvelopedDataGenerator.DES_EDE3_CBC, env.getEncryptionAlgOID());
+ }
+
+ private void passwordTest(String algorithm)
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JcePasswordRecipientInfoGenerator(new ASN1ObjectIdentifier(algorithm), "password".toCharArray()).setProvider(BC).setPasswordConversionScheme(PasswordRecipient.PKCS5_SCHEME2).setSaltAndIterationCount(new byte[20], 5));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(),
+ CMSEnvelopedDataGenerator.AES128_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ PasswordRecipientInformation recipient = (PasswordRecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JcePasswordEnvelopedRecipient("password".toCharArray()).setPasswordConversionScheme(PasswordRecipient.PKCS5_SCHEME2).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+
+ //
+ // try algorithm parameters constructor
+ //
+ it = c.iterator();
+
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JcePasswordEnvelopedRecipient("password".toCharArray()).setPasswordConversionScheme(PasswordRecipient.PKCS5_SCHEME2).setProvider(BC));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+
+ private void passwordUTF8Test(String algorithm)
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JcePasswordRecipientInfoGenerator(new ASN1ObjectIdentifier(algorithm), "abc\u5639\u563b".toCharArray()).setProvider(BC).setSaltAndIterationCount(new byte[20], 5));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(),
+ CMSEnvelopedDataGenerator.AES128_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JcePasswordEnvelopedRecipient("abc\u5639\u563b".toCharArray()).setProvider(BC));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+
+ //
+ // try algorithm parameters constructor
+ //
+ it = c.iterator();
+
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JcePasswordEnvelopedRecipient("abc\u5639\u563b".toCharArray()).setProvider(BC));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+
+ private void verifyECKeyAgreeVectors(PrivateKey privKey, String wrapAlg, byte[] message)
+ throws CMSException, GeneralSecurityException
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedData ed = new CMSEnvelopedData(message);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ assertEquals(wrapAlg, ed.getEncryptionAlgOID());
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals("1.3.133.16.840.63.0.2", recipient.getKeyEncryptionAlgOID());
+
+ byte[] recData = recipient.getContent(new JceKeyAgreeEnvelopedRecipient(privKey).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ private void verifyECMQVKeyAgreeVectors(PrivateKey privKey, String wrapAlg, byte[] message)
+ throws CMSException, GeneralSecurityException
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedData ed = new CMSEnvelopedData(message);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ assertEquals(wrapAlg, ed.getEncryptionAlgOID());
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals("1.3.133.16.840.63.0.16", recipient.getKeyEncryptionAlgOID());
+
+ byte[] recData = recipient.getContent(new JceKeyAgreeEnvelopedRecipient(privKey).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewSignedDataStreamTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewSignedDataStreamTest.java
new file mode 100644
index 000000000..8032b71cd
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewSignedDataStreamTest.java
@@ -0,0 +1,1311 @@
+package org.spongycastle.cms.test;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.security.KeyPair;
+import java.security.MessageDigest;
+import java.security.Security;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.cms.Attribute;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSAttributes;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.ocsp.OCSPResponse;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.jcajce.JcaCRLStore;
+import org.spongycastle.cert.jcajce.JcaCertStore;
+import org.spongycastle.cert.jcajce.JcaX509CRLHolder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.cert.ocsp.OCSPResp;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSAttributeTableGenerator;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.CMSSignedData;
+import org.spongycastle.cms.CMSSignedDataGenerator;
+import org.spongycastle.cms.CMSSignedDataParser;
+import org.spongycastle.cms.CMSSignedDataStreamGenerator;
+import org.spongycastle.cms.CMSTypedData;
+import org.spongycastle.cms.CMSTypedStream;
+import org.spongycastle.cms.DefaultSignedAttributeTableGenerator;
+import org.spongycastle.cms.SignerInformation;
+import org.spongycastle.cms.SignerInformationStore;
+import org.spongycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
+import org.spongycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder;
+import org.spongycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.spongycastle.util.CollectionStore;
+import org.spongycastle.util.Store;
+import org.spongycastle.util.encoders.Base64;
+
+public class NewSignedDataStreamTest
+ extends TestCase
+{
+
+ byte[] successResp = Base64.decode(
+ "MIIFnAoBAKCCBZUwggWRBgkrBgEFBQcwAQEEggWCMIIFfjCCARehgZ8wgZwx"
+ + "CzAJBgNVBAYTAklOMRcwFQYDVQQIEw5BbmRocmEgcHJhZGVzaDESMBAGA1UE"
+ + "BxMJSHlkZXJhYmFkMQwwCgYDVQQKEwNUQ1MxDDAKBgNVBAsTA0FUQzEeMBwG"
+ + "A1UEAxMVVENTLUNBIE9DU1AgUmVzcG9uZGVyMSQwIgYJKoZIhvcNAQkBFhVv"
+ + "Y3NwQHRjcy1jYS50Y3MuY28uaW4YDzIwMDMwNDAyMTIzNDU4WjBiMGAwOjAJ"
+ + "BgUrDgMCGgUABBRs07IuoCWNmcEl1oHwIak1BPnX8QQUtGyl/iL9WJ1VxjxF"
+ + "j0hAwJ/s1AcCAQKhERgPMjAwMjA4MjkwNzA5MjZaGA8yMDAzMDQwMjEyMzQ1"
+ + "OFowDQYJKoZIhvcNAQEFBQADgYEAfbN0TCRFKdhsmvOdUoiJ+qvygGBzDxD/"
+ + "VWhXYA+16AphHLIWNABR3CgHB3zWtdy2j7DJmQ/R7qKj7dUhWLSqclAiPgFt"
+ + "QQ1YvSJAYfEIdyHkxv4NP0LSogxrumANcDyC9yt/W9yHjD2ICPBIqCsZLuLk"
+ + "OHYi5DlwWe9Zm9VFwCGgggPMMIIDyDCCA8QwggKsoAMCAQICAQYwDQYJKoZI"
+ + "hvcNAQEFBQAwgZQxFDASBgNVBAMTC1RDUy1DQSBPQ1NQMSYwJAYJKoZIhvcN"
+ + "AQkBFhd0Y3MtY2FAdGNzLWNhLnRjcy5jby5pbjEMMAoGA1UEChMDVENTMQww"
+ + "CgYDVQQLEwNBVEMxEjAQBgNVBAcTCUh5ZGVyYWJhZDEXMBUGA1UECBMOQW5k"
+ + "aHJhIHByYWRlc2gxCzAJBgNVBAYTAklOMB4XDTAyMDgyOTA3MTE0M1oXDTAz"
+ + "MDgyOTA3MTE0M1owgZwxCzAJBgNVBAYTAklOMRcwFQYDVQQIEw5BbmRocmEg"
+ + "cHJhZGVzaDESMBAGA1UEBxMJSHlkZXJhYmFkMQwwCgYDVQQKEwNUQ1MxDDAK"
+ + "BgNVBAsTA0FUQzEeMBwGA1UEAxMVVENTLUNBIE9DU1AgUmVzcG9uZGVyMSQw"
+ + "IgYJKoZIhvcNAQkBFhVvY3NwQHRjcy1jYS50Y3MuY28uaW4wgZ8wDQYJKoZI"
+ + "hvcNAQEBBQADgY0AMIGJAoGBAM+XWW4caMRv46D7L6Bv8iwtKgmQu0SAybmF"
+ + "RJiz12qXzdvTLt8C75OdgmUomxp0+gW/4XlTPUqOMQWv463aZRv9Ust4f8MH"
+ + "EJh4ekP/NS9+d8vEO3P40ntQkmSMcFmtA9E1koUtQ3MSJlcs441JjbgUaVnm"
+ + "jDmmniQnZY4bU3tVAgMBAAGjgZowgZcwDAYDVR0TAQH/BAIwADALBgNVHQ8E"
+ + "BAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwkwNgYIKwYBBQUHAQEEKjAoMCYG"
+ + "CCsGAQUFBzABhhpodHRwOi8vMTcyLjE5LjQwLjExMDo3NzAwLzAtBgNVHR8E"
+ + "JjAkMCKgIKAehhxodHRwOi8vMTcyLjE5LjQwLjExMC9jcmwuY3JsMA0GCSqG"
+ + "SIb3DQEBBQUAA4IBAQB6FovM3B4VDDZ15o12gnADZsIk9fTAczLlcrmXLNN4"
+ + "PgmqgnwF0Ymj3bD5SavDOXxbA65AZJ7rBNAguLUo+xVkgxmoBH7R2sBxjTCc"
+ + "r07NEadxM3HQkt0aX5XYEl8eRoifwqYAI9h0ziZfTNes8elNfb3DoPPjqq6V"
+ + "mMg0f0iMS4W8LjNPorjRB+kIosa1deAGPhq0eJ8yr0/s2QR2/WFD5P4aXc8I"
+ + "KWleklnIImS3zqiPrq6tl2Bm8DZj7vXlTOwmraSQxUwzCKwYob1yGvNOUQTq"
+ + "pG6jxn7jgDawHU1+WjWQe4Q34/pWeGLysxTraMa+Ug9kPe+jy/qRX2xwvKBZ");
+
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ private static final String TEST_MESSAGE = "Hello World!";
+ private static String _signDN;
+ private static KeyPair _signKP;
+ private static X509Certificate _signCert;
+
+ private static String _origDN;
+ private static KeyPair _origKP;
+ private static X509Certificate _origCert;
+
+ private static String _reciDN;
+ private static KeyPair _reciKP;
+ private static X509Certificate _reciCert;
+
+ private static KeyPair _origDsaKP;
+ private static X509Certificate _origDsaCert;
+
+ private static X509CRL _signCrl;
+ private static X509CRL _origCrl;
+
+ private static boolean _initialised = false;
+
+ public NewSignedDataStreamTest(String name)
+ {
+ super(name);
+ }
+
+ private static void init()
+ throws Exception
+ {
+ if (!_initialised)
+ {
+ _initialised = true;
+
+ if (Security.getProvider(BC) == null)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ _signDN = "O=Bouncy Castle, C=AU";
+ _signKP = CMSTestUtil.makeKeyPair();
+ _signCert = CMSTestUtil.makeCertificate(_signKP, _signDN, _signKP, _signDN);
+
+ _origDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+ _origKP = CMSTestUtil.makeKeyPair();
+ _origCert = CMSTestUtil.makeCertificate(_origKP, _origDN, _signKP, _signDN);
+
+ _origDsaKP = CMSTestUtil.makeDsaKeyPair();
+ _origDsaCert = CMSTestUtil.makeCertificate(_origDsaKP, _origDN, _signKP, _signDN);
+
+ _reciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+ _reciKP = CMSTestUtil.makeKeyPair();
+ _reciCert = CMSTestUtil.makeCertificate(_reciKP, _reciDN, _signKP, _signDN);
+
+ _signCrl = CMSTestUtil.makeCrl(_signKP);
+ _origCrl = CMSTestUtil.makeCrl(_origKP);
+ }
+ }
+
+ private void verifySignatures(CMSSignedDataParser sp, byte[] contentDigest)
+ throws Exception
+ {
+ Store certStore = sp.getCertificates();
+ Store crlStore = sp.getCRLs();
+ SignerInformationStore signers = sp.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certStore.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+
+ if (contentDigest != null)
+ {
+ assertTrue(MessageDigest.isEqual(contentDigest, signer.getContentDigest()));
+ }
+ }
+
+ assertEquals(certStore.getMatches(null).size(), sp.getCertificates().getMatches(null).size());
+ assertEquals(crlStore.getMatches(null).size(), sp.getCRLs().getMatches(null).size());
+ }
+
+ private void verifySignatures(CMSSignedDataParser sp)
+ throws Exception
+ {
+ verifySignatures(sp, null);
+ }
+
+ private void verifyEncodedData(ByteArrayOutputStream bOut)
+ throws Exception
+ {
+ CMSSignedDataParser sp;
+ sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+
+ sp.close();
+ }
+
+ private void checkSigParseable(byte[] sig)
+ throws Exception
+ {
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), sig);
+ sp.getVersion();
+ CMSTypedStream sc = sp.getSignedContent();
+ if (sc != null)
+ {
+ sc.drain();
+ }
+ sp.getCertificates();
+ sp.getCRLs();
+ sp.getSignerInfos();
+ sp.close();
+ }
+
+// public void testEarlyInvalidKeyException() throws Exception
+// {
+// try
+// {
+// CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+// gen.addSigner( _origKP.getPrivate(), _origCert,
+// "DSA", // DOESN'T MATCH KEY ALG
+// CMSSignedDataStreamGenerator.DIGEST_SHA1, BC);
+//
+// fail("Expected InvalidKeyException in addSigner");
+// }
+// catch (InvalidKeyException e)
+// {
+// // Ignore
+// }
+// }
+
+// public void testEarlyNoSuchAlgorithmException() throws Exception
+// {
+// try
+// {
+// CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+// gen.addSigner( _origKP.getPrivate(), _origCert,
+// CMSSignedDataStreamGenerator.DIGEST_SHA1, // BAD OID!
+// CMSSignedDataStreamGenerator.DIGEST_SHA1, BC);
+//
+// fail("Expected NoSuchAlgorithmException in addSigner");
+// }
+// catch (NoSuchAlgorithmException e)
+// {
+// // Ignore
+// }
+// }
+
+ public void testSha1EncapsulatedSignature()
+ throws Exception
+ {
+ byte[] encapSigData = Base64.decode(
+ "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"
+ + "n7MsJMoKN3Kd2Vzh6s10PFgeAAAAAAAA");
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), encapSigData);
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+ }
+
+ public void testSHA1WithRSANoAttributes()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray(TEST_MESSAGE.getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ JcaSignerInfoGeneratorBuilder siBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ siBuilder.setDirectSignature(true);
+
+ gen.addSignerInfoGenerator(siBuilder.build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(msg, false);
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(),
+ new CMSTypedStream(new ByteArrayInputStream(TEST_MESSAGE.getBytes())), s.getEncoded());
+
+ sp.getSignedContent().drain();
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+
+ verifySignatures(sp, md.digest(TEST_MESSAGE.getBytes()));
+ }
+
+ public void testDSANoAttributes()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray(TEST_MESSAGE.getBytes());
+
+ certList.add(_origDsaCert);
+ certList.add(_signCert);
+
+ JcaCertStore certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ JcaSignerInfoGeneratorBuilder builder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ builder.setDirectSignature(true);
+
+ gen.addSignerInfoGenerator(builder.build(new JcaContentSignerBuilder("SHA1withDSA").setProvider(BC).build(_origDsaKP.getPrivate()), _origDsaCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(msg);
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(),
+ new CMSTypedStream(new ByteArrayInputStream(TEST_MESSAGE.getBytes())), s.getEncoded());
+
+ sp.getSignedContent().drain();
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+
+ verifySignatures(sp, md.digest(TEST_MESSAGE.getBytes()));
+ }
+
+ public void testSHA1WithRSA()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ List crlList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ crlList.add(_signCrl);
+ crlList.add(_origCrl);
+
+ Store certs = new JcaCertStore(certList);
+ Store crls = new JcaCRLStore(crlList);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ gen.addCRLs(crls);
+
+ OutputStream sigOut = gen.open(bOut);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ checkSigParseable(bOut.toByteArray());
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(),
+ new CMSTypedStream(new ByteArrayInputStream(TEST_MESSAGE.getBytes())), bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+
+ verifySignatures(sp, md.digest(TEST_MESSAGE.getBytes()));
+
+ //
+ // try using existing signer
+ //
+ gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigners(sp.getSignerInfos());
+
+ gen.addCertificates(sp.getCertificates());
+ gen.addCRLs(sp.getCRLs());
+
+ bOut.reset();
+
+ sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ verifyEncodedData(bOut);
+
+ //
+ // look for the CRLs
+ //
+ Collection col = sp.getCRLs().getMatches(null);
+
+ assertEquals(2, col.size());
+ assertTrue(col.contains(new JcaX509CRLHolder(_signCrl)));
+ assertTrue(col.contains(new JcaX509CRLHolder(_origCrl)));
+ }
+
+ public void testSHA1WithRSAAndOtherRevocation()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ List otherInfo = new ArrayList();
+ OCSPResp response = new OCSPResp(successResp);
+
+ otherInfo.add(response.toASN1Structure());
+
+ gen.addOtherRevocationInfo(CMSObjectIdentifiers.id_ri_ocsp_response, new CollectionStore(otherInfo));
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), bOut.toByteArray());
+
+ CMSTypedStream stream = sp.getSignedContent();
+
+ assertEquals(CMSObjectIdentifiers.data, stream.getContentType());
+
+ stream.drain();
+
+ //
+ // check version
+ //
+ assertEquals(5, sp.getVersion());
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+
+ verifySignatures(sp, md.digest(TEST_MESSAGE.getBytes()));
+
+ Store dataOtherInfo = sp.getOtherRevocationInfo(CMSObjectIdentifiers.id_ri_ocsp_response);
+
+ assertEquals(1, dataOtherInfo.getMatches(null).size());
+
+ OCSPResp dataResponse = new OCSPResp(OCSPResponse.getInstance(dataOtherInfo.getMatches(null).iterator().next()));
+
+ assertEquals(response, dataResponse);
+ }
+
+ public void testSHA1WithRSANonData()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ List crlList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(new JcaX509CertificateHolder(_origCert));
+ certList.add(new JcaX509CertificateHolder(_signCert));
+
+ crlList.add(new JcaX509CRLHolder(_signCrl));
+ crlList.add(new JcaX509CRLHolder(_origCrl));
+
+ Store certs = new JcaCertStore(certList);
+ Store crls = new JcaCRLStore(crlList);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+ gen.addCRLs(crls);
+
+ OutputStream sigOut = gen.open(new ASN1ObjectIdentifier("1.2.3.4"), bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), bOut.toByteArray());
+
+ CMSTypedStream stream = sp.getSignedContent();
+
+ assertEquals(new ASN1ObjectIdentifier("1.2.3.4"), stream.getContentType());
+
+ stream.drain();
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+
+ verifySignatures(sp, md.digest(TEST_MESSAGE.getBytes()));
+ }
+
+ public void testSHA1AndMD5WithRSA()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+ JcaSignerInfoGeneratorBuilder signerInfoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+ ContentSigner md5Signer = new JcaContentSignerBuilder("MD5withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(signerInfoGeneratorBuilder.build(sha1Signer, _origCert));
+
+ gen.addSignerInfoGenerator(signerInfoGeneratorBuilder.build(md5Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ OutputStream sigOut = gen.open(bOut);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ checkSigParseable(bOut.toByteArray());
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(),
+ new CMSTypedStream(new ByteArrayInputStream(TEST_MESSAGE.getBytes())), bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+ }
+
+ public void testSHA1WithRSAEncapsulatedBufferedStream()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ //
+ // find unbuffered length
+ //
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ for (int i = 0; i != 2000; i++)
+ {
+ sigOut.write(i & 0xff);
+ }
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+
+ int unbufferedLength = bOut.toByteArray().length;
+
+ //
+ // find buffered length with buffered stream - should be equal
+ //
+ bOut = new ByteArrayOutputStream();
+
+ gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ sigOut = gen.open(bOut, true);
+
+ BufferedOutputStream bfOut = new BufferedOutputStream(sigOut, 300);
+
+ for (int i = 0; i != 2000; i++)
+ {
+ bfOut.write(i & 0xff);
+ }
+
+ bfOut.close();
+
+ verifyEncodedData(bOut);
+
+ assertTrue(bOut.toByteArray().length == unbufferedLength);
+ }
+
+ public void testSHA1WithRSAEncapsulatedBuffered()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ //
+ // find unbuffered length
+ //
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ for (int i = 0; i != 2000; i++)
+ {
+ sigOut.write(i & 0xff);
+ }
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+
+ int unbufferedLength = bOut.toByteArray().length;
+
+ //
+ // find buffered length - buffer size less than default
+ //
+ bOut = new ByteArrayOutputStream();
+
+ gen = new CMSSignedDataStreamGenerator();
+
+ gen.setBufferSize(300);
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ sigOut = gen.open(bOut, true);
+
+ for (int i = 0; i != 2000; i++)
+ {
+ sigOut.write(i & 0xff);
+ }
+
+ sigOut.close();
+
+ verifyEncodedData(bOut);
+
+ assertTrue(bOut.toByteArray().length > unbufferedLength);
+ }
+
+ public void testSHA1WithRSAEncapsulated()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+
+ byte[] contentDigest = (byte[])gen.getGeneratedDigests().get(CMSAlgorithm.SHA1.getId());
+
+ AttributeTable table = ((SignerInformation)sp.getSignerInfos().getSigners().iterator().next()).getSignedAttributes();
+ Attribute hash = table.get(CMSAttributes.messageDigest);
+
+ assertTrue(MessageDigest.isEqual(contentDigest, ((ASN1OctetString)hash.getAttrValues().getObjectAt(0)).getOctets()));
+
+ //
+ // try using existing signer
+ //
+ gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigners(sp.getSignerInfos());
+
+ gen.addCertificates(sp.getCertificates());
+
+ bOut.reset();
+
+ sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedData sd = new CMSSignedData(new CMSProcessableByteArray(TEST_MESSAGE.getBytes()), bOut.toByteArray());
+
+ assertEquals(1, sd.getSignerInfos().getSigners().size());
+
+ verifyEncodedData(bOut);
+ }
+
+ public void testSHA1WithRSAEncapsulatedSubjectKeyID()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, CMSTestUtil.createSubjectKeyId(_origCert.getPublicKey()).getKeyIdentifier()));
+
+ gen.addCertificates(certs);
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+
+ byte[] contentDigest = (byte[])gen.getGeneratedDigests().get(CMSAlgorithm.SHA1.getId());
+
+ AttributeTable table = ((SignerInformation)sp.getSignerInfos().getSigners().iterator().next()).getSignedAttributes();
+ Attribute hash = table.get(CMSAttributes.messageDigest);
+
+ assertTrue(MessageDigest.isEqual(contentDigest, ((ASN1OctetString)hash.getAttrValues().getObjectAt(0)).getOctets()));
+
+ //
+ // try using existing signer
+ //
+ gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigners(sp.getSignerInfos());
+
+ gen.addCertificates(sp.getCertificates());
+
+ bOut.reset();
+
+ sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedData sd = new CMSSignedData(new CMSProcessableByteArray(TEST_MESSAGE.getBytes()), bOut.toByteArray());
+
+ assertEquals(1, sd.getSignerInfos().getSigners().size());
+
+ verifyEncodedData(bOut);
+ }
+
+ public void testAttributeGenerators()
+ throws Exception
+ {
+ final ASN1ObjectIdentifier dummyOid1 = new ASN1ObjectIdentifier("1.2.3");
+ final ASN1ObjectIdentifier dummyOid2 = new ASN1ObjectIdentifier("1.2.3.4");
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ JcaCertStore certs = new JcaCertStore(certList);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ CMSAttributeTableGenerator signedGen = new DefaultSignedAttributeTableGenerator()
+ {
+ public AttributeTable getAttributes(Map parameters)
+ {
+ Hashtable table = createStandardAttributeTable(parameters);
+
+ DEROctetString val = new DEROctetString((byte[])parameters.get(CMSAttributeTableGenerator.DIGEST));
+ Attribute attr = new Attribute(dummyOid1, new DERSet(val));
+
+ table.put(attr.getAttrType(), attr);
+
+ return new AttributeTable(table);
+ }
+ };
+
+ CMSAttributeTableGenerator unsignedGen = new CMSAttributeTableGenerator()
+ {
+ public AttributeTable getAttributes(Map parameters)
+ {
+ DEROctetString val = new DEROctetString((byte[])parameters.get(CMSAttributeTableGenerator.SIGNATURE));
+ Attribute attr = new Attribute(dummyOid2, new DERSet(val));
+
+ return new AttributeTable(new DERSet(attr));
+ }
+ };
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ JcaSignerInfoGeneratorBuilder siBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ siBuilder.setSignedAttributeGenerator(signedGen).setUnsignedAttributeGenerator(unsignedGen);
+
+ gen.addSignerInfoGenerator(siBuilder.build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+
+ //
+ // check attributes
+ //
+ SignerInformationStore signers = sp.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ checkAttribute(signer.getContentDigest(), signer.getSignedAttributes().get(dummyOid1));
+ checkAttribute(signer.getSignature(), signer.getUnsignedAttributes().get(dummyOid2));
+ }
+ }
+
+ private void checkAttribute(byte[] expected, Attribute attr)
+ {
+ DEROctetString value = (DEROctetString)attr.getAttrValues().getObjectAt(0);
+
+ assertEquals(new DEROctetString(expected), value);
+ }
+
+ public void testWithAttributeCertificate()
+ throws Exception
+ {
+ List certList = new ArrayList();
+
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ X509AttributeCertificateHolder attrCert = CMSTestUtil.getAttributeCertificate();
+
+ Store store = new CollectionStore(Collections.singleton(attrCert));
+
+ gen.addAttributeCertificates(store);
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ assertEquals(4, sp.getVersion());
+
+// store = sp.getAttributeCertificates();
+//
+// Collection coll = store.getMatches(null);
+//
+// assertEquals(1, coll.size());
+//
+// assertTrue(coll.contains(new JcaX509AttributeCertificateHolder(attrCert)));
+ }
+
+ public void testSignerStoreReplacement()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ byte[] data = TEST_MESSAGE.getBytes();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder().setProvider(BC).build("SHA1withRSA", _origKP.getPrivate(), _origCert));
+
+ gen.addCertificates(certs);
+
+ OutputStream sigOut = gen.open(bOut, false);
+
+ sigOut.write(data);
+
+ sigOut.close();
+
+ checkSigParseable(bOut.toByteArray());
+
+ //
+ // create new Signer
+ //
+ ByteArrayInputStream original = new ByteArrayInputStream(bOut.toByteArray());
+
+ bOut.reset();
+
+ gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder().setProvider(BC).build("SHA224withRSA", _origKP.getPrivate(), _origCert));
+
+ gen.addCertificates(certs);
+
+ sigOut = gen.open(bOut);
+
+ sigOut.write(data);
+
+ sigOut.close();
+
+ checkSigParseable(bOut.toByteArray());
+
+ CMSSignedData sd = new CMSSignedData(bOut.toByteArray());
+
+ //
+ // replace signer
+ //
+ ByteArrayOutputStream newOut = new ByteArrayOutputStream();
+
+ CMSSignedDataParser.replaceSigners(original, sd.getSignerInfos(), newOut);
+
+ sd = new CMSSignedData(new CMSProcessableByteArray(data), newOut.toByteArray());
+ SignerInformation signer = (SignerInformation)sd.getSignerInfos().getSigners().iterator().next();
+
+ assertEquals(signer.getDigestAlgOID(), CMSAlgorithm.SHA224.getId());
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), new CMSTypedStream(new ByteArrayInputStream(data)), newOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+ }
+
+ public void testEncapsulatedSignerStoreReplacement()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder().setProvider(BC).build("SHA1withRSA", _origKP.getPrivate(), _origCert));
+
+ gen.addCertificates(certs);
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ //
+ // create new Signer
+ //
+ ByteArrayInputStream original = new ByteArrayInputStream(bOut.toByteArray());
+
+ bOut.reset();
+
+ gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder().setProvider(BC).build("SHA224withRSA", _origKP.getPrivate(), _origCert));
+
+ gen.addCertificates(certs);
+
+ sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedData sd = new CMSSignedData(bOut.toByteArray());
+
+ //
+ // replace signer
+ //
+ ByteArrayOutputStream newOut = new ByteArrayOutputStream();
+
+ CMSSignedDataParser.replaceSigners(original, sd.getSignerInfos(), newOut);
+
+ sd = new CMSSignedData(newOut.toByteArray());
+ SignerInformation signer = (SignerInformation)sd.getSignerInfos().getSigners().iterator().next();
+
+ assertEquals(signer.getDigestAlgOID(), CMSAlgorithm.SHA224.getId());
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), newOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+ }
+
+ public void testCertStoreReplacement()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ byte[] data = TEST_MESSAGE.getBytes();
+
+ certList.add(_origDsaCert);
+
+ JcaCertStore certs = new JcaCertStore(certList);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ JcaSignerInfoGeneratorBuilder builder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ gen.addSignerInfoGenerator(builder.build(new JcaContentSignerBuilder("SHA1withRSA").build(_origKP.getPrivate()), _origCert));
+
+ gen.addCertificates(certs);
+
+ OutputStream sigOut = gen.open(bOut);
+
+ sigOut.write(data);
+
+ sigOut.close();
+
+ checkSigParseable(bOut.toByteArray());
+
+ //
+ // create new certstore with the right certificates
+ //
+ certList = new ArrayList();
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ certs = new JcaCertStore(certList);
+
+
+ //
+ // replace certs
+ //
+ ByteArrayInputStream original = new ByteArrayInputStream(bOut.toByteArray());
+ ByteArrayOutputStream newOut = new ByteArrayOutputStream();
+
+ CMSSignedDataParser.replaceCertificatesAndCRLs(original, certs, null, null, newOut);
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), new CMSTypedStream(new ByteArrayInputStream(data)), newOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+ }
+
+ public void testEncapsulatedCertStoreReplacement()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origDsaCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ JcaSignerInfoGeneratorBuilder builder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ gen.addSignerInfoGenerator(builder.build(new JcaContentSignerBuilder("SHA1withRSA").build(_origKP.getPrivate()), _origCert));
+
+ gen.addCertificates(certs);
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ //
+ // create new certstore with the right certificates
+ //
+ certList = new ArrayList();
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ certs = new JcaCertStore(certList);
+
+ //
+ // replace certs
+ //
+ ByteArrayInputStream original = new ByteArrayInputStream(bOut.toByteArray());
+ ByteArrayOutputStream newOut = new ByteArrayOutputStream();
+
+ CMSSignedDataParser.replaceCertificatesAndCRLs(original, certs, null, null, newOut);
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), newOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+ }
+
+ public void testCertOrdering1()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder().setProvider(BC).build("SHA1withRSA", _origKP.getPrivate(), _origCert));
+
+ gen.addCertificates(certs);
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+ certs = sp.getCertificates();
+ Iterator it = certs.getMatches(null).iterator();
+
+ assertEquals(new JcaX509CertificateHolder(_origCert), it.next());
+ assertEquals(new JcaX509CertificateHolder(_signCert), it.next());
+ }
+
+ public void testCertOrdering2()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_signCert);
+ certList.add(_origCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder().setProvider(BC).build("SHA1withRSA", _origKP.getPrivate(), _origCert));
+
+ gen.addCertificates(certs);
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+ certs = sp.getCertificates();
+ Iterator it = certs.getMatches(null).iterator();
+
+ assertEquals(new JcaX509CertificateHolder(_signCert), it.next());
+ assertEquals(new JcaX509CertificateHolder(_origCert), it.next());
+ }
+
+ public void testCertsOnly()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+ gen.addCertificates(certs);
+
+ gen.open(bOut).close();
+
+ checkSigParseable(bOut.toByteArray());
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ init();
+
+ return new CMSTestSetup(new TestSuite(NewSignedDataStreamTest.class));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewSignedDataTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewSignedDataTest.java
new file mode 100644
index 000000000..54152ea77
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NewSignedDataTest.java
@@ -0,0 +1,2060 @@
+package org.spongycastle.cms.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.MessageDigest;
+import java.security.Security;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.cms.Attribute;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSAttributes;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.ocsp.OCSPResponse;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.jcajce.JcaCRLStore;
+import org.spongycastle.cert.jcajce.JcaCertStore;
+import org.spongycastle.cert.jcajce.JcaX509CRLHolder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.cert.ocsp.OCSPResp;
+import org.spongycastle.cms.CMSAbsentContent;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.CMSSignedData;
+import org.spongycastle.cms.CMSSignedDataGenerator;
+import org.spongycastle.cms.CMSSignedDataParser;
+import org.spongycastle.cms.CMSTypedData;
+import org.spongycastle.cms.DefaultCMSSignatureAlgorithmNameGenerator;
+import org.spongycastle.cms.DefaultSignedAttributeTableGenerator;
+import org.spongycastle.cms.SignerId;
+import org.spongycastle.cms.SignerInfoGeneratorBuilder;
+import org.spongycastle.cms.SignerInformation;
+import org.spongycastle.cms.SignerInformationStore;
+import org.spongycastle.cms.SignerInformationVerifier;
+import org.spongycastle.cms.SignerInformationVerifierProvider;
+import org.spongycastle.cms.bc.BcRSASignerInfoVerifierBuilder;
+import org.spongycastle.cms.jcajce.JcaSignerId;
+import org.spongycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
+import org.spongycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder;
+import org.spongycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.util.PrivateKeyFactory;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.bc.BcContentSignerBuilder;
+import org.spongycastle.operator.bc.BcDigestCalculatorProvider;
+import org.spongycastle.operator.bc.BcRSAContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.spongycastle.util.CollectionStore;
+import org.spongycastle.util.Store;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.io.Streams;
+
+public class NewSignedDataTest
+ extends TestCase
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ boolean DEBUG = true;
+
+ private static String _origDN;
+ private static KeyPair _origKP;
+ private static X509Certificate _origCert;
+
+ private static String _signDN;
+ private static KeyPair _signKP;
+ private static X509Certificate _signCert;
+
+ private static KeyPair _signGostKP;
+ private static X509Certificate _signGostCert;
+
+ private static KeyPair _signEcDsaKP;
+ private static X509Certificate _signEcDsaCert;
+
+ private static KeyPair _signEcGostKP;
+ private static X509Certificate _signEcGostCert;
+
+ private static KeyPair _signDsaKP;
+ private static X509Certificate _signDsaCert;
+
+ private static String _reciDN;
+ private static KeyPair _reciKP;
+ private static X509Certificate _reciCert;
+
+ private static X509CRL _signCrl;
+
+ private static boolean _initialised = false;
+
+ private byte[] disorderedMessage = Base64.decode(
+ "SU9fc3RkaW5fdXNlZABfX2xpYmNfc3RhcnRfbWFpbgBnZXRob3N0aWQAX19n"
+ + "bW9uX3M=");
+
+ private byte[] disorderedSet = Base64.decode(
+ "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"
+ + "gQBpSRdnDb6AcNVaXSmGo6+kVPIBhot1LzJOGaPyDNpGXxd7LV4tMBF1U7gr"
+ + "4k1g9BO6YiMWvw9uiTZmn0CfV8+k4fWEuG/nmafRoGIuay2f+ILuT+C0rnp1"
+ + "4FgMsEhuVNJJAmb12QV0PZII+UneyhAneZuQQzVUkTcVgYxogxdSOzCCAlUw"
+ + "ggHBoAMCAQICBACdekowCgYGKyQDAwECBQAwbzELMAkGA1UEBhMCREUxPTA7"
+ + "BgNVBAoUNFJlZ3VsaWVydW5nc2JlaMhvcmRlIGbIdXIgVGVsZWtvbW11bmlr"
+ + "YXRpb24gdW5kIFBvc3QxITAMBgcCggYBCgcUEwExMBEGA1UEAxQKNlItQ2Eg"
+ + "MTpQTjAiGA8yMDAxMDIwMTEzNDcwN1oYDzIwMDUwMzIyMDg1NTUxWjBvMQsw"
+ + "CQYDVQQGEwJERTE9MDsGA1UEChQ0UmVndWxpZXJ1bmdzYmVoyG9yZGUgZsh1"
+ + "ciBUZWxla29tbXVuaWthdGlvbiB1bmQgUG9zdDEhMAwGBwKCBgEKBxQTATEw"
+ + "EQYDVQQDFAo1Ui1DQSAxOlBOMIGhMA0GCSqGSIb3DQEBAQUAA4GPADCBiwKB"
+ + "gQCKHkFTJx8GmoqFTxEOxpK9XkC3NZ5dBEKiUv0Ife3QMqeGMoCUnyJxwW0k"
+ + "2/53duHxtv2yHSZpFKjrjvE/uGwdOMqBMTjMzkFg19e9JPv061wyADOucOIa"
+ + "NAgha/zFt9XUyrHF21knKCvDNExv2MYIAagkTKajLMAw0bu1J0FadQIFAMAA"
+ + "AAEwCgYGKyQDAwECBQADgYEAV1yTi+2gyB7sUhn4PXmi/tmBxAfe5oBjDW8m"
+ + "gxtfudxKGZ6l/FUPNcrSc5oqBYxKWtLmf3XX87LcblYsch617jtNTkMzhx9e"
+ + "qxiD02ufcrxz2EVt0Akdqiz8mdVeqp3oLcNU/IttpSrcA91CAnoUXtDZYwb/"
+ + "gdQ4FI9l3+qo/0UwggJVMIIBwaADAgECAgQAxIymMAoGBiskAwMBAgUAMG8x"
+ + "CzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1bGllcnVuZ3NiZWjIb3JkZSBm"
+ + "yHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0MSEwDAYHAoIGAQoHFBMB"
+ + "MTARBgNVBAMUCjZSLUNhIDE6UE4wIhgPMjAwMTEwMTUxMzMxNThaGA8yMDA1"
+ + "MDYwMTA5NTIxN1owbzELMAkGA1UEBhMCREUxPTA7BgNVBAoUNFJlZ3VsaWVy"
+ + "dW5nc2JlaMhvcmRlIGbIdXIgVGVsZWtvbW11bmlrYXRpb24gdW5kIFBvc3Qx"
+ + "ITAMBgcCggYBCgcUEwExMBEGA1UEAxQKN1ItQ0EgMTpQTjCBoTANBgkqhkiG"
+ + "9w0BAQEFAAOBjwAwgYsCgYEAiokD/j6lEP4FexF356OpU5teUpGGfUKjIrFX"
+ + "BHc79G0TUzgVxqMoN1PWnWktQvKo8ETaugxLkP9/zfX3aAQzDW4Zki6x6GDq"
+ + "fy09Agk+RJvhfbbIzRkV4sBBco0n73x7TfG/9NTgVr/96U+I+z/1j30aboM6"
+ + "9OkLEhjxAr0/GbsCBQDAAAABMAoGBiskAwMBAgUAA4GBAHWRqRixt+EuqHhR"
+ + "K1kIxKGZL2vZuakYV0R24Gv/0ZR52FE4ECr+I49o8FP1qiGSwnXB0SwjuH2S"
+ + "iGiSJi+iH/MeY85IHwW1P5e+bOMvEOFhZhQXQixOD7totIoFtdyaj1XGYRef"
+ + "0f2cPOjNJorXHGV8wuBk+/j++sxbd/Net3FtMIICVTCCAcGgAwIBAgIEAMSM"
+ + "pzAKBgYrJAMDAQIFADBvMQswCQYDVQQGEwJERTE9MDsGA1UEChQ0UmVndWxp"
+ + "ZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxla29tbXVuaWthdGlvbiB1bmQgUG9z"
+ + "dDEhMAwGBwKCBgEKBxQTATEwEQYDVQQDFAo3Ui1DQSAxOlBOMCIYDzIwMDEx"
+ + "MDE1MTMzNDE0WhgPMjAwNTA2MDEwOTUyMTdaMG8xCzAJBgNVBAYTAkRFMT0w"
+ + "OwYDVQQKFDRSZWd1bGllcnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5p"
+ + "a2F0aW9uIHVuZCBQb3N0MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjZSLUNh"
+ + "IDE6UE4wgaEwDQYJKoZIhvcNAQEBBQADgY8AMIGLAoGBAIOiqxUkzVyqnvth"
+ + "ihnltsE5m1Xn5TZKeR/2MQPStc5hJ+V4yptEtIx+Fn5rOoqT5VEVWhcE35wd"
+ + "bPvgJyQFn5msmhPQT/6XSGOlrWRoFummXN9lQzAjCj1sgTcmoLCVQ5s5WpCA"
+ + "OXFwVWu16qndz3sPItn3jJ0F3Kh3w79NglvPAgUAwAAAATAKBgYrJAMDAQIF"
+ + "AAOBgQBi5W96UVDoNIRkCncqr1LLG9vF9SGBIkvFpLDIIbcvp+CXhlvsdCJl"
+ + "0pt2QEPSDl4cmpOet+CxJTdTuMeBNXxhb7Dvualog69w/+K2JbPhZYxuVFZs"
+ + "Zh5BkPn2FnbNu3YbJhE60aIkikr72J4XZsI5DxpZCGh6xyV/YPRdKSljFjCC"
+ + "AlQwggHAoAMCAQICAwyDqzAKBgYrJAMDAQIFADBvMQswCQYDVQQGEwJERTE9"
+ + "MDsGA1UEChQ0UmVndWxpZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxla29tbXVu"
+ + "aWthdGlvbiB1bmQgUG9zdDEhMAwGBwKCBgEKBxQTATEwEQYDVQQDFAo1Ui1D"
+ + "QSAxOlBOMCIYDzIwMDAwMzIyMDk0MTI3WhgPMjAwNDAxMjExNjA0NTNaMG8x"
+ + "CzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1bGllcnVuZ3NiZWjIb3JkZSBm"
+ + "yHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0MSEwDAYHAoIGAQoHFBMB"
+ + "MTARBgNVBAMUCjRSLUNBIDE6UE4wgaEwDQYJKoZIhvcNAQEBBQADgY8AMIGL"
+ + "AoGBAI8x26tmrFJanlm100B7KGlRemCD1R93PwdnG7svRyf5ZxOsdGrDszNg"
+ + "xg6ouO8ZHQMT3NC2dH8TvO65Js+8bIyTm51azF6clEg0qeWNMKiiXbBXa+ph"
+ + "hTkGbXiLYvACZ6/MTJMJ1lcrjpRF7BXtYeYMcEF6znD4pxOqrtbf9z5hAgUA"
+ + "wAAAATAKBgYrJAMDAQIFAAOBgQB99BjSKlGPbMLQAgXlvA9jUsDNhpnVm3a1"
+ + "YkfxSqS/dbQlYkbOKvCxkPGA9NBxisBM8l1zFynVjJoy++aysRmcnLY/sHaz"
+ + "23BF2iU7WERy18H3lMBfYB6sXkfYiZtvQZcWaO48m73ZBySuiV3iXpb2wgs/"
+ + "Cs20iqroAWxwq/W/9jCCAlMwggG/oAMCAQICBDsFZ9UwCgYGKyQDAwECBQAw"
+ + "bzELMAkGA1UEBhMCREUxITAMBgcCggYBCgcUEwExMBEGA1UEAxQKNFItQ0Eg"
+ + "MTpQTjE9MDsGA1UEChQ0UmVndWxpZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxl"
+ + "a29tbXVuaWthdGlvbiB1bmQgUG9zdDAiGA8xOTk5MDEyMTE3MzUzNFoYDzIw"
+ + "MDQwMTIxMTYwMDAyWjBvMQswCQYDVQQGEwJERTE9MDsGA1UEChQ0UmVndWxp"
+ + "ZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxla29tbXVuaWthdGlvbiB1bmQgUG9z"
+ + "dDEhMAwGBwKCBgEKBxQTATEwEQYDVQQDFAozUi1DQSAxOlBOMIGfMA0GCSqG"
+ + "SIb3DQEBAQUAA4GNADCBiQKBgI4B557mbKQg/AqWBXNJhaT/6lwV93HUl4U8"
+ + "u35udLq2+u9phns1WZkdM3gDfEpL002PeLfHr1ID/96dDYf04lAXQfombils"
+ + "of1C1k32xOvxjlcrDOuPEMxz9/HDAQZA5MjmmYHAIulGI8Qg4Tc7ERRtg/hd"
+ + "0QX0/zoOeXoDSEOBAgTAAAABMAoGBiskAwMBAgUAA4GBAIyzwfT3keHI/n2P"
+ + "LrarRJv96mCohmDZNpUQdZTVjGu5VQjVJwk3hpagU0o/t/FkdzAjOdfEw8Ql"
+ + "3WXhfIbNLv1YafMm2eWSdeYbLcbB5yJ1od+SYyf9+tm7cwfDAcr22jNRBqx8"
+ + "wkWKtKDjWKkevaSdy99sAI8jebHtWz7jzydKMIID9TCCA16gAwIBAgICbMcw"
+ + "DQYJKoZIhvcNAQEFBQAwSzELMAkGA1UEBhMCREUxEjAQBgNVBAoUCVNpZ250"
+ + "cnVzdDEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFDQSBTSUdOVFJVU1QgMTpQ"
+ + "TjAeFw0wNDA3MzAxMzAyNDZaFw0wNzA3MzAxMzAyNDZaMDwxETAPBgNVBAMM"
+ + "CFlhY29tOlBOMQ4wDAYDVQRBDAVZYWNvbTELMAkGA1UEBhMCREUxCjAIBgNV"
+ + "BAUTATEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAIWzLlYLQApocXIp"
+ + "pgCCpkkOUVLgcLYKeOd6/bXAnI2dTHQqT2bv7qzfUnYvOqiNgYdF13pOYtKg"
+ + "XwXMTNFL4ZOI6GoBdNs9TQiZ7KEWnqnr2945HYx7UpgTBclbOK/wGHuCdcwO"
+ + "x7juZs1ZQPFG0Lv8RoiV9s6HP7POqh1sO0P/AgMBAAGjggH1MIIB8TCBnAYD"
+ + "VR0jBIGUMIGRgBQcZzNghfnXoXRm8h1+VITC5caNRqFzpHEwbzELMAkGA1UE"
+ + "BhMCREUxPTA7BgNVBAoUNFJlZ3VsaWVydW5nc2JlaMhvcmRlIGbIdXIgVGVs"
+ + "ZWtvbW11bmlrYXRpb24gdW5kIFBvc3QxITAMBgcCggYBCgcUEwExMBEGA1UE"
+ + "AxQKNVItQ0EgMTpQToIEALs8rjAdBgNVHQ4EFgQU2e5KAzkVuKaM9I5heXkz"
+ + "bcAIuR8wDgYDVR0PAQH/BAQDAgZAMBIGA1UdIAQLMAkwBwYFKyQIAQEwfwYD"
+ + "VR0fBHgwdjB0oCygKoYobGRhcDovL2Rpci5zaWdudHJ1c3QuZGUvbz1TaWdu"
+ + "dHJ1c3QsYz1kZaJEpEIwQDEdMBsGA1UEAxMUQ1JMU2lnblNpZ250cnVzdDE6"
+ + "UE4xEjAQBgNVBAoTCVNpZ250cnVzdDELMAkGA1UEBhMCREUwYgYIKwYBBQUH"
+ + "AQEEVjBUMFIGCCsGAQUFBzABhkZodHRwOi8vZGlyLnNpZ250cnVzdC5kZS9T"
+ + "aWdudHJ1c3QvT0NTUC9zZXJ2bGV0L2h0dHBHYXRld2F5LlBvc3RIYW5kbGVy"
+ + "MBgGCCsGAQUFBwEDBAwwCjAIBgYEAI5GAQEwDgYHAoIGAQoMAAQDAQH/MA0G"
+ + "CSqGSIb3DQEBBQUAA4GBAHn1m3GcoyD5GBkKUY/OdtD6Sj38LYqYCF+qDbJR"
+ + "6pqUBjY2wsvXepUppEler+stH8mwpDDSJXrJyuzf7xroDs4dkLl+Rs2x+2tg"
+ + "BjU+ABkBDMsym2WpwgA8LCdymmXmjdv9tULxY+ec2pjSEzql6nEZNEfrU8nt"
+ + "ZCSCavgqW4TtMYIBejCCAXYCAQEwUTBLMQswCQYDVQQGEwJERTESMBAGA1UE"
+ + "ChQJU2lnbnRydXN0MSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEUNBIFNJR05U"
+ + "UlVTVCAxOlBOAgJsxzAJBgUrDgMCGgUAoIGAMBgGCSqGSIb3DQEJAzELBgkq"
+ + "hkiG9w0BBwEwIwYJKoZIhvcNAQkEMRYEFIYfhPoyfGzkLWWSSLjaHb4HQmaK"
+ + "MBwGCSqGSIb3DQEJBTEPFw0wNTAzMjQwNzM4MzVaMCEGBSskCAYFMRgWFi92"
+ + "YXIvZmlsZXMvdG1wXzEvdGVzdDEwDQYJKoZIhvcNAQEFBQAEgYA2IvA8lhVz"
+ + "VD5e/itUxbFboKxeKnqJ5n/KuO/uBCl1N14+7Z2vtw1sfkIG+bJdp3OY2Cmn"
+ + "mrQcwsN99Vjal4cXVj8t+DJzFG9tK9dSLvD3q9zT/GQ0kJXfimLVwCa4NaSf"
+ + "Qsu4xtG0Rav6bCcnzabAkKuNNvKtH8amSRzk870DBg==");
+
+ public static byte[] xtraCounterSig = Base64.decode(
+ "MIIR/AYJKoZIhvcNAQcCoIIR7TCCEekCAQExCzAJBgUrDgMCGgUAMBoGCSqG"
+ + "SIb3DQEHAaANBAtIZWxsbyB3b3JsZKCCDnkwggTPMIIDt6ADAgECAgRDnYD3"
+ + "MA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNVBAYTAklUMRowGAYDVQQKExFJbi5U"
+ + "ZS5TLkEuIFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5BLiAtIENlcnRpZmlj"
+ + "YXRpb24gQXV0aG9yaXR5MB4XDTA4MDkxMjExNDMxMloXDTEwMDkxMjExNDMx"
+ + "MlowgdgxCzAJBgNVBAYTAklUMSIwIAYDVQQKDBlJbnRlc2EgUy5wLkEuLzA1"
+ + "MjYyODkwMDE0MSowKAYDVQQLDCFCdXNpbmVzcyBDb2xsYWJvcmF0aW9uICYg"
+ + "U2VjdXJpdHkxHjAcBgNVBAMMFU1BU1NJTUlMSUFOTyBaSUNDQVJESTERMA8G"
+ + "A1UEBAwIWklDQ0FSREkxFTATBgNVBCoMDE1BU1NJTUlMSUFOTzEcMBoGA1UE"
+ + "BRMTSVQ6WkNDTVNNNzZIMTRMMjE5WTERMA8GA1UELhMIMDAwMDI1ODUwgaAw"
+ + "DQYJKoZIhvcNAQEBBQADgY4AMIGKAoGBALeJTjmyFgx1SIP6c2AuB/kuyHo5"
+ + "j/prKELTALsFDimre/Hxr3wOSet1TdQfFzU8Lu+EJqgfV9cV+cI1yeH1rZs7"
+ + "lei7L3tX/VR565IywnguX5xwvteASgWZr537Fkws50bvTEMyYOj1Tf3FZvZU"
+ + "z4n4OD39KI4mfR9i1eEVIxR3AgQAizpNo4IBoTCCAZ0wHQYDVR0RBBYwFIES"
+ + "emljY2FyZGlAaW50ZXNhLml0MC8GCCsGAQUFBwEDBCMwITAIBgYEAI5GAQEw"
+ + "CwYGBACORgEDAgEUMAgGBgQAjkYBBDBZBgNVHSAEUjBQME4GBgQAizABATBE"
+ + "MEIGCCsGAQUFBwIBFjZodHRwOi8vZS10cnVzdGNvbS5pbnRlc2EuaXQvY2Ff"
+ + "cHViYmxpY2EvQ1BTX0lOVEVTQS5odG0wDgYDVR0PAQH/BAQDAgZAMIGDBgNV"
+ + "HSMEfDB6gBQZCQOW0bjFWBt+EORuxPagEgkQqKFcpFowWDELMAkGA1UEBhMC"
+ + "SVQxGjAYBgNVBAoTEUluLlRlLlMuQS4gUy5wLkEuMS0wKwYDVQQDEyRJbi5U"
+ + "ZS5TLkEuIC0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHmCBDzRARMwOwYDVR0f"
+ + "BDQwMjAwoC6gLIYqaHR0cDovL2UtdHJ1c3Rjb20uaW50ZXNhLml0L0NSTC9J"
+ + "TlRFU0EuY3JsMB0GA1UdDgQWBBTf5ItL8KmQh541Dxt7YxcWI1254TANBgkq"
+ + "hkiG9w0BAQUFAAOCAQEAgW+uL1CVWQepbC/wfCmR6PN37Sueb4xiKQj2mTD5"
+ + "UZ5KQjpivy/Hbuf0NrfKNiDEhAvoHSPC31ebGiKuTMFNyZPHfPEUnyYGSxea"
+ + "2w837aXJFr6utPNQGBRi89kH90sZDlXtOSrZI+AzJJn5QK3F9gjcayU2NZXQ"
+ + "MJgRwYmFyn2w4jtox+CwXPQ9E5XgxiMZ4WDL03cWVXDLX00EOJwnDDMUNTRI"
+ + "m9Zv+4SKTNlfFbi9UTBqWBySkDzAelsfB2U61oqc2h1xKmCtkGMmN9iZT+Qz"
+ + "ZC/vaaT+hLEBFGAH2gwFrYc4/jTBKyBYeU1vsAxsibIoTs1Apgl6MH75qPDL"
+ + "BzCCBM8wggO3oAMCAQICBEOdgPcwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UE"
+ + "BhMCSVQxGjAYBgNVBAoTEUluLlRlLlMuQS4gUy5wLkEuMS0wKwYDVQQDEyRJ"
+ + "bi5UZS5TLkEuIC0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwOTEy"
+ + "MTE0MzEyWhcNMTAwOTEyMTE0MzEyWjCB2DELMAkGA1UEBhMCSVQxIjAgBgNV"
+ + "BAoMGUludGVzYSBTLnAuQS4vMDUyNjI4OTAwMTQxKjAoBgNVBAsMIUJ1c2lu"
+ + "ZXNzIENvbGxhYm9yYXRpb24gJiBTZWN1cml0eTEeMBwGA1UEAwwVTUFTU0lN"
+ + "SUxJQU5PIFpJQ0NBUkRJMREwDwYDVQQEDAhaSUNDQVJESTEVMBMGA1UEKgwM"
+ + "TUFTU0lNSUxJQU5PMRwwGgYDVQQFExNJVDpaQ0NNU003NkgxNEwyMTlZMREw"
+ + "DwYDVQQuEwgwMDAwMjU4NTCBoDANBgkqhkiG9w0BAQEFAAOBjgAwgYoCgYEA"
+ + "t4lOObIWDHVIg/pzYC4H+S7IejmP+msoQtMAuwUOKat78fGvfA5J63VN1B8X"
+ + "NTwu74QmqB9X1xX5wjXJ4fWtmzuV6Lsve1f9VHnrkjLCeC5fnHC+14BKBZmv"
+ + "nfsWTCznRu9MQzJg6PVN/cVm9lTPifg4Pf0ojiZ9H2LV4RUjFHcCBACLOk2j"
+ + "ggGhMIIBnTAdBgNVHREEFjAUgRJ6aWNjYXJkaUBpbnRlc2EuaXQwLwYIKwYB"
+ + "BQUHAQMEIzAhMAgGBgQAjkYBATALBgYEAI5GAQMCARQwCAYGBACORgEEMFkG"
+ + "A1UdIARSMFAwTgYGBACLMAEBMEQwQgYIKwYBBQUHAgEWNmh0dHA6Ly9lLXRy"
+ + "dXN0Y29tLmludGVzYS5pdC9jYV9wdWJibGljYS9DUFNfSU5URVNBLmh0bTAO"
+ + "BgNVHQ8BAf8EBAMCBkAwgYMGA1UdIwR8MHqAFBkJA5bRuMVYG34Q5G7E9qAS"
+ + "CRCooVykWjBYMQswCQYDVQQGEwJJVDEaMBgGA1UEChMRSW4uVGUuUy5BLiBT"
+ + "LnAuQS4xLTArBgNVBAMTJEluLlRlLlMuQS4gLSBDZXJ0aWZpY2F0aW9uIEF1"
+ + "dGhvcml0eYIEPNEBEzA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vZS10cnVz"
+ + "dGNvbS5pbnRlc2EuaXQvQ1JML0lOVEVTQS5jcmwwHQYDVR0OBBYEFN/ki0vw"
+ + "qZCHnjUPG3tjFxYjXbnhMA0GCSqGSIb3DQEBBQUAA4IBAQCBb64vUJVZB6ls"
+ + "L/B8KZHo83ftK55vjGIpCPaZMPlRnkpCOmK/L8du5/Q2t8o2IMSEC+gdI8Lf"
+ + "V5saIq5MwU3Jk8d88RSfJgZLF5rbDzftpckWvq6081AYFGLz2Qf3SxkOVe05"
+ + "Ktkj4DMkmflArcX2CNxrJTY1ldAwmBHBiYXKfbDiO2jH4LBc9D0TleDGIxnh"
+ + "YMvTdxZVcMtfTQQ4nCcMMxQ1NEib1m/7hIpM2V8VuL1RMGpYHJKQPMB6Wx8H"
+ + "ZTrWipzaHXEqYK2QYyY32JlP5DNkL+9ppP6EsQEUYAfaDAWthzj+NMErIFh5"
+ + "TW+wDGyJsihOzUCmCXowfvmo8MsHMIIEzzCCA7egAwIBAgIEQ52A9zANBgkq"
+ + "hkiG9w0BAQUFADBYMQswCQYDVQQGEwJJVDEaMBgGA1UEChMRSW4uVGUuUy5B"
+ + "LiBTLnAuQS4xLTArBgNVBAMTJEluLlRlLlMuQS4gLSBDZXJ0aWZpY2F0aW9u"
+ + "IEF1dGhvcml0eTAeFw0wODA5MTIxMTQzMTJaFw0xMDA5MTIxMTQzMTJaMIHY"
+ + "MQswCQYDVQQGEwJJVDEiMCAGA1UECgwZSW50ZXNhIFMucC5BLi8wNTI2Mjg5"
+ + "MDAxNDEqMCgGA1UECwwhQnVzaW5lc3MgQ29sbGFib3JhdGlvbiAmIFNlY3Vy"
+ + "aXR5MR4wHAYDVQQDDBVNQVNTSU1JTElBTk8gWklDQ0FSREkxETAPBgNVBAQM"
+ + "CFpJQ0NBUkRJMRUwEwYDVQQqDAxNQVNTSU1JTElBTk8xHDAaBgNVBAUTE0lU"
+ + "OlpDQ01TTTc2SDE0TDIxOVkxETAPBgNVBC4TCDAwMDAyNTg1MIGgMA0GCSqG"
+ + "SIb3DQEBAQUAA4GOADCBigKBgQC3iU45shYMdUiD+nNgLgf5Lsh6OY/6ayhC"
+ + "0wC7BQ4pq3vx8a98DknrdU3UHxc1PC7vhCaoH1fXFfnCNcnh9a2bO5Xouy97"
+ + "V/1UeeuSMsJ4Ll+ccL7XgEoFma+d+xZMLOdG70xDMmDo9U39xWb2VM+J+Dg9"
+ + "/SiOJn0fYtXhFSMUdwIEAIs6TaOCAaEwggGdMB0GA1UdEQQWMBSBEnppY2Nh"
+ + "cmRpQGludGVzYS5pdDAvBggrBgEFBQcBAwQjMCEwCAYGBACORgEBMAsGBgQA"
+ + "jkYBAwIBFDAIBgYEAI5GAQQwWQYDVR0gBFIwUDBOBgYEAIswAQEwRDBCBggr"
+ + "BgEFBQcCARY2aHR0cDovL2UtdHJ1c3Rjb20uaW50ZXNhLml0L2NhX3B1YmJs"
+ + "aWNhL0NQU19JTlRFU0EuaHRtMA4GA1UdDwEB/wQEAwIGQDCBgwYDVR0jBHww"
+ + "eoAUGQkDltG4xVgbfhDkbsT2oBIJEKihXKRaMFgxCzAJBgNVBAYTAklUMRow"
+ + "GAYDVQQKExFJbi5UZS5TLkEuIFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5B"
+ + "LiAtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ80QETMDsGA1UdHwQ0MDIw"
+ + "MKAuoCyGKmh0dHA6Ly9lLXRydXN0Y29tLmludGVzYS5pdC9DUkwvSU5URVNB"
+ + "LmNybDAdBgNVHQ4EFgQU3+SLS/CpkIeeNQ8be2MXFiNdueEwDQYJKoZIhvcN"
+ + "AQEFBQADggEBAIFvri9QlVkHqWwv8Hwpkejzd+0rnm+MYikI9pkw+VGeSkI6"
+ + "Yr8vx27n9Da3yjYgxIQL6B0jwt9XmxoirkzBTcmTx3zxFJ8mBksXmtsPN+2l"
+ + "yRa+rrTzUBgUYvPZB/dLGQ5V7Tkq2SPgMySZ+UCtxfYI3GslNjWV0DCYEcGJ"
+ + "hcp9sOI7aMfgsFz0PROV4MYjGeFgy9N3FlVwy19NBDicJwwzFDU0SJvWb/uE"
+ + "ikzZXxW4vVEwalgckpA8wHpbHwdlOtaKnNodcSpgrZBjJjfYmU/kM2Qv72mk"
+ + "/oSxARRgB9oMBa2HOP40wSsgWHlNb7AMbImyKE7NQKYJejB++ajwywcxggM8"
+ + "MIIDOAIBATBgMFgxCzAJBgNVBAYTAklUMRowGAYDVQQKExFJbi5UZS5TLkEu"
+ + "IFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5BLiAtIENlcnRpZmljYXRpb24g"
+ + "QXV0aG9yaXR5AgRDnYD3MAkGBSsOAwIaBQAwDQYJKoZIhvcNAQEBBQAEgYB+"
+ + "lH2cwLqc91mP8prvgSV+RRzk13dJdZvdoVjgQoFrPhBiZCNIEoHvIhMMA/sM"
+ + "X6euSRZk7EjD24FasCEGYyd0mJVLEy6TSPmuW+wWz/28w3a6IWXBGrbb/ild"
+ + "/CJMkPgLPGgOVD1WDwiNKwfasiQSFtySf5DPn3jFevdLeMmEY6GCAjIwggEV"
+ + "BgkqhkiG9w0BCQYxggEGMIIBAgIBATBgMFgxCzAJBgNVBAYTAklUMRowGAYD"
+ + "VQQKExFJbi5UZS5TLkEuIFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5BLiAt"
+ + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5AgRDnYD3MAkGBSsOAwIaBQAwDQYJ"
+ + "KoZIhvcNAQEBBQAEgYBHlOULfT5GDigIvxP0qZOy8VbpntmzaPF55VV4buKV"
+ + "35J+uHp98gXKp0LrHM69V5IRKuyuQzHHFBqsXxsRI9o6KoOfgliD9Xc+BeMg"
+ + "dKzQhBhBYoFREq8hQM0nSbqDNHYAQyNHMzUA/ZQUO5dlFuH8Dw3iDYAhNtfd"
+ + "PrlchKJthDCCARUGCSqGSIb3DQEJBjGCAQYwggECAgEBMGAwWDELMAkGA1UE"
+ + "BhMCSVQxGjAYBgNVBAoTEUluLlRlLlMuQS4gUy5wLkEuMS0wKwYDVQQDEyRJ"
+ + "bi5UZS5TLkEuIC0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkCBEOdgPcwCQYF"
+ + "Kw4DAhoFADANBgkqhkiG9w0BAQEFAASBgEeU5Qt9PkYOKAi/E/Spk7LxVume"
+ + "2bNo8XnlVXhu4pXfkn64en3yBcqnQusczr1XkhEq7K5DMccUGqxfGxEj2joq"
+ + "g5+CWIP1dz4F4yB0rNCEGEFigVESryFAzSdJuoM0dgBDI0czNQD9lBQ7l2UW"
+ + "4fwPDeINgCE2190+uVyEom2E");
+
+ byte[] noSignedAttrSample2 = Base64.decode(
+ "MIIIlAYJKoZIhvcNAQcCoIIIhTCCCIECAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+ + "SIb3DQEHAaCCB3UwggOtMIIDa6ADAgECAgEzMAsGByqGSM44BAMFADCBkDEL"
+ + "MAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlQYWxvIEFsdG8x"
+ + "HTAbBgNVBAoTFFN1biBNaWNyb3N5c3RlbXMgSW5jMSMwIQYDVQQLExpKYXZh"
+ + "IFNvZnR3YXJlIENvZGUgU2lnbmluZzEcMBoGA1UEAxMTSkNFIENvZGUgU2ln"
+ + "bmluZyBDQTAeFw0wMTA1MjkxNjQ3MTFaFw0wNjA1MjgxNjQ3MTFaMG4xHTAb"
+ + "BgNVBAoTFFN1biBNaWNyb3N5c3RlbXMgSW5jMSMwIQYDVQQLExpKYXZhIFNv"
+ + "ZnR3YXJlIENvZGUgU2lnbmluZzEoMCYGA1UEAxMfVGhlIExlZ2lvbiBvZiB0"
+ + "aGUgQm91bmN5IENhc3RsZTCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OB"
+ + "HXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2"
+ + "y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58aophUP"
+ + "BPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvM"
+ + "spK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9"
+ + "B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCj"
+ + "rh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtV"
+ + "JWQBTDv+z0kqA4GEAAKBgBWry/FCAZ6miyy39+ftsa+h9lxoL+JtV0MJcUyQ"
+ + "E4VAhpAwWb8vyjba9AwOylYQTktHX5sAkFvjBiU0LOYDbFSTVZSHMRJgfjxB"
+ + "SHtICjOEvr1BJrrOrdzqdxcOUge5n7El124BCrv91x5Ol8UTwtiO9LrRXF/d"
+ + "SyK+RT5n1klRo3YwdDARBglghkgBhvhCAQEEBAMCAIcwDgYDVR0PAQH/BAQD"
+ + "AgHGMB0GA1UdDgQWBBQwMY4NRcco1AO3w1YsokfDLVseEjAPBgNVHRMBAf8E"
+ + "BTADAQH/MB8GA1UdIwQYMBaAFGXi9IbJ007wkU5Yomr12HhamsGmMAsGByqG"
+ + "SM44BAMFAAMvADAsAhRmigTu6QV0sTfEkVljgij/hhdVfAIUQZvMxAnIHc30"
+ + "y/u0C1T5UEG9glUwggPAMIIDfqADAgECAgEQMAsGByqGSM44BAMFADCBkDEL"
+ + "MAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlQYWxvIEFsdG8x"
+ + "HTAbBgNVBAoTFFN1biBNaWNyb3N5c3RlbXMgSW5jMSMwIQYDVQQLExpKYXZh"
+ + "IFNvZnR3YXJlIENvZGUgU2lnbmluZzEcMBoGA1UEAxMTSkNFIENvZGUgU2ln"
+ + "bmluZyBDQTAeFw0wMTA0MjUwNzAwMDBaFw0yMDA0MjUwNzAwMDBaMIGQMQsw"
+ + "CQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVBhbG8gQWx0bzEd"
+ + "MBsGA1UEChMUU3VuIE1pY3Jvc3lzdGVtcyBJbmMxIzAhBgNVBAsTGkphdmEg"
+ + "U29mdHdhcmUgQ29kZSBTaWduaW5nMRwwGgYDVQQDExNKQ0UgQ29kZSBTaWdu"
+ + "aW5nIENBMIIBtzCCASwGByqGSM44BAEwggEfAoGBAOuvNwQeylEeaV2w8o/2"
+ + "tUkfxqSZBdcpv3S3avUZ2B7kG/gKAZqY/3Cr4kpWhmxTs/zhyIGMMfDE87CL"
+ + "5nAG7PdpaNuDTHIpiSk2F1w7SgegIAIqRpdRHXDICBgLzgxum3b3BePn+9Nh"
+ + "eeFgmiSNBpWDPFEg4TDPOFeCphpyDc7TAhUAhCVF4bq5qWKreehbMLiJaxv/"
+ + "e3UCgYEAq8l0e3Tv7kK1alNNO92QBnJokQ8LpCl2LlU71a5NZVx+KjoEpmem"
+ + "0HGqpde34sFyDaTRqh6SVEwgAAmisAlBGTMAssNcrkL4sYvKfJbYEH83RFuq"
+ + "zHjI13J2N2tAmahVZvqoAx6LShECactMuCUGHKB30sms0j3pChD6dnC3+9wD"
+ + "gYQAAoGALQmYXKy4nMeZfu4gGSo0kPnXq6uu3WtylQ1m+O8nj0Sy7ShEx/6v"
+ + "sKYnbwBnRYJbB6hWVjvSKVFhXmk51y50dxLPGUr1LcjLcmHETm/6R0M/FLv6"
+ + "vBhmKMLZZot6LS/CYJJLFP5YPiF/aGK+bEhJ+aBLXoWdGRD5FUVRG3HU9wuj"
+ + "ZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1Ud"
+ + "IwQYMBaAFGXi9IbJ007wkU5Yomr12HhamsGmMB0GA1UdDgQWBBRl4vSGydNO"
+ + "8JFOWKJq9dh4WprBpjALBgcqhkjOOAQDBQADLwAwLAIUKvfPPJdd+Xi2CNdB"
+ + "tNkNRUzktJwCFEXNdWkOIfod1rMpsun3Mx0z/fxJMYHoMIHlAgEBMIGWMIGQ"
+ + "MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVBhbG8gQWx0"
+ + "bzEdMBsGA1UEChMUU3VuIE1pY3Jvc3lzdGVtcyBJbmMxIzAhBgNVBAsTGkph"
+ + "dmEgU29mdHdhcmUgQ29kZSBTaWduaW5nMRwwGgYDVQQDExNKQ0UgQ29kZSBT"
+ + "aWduaW5nIENBAgEzMAkGBSsOAwIaBQAwCwYHKoZIzjgEAQUABC8wLQIVAIGV"
+ + "khm+kbV4a/+EP45PHcq0hIViAhR4M9os6IrJnoEDS3Y3l7O6zrSosA==");
+
+ private static final byte[] rawGost = Base64.decode(
+ "MIIEBwYJKoZIhvcNAQcCoIID+DCCA/QCAQExDDAKBgYqhQMCAgkFADAfBgkq"
+ + "hkiG9w0BBwGgEgQQU29tZSBEYXRhIEhFUkUhIaCCAuYwggLiMIICkaADAgEC"
+ + "AgopoLG9AAIAArWeMAgGBiqFAwICAzBlMSAwHgYJKoZIhvcNAQkBFhFpbmZv"
+ + "QGNyeXB0b3Byby5ydTELMAkGA1UEBhMCUlUxEzARBgNVBAoTCkNSWVBUTy1Q"
+ + "Uk8xHzAdBgNVBAMTFlRlc3QgQ2VudGVyIENSWVBUTy1QUk8wHhcNMTIxMDE1"
+ + "MTEwNDIzWhcNMTQxMDA0MDcwOTQxWjAhMRIwEAYDVQQDDAl0ZXN0IGdvc3Qx"
+ + "CzAJBgNVBAYTAlJVMGMwHAYGKoUDAgITMBIGByqFAwICJAAGByqFAwICHgED"
+ + "QwAEQPz/F99AG8wyMQz5uK3vJ3MdHk7ZyFzM4Ofnq8nAmDgI5/Nuzcu791/0"
+ + "hRd+1i+fArRsiPMdQXOF0E7bEMHwWfWjggFjMIIBXzAOBgNVHQ8BAf8EBAMC"
+ + "BPAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwHQYDVR0OBBYEFO353ZD7sLCx6rVR"
+ + "2o/IsSxuE1gAMB8GA1UdIwQYMBaAFG2PXgXZX6yRF5QelZoFMDg3ehAqMFUG"
+ + "A1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuY3J5cHRvcHJvLnJ1L0NlcnRF"
+ + "bnJvbGwvVGVzdCUyMENlbnRlciUyMENSWVBUTy1QUk8oMikuY3JsMIGgBggr"
+ + "BgEFBQcBAQSBkzCBkDAzBggrBgEFBQcwAYYnaHR0cDovL3d3dy5jcnlwdG9w"
+ + "cm8ucnUvb2NzcG5jL29jc3Auc3JmMFkGCCsGAQUFBzAChk1odHRwOi8vd3d3"
+ + "LmNyeXB0b3Byby5ydS9DZXJ0RW5yb2xsL3BraS1zaXRlX1Rlc3QlMjBDZW50"
+ + "ZXIlMjBDUllQVE8tUFJPKDIpLmNydDAIBgYqhQMCAgMDQQBAR4mr69a62d3l"
+ + "yK/UZ4Yz/Yi3jqURtbnJR2gugdzkG5pYHRwC41BbDaa1ItP+1gDp4s78+EiK"
+ + "AJc17CHGZTz3MYHVMIHSAgEBMHMwZTEgMB4GCSqGSIb3DQEJARYRaW5mb0Bj"
+ + "cnlwdG9wcm8ucnUxCzAJBgNVBAYTAlJVMRMwEQYDVQQKEwpDUllQVE8tUFJP"
+ + "MR8wHQYDVQQDExZUZXN0IENlbnRlciBDUllQVE8tUFJPAgopoLG9AAIAArWe"
+ + "MAoGBiqFAwICCQUAMAoGBiqFAwICEwUABED0Gs9zP9lSz/2/e3BUSpzCI3dx"
+ + "39gfl/pFVkx4p5N/GW5o4gHIST9OhDSmdxwpMSK+39YSRD4R0Ue0faOqWEsj"
+ + "AAAAAAAAAAAAAAAAAAAAAA==");
+
+ private static final byte[] noAttrEncData = Base64.decode(
+ "MIIFjwYJKoZIhvcNAQcCoIIFgDCCBXwCAQExDTALBglghkgBZQMEAgEwgdAG"
+ + "CSqGSIb3DQEHAaCBwgSBv01JTUUtVmVyc2lvbjogMS4wCkNvbnRlbnQtVHlw"
+ + "ZTogYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtCkNvbnRlbnQtVHJhbnNmZXIt"
+ + "RW5jb2Rpbmc6IGJpbmFyeQpDb250ZW50LURpc3Bvc2l0aW9uOiBhdHRhY2ht"
+ + "ZW50OyBmaWxlbmFtZT1kb2MuYmluCgpUaGlzIGlzIGEgdmVyeSBodWdlIHNl"
+ + "Y3JldCwgbWFkZSB3aXRoIG9wZW5zc2wKCgoKoIIDNDCCAzAwggKZoAMCAQIC"
+ + "AQEwDQYJKoZIhvcNAQEFBQAwgawxCzAJBgNVBAYTAkFUMRAwDgYDVQQIEwdB"
+ + "dXN0cmlhMQ8wDQYDVQQHEwZWaWVubmExFTATBgNVBAoTDFRpYW5pIFNwaXJp"
+ + "dDEUMBIGA1UECxMLSlVuaXQgdGVzdHMxGjAYBgNVBAMTEU1hc3NpbWlsaWFu"
+ + "byBNYXNpMTEwLwYJKoZIhvcNAQkBFiJtYXNzaW1pbGlhbm8ubWFzaUB0aWFu"
+ + "aS1zcGlyaXQuY29tMCAXDTEyMDEwMjA5MDAzNVoYDzIxOTEwNjA4MDkwMDM1"
+ + "WjCBjzELMAkGA1UEBhMCQVQxEDAOBgNVBAgTB0F1c3RyaWExFTATBgNVBAoT"
+ + "DFRpYW5pIFNwaXJpdDEUMBIGA1UECxMLSlVuaXQgVGVzdHMxDjAMBgNVBAMT"
+ + "BWNlcnQxMTEwLwYJKoZIhvcNAQkBFiJtYXNzaW1pbGlhbm8ubWFzaUB0aWFu"
+ + "aS1zcGlyaXQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYHz8n"
+ + "soeWpILn+5tK8XgJc3k5n0h0MOlRXLbZZVB7yuxKMBIZwl8kqqnehfqxX+hr"
+ + "b2MXSCgKEstnVunJVPUGuNxnQ8Z0R9p1o/9gR0KTXmoJ+Epx5wdEofk4Phsi"
+ + "MxjC8FVvt3sSnzal1/m0/9KntrPWksefumGm5XD3W43e5wIDAQABo3sweTAJ"
+ + "BgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBD"
+ + "ZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQU8mTZGl0EFv6aHo3bup144d6wYW8wHwYD"
+ + "VR0jBBgwFoAUdHG2RdrchT0PFcUBiIiYcy5hAA4wDQYJKoZIhvcNAQEFBQAD"
+ + "gYEATcc52eo73zEA4wmbyPv0lRrmyAxrHvZGIHiKpM8bP38WUB39lgmS8J0S"
+ + "1ioj21bosiakGj/gXnxlk8M8O+mm4zzpYjy8gqGXiUt20+j3bm7MJYM8ePcq"
+ + "dG/kReNuLUbRgIA6b0T4o+0WCELhrd9IlTk5IBKjHIjsP/GR1h0t//kxggFb"
+ + "MIIBVwIBATCBsjCBrDELMAkGA1UEBhMCQVQxEDAOBgNVBAgTB0F1c3RyaWEx"
+ + "DzANBgNVBAcTBlZpZW5uYTEVMBMGA1UEChMMVGlhbmkgU3Bpcml0MRQwEgYD"
+ + "VQQLEwtKVW5pdCB0ZXN0czEaMBgGA1UEAxMRTWFzc2ltaWxpYW5vIE1hc2kx"
+ + "MTAvBgkqhkiG9w0BCQEWIm1hc3NpbWlsaWFuby5tYXNpQHRpYW5pLXNwaXJp"
+ + "dC5jb20CAQEwCwYJYIZIAWUDBAIBMA0GCSqGSIb3DQEBAQUABIGAEthqA7FK"
+ + "V1i+MzzS4zz4DxT4lwUYkWfHaDtZADUyTD5lnP3Pf+t/ScpBEGkEtI7hDqOO"
+ + "zE0WfkBshTx5B/uxDibc/jqjQpSYSz5cvBTgpocIalbqsErOkDYF1QP6UgaV"
+ + "ZoVGwvGYIuIrFgWqgk08NsPHVVjYseTEhUDwkI1KSxU=");
+
+ byte[] successResp = Base64.decode(
+ "MIIFnAoBAKCCBZUwggWRBgkrBgEFBQcwAQEEggWCMIIFfjCCARehgZ8wgZwx"
+ + "CzAJBgNVBAYTAklOMRcwFQYDVQQIEw5BbmRocmEgcHJhZGVzaDESMBAGA1UE"
+ + "BxMJSHlkZXJhYmFkMQwwCgYDVQQKEwNUQ1MxDDAKBgNVBAsTA0FUQzEeMBwG"
+ + "A1UEAxMVVENTLUNBIE9DU1AgUmVzcG9uZGVyMSQwIgYJKoZIhvcNAQkBFhVv"
+ + "Y3NwQHRjcy1jYS50Y3MuY28uaW4YDzIwMDMwNDAyMTIzNDU4WjBiMGAwOjAJ"
+ + "BgUrDgMCGgUABBRs07IuoCWNmcEl1oHwIak1BPnX8QQUtGyl/iL9WJ1VxjxF"
+ + "j0hAwJ/s1AcCAQKhERgPMjAwMjA4MjkwNzA5MjZaGA8yMDAzMDQwMjEyMzQ1"
+ + "OFowDQYJKoZIhvcNAQEFBQADgYEAfbN0TCRFKdhsmvOdUoiJ+qvygGBzDxD/"
+ + "VWhXYA+16AphHLIWNABR3CgHB3zWtdy2j7DJmQ/R7qKj7dUhWLSqclAiPgFt"
+ + "QQ1YvSJAYfEIdyHkxv4NP0LSogxrumANcDyC9yt/W9yHjD2ICPBIqCsZLuLk"
+ + "OHYi5DlwWe9Zm9VFwCGgggPMMIIDyDCCA8QwggKsoAMCAQICAQYwDQYJKoZI"
+ + "hvcNAQEFBQAwgZQxFDASBgNVBAMTC1RDUy1DQSBPQ1NQMSYwJAYJKoZIhvcN"
+ + "AQkBFhd0Y3MtY2FAdGNzLWNhLnRjcy5jby5pbjEMMAoGA1UEChMDVENTMQww"
+ + "CgYDVQQLEwNBVEMxEjAQBgNVBAcTCUh5ZGVyYWJhZDEXMBUGA1UECBMOQW5k"
+ + "aHJhIHByYWRlc2gxCzAJBgNVBAYTAklOMB4XDTAyMDgyOTA3MTE0M1oXDTAz"
+ + "MDgyOTA3MTE0M1owgZwxCzAJBgNVBAYTAklOMRcwFQYDVQQIEw5BbmRocmEg"
+ + "cHJhZGVzaDESMBAGA1UEBxMJSHlkZXJhYmFkMQwwCgYDVQQKEwNUQ1MxDDAK"
+ + "BgNVBAsTA0FUQzEeMBwGA1UEAxMVVENTLUNBIE9DU1AgUmVzcG9uZGVyMSQw"
+ + "IgYJKoZIhvcNAQkBFhVvY3NwQHRjcy1jYS50Y3MuY28uaW4wgZ8wDQYJKoZI"
+ + "hvcNAQEBBQADgY0AMIGJAoGBAM+XWW4caMRv46D7L6Bv8iwtKgmQu0SAybmF"
+ + "RJiz12qXzdvTLt8C75OdgmUomxp0+gW/4XlTPUqOMQWv463aZRv9Ust4f8MH"
+ + "EJh4ekP/NS9+d8vEO3P40ntQkmSMcFmtA9E1koUtQ3MSJlcs441JjbgUaVnm"
+ + "jDmmniQnZY4bU3tVAgMBAAGjgZowgZcwDAYDVR0TAQH/BAIwADALBgNVHQ8E"
+ + "BAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwkwNgYIKwYBBQUHAQEEKjAoMCYG"
+ + "CCsGAQUFBzABhhpodHRwOi8vMTcyLjE5LjQwLjExMDo3NzAwLzAtBgNVHR8E"
+ + "JjAkMCKgIKAehhxodHRwOi8vMTcyLjE5LjQwLjExMC9jcmwuY3JsMA0GCSqG"
+ + "SIb3DQEBBQUAA4IBAQB6FovM3B4VDDZ15o12gnADZsIk9fTAczLlcrmXLNN4"
+ + "PgmqgnwF0Ymj3bD5SavDOXxbA65AZJ7rBNAguLUo+xVkgxmoBH7R2sBxjTCc"
+ + "r07NEadxM3HQkt0aX5XYEl8eRoifwqYAI9h0ziZfTNes8elNfb3DoPPjqq6V"
+ + "mMg0f0iMS4W8LjNPorjRB+kIosa1deAGPhq0eJ8yr0/s2QR2/WFD5P4aXc8I"
+ + "KWleklnIImS3zqiPrq6tl2Bm8DZj7vXlTOwmraSQxUwzCKwYob1yGvNOUQTq"
+ + "pG6jxn7jgDawHU1+WjWQe4Q34/pWeGLysxTraMa+Ug9kPe+jy/qRX2xwvKBZ");
+
+ public NewSignedDataTest(String name)
+ {
+ super(name);
+ }
+
+ public static void main(String args[])
+ {
+
+ junit.textui.TestRunner.run(NewSignedDataTest.class);
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ init();
+
+ return new CMSTestSetup(new TestSuite(NewSignedDataTest.class));
+ }
+
+ private static void init()
+ throws Exception
+ {
+ if (!_initialised)
+ {
+ _initialised = true;
+
+ if (Security.getProvider(BC) == null)
+ {
+ Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider());
+ }
+
+ _origDN = "O=Bouncy Castle, C=AU";
+ _origKP = CMSTestUtil.makeKeyPair();
+ _origCert = CMSTestUtil.makeCertificate(_origKP, _origDN, _origKP, _origDN);
+
+ _signDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+ _signKP = CMSTestUtil.makeKeyPair();
+ _signCert = CMSTestUtil.makeCertificate(_signKP, _signDN, _origKP, _origDN);
+
+ _signGostKP = CMSTestUtil.makeGostKeyPair();
+ _signGostCert = CMSTestUtil.makeCertificate(_signGostKP, _signDN, _origKP, _origDN);
+
+ _signDsaKP = CMSTestUtil.makeDsaKeyPair();
+ _signDsaCert = CMSTestUtil.makeCertificate(_signDsaKP, _signDN, _origKP, _origDN);
+
+ _signEcDsaKP = CMSTestUtil.makeEcDsaKeyPair();
+ _signEcDsaCert = CMSTestUtil.makeCertificate(_signEcDsaKP, _signDN, _origKP, _origDN);
+
+ _signEcGostKP = CMSTestUtil.makeEcGostKeyPair();
+ _signEcGostCert = CMSTestUtil.makeCertificate(_signEcGostKP, _signDN, _origKP, _origDN);
+
+ _reciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+ _reciKP = CMSTestUtil.makeKeyPair();
+ _reciCert = CMSTestUtil.makeCertificate(_reciKP, _reciDN, _signKP, _signDN);
+
+ _signCrl = CMSTestUtil.makeCrl(_signKP);
+ }
+ }
+
+ private void verifyRSASignatures(CMSSignedData s, byte[] contentDigest)
+ throws Exception
+ {
+ Store certStore = s.getCertificates();
+ SignerInformationStore signers = s.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certStore.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new BcRSASignerInfoVerifierBuilder(new DefaultCMSSignatureAlgorithmNameGenerator(), new DefaultSignatureAlgorithmIdentifierFinder(), new DefaultDigestAlgorithmIdentifierFinder(), new BcDigestCalculatorProvider()).build(cert)));
+
+ if (contentDigest != null)
+ {
+ assertTrue(MessageDigest.isEqual(contentDigest, signer.getContentDigest()));
+ }
+ }
+ }
+
+ private void verifySignatures(CMSSignedData s, byte[] contentDigest)
+ throws Exception
+ {
+ Store certStore = s.getCertificates();
+ Store crlStore = s.getCRLs();
+ SignerInformationStore signers = s.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certStore.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+
+ if (contentDigest != null)
+ {
+ assertTrue(MessageDigest.isEqual(contentDigest, signer.getContentDigest()));
+ }
+ }
+
+ Collection certColl = certStore.getMatches(null);
+ Collection crlColl = crlStore.getMatches(null);
+
+ assertEquals(certColl.size(), s.getCertificates().getMatches(null).size());
+ assertEquals(crlColl.size(), s.getCRLs().getMatches(null).size());
+ }
+
+ private void verifySignatures(CMSSignedData s)
+ throws Exception
+ {
+ verifySignatures(s, null);
+ }
+
+ public void testDetachedVerification()
+ throws Exception
+ {
+ byte[] data = "Hello World!".getBytes();
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray(data);
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ DigestCalculatorProvider digProvider = new JcaDigestCalculatorProviderBuilder().setProvider(BC).build();
+ JcaSignerInfoGeneratorBuilder signerInfoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(digProvider);
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+ ContentSigner md5Signer = new JcaContentSignerBuilder("MD5withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(signerInfoGeneratorBuilder.build(sha1Signer, _origCert));
+ gen.addSignerInfoGenerator(signerInfoGeneratorBuilder.build(md5Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(msg);
+
+ MessageDigest sha1 = MessageDigest.getInstance("SHA1", BC);
+ MessageDigest md5 = MessageDigest.getInstance("MD5", BC);
+ Map hashes = new HashMap();
+ byte[] sha1Hash = sha1.digest(data);
+ byte[] md5Hash = md5.digest(data);
+
+ hashes.put(CMSAlgorithm.SHA1, sha1Hash);
+ hashes.put(CMSAlgorithm.MD5, md5Hash);
+
+ s = new CMSSignedData(hashes, s.getEncoded());
+
+ verifySignatures(s, null);
+ }
+
+ public void testSHA1AndMD5WithRSAEncapsulatedRepeated()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ DigestCalculatorProvider digCalcProv = new JcaDigestCalculatorProviderBuilder().setProvider(BC).build();
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(digCalcProv).build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate()), _origCert));
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(digCalcProv).build(new JcaContentSignerBuilder("MD5withRSA").setProvider(BC).build(_origKP.getPrivate()), _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(msg, true);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded());
+ ASN1InputStream aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ certs = s.getCertificates();
+
+ SignerInformationStore signers = s.getSignerInfos();
+
+ assertEquals(2, signers.size());
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+ SignerId sid = null;
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ sid = signer.getSID();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+
+ //
+ // check content digest
+ //
+
+ byte[] contentDigest = (byte[])gen.getGeneratedDigests().get(signer.getDigestAlgOID());
+
+ AttributeTable table = signer.getSignedAttributes();
+ Attribute hash = table.get(CMSAttributes.messageDigest);
+
+ assertTrue(MessageDigest.isEqual(contentDigest, ((ASN1OctetString)hash.getAttrValues().getObjectAt(0)).getOctets()));
+ }
+
+ c = signers.getSigners(sid);
+
+ assertEquals(2, c.size());
+
+
+ //
+ // try using existing signer
+ //
+
+ gen = new CMSSignedDataGenerator();
+
+ gen.addSigners(s.getSignerInfos());
+
+ gen.addCertificates(s.getCertificates());
+
+ s = gen.generate(msg, true);
+
+ bIn = new ByteArrayInputStream(s.getEncoded());
+ aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ certs = s.getCertificates();
+
+ signers = s.getSignerInfos();
+ c = signers.getSigners();
+ it = c.iterator();
+
+ assertEquals(2, c.size());
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+
+ checkSignerStoreReplacement(s, signers);
+ }
+
+ public void testSHA1WithRSANoAttributes()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ JcaSignerInfoGeneratorBuilder builder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ builder.setDirectSignature(true);
+
+ gen.addSignerInfoGenerator(builder.build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(msg, false);
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+
+ verifySignatures(s, md.digest("Hello world!".getBytes()));
+ }
+
+ public void testSHA1WithRSANoAttributesSimple()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ JcaSimpleSignerInfoGeneratorBuilder builder = new JcaSimpleSignerInfoGeneratorBuilder().setProvider(BC).setDirectSignature(true);
+
+ gen.addSignerInfoGenerator(builder.build("SHA1withRSA", _origKP.getPrivate(), _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(msg, false);
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+
+ verifySignatures(s, md.digest("Hello world!".getBytes()));
+ }
+
+ public void testSHA1WithRSAAndOtherRevocation()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ List otherInfo = new ArrayList();
+ OCSPResp response = new OCSPResp(successResp);
+
+ otherInfo.add(response.toASN1Structure());
+
+ gen.addOtherRevocationInfo(CMSObjectIdentifiers.id_ri_ocsp_response, new CollectionStore(otherInfo));
+
+ CMSSignedData s;
+
+ s = gen.generate(msg, false);
+
+ //
+ // check version
+ //
+ assertEquals(5, s.getVersion());
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+
+ verifySignatures(s, md.digest("Hello world!".getBytes()));
+
+ Store dataOtherInfo = s.getOtherRevocationInfo(CMSObjectIdentifiers.id_ri_ocsp_response);
+
+ assertEquals(1, dataOtherInfo.getMatches(null).size());
+
+ OCSPResp dataResponse = new OCSPResp(OCSPResponse.getInstance(dataOtherInfo.getMatches(null).iterator().next()));
+
+ assertEquals(response, dataResponse);
+ }
+
+ public void testSHA1WithRSAAndAttributeTableSimple()
+ throws Exception
+ {
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ Attribute attr = new Attribute(CMSAttributes.messageDigest,
+ new DERSet(
+ new DEROctetString(
+ md.digest("Hello world!".getBytes()))));
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(attr);
+
+ JcaSimpleSignerInfoGeneratorBuilder builder = new JcaSimpleSignerInfoGeneratorBuilder().setProvider(BC).setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)));
+
+ gen.addSignerInfoGenerator(builder.build("SHA1withRSA", _origKP.getPrivate(), _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(new CMSAbsentContent(), false);
+
+ //
+ // the signature is detached, so need to add msg before passing on
+ //
+ s = new CMSSignedData(msg, s.getEncoded());
+ //
+ // compute expected content digest
+ //
+
+ verifySignatures(s, md.digest("Hello world!".getBytes()));
+ verifyRSASignatures(s, md.digest("Hello world!".getBytes()));
+ }
+
+ public void testSHA1WithRSAAndAttributeTable()
+ throws Exception
+ {
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ Attribute attr = new Attribute(CMSAttributes.messageDigest,
+ new DERSet(
+ new DEROctetString(
+ md.digest("Hello world!".getBytes()))));
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(attr);
+
+ JcaSignerInfoGeneratorBuilder builder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ builder.setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)));
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(builder.build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(new CMSAbsentContent(), false);
+
+ //
+ // the signature is detached, so need to add msg before passing on
+ //
+ s = new CMSSignedData(msg, s.getEncoded());
+ //
+ // compute expected content digest
+ //
+
+ verifySignatures(s, md.digest("Hello world!".getBytes()));
+ verifyRSASignatures(s, md.digest("Hello world!".getBytes()));
+ }
+
+ public void testLwSHA1WithRSAAndAttributeTable()
+ throws Exception
+ {
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ Attribute attr = new Attribute(CMSAttributes.messageDigest,
+ new DERSet(
+ new DEROctetString(
+ md.digest("Hello world!".getBytes()))));
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(attr);
+
+ AsymmetricKeyParameter privKey = PrivateKeyFactory.createKey(_origKP.getPrivate().getEncoded());
+
+ AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA");
+ AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
+
+ BcContentSignerBuilder contentSignerBuilder = new BcRSAContentSignerBuilder(sigAlgId, digAlgId);
+
+ gen.addSignerInfoGenerator(
+ new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider())
+ .setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)))
+ .build(contentSignerBuilder.build(privKey), new JcaX509CertificateHolder(_origCert)));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(new CMSAbsentContent(), false);
+
+ //
+ // the signature is detached, so need to add msg before passing on
+ //
+ s = new CMSSignedData(msg, s.getEncoded());
+ //
+ // compute expected content digest
+ //
+
+ verifySignatures(s, md.digest("Hello world!".getBytes()));
+ verifyRSASignatures(s, md.digest("Hello world!".getBytes()));
+ }
+
+ public void testSHA1WithRSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signKP, _signCert, "SHA1withRSA");
+ }
+
+ public void testSHA1WithRSAEncapsulatedSubjectKeyID()
+ throws Exception
+ {
+ subjectKeyIDTest(_signKP, _signCert, "SHA1withRSA");
+ }
+
+ public void testSHA1WithRSAPSS()
+ throws Exception
+ {
+ rsaPSSTest("SHA1withRSAandMGF1");
+ }
+
+ public void testSHA224WithRSAPSS()
+ throws Exception
+ {
+ rsaPSSTest("SHA224withRSAandMGF1");
+ }
+
+ public void testSHA256WithRSAPSS()
+ throws Exception
+ {
+ rsaPSSTest("SHA256withRSAandMGF1");
+ }
+
+ public void testSHA384WithRSAPSS()
+ throws Exception
+ {
+ rsaPSSTest("SHA384withRSAandMGF1");
+ }
+
+ public void testSHA224WithRSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signKP, _signCert, "SHA224withRSA");
+ }
+
+ public void testSHA256WithRSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signKP, _signCert, "SHA256withRSA");
+ }
+
+ public void testRIPEMD128WithRSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signKP, _signCert, "RIPEMD128withRSA");
+ }
+
+ public void testRIPEMD160WithRSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signKP, _signCert, "RIPEMD160withRSA");
+ }
+
+ public void testRIPEMD256WithRSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signKP, _signCert, "RIPEMD256withRSA");
+ }
+
+ public void testECDSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signEcDsaKP, _signEcDsaCert, "SHA1withECDSA");
+ }
+
+ public void testECDSAEncapsulatedSubjectKeyID()
+ throws Exception
+ {
+ subjectKeyIDTest(_signEcDsaKP, _signEcDsaCert, "SHA1withECDSA");
+ }
+
+ public void testECDSASHA224Encapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signEcDsaKP, _signEcDsaCert, "SHA224withECDSA");
+ }
+
+ public void testECDSASHA256Encapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signEcDsaKP, _signEcDsaCert, "SHA256withECDSA");
+ }
+
+ public void testECDSASHA384Encapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signEcDsaKP, _signEcDsaCert, "SHA384withECDSA");
+ }
+
+ public void testECDSASHA512Encapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signEcDsaKP, _signEcDsaCert, "SHA512withECDSA");
+ }
+
+ public void testECDSASHA512EncapsulatedWithKeyFactoryAsEC()
+ throws Exception
+ {
+ X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(_signEcDsaKP.getPublic().getEncoded());
+ PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(_signEcDsaKP.getPrivate().getEncoded());
+ KeyFactory keyFact = KeyFactory.getInstance("EC", BC);
+ KeyPair kp = new KeyPair(keyFact.generatePublic(pubSpec), keyFact.generatePrivate(privSpec));
+
+ encapsulatedTest(kp, _signEcDsaCert, "SHA512withECDSA");
+ }
+
+ public void testDSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signDsaKP, _signDsaCert, "SHA1withDSA");
+ }
+
+ public void testDSAEncapsulatedSubjectKeyID()
+ throws Exception
+ {
+ subjectKeyIDTest(_signDsaKP, _signDsaCert, "SHA1withDSA");
+ }
+
+ public void testGOST3411WithGOST3410Encapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signGostKP, _signGostCert, "GOST3411withGOST3410");
+ }
+
+ public void testGOST3411WithECGOST3410Encapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signEcGostKP, _signEcGostCert, "GOST3411withECGOST3410");
+ }
+
+ public void testGostNoAttributesEncapsulated()
+ throws Exception
+ {
+ CMSSignedData data = new CMSSignedData(rawGost);
+
+ Store certStore = data.getCertificates();
+ SignerInformationStore signers = data.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certStore.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("SC").build(cert)));
+ }
+ }
+
+ public void testSHA1WithRSACounterSignature()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ List crlList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(_signCert);
+ certList.add(_origCert);
+
+ crlList.add(_signCrl);
+
+ Store certStore = new JcaCertStore(certList);
+ Store crlStore = new JcaCRLStore(crlList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_signKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _signCert));
+
+ gen.addCertificates(certStore);
+ gen.addCRLs(crlStore);
+
+ CMSSignedData s = gen.generate(msg, true);
+ SignerInformation origSigner = (SignerInformation)s.getSignerInfos().getSigners().toArray()[0];
+ SignerInformationStore counterSigners1 = gen.generateCounterSigners(origSigner);
+ SignerInformationStore counterSigners2 = gen.generateCounterSigners(origSigner);
+
+ SignerInformation signer1 = SignerInformation.addCounterSigners(origSigner, counterSigners1);
+ SignerInformation signer2 = SignerInformation.addCounterSigners(signer1, counterSigners2);
+
+ SignerInformationStore cs = signer2.getCounterSignatures();
+ Collection csSigners = cs.getSigners();
+ assertEquals(2, csSigners.size());
+
+ Iterator it = csSigners.iterator();
+ while (it.hasNext())
+ {
+ SignerInformation cSigner = (SignerInformation)it.next();
+ Collection certCollection = certStore.getMatches(cSigner.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertTrue(cSigner.isCounterSignature());
+ assertNull(cSigner.getSignedAttributes().get(PKCSObjectIdentifiers.pkcs_9_at_contentType));
+ assertEquals(true, cSigner.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+ }
+
+ public void testSHA1WithRSACounterSignatureAndVerifierProvider()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ List crlList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(_signCert);
+ certList.add(_origCert);
+
+ crlList.add(_signCrl);
+
+ Store certStore = new JcaCertStore(certList);
+ Store crlStore = new JcaCRLStore(crlList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_signKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _signCert));
+
+ gen.addCertificates(certStore);
+ gen.addCRLs(crlStore);
+
+ CMSSignedData s = gen.generate(msg, true);
+
+ SignerInformationVerifierProvider vProv = new SignerInformationVerifierProvider()
+ {
+ public SignerInformationVerifier get(SignerId signerId)
+ throws OperatorCreationException
+ {
+ return new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(_signCert);
+ }
+ };
+
+ assertTrue(s.verifySignatures(vProv));
+
+ SignerInformation origSigner = (SignerInformation)s.getSignerInfos().getSigners().toArray()[0];
+
+ gen = new CMSSignedDataGenerator();
+
+ sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ SignerInformationStore counterSigners = gen.generateCounterSigners(origSigner);
+
+ SignerInformation signer1 = SignerInformation.addCounterSigners(origSigner, counterSigners);
+
+ List signers = new ArrayList();
+
+ signers.add(signer1);
+
+ s = CMSSignedData.replaceSigners(s, new SignerInformationStore(signers));
+
+ assertTrue(s.verifySignatures(vProv, true));
+
+ // provider can't handle counter sig
+ assertFalse(s.verifySignatures(vProv, false));
+
+ vProv = new SignerInformationVerifierProvider()
+ {
+ public SignerInformationVerifier get(SignerId signerId)
+ throws OperatorCreationException
+ {
+ if (_signCert.getSerialNumber().equals(signerId.getSerialNumber()))
+ {
+ return new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(_signCert);
+ }
+ else
+ {
+ return new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(_origCert);
+ }
+ }
+ };
+
+ // verify sig and counter sig.
+ assertFalse(s.verifySignatures(vProv, false));
+ }
+
+ private void rsaPSSTest(String signatureAlgorithmName)
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithmName).setProvider(BC).build(_origKP.getPrivate());
+
+ JcaSignerInfoGeneratorBuilder siBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ siBuilder.setDirectSignature(true);
+
+ gen.addSignerInfoGenerator(siBuilder.build(contentSigner, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(msg, false);
+
+ //
+ // compute expected content digest
+ //
+ String digestName = signatureAlgorithmName.substring(0, signatureAlgorithmName.indexOf('w'));
+ MessageDigest md = MessageDigest.getInstance(digestName, BC);
+
+ verifySignatures(s, md.digest("Hello world!".getBytes()));
+ }
+
+ private void subjectKeyIDTest(
+ KeyPair signaturePair,
+ X509Certificate signatureCert,
+ String signatureAlgorithm)
+ throws Exception
+ {
+ List certList = new ArrayList();
+ List crlList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(signatureCert);
+ certList.add(_origCert);
+
+ crlList.add(_signCrl);
+
+ Store certStore = new JcaCertStore(certList);
+ Store crlStore = new JcaCRLStore(crlList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).setProvider(BC).build(signaturePair.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(contentSigner, CMSTestUtil.createSubjectKeyId(signatureCert.getPublicKey()).getKeyIdentifier()));
+
+ gen.addCertificates(certStore);
+ gen.addCRLs(crlStore);
+
+ CMSSignedData s = gen.generate(msg, true);
+
+ assertEquals(3, s.getVersion());
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded());
+ ASN1InputStream aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ certStore = s.getCertificates();
+
+ SignerInformationStore signers = s.getSignerInfos();
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certStore.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+
+ //
+ // check for CRLs
+ //
+ Collection crls = crlStore.getMatches(null);
+
+ assertEquals(1, crls.size());
+
+ assertTrue(crls.contains(new JcaX509CRLHolder(_signCrl)));
+
+ //
+ // try using existing signer
+ //
+
+ gen = new CMSSignedDataGenerator();
+
+ gen.addSigners(s.getSignerInfos());
+
+ gen.addCertificates(s.getCertificates());
+
+ s = gen.generate(msg, true);
+
+ bIn = new ByteArrayInputStream(s.getEncoded());
+ aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ certStore = s.getCertificates();
+
+ signers = s.getSignerInfos();
+ c = signers.getSigners();
+ it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certStore.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+
+ checkSignerStoreReplacement(s, signers);
+ }
+
+ private void encapsulatedTest(
+ KeyPair signaturePair,
+ X509Certificate signatureCert,
+ String signatureAlgorithm)
+ throws Exception
+ {
+ List certList = new ArrayList();
+ List crlList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(signatureCert);
+ certList.add(_origCert);
+
+ crlList.add(_signCrl);
+
+ Store certs = new JcaCertStore(certList);
+ Store crlStore = new JcaCRLStore(crlList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).setProvider(BC).build(signaturePair.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(contentSigner, signatureCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(msg, true);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded());
+ ASN1InputStream aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ certs = s.getCertificates();
+
+ SignerInformationStore signers = s.getSignerInfos();
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+
+ //
+ // check signer information lookup
+ //
+
+ SignerId sid = new JcaSignerId(signatureCert);
+
+ Collection collection = signers.getSigners(sid);
+
+ assertEquals(1, collection.size());
+ assertTrue(collection.iterator().next() instanceof SignerInformation);
+
+ //
+ // check for CRLs
+ //
+ Collection crls = crlStore.getMatches(null);
+
+ assertEquals(1, crls.size());
+
+ assertTrue(crls.contains(new JcaX509CRLHolder(_signCrl)));
+
+ //
+ // try using existing signer
+ //
+
+ gen = new CMSSignedDataGenerator();
+
+ gen.addSigners(s.getSignerInfos());
+
+ gen.addCertificates(s.getCertificates());
+
+ s = gen.generate(msg, true);
+
+ bIn = new ByteArrayInputStream(s.getEncoded());
+ aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ certs = s.getCertificates();
+
+ signers = s.getSignerInfos();
+ c = signers.getSigners();
+ it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+
+ checkSignerStoreReplacement(s, signers);
+ }
+
+ //
+ // signerInformation store replacement test.
+ //
+ private void checkSignerStoreReplacement(
+ CMSSignedData orig,
+ SignerInformationStore signers)
+ throws Exception
+ {
+ CMSSignedData s = CMSSignedData.replaceSigners(orig, signers);
+
+ Store certs = s.getCertificates();
+
+ signers = s.getSignerInfos();
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+ }
+
+ public void testUnsortedAttributes()
+ throws Exception
+ {
+ CMSSignedData s = new CMSSignedData(new CMSProcessableByteArray(disorderedMessage), disorderedSet);
+
+ Store certs = s.getCertificates();
+
+ SignerInformationStore signers = s.getSignerInfos();
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getMatches(signer.getSID());
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+ }
+
+ public void testNullContentWithSigner()
+ throws Exception
+ {
+ List certList = new ArrayList();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData s = gen.generate(new CMSAbsentContent(), false);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded());
+ ASN1InputStream aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ verifySignatures(s);
+ }
+
+ public void testWithAttributeCertificate()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+
+ certList.add(_signDsaCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ JcaSignerInfoGeneratorBuilder builder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(builder.build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ X509AttributeCertificateHolder attrCert = CMSTestUtil.getAttributeCertificate();
+ List attrList = new ArrayList();
+
+ attrList.add(new X509AttributeCertificateHolder(attrCert.getEncoded()));
+
+ Store store = new CollectionStore(attrList);
+
+ gen.addAttributeCertificates(store);
+
+ CMSSignedData sd = gen.generate(msg);
+
+ assertEquals(4, sd.getVersion());
+
+ store = sd.getAttributeCertificates();
+
+ Collection coll = store.getMatches(null);
+
+ assertEquals(1, coll.size());
+
+ assertTrue(coll.contains(new X509AttributeCertificateHolder(attrCert.getEncoded())));
+
+ //
+ // create new certstore
+ //
+ certList = new ArrayList();
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ certs = new JcaCertStore(certList);
+
+
+ //
+ // replace certs
+ //
+ sd = CMSSignedData.replaceCertificatesAndCRLs(sd, certs, null, null);
+
+ verifySignatures(sd);
+ }
+
+ public void testCertStoreReplacement()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+
+ certList.add(_signDsaCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData sd = gen.generate(msg);
+
+ //
+ // create new certstore
+ //
+ certList = new ArrayList();
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ certs = new JcaCertStore(certList);
+
+ //
+ // replace certs
+ //
+ sd = CMSSignedData.replaceCertificatesAndCRLs(sd, certs, null, null);
+
+ verifySignatures(sd);
+ }
+
+ public void testEncapsulatedCertStoreReplacement()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+
+ certList.add(_signDsaCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData sd = gen.generate(msg, true);
+
+ //
+ // create new certstore
+ //
+ certList = new ArrayList();
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ certs = new JcaCertStore(certList);
+
+
+ //
+ // replace certs
+ //
+ sd = CMSSignedData.replaceCertificatesAndCRLs(sd, certs, null, null);
+
+ verifySignatures(sd);
+ }
+
+ public void testCertOrdering1()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+ certList.add(_signDsaCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData sd = gen.generate(msg, true);
+
+ certs = sd.getCertificates();
+ Iterator it = certs.getMatches(null).iterator();
+
+ assertEquals(new JcaX509CertificateHolder(_origCert), it.next());
+ assertEquals(new JcaX509CertificateHolder(_signCert), it.next());
+ assertEquals(new JcaX509CertificateHolder(_signDsaCert), it.next());
+ }
+
+ public void testCertOrdering2()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(_signCert);
+ certList.add(_signDsaCert);
+ certList.add(_origCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData sd = gen.generate(msg, true);
+
+ certs = sd.getCertificates();
+ Iterator it = certs.getMatches(null).iterator();
+
+ assertEquals(new JcaX509CertificateHolder(_signCert), it.next());
+ assertEquals(new JcaX509CertificateHolder(_signDsaCert), it.next());
+ assertEquals(new JcaX509CertificateHolder(_origCert), it.next());
+ }
+
+ public void testSignerStoreReplacement()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData original = gen.generate(msg, true);
+
+ //
+ // create new Signer
+ //
+ gen = new CMSSignedDataGenerator();
+
+ ContentSigner sha224Signer = new JcaContentSignerBuilder("SHA224withRSA").setProvider(BC).build(_origKP.getPrivate());
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha224Signer, _origCert));
+
+ gen.addCertificates(certs);
+
+ CMSSignedData newSD = gen.generate(msg, true);
+
+ //
+ // replace signer
+ //
+ CMSSignedData sd = CMSSignedData.replaceSigners(original, newSD.getSignerInfos());
+
+ SignerInformation signer = (SignerInformation)sd.getSignerInfos().getSigners().iterator().next();
+
+ assertEquals(CMSAlgorithm.SHA224.getId(), signer.getDigestAlgOID());
+
+ // we use a parser here as it requires the digests to be correct in the digest set, if it
+ // isn't we'll get a NullPointerException
+ CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), sd.getEncoded());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+ }
+
+ public void testEncapsulatedSamples()
+ throws Exception
+ {
+ testSample("PSSSignDataSHA1Enc.sig");
+ testSample("PSSSignDataSHA256Enc.sig");
+ testSample("PSSSignDataSHA512Enc.sig");
+ }
+
+ public void testSamples()
+ throws Exception
+ {
+ testSample("PSSSignData.data", "PSSSignDataSHA1.sig");
+ testSample("PSSSignData.data", "PSSSignDataSHA256.sig");
+ testSample("PSSSignData.data", "PSSSignDataSHA512.sig");
+ }
+
+ public void testNoAttrEncapsulatedSample()
+ throws Exception
+ {
+ CMSSignedData s = new CMSSignedData(noAttrEncData);
+
+ Store certStore = s.getCertificates();
+
+ assertNotNull(certStore);
+
+ SignerInformationStore signers = s.getSignerInfos();
+
+ assertNotNull(signers);
+
+ Collection c = signers.getSigners();
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certStore.getMatches(signer.getSID());
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ if (!signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)))
+ {
+ fail("Verification FAILED! ");
+ }
+ }
+ }
+
+ public void testCounterSig()
+ throws Exception
+ {
+ CMSSignedData sig = new CMSSignedData(getInput("counterSig.p7m"));
+
+ SignerInformationStore ss = sig.getSignerInfos();
+ Collection signers = ss.getSigners();
+
+ SignerInformationStore cs = ((SignerInformation)signers.iterator().next()).getCounterSignatures();
+ Collection csSigners = cs.getSigners();
+ assertEquals(1, csSigners.size());
+
+ Iterator it = csSigners.iterator();
+ while (it.hasNext())
+ {
+ SignerInformation cSigner = (SignerInformation)it.next();
+ Collection certCollection = sig.getCertificates().getMatches(cSigner.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertTrue(cSigner.isCounterSignature());
+ assertNull(cSigner.getSignedAttributes().get(PKCSObjectIdentifiers.pkcs_9_at_contentType));
+ assertEquals(true, cSigner.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+
+ verifySignatures(sig);
+ }
+
+ public void testCertificateManagement()
+ throws Exception
+ {
+ CMSSignedDataGenerator sGen = new CMSSignedDataGenerator();
+
+ List certList = new ArrayList();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ sGen.addCertificates(certs);
+
+ CMSSignedData sData = sGen.generate(new CMSAbsentContent(), true);
+
+ CMSSignedData rsData = new CMSSignedData(sData.getEncoded());
+
+ assertEquals(2, rsData.getCertificates().getMatches(null).size());
+ }
+
+ private void testSample(String sigName)
+ throws Exception
+ {
+ CMSSignedData sig = new CMSSignedData(getInput(sigName));
+
+ verifySignatures(sig);
+ }
+
+ private void testSample(String messageName, String sigName)
+ throws Exception
+ {
+ CMSSignedData sig = new CMSSignedData(new CMSProcessableByteArray(getInput(messageName)), getInput(sigName));
+
+ verifySignatures(sig);
+ }
+
+ private byte[] getInput(String name)
+ throws IOException
+ {
+ return Streams.readAll(getClass().getResourceAsStream(name));
+ }
+
+ public void testForMultipleCounterSignatures()
+ throws Exception
+ {
+ CMSSignedData sd = new CMSSignedData(xtraCounterSig);
+
+ for (Iterator sI = sd.getSignerInfos().getSigners().iterator(); sI.hasNext();)
+ {
+ SignerInformation sigI = (SignerInformation)sI.next();
+
+ SignerInformationStore counter = sigI.getCounterSignatures();
+ List sigs = new ArrayList(counter.getSigners());
+
+ assertEquals(2, sigs.size());
+ }
+ }
+
+ private void verifySignatures(CMSSignedDataParser sp)
+ throws Exception
+ {
+ Store certs = sp.getCertificates();
+ SignerInformationStore signers = sp.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
+ }
+ }
+
+ private class TestCMSSignatureAlgorithmNameGenerator
+ extends DefaultCMSSignatureAlgorithmNameGenerator
+ {
+ void setDigestAlgorithmMapping(ASN1ObjectIdentifier oid, String algName)
+ {
+ super.setSigningDigestAlgorithmMapping(oid, algName);
+ }
+
+ void setEncryptionAlgorithmMapping(ASN1ObjectIdentifier oid, String algName)
+ {
+ super.setSigningEncryptionAlgorithmMapping(oid, algName);
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NullProviderTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NullProviderTest.java
new file mode 100644
index 000000000..640f3f591
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/NullProviderTest.java
@@ -0,0 +1,281 @@
+package org.spongycastle.cms.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cms.CMSEnvelopedData;
+import org.spongycastle.cms.CMSEnvelopedDataGenerator;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.CMSSignedData;
+import org.spongycastle.cms.CMSSignedDataGenerator;
+import org.spongycastle.cms.CMSSignedDataParser;
+import org.spongycastle.cms.CMSSignedDataStreamGenerator;
+import org.spongycastle.cms.CMSTypedData;
+import org.spongycastle.cms.CMSTypedStream;
+import org.spongycastle.cms.RecipientInformation;
+import org.spongycastle.cms.RecipientInformationStore;
+import org.spongycastle.cms.SignerInformation;
+import org.spongycastle.cms.SignerInformationStore;
+import org.spongycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
+import org.spongycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
+import org.spongycastle.cms.jcajce.JcaX509CertSelectorConverter;
+import org.spongycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
+import org.spongycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
+import org.spongycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.spongycastle.util.CollectionStore;
+import org.spongycastle.util.Store;
+import org.spongycastle.x509.X509V3CertificateGenerator;
+
+public class NullProviderTest
+ extends TestCase
+{
+ static KeyPair keyPair;
+ static X509Certificate keyCert;
+ private static final String TEST_MESSAGE = "Hello World!";
+
+ private JcaX509CertSelectorConverter selectorConverter = new JcaX509CertSelectorConverter();
+
+ static
+ {
+ try
+ {
+ keyPair = generateKeyPair();
+ String origDN = "O=Bouncy Castle, C=AU";
+ keyCert = makeCertificate(keyPair, origDN, keyPair, origDN);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void testSHA1WithRSAEncapsulated()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray(TEST_MESSAGE.getBytes());
+
+ certList.add(new X509CertificateHolder(keyCert.getEncoded()));
+
+ DigestCalculatorProvider digCalcProv = new JcaDigestCalculatorProviderBuilder().build();
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(digCalcProv).build(new JcaContentSignerBuilder("SHA1withRSA").build(keyPair.getPrivate()), keyCert));
+
+ gen.addCertificates(new CollectionStore(certList));
+
+ CMSSignedData s = gen.generate(msg, true);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded());
+ ASN1InputStream aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ Store certsAndCrls = s.getCertificates();
+
+ SignerInformationStore signers = s.getSignerInfos();
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certsAndCrls.getMatches(signer.getSID());
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().build(cert)));
+ }
+ }
+
+ public void testSHA1WithRSAStream()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(new X509CertificateHolder(keyCert.getEncoded()));
+
+ DigestCalculatorProvider digCalcProv = new JcaDigestCalculatorProviderBuilder().build();
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(digCalcProv).build(new JcaContentSignerBuilder("SHA1withRSA").build(keyPair.getPrivate()), keyCert));
+
+ gen.addCertificates(new CollectionStore(certList));
+
+ OutputStream sigOut = gen.open(bOut);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(digCalcProv,
+ new CMSTypedStream(new ByteArrayInputStream(TEST_MESSAGE.getBytes())), bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1");
+
+ byte[] contentDigest = md.digest(TEST_MESSAGE.getBytes());
+ Store certStore = sp.getCertificates();
+ SignerInformationStore signers = sp.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certStore.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().build(cert)));
+
+ if (contentDigest != null)
+ {
+ assertTrue(MessageDigest.isEqual(contentDigest, signer.getContentDigest()));
+ }
+ }
+ }
+
+ public void testKeyTransDES()
+ throws Exception
+ {
+ testKeyTrans(CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+ }
+
+ public void testKeyTransAES128()
+ throws Exception
+ {
+ testKeyTrans(CMSEnvelopedDataGenerator.AES128_CBC);
+ }
+
+ public void testKeyTransAES192()
+ throws Exception
+ {
+ testKeyTrans(CMSEnvelopedDataGenerator.AES192_CBC);
+ }
+
+ public void testKeyTransAES256()
+ throws Exception
+ {
+ testKeyTrans(CMSEnvelopedDataGenerator.AES256_CBC);
+ }
+
+ private void testKeyTrans(String algorithm)
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(keyCert));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier(algorithm)).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), algorithm);
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(keyPair.getPrivate()));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ }
+
+ private static KeyPair generateKeyPair()
+ throws NoSuchProviderException, NoSuchAlgorithmException
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "SunRsaSign");
+
+ kpg.initialize(512, new SecureRandom());
+
+ return kpg.generateKeyPair();
+ }
+
+ private static X509Certificate makeCertificate(KeyPair subKP, String _subDN, KeyPair issKP, String _issDN)
+ throws GeneralSecurityException, IOException
+ {
+
+ PublicKey subPub = subKP.getPublic();
+ PrivateKey issPriv = issKP.getPrivate();
+ PublicKey issPub = issKP.getPublic();
+
+ X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();
+
+ v3CertGen.reset();
+ v3CertGen.setSerialNumber(BigInteger.valueOf(1));
+ v3CertGen.setIssuerDN(new X509Name(_issDN));
+ v3CertGen.setNotBefore(new Date(System.currentTimeMillis()));
+ v3CertGen.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)));
+ v3CertGen.setSubjectDN(new X509Name(_subDN));
+ v3CertGen.setPublicKey(subPub);
+
+ v3CertGen.setSignatureAlgorithm("SHA1WithRSA");
+
+ X509Certificate _cert = v3CertGen.generate(issPriv, "SunRsaSign");
+
+ _cert.checkValidity(new Date());
+ _cert.verify(issPub);
+
+ return _cert;
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ return new TestSuite(NullProviderTest.class);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/Rfc4134Test.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/Rfc4134Test.java
new file mode 100644
index 000000000..ab3210278
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/Rfc4134Test.java
@@ -0,0 +1,445 @@
+package org.spongycastle.cms.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.KeyFactory;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERUTF8String;
+import org.spongycastle.asn1.cms.Attribute;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSAttributes;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.spongycastle.cms.CMSEnvelopedData;
+import org.spongycastle.cms.CMSEnvelopedDataGenerator;
+import org.spongycastle.cms.CMSEnvelopedDataParser;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.CMSSignedData;
+import org.spongycastle.cms.CMSSignedDataParser;
+import org.spongycastle.cms.CMSTypedStream;
+import org.spongycastle.cms.RecipientInformation;
+import org.spongycastle.cms.RecipientInformationStore;
+import org.spongycastle.cms.SignerInformation;
+import org.spongycastle.cms.SignerInformationStore;
+import org.spongycastle.cms.jcajce.JcaSignerInfoVerifierBuilder;
+import org.spongycastle.cms.jcajce.JcaX509CertSelectorConverter;
+import org.spongycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.spongycastle.util.Store;
+import org.spongycastle.util.encoders.Hex;
+import org.spongycastle.util.io.Streams;
+
+public class Rfc4134Test
+ extends TestCase
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+ private static final String TEST_DATA_HOME = "bc.test.data.home";
+
+ private static byte[] exContent = getRfc4134Data("ExContent.bin");
+ private static byte[] sha1 = Hex.decode("406aec085279ba6e16022d9e0629c0229687dd48");
+
+ private static final JcaX509CertSelectorConverter selectorConverter = new JcaX509CertSelectorConverter();
+ private static final DigestCalculatorProvider digCalcProv;
+
+ static
+ {
+ try
+ {
+ digCalcProv = new JcaDigestCalculatorProviderBuilder().build();
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new IllegalStateException("can't create default provider!!!");
+ }
+ }
+
+ public Rfc4134Test(String name)
+ {
+ super(name);
+ }
+
+ public static void main(String args[])
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ junit.textui.TestRunner.run(Rfc4134Test.class);
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ return new CMSTestSetup(new TestSuite(Rfc4134Test.class));
+ }
+
+ public void test4_1()
+ throws Exception
+ {
+ byte[] data = getRfc4134Data("4.1.bin");
+ CMSSignedData signedData = new CMSSignedData(data);
+
+ verifySignatures(signedData);
+
+ CMSSignedDataParser parser = new CMSSignedDataParser(digCalcProv, data);
+
+ verifySignatures(parser);
+ }
+
+ public void test4_2()
+ throws Exception
+ {
+ byte[] data = getRfc4134Data("4.2.bin");
+ CMSSignedData signedData = new CMSSignedData(data);
+
+ verifySignatures(signedData);
+
+ CMSSignedDataParser parser = new CMSSignedDataParser(digCalcProv, data);
+
+ verifySignatures(parser);
+ }
+
+ public void testRfc4_3()
+ throws Exception
+ {
+ byte[] data = getRfc4134Data("4.3.bin");
+ CMSSignedData signedData = new CMSSignedData(new CMSProcessableByteArray(exContent), data);
+
+ verifySignatures(signedData, sha1);
+
+ CMSSignedDataParser parser = new CMSSignedDataParser(digCalcProv,
+ new CMSTypedStream(new ByteArrayInputStream(exContent)),
+ data);
+
+ verifySignatures(parser);
+ }
+
+ public void test4_4()
+ throws Exception
+ {
+ byte[] data = getRfc4134Data("4.4.bin");
+ byte[] counterSigCert = getRfc4134Data("AliceRSASignByCarl.cer");
+ CMSSignedData signedData = new CMSSignedData(data);
+
+ verifySignatures(signedData, sha1);
+
+ verifySignerInfo4_4(getFirstSignerInfo(signedData.getSignerInfos()), counterSigCert);
+
+ CMSSignedDataParser parser = new CMSSignedDataParser(digCalcProv, data);
+
+ verifySignatures(parser);
+
+ verifySignerInfo4_4(getFirstSignerInfo(parser.getSignerInfos()), counterSigCert);
+ }
+
+ public void test4_5()
+ throws Exception
+ {
+ byte[] data = getRfc4134Data("4.5.bin");
+ CMSSignedData signedData = new CMSSignedData(data);
+
+ verifySignatures(signedData);
+
+ CMSSignedDataParser parser = new CMSSignedDataParser(digCalcProv, data);
+
+ verifySignatures(parser);
+ }
+
+ public void test4_6()
+ throws Exception
+ {
+ byte[] data = getRfc4134Data("4.6.bin");
+ CMSSignedData signedData = new CMSSignedData(data);
+
+ verifySignatures(signedData);
+
+ CMSSignedDataParser parser = new CMSSignedDataParser(digCalcProv, data);
+
+ verifySignatures(parser);
+ }
+
+ public void test4_7()
+ throws Exception
+ {
+ byte[] data = getRfc4134Data("4.7.bin");
+ CMSSignedData signedData = new CMSSignedData(data);
+
+ verifySignatures(signedData);
+
+ CMSSignedDataParser parser = new CMSSignedDataParser(digCalcProv, data);
+
+ verifySignatures(parser);
+ }
+
+ public void test5_1()
+ throws Exception
+ {
+ byte[] data = getRfc4134Data("5.1.bin");
+ CMSEnvelopedData envelopedData = new CMSEnvelopedData(data);
+
+ verifyEnvelopedData(envelopedData, CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ CMSEnvelopedDataParser envelopedParser = new CMSEnvelopedDataParser(data);
+
+ verifyEnvelopedData(envelopedParser, CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+ }
+
+ public void test5_2()
+ throws Exception
+ {
+ byte[] data = getRfc4134Data("5.2.bin");
+ CMSEnvelopedData envelopedData = new CMSEnvelopedData(data);
+
+ verifyEnvelopedData(envelopedData, CMSEnvelopedDataGenerator.RC2_CBC);
+
+ CMSEnvelopedDataParser envelopedParser = new CMSEnvelopedDataParser(data);
+
+ verifyEnvelopedData(envelopedParser, CMSEnvelopedDataGenerator.RC2_CBC);
+ }
+
+ private void verifyEnvelopedData(CMSEnvelopedData envelopedData, String symAlgorithmOID)
+ throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, CMSException
+ {
+ byte[] privKeyData = getRfc4134Data("BobPrivRSAEncrypt.pri");
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKeyData);
+ KeyFactory keyFact = KeyFactory.getInstance("RSA", BC);
+ PrivateKey privKey = keyFact.generatePrivate(keySpec);
+
+ RecipientInformationStore recipients = envelopedData.getRecipientInfos();
+
+ assertEquals(envelopedData.getEncryptionAlgOID(), symAlgorithmOID);
+
+ Collection c = recipients.getRecipients();
+ assertTrue(c.size() >= 1 && c.size() <= 2);
+
+ Iterator it = c.iterator();
+ verifyRecipient((RecipientInformation)it.next(), privKey);
+
+ if (c.size() == 2)
+ {
+ RecipientInformation recInfo = (RecipientInformation)it.next();
+
+ assertEquals(PKCSObjectIdentifiers.id_alg_CMSRC2wrap.getId(), recInfo.getKeyEncryptionAlgOID());
+ }
+ }
+
+ private void verifyEnvelopedData(CMSEnvelopedDataParser envelopedParser, String symAlgorithmOID)
+ throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, CMSException
+ {
+ byte[] privKeyData = getRfc4134Data("BobPrivRSAEncrypt.pri");
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKeyData);
+ KeyFactory keyFact = KeyFactory.getInstance("RSA", BC);
+ PrivateKey privKey = keyFact.generatePrivate(keySpec);
+
+ RecipientInformationStore recipients = envelopedParser.getRecipientInfos();
+
+ assertEquals(envelopedParser.getEncryptionAlgOID(), symAlgorithmOID);
+
+ Collection c = recipients.getRecipients();
+ assertTrue(c.size() >= 1 && c.size() <= 2);
+
+ Iterator it = c.iterator();
+ verifyRecipient((RecipientInformation)it.next(), privKey);
+
+ if (c.size() == 2)
+ {
+ RecipientInformation recInfo = (RecipientInformation)it.next();
+
+ assertEquals(PKCSObjectIdentifiers.id_alg_CMSRC2wrap.getId(), recInfo.getKeyEncryptionAlgOID());
+ }
+ }
+
+ private void verifyRecipient(RecipientInformation recipient, PrivateKey privKey)
+ throws CMSException, NoSuchProviderException
+ {
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(privKey).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(exContent, recData));
+ }
+
+ private void verifySignerInfo4_4(SignerInformation signerInfo, byte[] counterSigCert)
+ throws Exception
+ {
+ verifyCounterSignature(signerInfo, counterSigCert);
+
+ verifyContentHint(signerInfo);
+ }
+
+ private SignerInformation getFirstSignerInfo(SignerInformationStore store)
+ {
+ return (SignerInformation)store.getSigners().iterator().next();
+ }
+
+ private void verifyCounterSignature(SignerInformation signInfo, byte[] certificate)
+ throws Exception
+ {
+ SignerInformation csi = (SignerInformation)signInfo.getCounterSignatures().getSigners().iterator().next();
+
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", BC);
+ X509Certificate cert = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(certificate));
+
+ assertTrue(csi.verify(new JcaSignerInfoVerifierBuilder(digCalcProv).setProvider(BC).build(cert)));
+ }
+
+ private void verifyContentHint(SignerInformation signInfo)
+ {
+ AttributeTable attrTable = signInfo.getUnsignedAttributes();
+
+ Attribute attr = attrTable.get(CMSAttributes.contentHint);
+
+ assertEquals(1, attr.getAttrValues().size());
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new DERUTF8String("Content Hints Description Buffer"));
+ v.add(CMSObjectIdentifiers.data);
+
+ assertTrue(attr.getAttrValues().getObjectAt(0).equals(new DERSequence(v)));
+ }
+
+ private void verifySignatures(CMSSignedData s, byte[] contentDigest)
+ throws Exception
+ {
+ Store certStore = s.getCertificates();
+ SignerInformationStore signers = s.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certStore.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ verifySigner(signer, cert);
+
+ if (contentDigest != null)
+ {
+ assertTrue(MessageDigest.isEqual(contentDigest, signer.getContentDigest()));
+ }
+ }
+ }
+
+ private void verifySignatures(CMSSignedData s)
+ throws Exception
+ {
+ verifySignatures(s, null);
+ }
+
+ private void verifySignatures(CMSSignedDataParser sp)
+ throws Exception
+ {
+ CMSTypedStream sc = sp.getSignedContent();
+ if (sc != null)
+ {
+ sc.drain();
+ }
+
+ Store certs = sp.getCertificates();
+ SignerInformationStore signers = sp.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ verifySigner(signer, cert);
+ }
+ }
+
+ private void verifySigner(SignerInformation signer, X509CertificateHolder certHolder)
+ throws Exception
+ {
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider("SC").getCertificate(certHolder);
+ if (cert.getPublicKey() instanceof DSAPublicKey)
+ {
+ DSAPublicKey key = (DSAPublicKey)cert.getPublicKey();
+
+ if (key.getParams() == null)
+ {
+ assertEquals(true, signer.verify(new JcaSignerInfoVerifierBuilder(digCalcProv).setProvider(BC).build(getInheritedKey(key))));
+ }
+ else
+ {
+ assertEquals(true, signer.verify(new JcaSignerInfoVerifierBuilder(digCalcProv).setProvider(BC).build(cert)));
+ }
+ }
+ else
+ {
+ assertEquals(true, signer.verify(new JcaSignerInfoVerifierBuilder(digCalcProv).setProvider(BC).build(cert)));
+ }
+ }
+
+ private PublicKey getInheritedKey(DSAPublicKey key)
+ throws Exception
+ {
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", BC);
+
+ X509Certificate cert = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(getRfc4134Data("CarlDSSSelf.cer")));
+
+ DSAParams dsaParams = ((DSAPublicKey)cert.getPublicKey()).getParams();
+
+ DSAPublicKeySpec dsaPubKeySpec = new DSAPublicKeySpec(
+ key.getY(), dsaParams.getP(), dsaParams.getQ(), dsaParams.getG());
+
+ KeyFactory keyFactory = KeyFactory.getInstance("DSA", BC);
+
+ return keyFactory.generatePublic(dsaPubKeySpec);
+ }
+
+ private static byte[] getRfc4134Data(String name)
+ {
+ String dataHome = System.getProperty(TEST_DATA_HOME);
+
+ if (dataHome == null)
+ {
+ throw new IllegalStateException(TEST_DATA_HOME + " property not set");
+ }
+
+ try
+ {
+ return Streams.readAll(new FileInputStream(dataHome + "/rfc4134/" + name));
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/SHA1DigestCalculator.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/SHA1DigestCalculator.java
new file mode 100644
index 000000000..f3d5fd727
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/SHA1DigestCalculator.java
@@ -0,0 +1,44 @@
+package org.spongycastle.cms.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.operator.DigestCalculator;
+
+
+class SHA1DigestCalculator
+ implements DigestCalculator
+{
+ private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1);
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return bOut;
+ }
+
+ public byte[] getDigest()
+ {
+ byte[] bytes = bOut.toByteArray();
+
+ bOut.reset();
+
+ Digest sha1 = new SHA1Digest();
+
+ sha1.update(bytes, 0, bytes.length);
+
+ byte[] digest = new byte[sha1.getDigestSize()];
+
+ sha1.doFinal(digest, 0);
+
+ return digest;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/SunProviderTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/SunProviderTest.java
new file mode 100644
index 000000000..a92417c2c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/cms/test/SunProviderTest.java
@@ -0,0 +1,284 @@
+package org.spongycastle.cms.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.spongycastle.cms.CMSEnvelopedData;
+import org.spongycastle.cms.CMSEnvelopedDataGenerator;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.CMSSignedData;
+import org.spongycastle.cms.CMSSignedDataGenerator;
+import org.spongycastle.cms.CMSSignedDataParser;
+import org.spongycastle.cms.CMSSignedDataStreamGenerator;
+import org.spongycastle.cms.CMSTypedData;
+import org.spongycastle.cms.CMSTypedStream;
+import org.spongycastle.cms.RecipientInformation;
+import org.spongycastle.cms.RecipientInformationStore;
+import org.spongycastle.cms.SignerInformation;
+import org.spongycastle.cms.SignerInformationStore;
+import org.spongycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
+import org.spongycastle.cms.jcajce.JcaSignerInfoVerifierBuilder;
+import org.spongycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
+import org.spongycastle.cms.jcajce.JcaX509CertSelectorConverter;
+import org.spongycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
+import org.spongycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
+import org.spongycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.spongycastle.util.CollectionStore;
+import org.spongycastle.util.Store;
+import org.spongycastle.x509.X509V3CertificateGenerator;
+
+public class SunProviderTest
+ extends TestCase
+{
+ static KeyPair keyPair;
+ static X509Certificate keyCert;
+ private static final String TEST_MESSAGE = "Hello World!";
+ private static final JcaX509CertSelectorConverter selectorConverter = new JcaX509CertSelectorConverter();
+
+ static
+ {
+ try
+ {
+ keyPair = generateKeyPair();
+ String origDN = "O=Bouncy Castle, C=AU";
+ keyCert = makeCertificate(keyPair, origDN, keyPair, origDN);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void testSHA1WithRSAEncapsulated()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSTypedData msg = new CMSProcessableByteArray(TEST_MESSAGE.getBytes());
+
+ certList.add(new X509CertificateHolder(keyCert.getEncoded()));
+
+ DigestCalculatorProvider digCalcProv = new JcaDigestCalculatorProviderBuilder().build();
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(digCalcProv).build(new JcaContentSignerBuilder("SHA1withRSA").setProvider("SunRsaSign").build(keyPair.getPrivate()), keyCert));
+
+ gen.addCertificates(new CollectionStore(certList));
+
+ CMSSignedData s = gen.generate(msg, true);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded());
+ ASN1InputStream aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ Store certsAndCrls = s.getCertificates();
+
+ SignerInformationStore signers = s.getSignerInfos();
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certsAndCrls.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509Certificate cert = new JcaX509CertificateConverter().getCertificate((X509CertificateHolder)certIt.next());
+
+ assertEquals(true, signer.verify(new JcaSignerInfoVerifierBuilder(new JcaDigestCalculatorProviderBuilder().build()).setProvider("SunRsaSign").build(cert)));
+ }
+ }
+
+ public void testSHA1WithRSAStream()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(new X509CertificateHolder(keyCert.getEncoded()));
+
+ DigestCalculatorProvider digCalcProv = new JcaDigestCalculatorProviderBuilder().build();
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(digCalcProv).build(new JcaContentSignerBuilder("SHA1withRSA").setProvider("SunRsaSign").build(keyPair.getPrivate()), keyCert));
+
+ gen.addCertificates(new CollectionStore(certList));
+
+ OutputStream sigOut = gen.open(bOut);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(digCalcProv,
+ new CMSTypedStream(new ByteArrayInputStream(TEST_MESSAGE.getBytes())), bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1", "SUN");
+
+ byte[] contentDigest = md.digest(TEST_MESSAGE.getBytes());
+ Store certStore = sp.getCertificates();
+ SignerInformationStore signers = sp.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certStore.getMatches(signer.getSID());
+
+ Iterator certIt = certCollection.iterator();
+ X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
+
+ assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("SunRsaSign").build(new JcaX509CertificateConverter().getCertificate(cert))));
+
+ if (contentDigest != null)
+ {
+ assertTrue(MessageDigest.isEqual(contentDigest, signer.getContentDigest()));
+ }
+ }
+ }
+
+ public void testKeyTransDES()
+ throws Exception
+ {
+ testKeyTrans(CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+ }
+
+ public void testKeyTransAES128()
+ throws Exception
+ {
+ testKeyTrans(CMSEnvelopedDataGenerator.AES128_CBC);
+ }
+
+ public void testKeyTransAES192()
+ throws Exception
+ {
+ testKeyTrans(CMSEnvelopedDataGenerator.AES192_CBC);
+ }
+
+ public void testKeyTransAES256()
+ throws Exception
+ {
+ testKeyTrans(CMSEnvelopedDataGenerator.AES256_CBC);
+ }
+
+ private void testKeyTrans(String algorithm)
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(keyCert).setProvider("SunJCE"));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier(algorithm)).setProvider("SunJCE").build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+
+ assertEquals(ed.getEncryptionAlgOID(), algorithm);
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(keyPair.getPrivate()).setProvider("SunJCE"));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ }
+
+ private static KeyPair generateKeyPair()
+ throws NoSuchProviderException, NoSuchAlgorithmException
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "SunRsaSign");
+
+ kpg.initialize(512, new SecureRandom());
+
+ return kpg.generateKeyPair();
+ }
+
+ private static X509Certificate makeCertificate(KeyPair subKP, String _subDN, KeyPair issKP, String _issDN)
+ throws GeneralSecurityException, IOException
+ {
+
+ PublicKey subPub = subKP.getPublic();
+ PrivateKey issPriv = issKP.getPrivate();
+ PublicKey issPub = issKP.getPublic();
+
+ X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();
+
+ v3CertGen.reset();
+ v3CertGen.setSerialNumber(BigInteger.valueOf(1));
+ v3CertGen.setIssuerDN(new X509Name(_issDN));
+ v3CertGen.setNotBefore(new Date(System.currentTimeMillis()));
+ v3CertGen.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)));
+ v3CertGen.setSubjectDN(new X509Name(_subDN));
+ v3CertGen.setPublicKey(subPub);
+
+ v3CertGen.setSignatureAlgorithm("SHA1WithRSA");
+
+ X509Certificate _cert = v3CertGen.generate(issPriv, "SunRsaSign");
+
+ _cert.checkValidity(new Date());
+ _cert.verify(issPub);
+
+ return _cert;
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ return new TestSuite(SunProviderTest.class);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/dvcs/test/AllTests.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/dvcs/test/AllTests.java
new file mode 100644
index 000000000..b00a5052a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/dvcs/test/AllTests.java
@@ -0,0 +1,239 @@
+package org.spongycastle.dvcs.test;
+
+import java.io.IOException;
+import java.security.KeyPair;
+import java.security.Security;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.dvcs.CertEtcToken;
+import org.spongycastle.asn1.dvcs.TargetEtcChain;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.cms.CMSSignedData;
+import org.spongycastle.cms.CMSSignedDataGenerator;
+import org.spongycastle.cms.SignerId;
+import org.spongycastle.cms.SignerInformationVerifier;
+import org.spongycastle.cms.SignerInformationVerifierProvider;
+import org.spongycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
+import org.spongycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
+import org.spongycastle.cms.test.CMSTestUtil;
+import org.spongycastle.dvcs.CCPDRequestBuilder;
+import org.spongycastle.dvcs.CCPDRequestData;
+import org.spongycastle.dvcs.CPDRequestBuilder;
+import org.spongycastle.dvcs.CPDRequestData;
+import org.spongycastle.dvcs.DVCSException;
+import org.spongycastle.dvcs.DVCSRequest;
+import org.spongycastle.dvcs.MessageImprint;
+import org.spongycastle.dvcs.MessageImprintBuilder;
+import org.spongycastle.dvcs.SignedDVCSMessageGenerator;
+import org.spongycastle.dvcs.TargetChain;
+import org.spongycastle.dvcs.VPKCRequestBuilder;
+import org.spongycastle.dvcs.VPKCRequestData;
+import org.spongycastle.dvcs.VSDRequestBuilder;
+import org.spongycastle.dvcs.VSDRequestData;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.io.Streams;
+
+public class AllTests
+ extends TestCase
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ private static boolean initialised = false;
+
+ private static String origDN;
+ private static KeyPair origKP;
+ private static X509Certificate origCert;
+
+ private static String signDN;
+ private static KeyPair signKP;
+ private static X509Certificate signCert;
+
+ private static void init()
+ throws Exception
+ {
+ if (!initialised)
+ {
+ initialised = true;
+
+ if (Security.getProvider(BC) == null)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ origDN = "O=Bouncy Castle, C=AU";
+ origKP = CMSTestUtil.makeKeyPair();
+ origCert = CMSTestUtil.makeCertificate(origKP, origDN, origKP, origDN);
+
+ signDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+ signKP = CMSTestUtil.makeKeyPair();
+ signCert = CMSTestUtil.makeCertificate(signKP, signDN, origKP, origDN);
+ }
+ }
+
+ public void setUp()
+ throws Exception
+ {
+ init();
+ }
+
+ private byte[] getInput(String name)
+ throws IOException
+ {
+ return Streams.readAll(getClass().getResourceAsStream(name));
+ }
+
+ public void testCCPDRequest()
+ throws Exception
+ {
+ SignedDVCSMessageGenerator gen = getSignedDVCSMessageGenerator();
+
+ CCPDRequestBuilder reqBuilder = new CCPDRequestBuilder();
+
+ MessageImprintBuilder imprintBuilder = new MessageImprintBuilder(new SHA1DigestCalculator());
+
+ MessageImprint messageImprint = imprintBuilder.build(new byte[100]);
+
+ CMSSignedData reqMsg = gen.build(reqBuilder.build(messageImprint));
+
+ assertTrue(reqMsg.verifySignatures(new SignerInformationVerifierProvider()
+ {
+ public SignerInformationVerifier get(SignerId sid)
+ throws OperatorCreationException
+ {
+ return new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(signCert);
+ }
+ }));
+
+ DVCSRequest request = new DVCSRequest(reqMsg);
+
+ CCPDRequestData reqData = (CCPDRequestData)request.getData();
+
+ assertEquals(messageImprint, reqData.getMessageImprint());
+ }
+
+ private CMSSignedData getWrappedCPDRequest()
+ throws OperatorCreationException, CertificateEncodingException, DVCSException, IOException
+ {
+ SignedDVCSMessageGenerator gen = getSignedDVCSMessageGenerator();
+
+ CPDRequestBuilder reqBuilder = new CPDRequestBuilder();
+
+ return gen.build(reqBuilder.build(new byte[100]));
+ }
+
+ public void testCPDRequest()
+ throws Exception
+ {
+ CMSSignedData reqMsg = getWrappedCPDRequest();
+
+ assertTrue(reqMsg.verifySignatures(new SignerInformationVerifierProvider()
+ {
+ public SignerInformationVerifier get(SignerId sid)
+ throws OperatorCreationException
+ {
+ return new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(signCert);
+ }
+ }));
+
+ DVCSRequest request = new DVCSRequest(reqMsg);
+
+ CPDRequestData reqData = (CPDRequestData)request.getData();
+
+ assertTrue(Arrays.areEqual(new byte[100], reqData.getMessage()));
+ }
+
+ public void testVPKCRequest()
+ throws Exception
+ {
+ SignedDVCSMessageGenerator gen = getSignedDVCSMessageGenerator();
+
+ VPKCRequestBuilder reqBuilder = new VPKCRequestBuilder();
+
+ reqBuilder.addTargetChain(new JcaX509CertificateHolder(signCert));
+
+ CMSSignedData reqMsg = gen.build(reqBuilder.build());
+
+ assertTrue(reqMsg.verifySignatures(new SignerInformationVerifierProvider()
+ {
+ public SignerInformationVerifier get(SignerId sid)
+ throws OperatorCreationException
+ {
+ return new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(signCert);
+ }
+ }));
+
+ DVCSRequest request = new DVCSRequest(reqMsg);
+
+ VPKCRequestData reqData = (VPKCRequestData)request.getData();
+
+ assertEquals(new TargetEtcChain(new CertEtcToken(CertEtcToken.TAG_CERTIFICATE, new JcaX509CertificateHolder(signCert).toASN1Structure())), ((TargetChain)reqData.getCerts().get(0)).toASN1Structure());
+ }
+
+ public void testVSDRequest()
+ throws Exception
+ {
+ CMSSignedData message = getWrappedCPDRequest();
+
+ SignedDVCSMessageGenerator gen = getSignedDVCSMessageGenerator();
+
+ VSDRequestBuilder reqBuilder = new VSDRequestBuilder();
+
+ CMSSignedData reqMsg = gen.build(reqBuilder.build(message));
+
+ assertTrue(reqMsg.verifySignatures(new SignerInformationVerifierProvider()
+ {
+ public SignerInformationVerifier get(SignerId sid)
+ throws OperatorCreationException
+ {
+ return new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(signCert);
+ }
+ }));
+
+ DVCSRequest request = new DVCSRequest(reqMsg);
+
+ VSDRequestData reqData = (VSDRequestData)request.getData();
+
+ assertEquals(message.toASN1Structure().getContentType(), reqData.getParsedMessage().toASN1Structure().getContentType());
+ }
+
+ private SignedDVCSMessageGenerator getSignedDVCSMessageGenerator()
+ throws OperatorCreationException, CertificateEncodingException
+ {
+ CMSSignedDataGenerator sigDataGen = new CMSSignedDataGenerator();
+
+ JcaDigestCalculatorProviderBuilder calculatorProviderBuilder = new JcaDigestCalculatorProviderBuilder().setProvider(BC);
+
+ ContentSigner contentSigner = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(signKP.getPrivate());
+
+ sigDataGen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(calculatorProviderBuilder.build()).build(contentSigner, signCert));
+
+ return new SignedDVCSMessageGenerator(sigDataGen);
+ }
+
+ public static void main(String[] args)
+ throws Exception
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ TestSuite suite= new TestSuite("EAC tests");
+
+ suite.addTestSuite(AllTests.class);
+ suite.addTestSuite(DVCSParseTest.class);
+
+ return new DVCSTestSetup(suite);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/dvcs/test/DVCSParseTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/dvcs/test/DVCSParseTest.java
new file mode 100644
index 000000000..b38069b89
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/dvcs/test/DVCSParseTest.java
@@ -0,0 +1,393 @@
+package org.spongycastle.dvcs.test;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.TestCase;
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.cmp.PKIStatus;
+import org.spongycastle.asn1.cmp.PKIStatusInfo;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.cms.SignedData;
+import org.spongycastle.asn1.dvcs.CertEtcToken;
+import org.spongycastle.asn1.dvcs.DVCSCertInfo;
+import org.spongycastle.asn1.dvcs.DVCSCertInfoBuilder;
+import org.spongycastle.asn1.dvcs.DVCSErrorNotice;
+import org.spongycastle.asn1.dvcs.DVCSRequest;
+import org.spongycastle.asn1.dvcs.DVCSRequestInformation;
+import org.spongycastle.asn1.dvcs.DVCSRequestInformationBuilder;
+import org.spongycastle.asn1.dvcs.DVCSResponse;
+import org.spongycastle.asn1.dvcs.DVCSTime;
+import org.spongycastle.asn1.dvcs.Data;
+import org.spongycastle.asn1.dvcs.ServiceType;
+import org.spongycastle.asn1.dvcs.TargetEtcChain;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.DigestInfo;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.PolicyInformation;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.CMSSignedData;
+import org.spongycastle.dvcs.DVCSException;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.encoders.Hex;
+
+public class DVCSParseTest
+ extends TestCase
+{
+
+ // Clepsydre requests and responses
+ private static final String REQUEST_CCPD_CLEPSYDRE = "MIICRgYJKoZIhvcNAQcCoIICNzCCAjMCAQMxCzAJBgUrDgMCGgUAMIGZBgsqhkiG9w0BCRABB6CBiQSBhjCBgzBgCgEEoE2kSzBJMQswCQYDVQQGEwJGUjEOMAwGA1UEBxMFUGFyaXMxEDAOBgNVBAoTB0VkZWxXZWIxGDAWBgNVBAMTD1BldGVyIFN5bHZlc3RlcqEMBgorBgEEAak9AQIBMB8wBwYFKw4DAhoEFHW2ha9viUZ96AcVJR5Fl4/NH6VmMYIBgzCCAX8CAQEwfDBwMQswCQYDVQQGEwJGUjEVMBMGA1UEChMMRWRlbFdlYiBTLkEuMSgwJgYDVQQLEx9DbGVwc3lkcmUgRGVtb25zdHJhdGlvbiBTZXJ2aWNlMSAwHgYDVQQDExdUaW1lIFN0YW1waW5nIEF1dGhvcml0eQIIAJSIFyE0N3YwCQYFKw4DAhoFAKBfMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBzAcBgkqhkiG9w0BCQUxDxcNMDAwNDE3MTcxNDU3WjAjBgkqhkiG9w0BCQQxFgQUTajC0s58DQRBL0QTM3XbL1st+dwwDQYJKoZIhvcNAQEBBQAEgYBuew429QhfFjwxeyi7C8LGF2emtVTxmOJviZYODJnmy0DBm43Y147TK0H3FiZbtwi/5pWy2QFs/rEsUsFa0jHzjsrdEaFyBSlBat0oQKpcd8adHYBT22+cTKWjj5KLGD/VOq0Bh2nD/dPYw9DKa+YNTlNuUCCZfJTCRCUbBsCZlg==";
+ private static final String RESPONSE_CCPD_CLEPSYDRE = "MIIH9wYJKoZIhvcNAQcCoIIH6DCCB+QCAQMxCzAJBgUrDgMCGgUAMIIBLQYLKoZIhvcNAQkQAQigggEcBIIBGDCCARQwgdYKAQSgTaRLMEkxCzAJBgNVBAYTAkZSMQ4wDAYDVQQHEwVQYXJpczEQMA4GA1UEChMHRWRlbFdlYjEYMBYGA1UEAxMPUGV0ZXIgU3lsdmVzdGVyoQwGCisGAQQBqT0BAgGidKRyMHAxCzAJBgNVBAYTAkZSMRUwEwYDVQQKEwxFZGVsV2ViIFMuQS4xKDAmBgNVBAsTH0NsZXBzeWRyZSBEZW1vbnN0cmF0aW9uIFNlcnZpY2UxIDAeBgNVBAMTF1RpbWUgU3RhbXBpbmcgQXV0aG9yaXR5MB8wBwYFKw4DAhoEFHW2ha9viUZ96AcVJR5Fl4/NH6VmAgcBeAoeyogjGA8yMDAwMDQxNzE3MTYxN1qgggPgMIID3DCCAsSgAwIBAgIIAJSIFxdkNzIwDQYJKoZIhvcNAQEEBQAwcDELMAkGA1UEBhMCRlIxFTATBgNVBAoTDEVkZWxXZWIgUy5BLjEoMCYGA1UECxMfQ2xlcHN5ZHJlIERlbW9uc3RyYXRpb24gU2VydmljZTEgMB4GA1UEAxMXVGltZSBTdGFtcGluZyBBdXRob3JpdHkwHhcNMDAwMTI1MTYxOTM4WhcNMjAwMTIwMTYxOTM4WjBwMQswCQYDVQQGEwJGUjEVMBMGA1UEChMMRWRlbFdlYiBTLkEuMSgwJgYDVQQLEx9DbGVwc3lkcmUgRGVtb25zdHJhdGlvbiBTZXJ2aWNlMSAwHgYDVQQDExdUaW1lIFN0YW1waW5nIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPrDF67rt53rq70FfjlDbQRFWHQFpczzbC+Mjnd+wp8SEVx9274jKJqQ0qvGorq9o36ZppkhpdiQuc+nI06gVqDBCkaJjjyRZzf9m6tJF/xKpfLkTG7jahySlwRvfwxc+3TLlX5Mw1gS6KnW8N0SRBXniy6vUcAMX6hl/EehyZgf1OHqvBwaJ7uLVvESVRD0jtifGZwegffbY92INz9xeVuW4l+C1RIZBQ3hPaVtZuQsHu3HTLjfqjjIFWquJX1GKgf5g3fEUe6Q3AXQw/DxX+jU7V00cJGdnwhVfVvljV81WYNOchm7nIjRevwjpYSZtBeKTWyd0KY1gF/K+ySLVB0CAwEAAaN6MHgwDwYDVR0TBAgwBgEB/wIBADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCjBNBggrBgEFBQcBAQEB/wQ+MDwwOgYIKwYBBQUHMASGLmh0dHBzOi8vY2xlcHN5ZHJlLmVkZWx3ZWIuZnIvZHZjcy9zZXJ2aWNlLWNjcGQwDQYJKoZIhvcNAQEEBQADggEBAAjar1sJOWbTvoAd13K1LKME+0b4BfW/g/NtbTIoHEbuD+owYYoeigNOmIFgH5cXU9FUcz9ymEXTEJrTd7h0DpqQKY6spOvSJG32IR0/Uoss5pLnUsZUk5G8V3QhODl1zTBJVBOUbP7xZDgfX3274D6o8Sgc8dko+jIeO0i/XHAhKe++ciTaDflRev7X9f/owurGTEUUUVP9ANVbzGcqI5QxnsKQOJuw3/neZwxXXNew/PJylsTRep2g5lEkmZ6Jxjn5cnpE/S0/vN/HJSeUobV9ugZ1ZxyVbL0sdEE+zc05XC6cw8MJ43nV64Xo8XIpgPbGbmEbWPyHPtnhUxDgsQUxggK7MIICtwIBATB8MHAxCzAJBgNVBAYTAkZSMRUwEwYDVQQKEwxFZGVsV2ViIFMuQS4xKDAmBgNVBAsTH0NsZXBzeWRyZSBEZW1vbnN0cmF0aW9uIFNlcnZpY2UxIDAeBgNVBAMTF1RpbWUgU3RhbXBpbmcgQXV0aG9yaXR5AggAlIglcjUnUDAJBgUrDgMCGgUAoIIBFDAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQgwHAYJKoZIhvcNAQkFMQ8XDTAwMDQxNzE3MTYxOVowIwYJKoZIhvcNAQkEMRYEFGhQ3JAgLsLwVRV/d6mmDDTMEwb6MIGyBgsqhkiG9w0BCRACDDGBojCBnzCBnDCBmQQUXPEY80rKtGfW2Of4O0rZejKlQ6UwgYAwdKRyMHAxCzAJBgNVBAYTAkZSMRUwEwYDVQQKEwxFZGVsV2ViIFMuQS4xKDAmBgNVBAsTH0NsZXBzeWRyZSBEZW1vbnN0cmF0aW9uIFNlcnZpY2UxIDAeBgNVBAMTF1RpbWUgU3RhbXBpbmcgQXV0aG9yaXR5AggAlIglcjUnUDANBgkqhkiG9w0BAQEFAASCAQAucJ9WXgFWqeFHgRI1ISkJFnrtRflaou3k/p0s5NoSZmIUWWGLUHsBgj29fuY40KigN5h5EyY5KcZyIKmVcedTf3l3mO8jAk65vZCbrAWicI86QjacLLCUsSsLNpQOeA6w0QkgY7z/zTLxWtOrn5OcWqNYmaAoEeCATU0edwT0UAfVi1SgIzL/ppziurjbVUfJyLoH75AUSKi2xXzVqSB0HFbvjxuz/IdtgfHUbxqHMJJHaeB54LwQmc9NNkw2A1Fy0VumHi2G8R8K6L/rOPnOGuywj1GuKjtGhL9NjJ/uH+/FNaNjvjjAA3w6XrjPOxgQiNu7T3j2++QcjdT4++tQ";
+ // Top-Cross requests and responses
+ private static final String REQUEST_CPD_TOMSK = "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";
+ private static final String RESPONSE_CPD_TOMSK = "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";
+ // private static final String REQUEST_VSD_TOMSK = "";
+// private static final String RESPONSE_VSD_TOMSK = "";
+ private static final String REQUEST_VPKC_TOMSK = "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";
+ private static final String RESPONSE_VPKC_TOMSK = "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";
+ private static final String REQUEST_CCPD_TOMSK = "MIIFagYJKoZIhvcNAQcCoIIFWzCCBVcCAQMxDDAKBgYqhQMCAgkFADBuBgsqhkiG9w0BCRABB6BfBF0wWzAKCgEEAgUAwDELHDA1MBEGBiqFAwICCQYHKoUDAgIeAQQgvrgCrtSqJuzWwWE7XelQv0cB71ehcXkh/Oikezqvl1agFgYLKoUDAhUBAQIBAwKgBwIFAJ7ldeKgggN0MIIDcDCCAx2gAwIBAgIKJjs9ewAAAAA3FDAKBgYqhQMCAgMFADCB5zEbMBkGCSqGSIb3DQEJARYMdWRjc0B1ZGNzLnJ1MQswCQYDVQQGEwJSVTEXMBUGA1UECB4OBCIEPgQ8BEEEOgQwBE8xEzARBgNVBAceCgQiBD4EPARBBDoxRzBFBgNVBAoTPlRvbXNrIFN0YXRlIFVuaXZlcnNpdHkgb2YgQ29udHJvbCBTeXN0ZW1zIGFuZCBSYWRpb2VsZWN0cm9uaWNzMScwJQYDVQQLHh4EJgQiBBEAIAAtACAEIwQmACAEIQQ4BDEEOARABDgxGzAZBgNVBAMTElVEQyBTaWJpcmlhIFRTVUNTUjAeFw0xMTEyMDcwNDI0MDBaFw0xMjEyMDcwNDMzMDBaMB8xHTAbBgNVBAMeFABSAEMAQQBJAFIAXwB0AGUAYwBoMGMwHAYGKoUDAgITMBIGByqFAwICJAAGByqFAwICHgEDQwAEQLgMQUEkI9li1pn4dHHEWv5SSCjI77W6wfG3mSzEKw0vd3qQUTd86xZGAEwVC2dxJIdiQlSuMtyog6vSau3FriKjggFsMIIBaDAOBgNVHQ8BAf8EBAMCBPAwMAYDVR0lBCkwJwYIKwYBBQUHAwQGCCqFAwMTAgUCBgcqhQMCAiIGBggrBgEFBQcDAjAdBgNVHQ4EFgQU/hZ+9/9Tt/94ckUhTWabJMCegqQwHwYDVR0jBBgwFoAUuR6KgNhm2o7kHyiMQFiMXOrW5yIwWgYDVR0fBFMwUTBPoE2gS4YjaHR0cDovL3d3dy51ZGNzLnJ1L2NlcnRzcnYvdWRjcy5jcmyGJGh0dHA6Ly93d3cyLnVkY3MucnUvY2VydHNydi91ZGNzLmNybDBxBggrBgEFBQcBAQRlMGMwLwYIKwYBBQUHMAKGI2h0dHA6Ly93d3cudWRjcy5ydS9jZXJ0c3J2L3VkY3MuY2VyMDAGCCsGAQUFBzAChiRodHRwOi8vd3d3Mi51ZGNzLnJ1L2NlcnRzcnYvdWRjcy5jZXIwFQYDVR0gBA4wDDAKBggqhQMDEwIFATAKBgYqhQMCAgMFAANBALCWVdYVTPSLtijWd6utGC/rtl0mGvU3UjyaHC2jbFovDwyRpx13BseqbcsxBA+aNabeH2WuEQMirhVt7lpV4jMxggFaMIIBVgIBATCB9jCB5zEbMBkGCSqGSIb3DQEJARYMdWRjc0B1ZGNzLnJ1MQswCQYDVQQGEwJSVTEXMBUGA1UECB4OBCIEPgQ8BEEEOgQwBE8xEzARBgNVBAceCgQiBD4EPARBBDoxRzBFBgNVBAoTPlRvbXNrIFN0YXRlIFVuaXZlcnNpdHkgb2YgQ29udHJvbCBTeXN0ZW1zIGFuZCBSYWRpb2VsZWN0cm9uaWNzMScwJQYDVQQLHh4EJgQiBBEAIAAtACAEIwQmACAEIQQ4BDEEOARABDgxGzAZBgNVBAMTElVEQyBTaWJpcmlhIFRTVUNTUgIKJjs9ewAAAAA3FDAKBgYqhQMCAgkFADAKBgYqhQMCAhMFAARAl0/LMiXMPCJIkAgCI6x3/8wPBDTR8P5GGs40Xzbz1rdvxcBTPEsyp8kNYMzxmQNegTOFemy15KKnQq8e4Fja6w==";
+ private static final String RESPONSE_CCPD_TOMSK = "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";
+ // expected info initialization:
+ private static final DVCSRequest REQ_CCPD_CLEPSYDRE, REQ_CCPD_TOMSK, REQ_CPD_TOMSK, REQ_VPKC_TOMSK;
+ private static final DVCSResponse RES_CCPD_CLEPSYDRE, RES_CCPD_TOMSK, RES_CPD_TOMSK, RES_VPKC_TOMSK;
+ private static List requests = new ArrayList();
+ private static List responses = new ArrayList();
+
+ static
+ {
+ GeneralName CLEPSYDRE_REQUESTER = GeneralName.getInstance(Hex.decode("A44B3049310B3009060355040613024652310E300C0603550407130550617269733110300E060355040A13074564656C576562311830160603550403130F50657465722053796C766573746572"));
+ GeneralName CLEPSYDRE_RESPONDER = GeneralName.getInstance(Hex.decode("A4723070310B300906035504061302465231153013060355040A130C4564656C57656220532E412E31283026060355040B131F436C657073796472652044656D6F6E7374726174696F6E20536572766963653120301E0603550403131754696D65205374616D70696E6720417574686F72697479"));
+ PolicyInformation CLEPSYDRE_POLICY = new PolicyInformation(new ASN1ObjectIdentifier("1.3.6.1.4.1.5309.1.2.1"));
+
+ DVCSRequestInformationBuilder INFO_CCPD_CLEPSYDRE = new DVCSRequestInformationBuilder(ServiceType.CCPD);
+ INFO_CCPD_CLEPSYDRE.setRequester(CLEPSYDRE_REQUESTER);
+ INFO_CCPD_CLEPSYDRE.setRequestPolicy(CLEPSYDRE_POLICY);
+
+ DigestInfo DIGEST_CCPD_CLEPSYDRE = new DigestInfo(new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.3.14.3.2.26")), Hex.decode("75B685AF6F89467DE80715251E45978FCD1FA566"));
+
+ DVCSRequestInformationBuilder INFO_CCPD_CLEPSYDRE2 = new DVCSRequestInformationBuilder(ServiceType.CCPD);
+ INFO_CCPD_CLEPSYDRE2.setRequester(CLEPSYDRE_REQUESTER);
+ INFO_CCPD_CLEPSYDRE2.setRequestPolicy(CLEPSYDRE_POLICY);
+ INFO_CCPD_CLEPSYDRE2.setDVCS(CLEPSYDRE_RESPONDER);
+
+ REQ_CCPD_CLEPSYDRE = new DVCSRequest(INFO_CCPD_CLEPSYDRE.build(), new Data(DIGEST_CCPD_CLEPSYDRE));
+ RES_CCPD_CLEPSYDRE = new DVCSResponse(new DVCSCertInfo(INFO_CCPD_CLEPSYDRE2.build(), DIGEST_CCPD_CLEPSYDRE, new ASN1Integer(new BigInteger(Hex.decode("01780A1ECA8823"))), new DVCSTime(new ASN1GeneralizedTime("20000417171617Z"))));
+
+ DVCSRequestInformationBuilder INFO_CCPD_TOMSK = new DVCSRequestInformationBuilder(ServiceType.CCPD);
+ INFO_CCPD_TOMSK.setNonce(new BigInteger(Hex.decode("00C0310B1C")));
+
+ DigestInfo DIGEST_CCPD_TOMSK = new DigestInfo(new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.2.643.2.2.9"), new ASN1ObjectIdentifier("1.2.643.2.2.30.1")), Hex.decode("BEB802AED4AA26ECD6C1613B5DE950BF4701EF57A1717921FCE8A47B3AAF9756"));
+ GeneralName ID_CCPD_TOMSK = GeneralName.getInstance(Hex.decode("A016060B2A85030215010102010302A0070205009EE575E2"));
+
+ REQ_CCPD_TOMSK = new DVCSRequest(INFO_CCPD_TOMSK.build(), new Data(DIGEST_CCPD_TOMSK), ID_CCPD_TOMSK);
+
+ DVCSCertInfoBuilder certInfoBldr = new DVCSCertInfoBuilder(INFO_CCPD_TOMSK.build(), DIGEST_CCPD_TOMSK, new ASN1Integer(6256), new DVCSTime(new ASN1GeneralizedTime("20121204040643Z")));
+ certInfoBldr.setDvStatus(new PKIStatusInfo(PKIStatus.granted));
+ RES_CCPD_TOMSK = new DVCSResponse(certInfoBldr.build());
+
+
+ DVCSRequestInformationBuilder INFO_CPD_TOMSK = new DVCSRequestInformationBuilder(ServiceType.CPD);
+ INFO_CPD_TOMSK.setNonce(new BigInteger("234303415"));
+
+ DVCSRequestInformationBuilder INFO_CPD_TOMSK2 = new DVCSRequestInformationBuilder(ServiceType.CPD);
+ INFO_CPD_TOMSK2.setNonce(new BigInteger("1957381177"));
+
+ String CPD_DATA_TOMSK = "30820418308203C5A003020102020A4CE0FAF7000000003CD0300A06062A850302020305003081E7311B301906092A864886F70D010901160C7564637340756463732E7275310B30090603550406130252553117301506035504081E0E0422043E043C0441043A0430044F3113301106035504071E0A0422043E043C0441043A31473045060355040A133E546F6D736B20537461746520556E6976657273697479206F6620436F6E74726F6C2053797374656D7320616E6420526164696F656C656374726F6E69637331273025060355040B1E1E0426042204110020002D0020042304260020042104380431043804400438311B301906035504031312554443205369626972696120545355435352301E170D3132313131323033323830305A170D3133303330333036313930305A3081D13128302606092A864886F70D0109011619746573745F75646373406374622E726B2E74757375722E7275310B30090603550406130252553113301106035504070C0AD0A2D0BED0BCD181D0BA313D303B060355040A0C34D0A3D0B4D0BED181D182D0BED0B2D0B5D180D18FD18ED189D0B8D0B920D0A6D0B5D0BDD182D18020D0A1D0B8D0B1D0B8D180D0B83144304206035504030C3BD0A2D0B5D181D182D0BED0B2D18BD0B920D09FD0BED0BBD18CD0B7D0BED0B2D0B0D182D0B5D0BBD18C20D0A3D0A620D0A1D0B8D0B1D0B8D180D0B83063301C06062A8503020213301206072A85030202240006072A850302021E010343000440474D47E4F21779C52C2249D0C07BA20D14B2E64E2E35ECCA7BBCC44D67E13DBF419B4F9D8F326411CD77B7621E3302C75D53A56BDD6016849B85F591629D3B58A38201613082015D300E0603551D0F0101FF0404030204F030260603551D25041F301D06082B0601050507030406072A85030202220606082B06010505070302301D0603551D0E04160414E2554D2891FF3AA4394D07B41711D40B57D8253D301F0603551D23041830168014B91E8A80D866DA8EE41F288C40588C5CEAD6E722305A0603551D1F04533051304FA04DA04B8623687474703A2F2F7777772E756463732E72752F636572747372762F756463732E63726C8624687474703A2F2F777777322E756463732E72752F636572747372762F756463732E63726C307106082B0601050507010104653063302F06082B060105050730028623687474703A2F2F7777772E756463732E72752F636572747372762F756463732E636572303006082B060105050730028624687474703A2F2F777777322E756463732E72752F636572747372762F756463732E63657230140603551D20040D300B300906072A850303130204300A06062A850302020305000341001189C3FA073C79B4691766296F0B1DC21308EEEC03406B031CD9425574512999192E5528F0A09E97683D06EC5B8CA79F14E2BC37E1F1900919C29567D9220FF4";
+ DigestInfo DIGEST_CPD_TOMSK = DIGEST_CCPD_TOMSK;
+ GeneralName ID_CPD_TOMSK = GeneralName.getInstance(Hex.decode("A016060B2A85030215010102010302A00702050085BA0D41"));
+
+ REQ_CPD_TOMSK = new DVCSRequest(INFO_CPD_TOMSK.build(), new Data(Hex.decode(CPD_DATA_TOMSK)), ID_CPD_TOMSK);
+
+ certInfoBldr = new DVCSCertInfoBuilder(INFO_CPD_TOMSK2.build(), DIGEST_CPD_TOMSK, new ASN1Integer(6329), new DVCSTime(new ASN1GeneralizedTime("20121205065720Z")));
+ certInfoBldr.setDvStatus(new PKIStatusInfo(PKIStatus.granted));
+ RES_CPD_TOMSK = new DVCSResponse(certInfoBldr.build());
+
+
+ DVCSRequestInformationBuilder INFO_VPKC_TOMSK = new DVCSRequestInformationBuilder(ServiceType.VPKC);
+ INFO_VPKC_TOMSK.setNonce(new BigInteger(Hex.decode("00D3F85051")));
+
+ String VPKC_DATA_TOMSK = CPD_DATA_TOMSK;
+ DigestInfo DIGEST_VPKC_TOMSK = new DigestInfo(new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.2.643.2.2.9"), new ASN1ObjectIdentifier("1.2.643.2.2.30.1")), Hex.decode("FD97A3191C95D2AD733C11ABE0E6AEB081AF8735177F50F6B08C29D3AAFE8DE7"));
+ GeneralName ID_VPKC_TOMSK = GeneralName.getInstance(Hex.decode("A016060B2A85030215010102010302A007020500AE344E64"));
+
+ CertEtcToken target = new CertEtcToken(CertEtcToken.TAG_CERTIFICATE, Certificate.getInstance(Hex.decode(VPKC_DATA_TOMSK)));
+ TargetEtcChain REQ_CERTS = new TargetEtcChain(target);
+
+ TargetEtcChain[] RES_CERTS = TargetEtcChain.arrayFromSequence(new DERSequence(ASN1Sequence.getInstance(Hex.decode("308216BBA0820418308203C5A003020102020A4CE0FAF7000000003CD0300A06062A850302020305003081E7311B301906092A864886F70D010901160C7564637340756463732E7275310B30090603550406130252553117301506035504081E0E0422043E043C0441043A0430044F3113301106035504071E0A0422043E043C0441043A31473045060355040A133E546F6D736B20537461746520556E6976657273697479206F6620436F6E74726F6C2053797374656D7320616E6420526164696F656C656374726F6E69637331273025060355040B1E1E0426042204110020002D0020042304260020042104380431043804400438311B301906035504031312554443205369626972696120545355435352301E170D3132313131323033323830305A170D3133303330333036313930305A3081D13128302606092A864886F70D0109011619746573745F75646373406374622E726B2E74757375722E7275310B30090603550406130252553113301106035504070C0AD0A2D0BED0BCD181D0BA313D303B060355040A0C34D0A3D0B4D0BED181D182D0BED0B2D0B5D180D18FD18ED189D0B8D0B920D0A6D0B5D0BDD182D18020D0A1D0B8D0B1D0B8D180D0B83144304206035504030C3BD0A2D0B5D181D182D0BED0B2D18BD0B920D09FD0BED0BBD18CD0B7D0BED0B2D0B0D182D0B5D0BBD18C20D0A3D0A620D0A1D0B8D0B1D0B8D180D0B83063301C06062A8503020213301206072A85030202240006072A850302021E010343000440474D47E4F21779C52C2249D0C07BA20D14B2E64E2E35ECCA7BBCC44D67E13DBF419B4F9D8F326411CD77B7621E3302C75D53A56BDD6016849B85F591629D3B58A38201613082015D300E0603551D0F0101FF0404030204F030260603551D25041F301D06082B0601050507030406072A85030202220606082B06010505070302301D0603551D0E04160414E2554D2891FF3AA4394D07B41711D40B57D8253D301F0603551D23041830168014B91E8A80D866DA8EE41F288C40588C5CEAD6E722305A0603551D1F04533051304FA04DA04B8623687474703A2F2F7777772E756463732E72752F636572747372762F756463732E63726C8624687474703A2F2F777777322E756463732E72752F636572747372762F756463732E63726C307106082B0601050507010104653063302F06082B060105050730028623687474703A2F2F7777772E756463732E72752F636572747372762F756463732E636572303006082B060105050730028624687474703A2F2F777777322E756463732E72752F636572747372762F756463732E63657230140603551D20040D300B300906072A850303130204300A06062A850302020305000341001189C3FA073C79B4691766296F0B1DC21308EEEC03406B031CD9425574512999192E5528F0A09E97683D06EC5B8CA79F14E2BC37E1F1900919C29567D9220FF43082129BA48212923082123F020101300A06062A850302020305003081E7311B301906092A864886F70D010901160C7564637340756463732E7275310B30090603550406130252553117301506035504081E0E0422043E043C0441043A0430044F3113301106035504071E0A0422043E043C0441043A31473045060355040A133E546F6D736B20537461746520556E6976657273697479206F6620436F6E74726F6C2053797374656D7320616E6420526164696F656C656374726F6E69637331273025060355040B1E1E0426042204110020002D0020042304260020042104380431043804400438311B301906035504031312554443205369626972696120545355435352170D3132313230333233313434325A170D3132313230343131333434325A308210C23029020A63D1113D0000000037F4170D3132303532393035343134325A300C300A0603551D1504030A01053029020A531056A0000000003C9D170D3132303530343036343030375A300C300A0603551D1504030A01053029020A7355CE0D000000003859170D3132303530323035333830375A300C300A0603551D1504030A01053029020A4AE834300000000037AC170D3132303430353130303130385A300C300A0603551D1504030A01053029020A59B4198A000000003CB0170D3132303330323038313635395A300C300A0603551D1504030A01063029020A18249CA60000000038B2170D3132303330313038343833375A300C300A0603551D1504030A01053029020A6DEAF612000000003824170D3132303232373131303433335A300C300A0603551D1504030A0105301B020A39D1DE4A000000003C87170D3132303232343035333433325A3029020A4444F4C4000000003BA1170D3132303232323037333635315A300C300A0603551D1504030A01063029020A43625071000000003B8E170D3132303231373033343333395A300C300A0603551D1504030A01063029020A431B3050000000003B82170D3132303231373033333935335A300C300A0603551D1504030A01063029020A6433B6890000000037FC170D3132303231373032353935395A300C300A0603551D1504030A0106301B020A1C5BF404000000003C4B170D3132303231363039343931305A3029020A1CF6345A0000000036F5170D3132303231363038353732365A300C300A0603551D1504030A01063029020A6D864F01000000003C04170D3132303231343039303935375A300C300A0603551D1504030A0106301B020A162D584F000000003C2C170D3132303231343037343732335A301B020A16E8FE85000000003C31170D3132303231343037343730395A3029020A72C498EC000000003C19170D3132303231303130303135395A300C300A0603551D1504030A01063029020A14FA364A000000003ADE170D3132303230363130313334345A300C300A0603551D1504030A01063029020A43182533000000003B81170D3132303230363034323931375A300C300A0603551D1504030A01063029020A431508FF000000003B80170D3132303230363032353230355A300C300A0603551D1504030A01063029020A43120ED9000000003B7F170D3132303230363032343630315A300C300A0603551D1504030A01063029020A430E73FF000000003B7E170D3132303230363032343232365A300C300A0603551D1504030A01063029020A43061D4B000000003B7C170D3132303230333035313032365A300C300A0603551D1504030A01063029020A42FEF88F000000003B7A170D3132303230323130323435365A300C300A0603551D1504030A01063029020A430AC0DB000000003B7D170D3132303230313037323132365A300C300A0603551D1504030A01063029020A4302B4DB000000003B7B170D3132303230313033323635345A300C300A0603551D1504030A01063029020A3DCCBBBA000000003B63170D3132303133313033313030315A300C300A0603551D1504030A01063029020A2A403F0B000000003B32170D3132303133303038343932325A300C300A0603551D1504030A01063029020A396432E1000000003B43170D3132303133303036333730355A300C300A0603551D1504030A01063029020A49EC23230000000037A2170D3132303133303035353233395A300C300A0603551D1504030A01063029020A60B42B980000000039AC170D3132303132373037353935345A300C300A0603551D1504030A0106301B020A25540752000000003B1C170D3132303132363130353831305A3029020A6137E543000000003AB7170D3132303132363034343034335A300C300A0603551D1504030A01063029020A612DCD96000000003AB6170D3132303132363034333531395A300C300A0603551D1504030A01063029020A60C303950000000039AE170D3132303132363034323632365A300C300A0603551D1504030A0106301B020A2439FB96000000003B02170D3132303132363034313035355A3029020A30AE0A2300000000376D170D3132303132353130313933305A300C300A0603551D1504030A01063029020A2BFFA7C3000000003756170D3132303132353130303432375A300C300A0603551D1504030A01063029020A1BB71C85000000003A26170D3132303132353130303135315A300C300A0603551D1504030A01063029020A2BCF205C00000000373B170D3132303132353130303130325A300C300A0603551D1504030A01063029020A2BF039FE00000000374B170D3132303132353130303031395A300C300A0603551D1504030A01063029020A1F099C2E000000003A77170D3132303132353039353934305A300C300A0603551D1504030A01063029020A2BC7A320000000003736170D3132303132353039353930305A300C300A0603551D1504030A01063029020A2BFBD81D000000003753170D3132303132353039353833385A300C300A0603551D1504030A01063029020A2BD484BB00000000373D170D3132303132353039353831355A300C300A0603551D1504030A01063029020A2BF49B8400000000374E170D3132303132353039353735335A300C300A0603551D1504030A01063029020A2C00D595000000003757170D3132303132353039353730335A300C300A0603551D1504030A01063029020A2BBC0A02000000003730170D3132303132353039353630315A300C300A0603551D1504030A01063029020A2BEB9798000000003748170D3132303132353039353533355A300C300A0603551D1504030A01063029020A2BDAB5A2000000003741170D3132303132353039353431355A300C300A0603551D1504030A01063029020A2C090F8A000000003759170D3132303132353039353333305A300C300A0603551D1504030A01063029020A2BF79616000000003750170D3132303132353039353231325A300C300A0603551D1504030A01063029020A2BEEB34F00000000374A170D3132303132353039353130385A300C300A0603551D1504030A01063029020A2BF675B200000000374F170D3132303132353039353034325A300C300A0603551D1504030A01063029020A2BD60C9400000000373E170D3132303132353039343932345A300C300A0603551D1504030A01063029020A2BD79BDF00000000373F170D3132303132353039303130385A300C300A0603551D1504030A01063029020A2BFD4C4F000000003754170D3132303132353039303034335A300C300A0603551D1504030A01063029020A6F1D206D000000003849170D3132303132353038353730345A300C300A0603551D1504030A01063029020A2BF93ACE000000003751170D3132303132353038353434385A300C300A0603551D1504030A01063029020A2BDD470B000000003743170D3132303132353038353431365A300C300A0603551D1504030A01063029020A2BE15CE1000000003746170D3132303132353038353132345A300C300A0603551D1504030A01063029020A2BDE86AF000000003744170D3132303132353038353035315A300C300A0603551D1504030A01063029020A2BFAA02A000000003752170D3132303132353038353032335A300C300A0603551D1504030A01063029020A2BC89D6E000000003737170D3132303132353038343935355A300C300A0603551D1504030A01063029020A2BD8D7CA000000003740170D3132303132353038343932395A300C300A0603551D1504030A01063029020A2BD1434C00000000373C170D3132303132353038343930355A300C300A0603551D1504030A01063029020A2BCA8FB8000000003738170D3132303132353038343834325A300C300A0603551D1504030A01063029020A1BD74138000000003A2B170D3132303132353038343733305A300C300A0603551D1504030A01063029020A1BC46DC3000000003A27170D3132303132353038343435325A300C300A0603551D1504030A01063029020A31B2B567000000003770170D3132303132353038343331305A300C300A0603551D1504030A01063029020A1EBAE5CA000000003A6A170D3132303132333038343431355A300C300A0603551D1504030A01063029020A16507403000000003ACD170D3132303132303038333631325A300C300A0603551D1504030A0106301B020A1133D59A000000003AC0170D3132303131393038353835335A301B020A54EC6BAC00000000391F170D3132303131393038343732345A3029020A562EC02700000000393D170D3132303131393038303834315A300C300A0603551D1504030A01063029020A13E616DA000000003A8D170D3132303131373038333431335A300C300A0603551D1504030A01063029020A2BE02163000000003745170D3132303131363039353233345A300C300A0603551D1504030A01063029020A2BBE7768000000003731170D3132303131363037353833385A300C300A0603551D1504030A01063029020A2BF1A4AA00000000374C170D3132303131363037353430335A300C300A0603551D1504030A0106301B020A1DEC32B1000000003A4B170D3132303131363034343831345A3029020A1BF65268000000003A32170D3132303131353139333235335A300C300A0603551D1504030A01063029020A2BC3E0F7000000003733170D3132303131353138313433315A300C300A0603551D1504030A01063029020A6106BEDE0000000039E4170D3132303131333039313832395A300C300A0603551D1504030A01063029020A55C46B6B0000000037E8170D3132303131333032323430305A300C300A0603551D1504030A01063029020A5AFE0124000000003967170D3132303131313036353831315A300C300A0603551D1504030A01063029020A2142E738000000003705170D3132303131313035353030315A300C300A0603551D1504030A0106301B020A568BE0F9000000003944170D3132303131303130323032345A301B020A129514C00000000038E5170D3131313233303036323033345A301B020A12A8C2E50000000038E6170D3131313233303036313933305A301B020A1752822400000000390A170D3131313232393033333733375A3029020A1337AE5C0000000038ED170D3131313232393033313532325A300C300A0603551D1504030A01063029020A1E4BBF640000000038D3170D3131313232373039343330315A300C300A0603551D1504030A01043029020A1E4892770000000038D2170D3131313232373039343230335A300C300A0603551D1504030A01043029020A7907BD3100000000388F170D3131313232333036323630315A300C300A0603551D1504030A01063029020A2B130CE6000000003721170D3131313232313038323935345A300C300A0603551D1504030A01063029020A2BC1E40E000000003732170D3131313232313034353730375A300C300A0603551D1504030A01063029020A69D631FD00000000381A170D3131313232303037343330345A300C300A0603551D1504030A01063029020A4062B7A800000000377B170D3131313231323036323733385A300C300A0603551D1504030A01043029020A31D45B0C000000003771170D3131313231323034333733335A300C300A0603551D1504030A01063029020A3069086E00000000376A170D3131313230393034303333385A300C300A0603551D1504030A01043029020A2C02217D000000003758170D3131313230383037323930355A300C300A0603551D1504030A01043029020A2B6B5CEF00000000372B170D3131313230383035333232315A300C300A0603551D1504030A01043029020A21D19C1E000000003709170D3131313230363037353935375A300C300A0603551D1504030A0106A060305E301F0603551D23041830168014B91E8A80D866DA8EE41F288C40588C5CEAD6E722301006092B06010401823715010403020100300B0603551D140404020209E0301C06092B0601040182371504040F170D3132313230343035323434325A300A06062A850302020305000341006D9C3CCD9EFB17C5BB0F8EA40FAF62F9C7A5765D163E270AFC998AF701D7F984F5AF494B963DA7647638D2C3E252D5C2E00EA75DE8B5C1A405F692D206961B3AA203020100"))));
+
+ REQ_VPKC_TOMSK = new DVCSRequest(INFO_VPKC_TOMSK.build(), new Data(REQ_CERTS), ID_VPKC_TOMSK);
+
+ certInfoBldr = new DVCSCertInfoBuilder(INFO_VPKC_TOMSK.build(), DIGEST_VPKC_TOMSK, new ASN1Integer(6257), new DVCSTime(new ASN1GeneralizedTime("20121204040753Z")));
+
+ certInfoBldr.setDvStatus(new PKIStatusInfo(PKIStatus.granted));
+ certInfoBldr.setCerts(RES_CERTS);
+
+ RES_VPKC_TOMSK = new DVCSResponse(certInfoBldr.build());
+
+ requests.add(new Info("req_ccpd_clepsydre", REQUEST_CCPD_CLEPSYDRE, REQ_CCPD_CLEPSYDRE));
+ requests.add(new Info("req_ccpd_tomsk", REQUEST_CCPD_TOMSK, REQ_CCPD_TOMSK));
+ requests.add(new Info("req_cpd_tomsk", REQUEST_CPD_TOMSK, REQ_CPD_TOMSK));
+ requests.add(new Info("req_vpkc_tomsk", REQUEST_VPKC_TOMSK, REQ_VPKC_TOMSK));
+
+ responses.add(new Info("res_ccpd_clepsydre", RESPONSE_CCPD_CLEPSYDRE, RES_CCPD_CLEPSYDRE));
+ responses.add(new Info("res_ccpd_tomsk", RESPONSE_CCPD_TOMSK, RES_CCPD_TOMSK));
+ responses.add(new Info("res_cpd_tomsk", RESPONSE_CPD_TOMSK, RES_CPD_TOMSK));
+ responses.add(new Info("res_vpkc_tomsk", RESPONSE_VPKC_TOMSK, RES_VPKC_TOMSK));
+
+ }
+
+ private static boolean areNull(String type, Object result, Object expected)
+ {
+ if (result == null && expected == null)
+ {
+ return true;
+ }
+ if (result == null && expected != null)
+ {
+ fail("Result '" + type + "' is null, whereas expected '" + type + "' is not null");
+ }
+ if (result != null && expected == null)
+ {
+ fail("Result '" + type + "' is not null, whereas expected '" + type + "' is null");
+ }
+ return false;
+ }
+
+ ////////////////////////////////////////////////////
+ // PARSE TESTS //
+ ////////////////////////////////////////////////////
+
+ private static void validate(String type, Object result, Object expected)
+ {
+ if (areNull(type, result, expected))
+ {
+ return;
+ }
+
+ if (!result.equals(expected))
+ {
+ fail("Different " + type + ": " + result + " while expected: " + expected);
+ }
+ }
+
+ private static void validateArray(String type, Object[] result, Object[] expected)
+ {
+ if (areNull(type, result, expected))
+ {
+ return;
+ }
+
+ if (result.length != expected.length)
+ {
+ fail("Different " + type + ": " + result + " while expected: " + expected);
+ }
+ for (int i = 0; i != result.length; i++)
+ {
+ if (!result[i].equals(expected[i]))
+ {
+ fail("Different " + type + ": " + result[i] + " while expected: " + expected[i]);
+ }
+ }
+ }
+
+ public void testParseRequests()
+ throws IOException, DVCSException, CMSException
+ {
+ for (Iterator it = requests.iterator(); it.hasNext();)
+ {
+ Info info = (Info)it.next();
+ testParseRequest(info.name, info.base64, (DVCSRequest)info.expected);
+ }
+ }
+
+ private void testParseRequest(String name, String base64request, DVCSRequest expected)
+ throws DVCSException, IOException, CMSException
+ {
+ byte[] requestBytes = Base64.decode(base64request);
+
+ org.spongycastle.dvcs.DVCSRequest request = new org.spongycastle.dvcs.DVCSRequest(new CMSSignedData(requestBytes));
+
+ validate(name, request.getContent(), expected);
+ }
+
+ public void testParseResponses()
+ throws IOException, DVCSException, CMSException
+ {
+ for (Iterator it = responses.iterator(); it.hasNext();)
+ {
+ Info info = (Info)it.next();
+ testParseResponse(info.name, info.base64, (DVCSResponse)info.expected);
+ }
+ }
+
+ ////////////////////////////////////////////////////
+ // VALIDATIONS //
+ ////////////////////////////////////////////////////
+
+ private void testParseResponse(String name, String base64response, DVCSResponse expected)
+ throws DVCSException, IOException, CMSException
+ {
+ byte[] responseBytes = Base64.decode(base64response);
+ org.spongycastle.dvcs.DVCSResponse response = new org.spongycastle.dvcs.DVCSResponse(new CMSSignedData(responseBytes));
+
+ validate(name, response.getContent(), expected);
+ }
+
+ /*
+ DVCSRequest ::= SEQUENCE {
+ requestInformation DVCSRequestInformation,
+ data Data,
+ transactionIdentifier GeneralName OPTIONAL
+ }
+ */
+ private void validate(String name, DVCSRequest result, DVCSRequest expected)
+ {
+ validate(name + ".requestInformation", result.getRequestInformation(), expected.getRequestInformation());
+ validate(name + ".data", result.getData(), expected.getData());
+ validate(name + ".transactionIdentifier", result.getTransactionIdentifier(), expected.getTransactionIdentifier());
+ }
+
+ /*
+ DVCSRequestInformation ::= SEQUENCE {
+ version INTEGER DEFAULT 1 ,
+ service ServiceType,
+ nonce Nonce OPTIONAL,
+ requestTime DVCSTime OPTIONAL,
+ requester [0] GeneralNames OPTIONAL,
+ requestPolicy [1] PolicyInformation OPTIONAL,
+ dvcs [2] GeneralNames OPTIONAL,
+ dataLocations [3] GeneralNames OPTIONAL,
+ extensions [4] IMPLICIT Extensions OPTIONAL
+ }
+ */
+ private void validate(String name, DVCSRequestInformation info, DVCSRequestInformation expected)
+ {
+ validate(name + ".version", new Integer(info.getVersion()), new Integer(expected.getVersion()));
+ validate(name + ".service", info.getService().getValue(), expected.getService().getValue());
+ validate(name + ".nonce", info.getNonce(), expected.getNonce());
+ validate(name + ".requestTime", info.getRequestTime(), expected.getRequestTime());
+ validate(name + ".requester", info.getRequester(), expected.getRequester());
+ validate(name + ".requestPolicy", info.getRequestPolicy(), expected.getRequestPolicy());
+ validate(name + ".dvcs", info.getDVCS(), expected.getDVCS());
+ validate(name + ".dataLocations", info.getDataLocations(), expected.getDataLocations());
+ validate(name + ".extensions", info.getExtensions(), expected.getExtensions());
+ }
+
+ /*
+ DVCSTime ::= CHOICE {
+ genTime GeneralizedTime,
+ timeStampToken ContentInfo
+ }
+ */
+ private void validate(String name, DVCSTime result, DVCSTime expected)
+ {
+ if (areNull(name, result, expected))
+ {
+ return;
+ }
+ validate(name + ".genTime", result.getGenTime(), expected.getGenTime());
+ validate(name + ".timeStampToken", result.getTimeStampToken(), expected.getTimeStampToken());
+ }
+
+ /*
+ Data ::= CHOICE {
+ message OCTET STRING ,
+ messageImprint DigestInfo,
+ certs SEQUENCE SIZE (1..MAX) OF
+ TargetEtcChain
+ }
+ */
+ private void validate(String name, Data result, Data expected)
+ {
+ validate(name + ".message", result.getMessage(), expected.getMessage());
+ validate(name + ".messageImprint", result.getMessageImprint(), expected.getMessageImprint());
+ validateArray(name + ".certs", result.getCerts(), expected.getCerts());
+ }
+
+ /*
+ DVCSResponse ::= CHOICE
+ {
+ dvCertInfo DVCSCertInfo ,
+ dvErrorNote [0] DVCSErrorNotice
+ }
+ */
+ private void validate(String name, DVCSResponse result, DVCSResponse expected)
+ {
+ validate(name + ".dvCertInfo", result.getCertInfo(), expected.getCertInfo());
+ validate(name + ".dvErrorNote", result.getErrorNotice(), expected.getErrorNotice());
+ }
+
+ /*
+ DVCSCertInfo::= SEQUENCE {
+ version Integer DEFAULT 1 ,
+ dvReqInfo DVCSRequestInformation,
+ messageImprint DigestInfo,
+ serialNumber Integer,
+ responseTime DVCSTime,
+ dvStatus [0] PKIStatusInfo OPTIONAL,
+ policy [1] PolicyInformation OPTIONAL,
+ reqSignature [2] SignerInfos OPTIONAL,
+ certs [3] SEQUENCE SIZE (1..MAX) OF
+ TargetEtcChain OPTIONAL,
+ extensions Extensions OPTIONAL
+ }
+ */
+ private void validate(String name, DVCSCertInfo result, DVCSCertInfo expected)
+ {
+ if (areNull(name, result, expected))
+ {
+ return;
+ }
+ validate(name + ".version", new Integer(result.getVersion()), new Integer(expected.getVersion()));
+ validate(name + ".dvReqInfo", result.getDvReqInfo(), expected.getDvReqInfo());
+ validate(name + ".messageImprint", result.getMessageImprint(), expected.getMessageImprint());
+ validate(name + ".serialNumber", result.getSerialNumber(), expected.getSerialNumber());
+ validate(name + ".responseTime", result.getResponseTime(), expected.getResponseTime());
+ validate(name + ".dvStatus", result.getDvStatus(), expected.getDvStatus());
+ validate(name + ".policy", result.getPolicy(), expected.getPolicy());
+ validate(name + ".reqSignature", result.getReqSignature(), expected.getReqSignature());
+ validateArray(name + ".certs", result.getCerts(), expected.getCerts());
+ validateArray(name + ".certs", result.getCerts(), expected.getCerts());
+ validate(name + ".extensions", result.getExtensions(), expected.getExtensions());
+ }
+
+ /*
+ DVCSErrorNotice ::= SEQUENCE {
+ transactionStatus PKIStatusInfo ,
+ transactionIdentifier GeneralName OPTIONAL
+ }
+ */
+ private void validate(String name, DVCSErrorNotice result, DVCSErrorNotice expected)
+ {
+ if (areNull(name, result, expected))
+ {
+ return;
+ }
+ validate(name + ".transactionStatus", result.getTransactionStatus(), expected.getTransactionStatus());
+ validate(name + ".transactionIdentifier", result.getTransactionIdentifier(), expected.getTransactionIdentifier());
+ }
+
+ private static class Info
+ {
+ public String name;
+ public String base64;
+ public Object expected;
+
+ public Info(String name, String base64, Object expected)
+ {
+ this.name = name;
+ this.base64 = base64;
+ this.expected = expected;
+ }
+ }
+
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/dvcs/test/DVCSTestSetup.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/dvcs/test/DVCSTestSetup.java
new file mode 100644
index 000000000..012738af0
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/dvcs/test/DVCSTestSetup.java
@@ -0,0 +1,28 @@
+
+package org.spongycastle.dvcs.test;
+
+import java.security.Security;
+
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+class DVCSTestSetup
+ extends TestSetup
+{
+ public DVCSTestSetup(Test test)
+ {
+ super(test);
+ }
+
+ protected void setUp()
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ protected void tearDown()
+ {
+ Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/dvcs/test/SHA1DigestCalculator.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/dvcs/test/SHA1DigestCalculator.java
new file mode 100644
index 000000000..828746962
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/dvcs/test/SHA1DigestCalculator.java
@@ -0,0 +1,44 @@
+package org.spongycastle.dvcs.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.operator.DigestCalculator;
+
+
+class SHA1DigestCalculator
+ implements DigestCalculator
+{
+ private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1);
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return bOut;
+ }
+
+ public byte[] getDigest()
+ {
+ byte[] bytes = bOut.toByteArray();
+
+ bOut.reset();
+
+ Digest sha1 = new SHA1Digest();
+
+ sha1.update(bytes, 0, bytes.length);
+
+ byte[] digest = new byte[sha1.getDigestSize()];
+
+ sha1.doFinal(digest, 0);
+
+ return digest;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/eac/test/AllTests.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/eac/test/AllTests.java
new file mode 100644
index 000000000..30e33cdbe
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/eac/test/AllTests.java
@@ -0,0 +1,201 @@
+package org.spongycastle.eac.test;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.eac.CertificateHolderAuthorization;
+import org.spongycastle.asn1.eac.CertificateHolderReference;
+import org.spongycastle.asn1.eac.CertificationAuthorityReference;
+import org.spongycastle.asn1.eac.EACObjectIdentifiers;
+import org.spongycastle.asn1.eac.PackedDate;
+import org.spongycastle.eac.EACCertificateBuilder;
+import org.spongycastle.eac.EACCertificateHolder;
+import org.spongycastle.eac.EACCertificateRequestHolder;
+import org.spongycastle.eac.jcajce.JcaPublicKeyConverter;
+import org.spongycastle.eac.operator.EACSignatureVerifier;
+import org.spongycastle.eac.operator.EACSigner;
+import org.spongycastle.eac.operator.jcajce.JcaEACSignatureVerifierBuilder;
+import org.spongycastle.eac.operator.jcajce.JcaEACSignerBuilder;
+import org.spongycastle.jce.ECNamedCurveTable;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.util.io.Streams;
+
+public class AllTests
+ extends TestCase
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ public void setUp()
+ {
+ if (Security.getProvider(BC) != null)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ }
+
+ public void testLoadCertificate() throws Exception
+ {
+ EACCertificateHolder certHolder = new EACCertificateHolder(getInput("Belgique CVCA-02032010.7816.cvcert"));
+
+ PublicKey pubKey = new JcaPublicKeyConverter().setProvider(BC).getKey(certHolder.getPublicKeyDataObject());
+ EACSignatureVerifier verifier = new JcaEACSignatureVerifierBuilder().build(certHolder.getPublicKeyDataObject().getUsage(), pubKey);
+
+ if (!certHolder.isSignatureValid(verifier))
+ {
+ fail("signature test failed");
+ }
+ }
+
+ private byte[] getInput(String name)
+ throws IOException
+ {
+ return Streams.readAll(getClass().getResourceAsStream(name));
+ }
+
+ public void testLoadInvalidRequest() throws Exception
+ {
+ // this request contains invalid unsigned integers (see D 2.1.1)
+ EACCertificateRequestHolder requestHolder = new EACCertificateRequestHolder(getInput("REQ_18102010.csr"));
+
+ PublicKey pubKey = new JcaPublicKeyConverter().setProvider(BC).getKey(requestHolder.getPublicKeyDataObject());
+ EACSignatureVerifier verifier = new JcaEACSignatureVerifierBuilder().build(requestHolder.getPublicKeyDataObject().getUsage(), pubKey);
+
+ if (requestHolder.isInnerSignatureValid(verifier))
+ {
+ fail("signature test failed");
+ }
+ }
+
+ public void testLoadRefCert() throws Exception
+ {
+ EACCertificateHolder certHolder = new EACCertificateHolder(getInput("at_cert_19a.cvcert"));
+
+
+ }
+
+ public void testGenerateEC()
+ throws Exception
+ {
+ ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("prime256v1");
+ KeyPair kp = generateECKeyPair(ecSpec);
+
+ JcaEACSignerBuilder signerBuilder = new JcaEACSignerBuilder().setProvider(BC);
+
+ EACSigner signer = signerBuilder.build("SHA256withECDSA", kp.getPrivate());
+
+ int role = CertificateHolderAuthorization.CVCA;
+ int rights = CertificateHolderAuthorization.RADG3 | CertificateHolderAuthorization.RADG4;
+
+ EACCertificateBuilder certBuilder = new EACCertificateBuilder(
+ new CertificationAuthorityReference("AU", "BC TEST", "12345"),
+ new JcaPublicKeyConverter().getPublicKeyDataObject(signer.getUsageIdentifier(), kp.getPublic()),
+ new CertificateHolderReference("AU", "BC TEST", "12345"),
+ new CertificateHolderAuthorization(EACObjectIdentifiers.id_EAC_ePassport, role | rights),
+ new PackedDate("110101"),
+ new PackedDate("120101"));
+
+ EACCertificateHolder certHolder = certBuilder.build(signer);
+
+ EACSignatureVerifier verifier = new JcaEACSignatureVerifierBuilder().build(certHolder.getPublicKeyDataObject().getUsage(), kp.getPublic());
+
+ if (!certHolder.isSignatureValid(verifier))
+ {
+ fail("first signature test failed");
+ }
+
+ PublicKey pubKey = new JcaPublicKeyConverter().setProvider(BC).getKey(certHolder.getPublicKeyDataObject());
+ verifier = new JcaEACSignatureVerifierBuilder().build(certHolder.getPublicKeyDataObject().getUsage(), pubKey);
+
+ if (!certHolder.isSignatureValid(verifier))
+ {
+ fail("first signature test failed");
+ }
+ }
+
+ public void testGenerateRSA()
+ throws Exception
+ {
+ KeyPair kp = generateRSAKeyPair();
+
+ JcaEACSignerBuilder signerBuilder = new JcaEACSignerBuilder().setProvider(BC);
+
+ EACSigner signer = signerBuilder.build("SHA256withRSA", kp.getPrivate());
+
+ int role = CertificateHolderAuthorization.CVCA;
+ int rights = CertificateHolderAuthorization.RADG3 | CertificateHolderAuthorization.RADG4;
+
+ EACCertificateBuilder certBuilder = new EACCertificateBuilder(
+ new CertificationAuthorityReference("AU", "BC TEST", "12345"),
+ new JcaPublicKeyConverter().getPublicKeyDataObject(signer.getUsageIdentifier(), kp.getPublic()),
+ new CertificateHolderReference("AU", "BC TEST", "12345"),
+ new CertificateHolderAuthorization(EACObjectIdentifiers.id_EAC_ePassport, role | rights),
+ new PackedDate("110101"),
+ new PackedDate("120101"));
+
+ EACCertificateHolder certHolder = certBuilder.build(signer);
+
+ EACSignatureVerifier verifier = new JcaEACSignatureVerifierBuilder().build(certHolder.getPublicKeyDataObject().getUsage(), kp.getPublic());
+
+ if (!certHolder.isSignatureValid(verifier))
+ {
+ fail("first signature test failed");
+ }
+
+ PublicKey pubKey = new JcaPublicKeyConverter().setProvider(BC).getKey(certHolder.getPublicKeyDataObject());
+ verifier = new JcaEACSignatureVerifierBuilder().build(certHolder.getPublicKeyDataObject().getUsage(), pubKey);
+
+ if (!certHolder.isSignatureValid(verifier))
+ {
+ fail("first signature test failed");
+ }
+ }
+
+ private KeyPair generateECKeyPair(ECParameterSpec spec) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException
+ {
+ KeyPairGenerator gen = KeyPairGenerator.getInstance("ECDSA",BC);
+
+ gen.initialize(spec, new SecureRandom());
+
+ KeyPair generatedKeyPair = gen.generateKeyPair();
+ return generatedKeyPair;
+ }
+
+ private KeyPair generateRSAKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException
+ {
+ KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA",BC);
+
+ gen.initialize(1024, new SecureRandom());
+
+ KeyPair generatedKeyPair = gen.generateKeyPair();
+ return generatedKeyPair;
+ }
+
+ public static void main(String[] args)
+ throws Exception
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ TestSuite suite= new TestSuite("EAC tests");
+
+ suite.addTestSuite(AllTests.class);
+
+ return new EACTestSetup(suite);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/eac/test/EACTestSetup.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/eac/test/EACTestSetup.java
new file mode 100644
index 000000000..f9158586e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/eac/test/EACTestSetup.java
@@ -0,0 +1,28 @@
+
+package org.spongycastle.eac.test;
+
+import java.security.Security;
+
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+class EACTestSetup
+ extends TestSetup
+{
+ public EACTestSetup(Test test)
+ {
+ super(test);
+ }
+
+ protected void setUp()
+ {
+ Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider());
+ }
+
+ protected void tearDown()
+ {
+ Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/mozilla/test/AllTests.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/mozilla/test/AllTests.java
new file mode 100644
index 000000000..e742710b1
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/mozilla/test/AllTests.java
@@ -0,0 +1,43 @@
+package org.spongycastle.mozilla.test;
+
+import java.security.Security;
+
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.test.SimpleTestResult;
+
+import junit.framework.*;
+
+public class AllTests
+ extends TestCase
+{
+ public void testMozilla()
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ org.spongycastle.util.test.Test[] tests = new org.spongycastle.util.test.Test[] { new SPKACTest() };
+
+ for (int i = 0; i != tests.length; i++)
+ {
+ SimpleTestResult result = (SimpleTestResult)tests[i].perform();
+
+ if (!result.isSuccessful())
+ {
+ fail(result.toString());
+ }
+ }
+ }
+
+ public static void main (String[] args)
+ {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite()
+ {
+ TestSuite suite = new TestSuite("Mozilla Tests");
+
+ suite.addTestSuite(AllTests.class);
+
+ return suite;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/mozilla/test/SPKACTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/mozilla/test/SPKACTest.java
new file mode 100644
index 000000000..b8d59f3f1
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/mozilla/test/SPKACTest.java
@@ -0,0 +1,113 @@
+package org.spongycastle.mozilla.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.security.PublicKey;
+import java.security.Security;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.mozilla.PublicKeyAndChallenge;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.mozilla.SignedPublicKeyAndChallenge;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.test.SimpleTest;
+
+public class SPKACTest
+ extends SimpleTest
+{
+ byte[] spkac = Base64.decode(
+ "MIIBOjCBpDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEApne7ti0ibPhV8Iht"+
+ "7Pws5iRckM7x4mtZYxEpeX5/IO8tDsBFdY86ewuY2f2KCca0oMWr43kdkZbPyzf4"+
+ "CSV+0fZm9MJyNMywygZjoOCC+rS8kr0Ef31iHChhYsyejJnjw116Jnn96syhdHY6"+
+ "lVD1rK0nn5ZkHjxU74gjoZu6BJMCAwEAARYAMA0GCSqGSIb3DQEBBAUAA4GBAKFL"+
+ "g/luv0C7gMTI8ZKfFoSyi7Q7kiSQcmSj1WJgT56ouIRJO5NdvB/1n4GNik8VOAU0"+
+ "NRztvGy3ZGqgbSav7lrxcNEvXH+dLbtS97s7yiaozpsOcEHqsBribpLOTRzYa8ci"+
+ "CwkPmIiYqcby11diKLpd+W9RFYNme2v0rrbM2CyV");
+
+
+ public String getName()
+ {
+ return "SignedPubicKeyAndChallenge";
+ }
+
+ public void spkacTest(String testName, byte[] req)
+ throws Exception
+ {
+ SignedPublicKeyAndChallenge spkac;
+
+ spkac = new SignedPublicKeyAndChallenge(req);
+
+ PublicKeyAndChallenge pkac = spkac.getPublicKeyAndChallenge();
+ PublicKey pubKey = spkac.getPublicKey("SC");
+ ASN1Primitive obj = pkac.toASN1Primitive();
+ if (obj == null)
+ {
+ fail("Error - " + testName + " PKAC ASN1Primitive was null.");
+ }
+
+ obj = spkac.toASN1Primitive();
+ if (obj == null)
+ {
+ fail("Error - "+testName+ " SPKAC ASN1Primitive was null.");
+ }
+
+ SubjectPublicKeyInfo spki = pkac.getSubjectPublicKeyInfo();
+ if (spki == null)
+ {
+ fail("Error - "+testName + " SubjectPublicKeyInfo was null.");
+ }
+
+ DERIA5String challenge = pkac.getChallenge();
+ // Most cases this will be a string of length zero.
+ if (challenge == null)
+ {
+ fail(":Error - "+testName+ " challenge was null.");
+ }
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(req);
+ ASN1InputStream dIn = new ASN1InputStream(bIn);
+
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+
+ dOut.writeObject(spkac.toASN1Primitive());
+
+ byte[] bytes = bOut.toByteArray();
+
+ if (bytes.length != req.length)
+ {
+ fail(testName + " failed length test");
+ }
+
+ for (int i = 0; i != req.length; i++)
+ {
+ if (bytes[i] != req[i])
+ {
+ fail(testName + " failed comparison test");
+ }
+ }
+
+ if (!spkac.verify("SC"))
+ {
+ fail(testName + " verification failed");
+ }
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ spkacTest("spkac", spkac);
+ }
+
+ public static void main(String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new SPKACTest());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/ocsp/test/AllTests.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/ocsp/test/AllTests.java
new file mode 100644
index 000000000..1213b3cc3
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/ocsp/test/AllTests.java
@@ -0,0 +1,45 @@
+package org.spongycastle.ocsp.test;
+
+import java.security.Security;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.test.SimpleTestResult;
+
+public class AllTests
+ extends TestCase
+{
+ public void testOCSP()
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ org.spongycastle.util.test.Test[] tests = new org.spongycastle.util.test.Test[] { new OCSPTest() };
+
+ for (int i = 0; i != tests.length; i++)
+ {
+ SimpleTestResult result = (SimpleTestResult)tests[i].perform();
+
+ if (!result.isSuccessful())
+ {
+ fail(result.toString());
+ }
+ }
+ }
+
+ public static void main (String[] args)
+ {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite()
+ {
+ TestSuite suite = new TestSuite("OCSP Tests");
+
+ suite.addTestSuite(AllTests.class);
+
+ return suite;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/ocsp/test/OCSPTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/ocsp/test/OCSPTest.java
new file mode 100644
index 000000000..2708e0c9b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/ocsp/test/OCSPTest.java
@@ -0,0 +1,865 @@
+package org.spongycastle.ocsp.test;
+
+import java.io.ByteArrayInputStream;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.Security;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Random;
+import java.util.Set;
+import java.util.Vector;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.ocsp.OCSPObjectIdentifiers;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.ocsp.BasicOCSPResp;
+import org.spongycastle.ocsp.BasicOCSPRespGenerator;
+import org.spongycastle.ocsp.CertificateID;
+import org.spongycastle.ocsp.CertificateStatus;
+import org.spongycastle.ocsp.OCSPReq;
+import org.spongycastle.ocsp.OCSPReqGenerator;
+import org.spongycastle.ocsp.OCSPResp;
+import org.spongycastle.ocsp.OCSPRespGenerator;
+import org.spongycastle.ocsp.Req;
+import org.spongycastle.ocsp.SingleResp;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.test.SimpleTest;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+
+public class OCSPTest
+ extends SimpleTest
+{
+ byte[] testResp1 = Base64.decode(
+ "MIIFnAoBAKCCBZUwggWRBgkrBgEFBQcwAQEEggWCMIIFfjCCARehgZ8wgZwx"
+ + "CzAJBgNVBAYTAklOMRcwFQYDVQQIEw5BbmRocmEgcHJhZGVzaDESMBAGA1UE"
+ + "BxMJSHlkZXJhYmFkMQwwCgYDVQQKEwNUQ1MxDDAKBgNVBAsTA0FUQzEeMBwG"
+ + "A1UEAxMVVENTLUNBIE9DU1AgUmVzcG9uZGVyMSQwIgYJKoZIhvcNAQkBFhVv"
+ + "Y3NwQHRjcy1jYS50Y3MuY28uaW4YDzIwMDMwNDAyMTIzNDU4WjBiMGAwOjAJ"
+ + "BgUrDgMCGgUABBRs07IuoCWNmcEl1oHwIak1BPnX8QQUtGyl/iL9WJ1VxjxF"
+ + "j0hAwJ/s1AcCAQKhERgPMjAwMjA4MjkwNzA5MjZaGA8yMDAzMDQwMjEyMzQ1"
+ + "OFowDQYJKoZIhvcNAQEFBQADgYEAfbN0TCRFKdhsmvOdUoiJ+qvygGBzDxD/"
+ + "VWhXYA+16AphHLIWNABR3CgHB3zWtdy2j7DJmQ/R7qKj7dUhWLSqclAiPgFt"
+ + "QQ1YvSJAYfEIdyHkxv4NP0LSogxrumANcDyC9yt/W9yHjD2ICPBIqCsZLuLk"
+ + "OHYi5DlwWe9Zm9VFwCGgggPMMIIDyDCCA8QwggKsoAMCAQICAQYwDQYJKoZI"
+ + "hvcNAQEFBQAwgZQxFDASBgNVBAMTC1RDUy1DQSBPQ1NQMSYwJAYJKoZIhvcN"
+ + "AQkBFhd0Y3MtY2FAdGNzLWNhLnRjcy5jby5pbjEMMAoGA1UEChMDVENTMQww"
+ + "CgYDVQQLEwNBVEMxEjAQBgNVBAcTCUh5ZGVyYWJhZDEXMBUGA1UECBMOQW5k"
+ + "aHJhIHByYWRlc2gxCzAJBgNVBAYTAklOMB4XDTAyMDgyOTA3MTE0M1oXDTAz"
+ + "MDgyOTA3MTE0M1owgZwxCzAJBgNVBAYTAklOMRcwFQYDVQQIEw5BbmRocmEg"
+ + "cHJhZGVzaDESMBAGA1UEBxMJSHlkZXJhYmFkMQwwCgYDVQQKEwNUQ1MxDDAK"
+ + "BgNVBAsTA0FUQzEeMBwGA1UEAxMVVENTLUNBIE9DU1AgUmVzcG9uZGVyMSQw"
+ + "IgYJKoZIhvcNAQkBFhVvY3NwQHRjcy1jYS50Y3MuY28uaW4wgZ8wDQYJKoZI"
+ + "hvcNAQEBBQADgY0AMIGJAoGBAM+XWW4caMRv46D7L6Bv8iwtKgmQu0SAybmF"
+ + "RJiz12qXzdvTLt8C75OdgmUomxp0+gW/4XlTPUqOMQWv463aZRv9Ust4f8MH"
+ + "EJh4ekP/NS9+d8vEO3P40ntQkmSMcFmtA9E1koUtQ3MSJlcs441JjbgUaVnm"
+ + "jDmmniQnZY4bU3tVAgMBAAGjgZowgZcwDAYDVR0TAQH/BAIwADALBgNVHQ8E"
+ + "BAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwkwNgYIKwYBBQUHAQEEKjAoMCYG"
+ + "CCsGAQUFBzABhhpodHRwOi8vMTcyLjE5LjQwLjExMDo3NzAwLzAtBgNVHR8E"
+ + "JjAkMCKgIKAehhxodHRwOi8vMTcyLjE5LjQwLjExMC9jcmwuY3JsMA0GCSqG"
+ + "SIb3DQEBBQUAA4IBAQB6FovM3B4VDDZ15o12gnADZsIk9fTAczLlcrmXLNN4"
+ + "PgmqgnwF0Ymj3bD5SavDOXxbA65AZJ7rBNAguLUo+xVkgxmoBH7R2sBxjTCc"
+ + "r07NEadxM3HQkt0aX5XYEl8eRoifwqYAI9h0ziZfTNes8elNfb3DoPPjqq6V"
+ + "mMg0f0iMS4W8LjNPorjRB+kIosa1deAGPhq0eJ8yr0/s2QR2/WFD5P4aXc8I"
+ + "KWleklnIImS3zqiPrq6tl2Bm8DZj7vXlTOwmraSQxUwzCKwYob1yGvNOUQTq"
+ + "pG6jxn7jgDawHU1+WjWQe4Q34/pWeGLysxTraMa+Ug9kPe+jy/qRX2xwvKBZ");
+
+ byte[] testResp2 = Base64.decode(
+ "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"
+ + "A5oyOoNv0w+8bbtMNEc1");
+
+ /**
+ * extra version number encoding.
+ */
+ private static byte[] irregReq = Base64.decode(
+ "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");
+ public String getName()
+ {
+ return "OCSP";
+ }
+
+ private void testECDSA()
+ throws Exception
+ {
+ String signDN = "O=Bouncy Castle, C=AU";
+ KeyPair signKP = OCSPTestUtil.makeECKeyPair();
+ X509Certificate testCert = OCSPTestUtil.makeECDSACertificate(signKP, signDN, signKP, signDN);
+
+ String origDN = "CN=Eric H. Echidna, E=eric@bouncycastle.org, O=Bouncy Castle, C=AU";
+ GeneralName origName = new GeneralName(new X509Name(origDN));
+
+ //
+ // general id value for our test issuer cert and a serial number.
+ //
+ CertificateID id = new CertificateID(CertificateID.HASH_SHA1, testCert, BigInteger.valueOf(1));
+
+ //
+ // basic request generation
+ //
+ OCSPReqGenerator gen = new OCSPReqGenerator();
+ gen.addRequest(id);
+
+ OCSPReq req = gen.generate();
+
+ if (req.isSigned())
+ {
+ fail("signed but shouldn't be");
+ }
+
+ X509Certificate[] certs = req.getCerts("SC");
+
+ if (certs != null)
+ {
+ fail("null certs expected, but not found");
+ }
+
+ Req[] requests = req.getRequestList();
+
+ if (!requests[0].getCertID().equals(id))
+ {
+ fail("Failed isFor test");
+ }
+
+ //
+ // request generation with signing
+ //
+ X509Certificate[] chain = new X509Certificate[1];
+
+ gen = new OCSPReqGenerator();
+
+ gen.setRequestorName(new GeneralName(GeneralName.directoryName, new X509Principal("CN=fred")));
+
+ gen.addRequest(
+ new CertificateID(CertificateID.HASH_SHA1, testCert, BigInteger.valueOf(1)));
+
+ chain[0] = testCert;
+
+ req = gen.generate("SHA1withECDSA", signKP.getPrivate(), chain, "SC");
+
+ if (!req.isSigned())
+ {
+ fail("not signed but should be");
+ }
+
+ if (!req.verify(signKP.getPublic(), "SC"))
+ {
+ fail("signature failed to verify");
+ }
+
+ requests = req.getRequestList();
+
+ if (!requests[0].getCertID().equals(id))
+ {
+ fail("Failed isFor test");
+ }
+
+ certs = req.getCerts("SC");
+
+ if (certs == null)
+ {
+ fail("null certs found");
+ }
+
+ if (certs.length != 1 || !certs[0].equals(testCert))
+ {
+ fail("incorrect certs found in request");
+ }
+
+ //
+ // encoding test
+ //
+ byte[] reqEnc = req.getEncoded();
+
+ OCSPReq newReq = new OCSPReq(reqEnc);
+
+ if (!newReq.verify(signKP.getPublic(), "SC"))
+ {
+ fail("newReq signature failed to verify");
+ }
+
+ //
+ // request generation with signing and nonce
+ //
+ chain = new X509Certificate[1];
+
+ gen = new OCSPReqGenerator();
+
+ Vector oids = new Vector();
+ Vector values = new Vector();
+ byte[] sampleNonce = new byte[16];
+ Random rand = new Random();
+
+ rand.nextBytes(sampleNonce);
+
+ gen.setRequestorName(new GeneralName(GeneralName.directoryName, new X509Principal("CN=fred")));
+
+ oids.addElement(OCSPObjectIdentifiers.id_pkix_ocsp_nonce);
+ values.addElement(new X509Extension(false, new DEROctetString(new DEROctetString(sampleNonce))));
+
+ gen.setRequestExtensions(new X509Extensions(oids, values));
+
+ gen.addRequest(
+ new CertificateID(CertificateID.HASH_SHA1, testCert, BigInteger.valueOf(1)));
+
+ chain[0] = testCert;
+
+ req = gen.generate("SHA1withECDSA", signKP.getPrivate(), chain, "SC");
+
+ if (!req.isSigned())
+ {
+ fail("not signed but should be");
+ }
+
+ if (!req.verify(signKP.getPublic(), "SC"))
+ {
+ fail("signature failed to verify");
+ }
+
+ //
+ // extension check.
+ //
+ Set extOids = req.getCriticalExtensionOIDs();
+
+ if (extOids.size() != 0)
+ {
+ fail("wrong number of critical extensions in OCSP request.");
+ }
+
+ extOids = req.getNonCriticalExtensionOIDs();
+
+ if (extOids.size() != 1)
+ {
+ fail("wrong number of non-critical extensions in OCSP request.");
+ }
+
+ byte[] extValue = req.getExtensionValue(OCSPObjectIdentifiers.id_pkix_ocsp_nonce.getId());
+
+ ASN1Encodable extObj = X509ExtensionUtil.fromExtensionValue(extValue);
+
+ if (!(extObj instanceof ASN1OctetString))
+ {
+ fail("wrong extension type found.");
+ }
+
+ if (!areEqual(((ASN1OctetString)extObj).getOctets(), sampleNonce))
+ {
+ fail("wrong extension value found.");
+ }
+
+ //
+ // request list check
+ //
+ requests = req.getRequestList();
+
+ if (!requests[0].getCertID().equals(id))
+ {
+ fail("Failed isFor test");
+ }
+
+ //
+ // response generation
+ //
+ BasicOCSPRespGenerator respGen = new BasicOCSPRespGenerator(signKP.getPublic());
+
+ respGen.addResponse(id, CertificateStatus.GOOD);
+
+ BasicOCSPResp resp = respGen.generate("SHA1withECDSA", signKP.getPrivate(), chain, new Date(), "SC");
+ }
+
+ private void testRSA()
+ throws Exception
+ {
+ String signDN = "O=Bouncy Castle, C=AU";
+ KeyPair signKP = OCSPTestUtil.makeKeyPair();
+ X509Certificate testCert = OCSPTestUtil.makeCertificate(signKP, signDN, signKP, signDN);
+
+ String origDN = "CN=Eric H. Echidna, E=eric@bouncycastle.org, O=Bouncy Castle, C=AU";
+ GeneralName origName = new GeneralName(new X509Name(origDN));
+
+ //
+ // general id value for our test issuer cert and a serial number.
+ //
+ CertificateID id = new CertificateID(CertificateID.HASH_SHA1, testCert, BigInteger.valueOf(1));
+
+ //
+ // basic request generation
+ //
+ OCSPReqGenerator gen = new OCSPReqGenerator();
+
+ gen.addRequest(
+ new CertificateID(CertificateID.HASH_SHA1, testCert, BigInteger.valueOf(1)));
+
+ OCSPReq req = gen.generate();
+
+ if (req.isSigned())
+ {
+ fail("signed but shouldn't be");
+ }
+
+ X509Certificate[] certs = req.getCerts("SC");
+
+ if (certs != null)
+ {
+ fail("null certs expected, but not found");
+ }
+
+ Req[] requests = req.getRequestList();
+
+ if (!requests[0].getCertID().equals(id))
+ {
+ fail("Failed isFor test");
+ }
+
+ //
+ // request generation with signing
+ //
+ X509Certificate[] chain = new X509Certificate[1];
+
+ gen = new OCSPReqGenerator();
+
+ gen.setRequestorName(new GeneralName(GeneralName.directoryName, new X509Principal("CN=fred")));
+
+ gen.addRequest(
+ new CertificateID(CertificateID.HASH_SHA1, testCert, BigInteger.valueOf(1)));
+
+ chain[0] = testCert;
+
+ req = gen.generate("SHA1withRSA", signKP.getPrivate(), chain, "SC");
+
+ if (!req.isSigned())
+ {
+ fail("not signed but should be");
+ }
+
+ if (!req.verify(signKP.getPublic(), "SC"))
+ {
+ fail("signature failed to verify");
+ }
+
+ requests = req.getRequestList();
+
+ if (!requests[0].getCertID().equals(id))
+ {
+ fail("Failed isFor test");
+ }
+
+ certs = req.getCerts("SC");
+
+ if (certs == null)
+ {
+ fail("null certs found");
+ }
+
+ if (certs.length != 1 || !certs[0].equals(testCert))
+ {
+ fail("incorrect certs found in request");
+ }
+
+ //
+ // encoding test
+ //
+ byte[] reqEnc = req.getEncoded();
+
+ OCSPReq newReq = new OCSPReq(reqEnc);
+
+ if (!newReq.verify(signKP.getPublic(), "SC"))
+ {
+ fail("newReq signature failed to verify");
+ }
+
+ //
+ // request generation with signing and nonce
+ //
+ chain = new X509Certificate[1];
+
+ gen = new OCSPReqGenerator();
+
+ Vector oids = new Vector();
+ Vector values = new Vector();
+ byte[] sampleNonce = new byte[16];
+ Random rand = new Random();
+
+ rand.nextBytes(sampleNonce);
+
+ gen.setRequestorName(new GeneralName(GeneralName.directoryName, new X509Principal("CN=fred")));
+
+ oids.addElement(OCSPObjectIdentifiers.id_pkix_ocsp_nonce);
+ values.addElement(new X509Extension(false, new DEROctetString(new DEROctetString(sampleNonce))));
+
+ gen.setRequestExtensions(new X509Extensions(oids, values));
+
+ gen.addRequest(
+ new CertificateID(CertificateID.HASH_SHA1, testCert, BigInteger.valueOf(1)));
+
+ chain[0] = testCert;
+
+ req = gen.generate("SHA1withRSA", signKP.getPrivate(), chain, "SC");
+
+ if (!req.isSigned())
+ {
+ fail("not signed but should be");
+ }
+
+ if (!req.verify(signKP.getPublic(), "SC"))
+ {
+ fail("signature failed to verify");
+ }
+
+ //
+ // extension check.
+ //
+ Set extOids = req.getCriticalExtensionOIDs();
+
+ if (extOids.size() != 0)
+ {
+ fail("wrong number of critical extensions in OCSP request.");
+ }
+
+ extOids = req.getNonCriticalExtensionOIDs();
+
+ if (extOids.size() != 1)
+ {
+ fail("wrong number of non-critical extensions in OCSP request.");
+ }
+
+ byte[] extValue = req.getExtensionValue(OCSPObjectIdentifiers.id_pkix_ocsp_nonce.getId());
+
+ ASN1Encodable extObj = X509ExtensionUtil.fromExtensionValue(extValue);
+
+ if (!(extObj instanceof ASN1OctetString))
+ {
+ fail("wrong extension type found.");
+ }
+
+ if (!areEqual(((ASN1OctetString)extObj).getOctets(), sampleNonce))
+ {
+ fail("wrong extension value found.");
+ }
+
+ //
+ // request list check
+ //
+ requests = req.getRequestList();
+
+ if (!requests[0].getCertID().equals(id))
+ {
+ fail("Failed isFor test");
+ }
+
+ //
+ // response generation
+ //
+ BasicOCSPRespGenerator respGen = new BasicOCSPRespGenerator(signKP.getPublic());
+
+ respGen.addResponse(id, CertificateStatus.GOOD);
+
+ BasicOCSPResp resp = respGen.generate("SHA1withRSA", signKP.getPrivate(), chain, new Date(), "SC");
+ OCSPRespGenerator rGen = new OCSPRespGenerator();
+
+ byte[] enc = rGen.generate(OCSPRespGenerator.SUCCESSFUL, resp).getEncoded();
+ }
+
+ private void testIrregularVersionReq()
+ throws Exception
+ {
+ OCSPReq ocspRequest = new OCSPReq(irregReq);
+ X509Certificate cert = ocspRequest.getCerts("SC")[0];
+ if (!ocspRequest.verify(cert.getPublicKey(), "SC"))
+ {
+ fail("extra version encoding test failed");
+ }
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ String signDN = "O=Bouncy Castle, C=AU";
+ KeyPair signKP = OCSPTestUtil.makeKeyPair();
+ X509Certificate testCert = OCSPTestUtil.makeCertificate(signKP, signDN, signKP, signDN);
+
+ String origDN = "CN=Eric H. Echidna, E=eric@bouncycastle.org, O=Bouncy Castle, C=AU";
+ GeneralName origName = new GeneralName(new X509Name(origDN));
+
+ //
+ // general id value for our test issuer cert and a serial number.
+ //
+ CertificateID id = new CertificateID(CertificateID.HASH_SHA1, testCert, BigInteger.valueOf(1));
+
+ //
+ // general id value for our test issuer cert and a serial number and the default provider
+ //
+ id = new CertificateID(CertificateID.HASH_SHA1, testCert, BigInteger.valueOf(1), null);
+
+ //
+ // basic request generation
+ //
+ OCSPReqGenerator gen = new OCSPReqGenerator();
+
+ gen.addRequest(
+ new CertificateID(CertificateID.HASH_SHA1, testCert, BigInteger.valueOf(1)));
+
+ OCSPReq req = gen.generate();
+
+ if (req.isSigned())
+ {
+ fail("signed but shouldn't be");
+ }
+
+ X509Certificate[] certs = req.getCerts("SC");
+
+ if (certs != null)
+ {
+ fail("null certs expected, but not found");
+ }
+
+ Req[] requests = req.getRequestList();
+
+ if (!requests[0].getCertID().equals(id))
+ {
+ fail("Failed isFor test");
+ }
+
+ //
+ // request generation with signing
+ //
+ X509Certificate[] chain = new X509Certificate[1];
+
+ gen = new OCSPReqGenerator();
+
+ gen.setRequestorName(new GeneralName(GeneralName.directoryName, new X509Principal("CN=fred")));
+
+ gen.addRequest(
+ new CertificateID(CertificateID.HASH_SHA1, testCert, BigInteger.valueOf(1)));
+
+ chain[0] = testCert;
+
+ req = gen.generate("SHA1withRSA", signKP.getPrivate(), chain, "SC");
+
+ if (!req.isSigned())
+ {
+ fail("not signed but should be");
+ }
+
+ if (!req.verify(signKP.getPublic(), "SC"))
+ {
+ fail("signature failed to verify");
+ }
+
+ requests = req.getRequestList();
+
+ if (!requests[0].getCertID().equals(id))
+ {
+ fail("Failed isFor test");
+ }
+
+ certs = req.getCerts("SC");
+
+ if (certs == null)
+ {
+ fail("null certs found");
+ }
+
+ if (certs.length != 1 || !certs[0].equals(testCert))
+ {
+ fail("incorrect certs found in request");
+ }
+
+ //
+ // encoding test
+ //
+ byte[] reqEnc = req.getEncoded();
+
+ OCSPReq newReq = new OCSPReq(reqEnc);
+
+ if (!newReq.verify(signKP.getPublic(), "SC"))
+ {
+ fail("newReq signature failed to verify");
+ }
+
+ //
+ // request generation with signing and nonce
+ //
+ chain = new X509Certificate[1];
+
+ gen = new OCSPReqGenerator();
+
+ Vector oids = new Vector();
+ Vector values = new Vector();
+ byte[] sampleNonce = new byte[16];
+ Random rand = new Random();
+
+ rand.nextBytes(sampleNonce);
+
+ gen.setRequestorName(new GeneralName(GeneralName.directoryName, new X509Principal("CN=fred")));
+
+ oids.addElement(OCSPObjectIdentifiers.id_pkix_ocsp_nonce);
+ values.addElement(new X509Extension(false, new DEROctetString(new DEROctetString(sampleNonce))));
+
+ gen.setRequestExtensions(new X509Extensions(oids, values));
+
+ gen.addRequest(
+ new CertificateID(CertificateID.HASH_SHA1, testCert, BigInteger.valueOf(1)));
+
+ chain[0] = testCert;
+
+ req = gen.generate("SHA1withRSA", signKP.getPrivate(), chain, "SC");
+
+ if (!req.isSigned())
+ {
+ fail("not signed but should be");
+ }
+
+ if (!req.verify(signKP.getPublic(), "SC"))
+ {
+ fail("signature failed to verify");
+ }
+
+ //
+ // extension check.
+ //
+ Set extOids = req.getCriticalExtensionOIDs();
+
+ if (extOids.size() != 0)
+ {
+ fail("wrong number of critical extensions in OCSP request.");
+ }
+
+ extOids = req.getNonCriticalExtensionOIDs();
+
+ if (extOids.size() != 1)
+ {
+ fail("wrong number of non-critical extensions in OCSP request.");
+ }
+
+ byte[] extValue = req.getExtensionValue(OCSPObjectIdentifiers.id_pkix_ocsp_nonce.getId());
+
+ ASN1Encodable extObj = X509ExtensionUtil.fromExtensionValue(extValue);
+
+ if (!(extObj instanceof ASN1OctetString))
+ {
+ fail("wrong extension type found.");
+ }
+
+ if (!areEqual(((ASN1OctetString)extObj).getOctets(), sampleNonce))
+ {
+ fail("wrong extension value found.");
+ }
+
+ //
+ // request list check
+ //
+ requests = req.getRequestList();
+
+ if (!requests[0].getCertID().equals(id))
+ {
+ fail("Failed isFor test");
+ }
+
+ //
+ // response parsing - test 1
+ //
+ OCSPResp response = new OCSPResp(new ByteArrayInputStream(testResp1));
+
+ if (response.getStatus() != 0)
+ {
+ fail("response status not zero.");
+ }
+
+ BasicOCSPResp brep = (BasicOCSPResp)response.getResponseObject();
+ chain = brep.getCerts("SC");
+
+ if (!brep.verify(chain[0].getPublicKey(), "SC"))
+ {
+ fail("response 1 failed to verify.");
+ }
+
+ //
+ // test 2
+ //
+ SingleResp[] singleResp = brep.getResponses();
+
+ response = new OCSPResp(new ByteArrayInputStream(testResp2));
+
+ if (response.getStatus() != 0)
+ {
+ fail("response status not zero.");
+ }
+
+ brep = (BasicOCSPResp)response.getResponseObject();
+ chain = brep.getCerts("SC");
+
+ if (!brep.verify(chain[0].getPublicKey(), "SC"))
+ {
+ fail("response 2 failed to verify.");
+ }
+
+ singleResp = brep.getResponses();
+
+ //
+ // simple response generation
+ //
+ OCSPRespGenerator respGen = new OCSPRespGenerator();
+ OCSPResp resp = respGen.generate(OCSPRespGenerator.SUCCESSFUL, response.getResponseObject());
+
+ if (!resp.getResponseObject().equals(response.getResponseObject()))
+ {
+ fail("response fails to match");
+ }
+
+ testECDSA();
+ testRSA();
+ testIrregularVersionReq();
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new OCSPTest());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/ocsp/test/OCSPTestUtil.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/ocsp/test/OCSPTestUtil.java
new file mode 100644
index 000000000..4b46b09b4
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/ocsp/test/OCSPTestUtil.java
@@ -0,0 +1,181 @@
+package org.spongycastle.ocsp.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+import javax.crypto.KeyGenerator;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.x509.X509V3CertificateGenerator;
+
+public class OCSPTestUtil
+{
+
+ public static SecureRandom rand;
+ public static KeyPairGenerator kpg, eckpg;
+ public static KeyGenerator desede128kg;
+ public static KeyGenerator desede192kg;
+ public static KeyGenerator rc240kg;
+ public static KeyGenerator rc264kg;
+ public static KeyGenerator rc2128kg;
+ public static BigInteger serialNumber;
+
+ public static final boolean DEBUG = true;
+
+ static
+ {
+ try
+ {
+ rand = new SecureRandom();
+
+ kpg = KeyPairGenerator.getInstance("RSA", "SC");
+ kpg.initialize(1024, rand);
+
+ serialNumber = new BigInteger("1");
+
+ eckpg = KeyPairGenerator.getInstance("ECDSA", "SC");
+ eckpg.initialize(192, rand);
+ }
+ catch(Exception ex)
+ {
+ throw new RuntimeException(ex.toString());
+ }
+ }
+
+ public static KeyPair makeKeyPair()
+ {
+ return kpg.generateKeyPair();
+ }
+
+ public static KeyPair makeECKeyPair()
+ {
+ return eckpg.generateKeyPair();
+ }
+
+ public static X509Certificate makeCertificate(KeyPair _subKP,
+ String _subDN, KeyPair _issKP, String _issDN)
+ throws Exception
+ {
+
+ return makeCertificate(_subKP, _subDN, _issKP, _issDN, false);
+ }
+
+ public static X509Certificate makeECDSACertificate(KeyPair _subKP,
+ String _subDN, KeyPair _issKP, String _issDN)
+ throws Exception
+ {
+
+ return makeECDSACertificate(_subKP, _subDN, _issKP, _issDN, false);
+ }
+
+ public static X509Certificate makeCACertificate(KeyPair _subKP,
+ String _subDN, KeyPair _issKP, String _issDN)
+ throws Exception
+ {
+
+ return makeCertificate(_subKP, _subDN, _issKP, _issDN, true);
+ }
+
+ public static X509Certificate makeCertificate(KeyPair _subKP,
+ String _subDN, KeyPair _issKP, String _issDN, boolean _ca)
+ throws Exception
+ {
+ return makeCertificate(_subKP,_subDN, _issKP, _issDN, "MD5withRSA", _ca);
+ }
+
+ public static X509Certificate makeECDSACertificate(KeyPair _subKP,
+ String _subDN, KeyPair _issKP, String _issDN, boolean _ca)
+ throws Exception
+ {
+ return makeCertificate(_subKP,_subDN, _issKP, _issDN, "SHA1WithECDSA", _ca);
+ }
+
+ public static X509Certificate makeCertificate(KeyPair _subKP,
+ String _subDN, KeyPair _issKP, String _issDN, String algorithm, boolean _ca)
+ throws Exception
+ {
+
+ PublicKey _subPub = _subKP.getPublic();
+ PrivateKey _issPriv = _issKP.getPrivate();
+ PublicKey _issPub = _issKP.getPublic();
+
+ X509V3CertificateGenerator _v3CertGen = new X509V3CertificateGenerator();
+
+ _v3CertGen.reset();
+ _v3CertGen.setSerialNumber(allocateSerialNumber());
+ _v3CertGen.setIssuerDN(new X509Name(_issDN));
+ _v3CertGen.setNotBefore(new Date(System.currentTimeMillis()));
+ _v3CertGen.setNotAfter(new Date(System.currentTimeMillis()
+ + (1000L * 60 * 60 * 24 * 100)));
+ _v3CertGen.setSubjectDN(new X509Name(_subDN));
+ _v3CertGen.setPublicKey(_subPub);
+ _v3CertGen.setSignatureAlgorithm(algorithm);
+
+ _v3CertGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
+ createSubjectKeyId(_subPub));
+
+ _v3CertGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
+ createAuthorityKeyId(_issPub));
+
+ _v3CertGen.addExtension(X509Extensions.BasicConstraints, false,
+ new BasicConstraints(_ca));
+
+ X509Certificate _cert = _v3CertGen.generate(_issPriv);
+
+ _cert.checkValidity(new Date());
+ _cert.verify(_issPub);
+
+ return _cert;
+ }
+
+ /*
+ *
+ * INTERNAL METHODS
+ *
+ */
+
+ private static AuthorityKeyIdentifier createAuthorityKeyId(PublicKey _pubKey)
+ throws IOException
+ {
+
+ ByteArrayInputStream _bais = new ByteArrayInputStream(_pubKey
+ .getEncoded());
+ SubjectPublicKeyInfo _info = new SubjectPublicKeyInfo(
+ (ASN1Sequence)new ASN1InputStream(_bais).readObject());
+
+ return new AuthorityKeyIdentifier(_info);
+ }
+
+ private static SubjectKeyIdentifier createSubjectKeyId(PublicKey _pubKey)
+ throws IOException
+ {
+
+ ByteArrayInputStream _bais = new ByteArrayInputStream(_pubKey
+ .getEncoded());
+ SubjectPublicKeyInfo _info = new SubjectPublicKeyInfo(
+ (ASN1Sequence)new ASN1InputStream(_bais).readObject());
+ return new SubjectKeyIdentifier(_info);
+ }
+
+ private static BigInteger allocateSerialNumber()
+ {
+ BigInteger _tmp = serialNumber;
+ serialNumber = serialNumber.add(BigInteger.valueOf(1));
+ return _tmp;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/openssl/test/AllTests.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/openssl/test/AllTests.java
new file mode 100644
index 000000000..c432dcaa4
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/openssl/test/AllTests.java
@@ -0,0 +1,151 @@
+package org.spongycastle.openssl.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Security;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.openssl.PEMParser;
+import org.spongycastle.openssl.PEMWriter;
+import org.spongycastle.openssl.PKCS8Generator;
+import org.spongycastle.openssl.jcajce.JcaPEMKeyConverter;
+import org.spongycastle.openssl.jcajce.JcaPKCS8Generator;
+import org.spongycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
+import org.spongycastle.openssl.jcajce.JceOpenSSLPKCS8EncryptorBuilder;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
+import org.spongycastle.pkcs.PKCSException;
+import org.spongycastle.util.test.SimpleTestResult;
+
+public class
+ AllTests
+ extends TestCase
+{
+ public void testOpenSSL()
+ {
+ if (Security.getProvider("SC") == null)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ org.spongycastle.util.test.Test[] tests = new org.spongycastle.util.test.Test[]
+ {
+ new WriterTest(),
+ new ParserTest()
+ };
+
+ for (int i = 0; i != tests.length; i++)
+ {
+ SimpleTestResult result = (SimpleTestResult)tests[i].perform();
+
+ if (!result.isSuccessful())
+ {
+ fail(result.toString());
+ }
+ }
+ }
+
+ public void testPKCS8Encrypted()
+ throws Exception
+ {
+ if (Security.getProvider("SC") == null)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "SC");
+
+ kpGen.initialize(1024);
+
+ PrivateKey key = kpGen.generateKeyPair().getPrivate();
+
+ encryptedTestNew(key, PKCS8Generator.AES_256_CBC);
+ encryptedTestNew(key, PKCS8Generator.DES3_CBC);
+ encryptedTestNew(key, PKCS8Generator.PBE_SHA1_3DES);
+ }
+
+ private void encryptedTestNew(PrivateKey key, ASN1ObjectIdentifier algorithm)
+ throws NoSuchProviderException, NoSuchAlgorithmException, IOException, OperatorCreationException, PKCSException
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ PEMWriter pWrt = new PEMWriter(new OutputStreamWriter(bOut));
+
+ JceOpenSSLPKCS8EncryptorBuilder encryptorBuilder = new JceOpenSSLPKCS8EncryptorBuilder(algorithm);
+
+ encryptorBuilder.setProvider("SC");
+ encryptorBuilder.setPasssword("hello".toCharArray());
+
+ PKCS8Generator pkcs8 = new JcaPKCS8Generator(key, encryptorBuilder.build());
+
+ pWrt.writeObject(pkcs8);
+
+ pWrt.close();
+
+ PEMParser pRd = new PEMParser(new InputStreamReader(new ByteArrayInputStream(bOut.toByteArray())));
+
+ PKCS8EncryptedPrivateKeyInfo pInfo = (PKCS8EncryptedPrivateKeyInfo)pRd.readObject();
+
+ PrivateKey rdKey = new JcaPEMKeyConverter().setProvider("SC").getPrivateKey(pInfo.decryptPrivateKeyInfo(new JceOpenSSLPKCS8DecryptorProviderBuilder().setProvider("SC").build("hello".toCharArray())));
+
+
+ assertEquals(key, rdKey);
+ }
+
+ public void testPKCS8PlainNew()
+ throws Exception
+ {
+ if (Security.getProvider("SC") == null)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "SC");
+
+ kpGen.initialize(1024);
+
+ PrivateKey key = kpGen.generateKeyPair().getPrivate();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ PEMWriter pWrt = new PEMWriter(new OutputStreamWriter(bOut));
+ PKCS8Generator pkcs8 = new JcaPKCS8Generator(key, null);
+
+ pWrt.writeObject(pkcs8);
+
+ pWrt.close();
+
+ PEMParser pRd = new PEMParser(new InputStreamReader(new ByteArrayInputStream(bOut.toByteArray())));
+
+ PrivateKeyInfo kp = (PrivateKeyInfo)pRd.readObject();
+
+ PrivateKey rdKey = new JcaPEMKeyConverter().setProvider("SC").getPrivateKey(kp);
+
+ assertEquals(key, rdKey);
+ }
+
+ public static void main (String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite()
+ {
+ TestSuite suite = new TestSuite("OpenSSL Tests");
+
+ suite.addTestSuite(AllTests.class);
+
+ return suite;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/openssl/test/ParserTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/openssl/test/ParserTest.java
new file mode 100644
index 000000000..94c105a67
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/openssl/test/ParserTest.java
@@ -0,0 +1,500 @@
+package org.spongycastle.openssl.test;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Signature;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.ECNamedCurveTable;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.openssl.PEMDecryptorProvider;
+import org.spongycastle.openssl.PEMEncryptedKeyPair;
+import org.spongycastle.openssl.PEMKeyPair;
+import org.spongycastle.openssl.PEMParser;
+import org.spongycastle.openssl.PEMWriter;
+import org.spongycastle.openssl.PasswordFinder;
+import org.spongycastle.openssl.jcajce.JcaPEMKeyConverter;
+import org.spongycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
+import org.spongycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
+import org.spongycastle.operator.InputDecryptorProvider;
+import org.spongycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
+import org.spongycastle.util.test.SimpleTest;
+
+/**
+ * basic class for reading test.pem - the password is "secret"
+ */
+public class ParserTest
+ extends SimpleTest
+{
+ private static class Password
+ implements PasswordFinder
+ {
+ char[] password;
+
+ Password(
+ char[] word)
+ {
+ this.password = word;
+ }
+
+ public char[] getPassword()
+ {
+ return password;
+ }
+ }
+
+ public String getName()
+ {
+ return "PEMParserTest";
+ }
+
+ private PEMParser openPEMResource(
+ String fileName)
+ {
+ InputStream res = this.getClass().getResourceAsStream(fileName);
+ Reader fRd = new BufferedReader(new InputStreamReader(res));
+ return new PEMParser(fRd);
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ PEMParser pemRd = openPEMResource("test.pem");
+ Object o;
+ PEMKeyPair pemPair;
+ KeyPair pair;
+
+ while ((o = pemRd.readObject()) != null)
+ {
+ if (o instanceof KeyPair)
+ {
+ //pair = (KeyPair)o;
+
+ //System.out.println(pair.getPublic());
+ //System.out.println(pair.getPrivate());
+ }
+ else
+ {
+ //System.out.println(o.toString());
+ }
+ }
+
+ // test bogus lines before begin are ignored.
+ pemRd = openPEMResource("extratest.pem");
+
+ while ((o = pemRd.readObject()) != null)
+ {
+ if (!(o instanceof X509CertificateHolder))
+ {
+ fail("wrong object found");
+ }
+ }
+
+ //
+ // pkcs 7 data
+ //
+ pemRd = openPEMResource("pkcs7.pem");
+ ContentInfo d = (ContentInfo)pemRd.readObject();
+
+ if (!d.getContentType().equals(CMSObjectIdentifiers.envelopedData))
+ {
+ fail("failed envelopedData check");
+ }
+
+ //
+ // ECKey
+ //
+ pemRd = openPEMResource("eckey.pem");
+ ASN1ObjectIdentifier ecOID = (ASN1ObjectIdentifier)pemRd.readObject();
+ X9ECParameters ecSpec = ECNamedCurveTable.getByOID(ecOID);
+
+ if (ecSpec == null)
+ {
+ fail("ecSpec not found for named curve");
+ }
+
+ pemPair = (PEMKeyPair)pemRd.readObject();
+
+ pair = new JcaPEMKeyConverter().setProvider("SC").getKeyPair(pemPair);
+
+ Signature sgr = Signature.getInstance("ECDSA", "SC");
+
+ sgr.initSign(pair.getPrivate());
+
+ byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
+
+ sgr.update(message);
+
+ byte[] sigBytes = sgr.sign();
+
+ sgr.initVerify(pair.getPublic());
+
+ sgr.update(message);
+
+ if (!sgr.verify(sigBytes))
+ {
+ fail("EC verification failed");
+ }
+
+ if (!pair.getPublic().getAlgorithm().equals("ECDSA"))
+ {
+ fail("wrong algorithm name on public got: " + pair.getPublic().getAlgorithm());
+ }
+
+ if (!pair.getPrivate().getAlgorithm().equals("ECDSA"))
+ {
+ fail("wrong algorithm name on private");
+ }
+
+ //
+ // ECKey -- explicit parameters
+ //
+ pemRd = openPEMResource("ecexpparam.pem");
+ ecSpec = (X9ECParameters)pemRd.readObject();
+
+ pemPair = (PEMKeyPair)pemRd.readObject();
+
+ pair = new JcaPEMKeyConverter().setProvider("SC").getKeyPair(pemPair);
+
+ sgr = Signature.getInstance("ECDSA", "SC");
+
+ sgr.initSign(pair.getPrivate());
+
+ message = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
+
+ sgr.update(message);
+
+ sigBytes = sgr.sign();
+
+ sgr.initVerify(pair.getPublic());
+
+ sgr.update(message);
+
+ if (!sgr.verify(sigBytes))
+ {
+ fail("EC verification failed");
+ }
+
+ if (!pair.getPublic().getAlgorithm().equals("ECDSA"))
+ {
+ fail("wrong algorithm name on public got: " + pair.getPublic().getAlgorithm());
+ }
+
+ if (!pair.getPrivate().getAlgorithm().equals("ECDSA"))
+ {
+ fail("wrong algorithm name on private");
+ }
+
+ //
+ // writer/parser test
+ //
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "SC");
+
+ pair = kpGen.generateKeyPair();
+
+ keyPairTest("RSA", pair);
+
+ kpGen = KeyPairGenerator.getInstance("DSA", "SC");
+ kpGen.initialize(512, new SecureRandom());
+ pair = kpGen.generateKeyPair();
+
+ keyPairTest("DSA", pair);
+
+ //
+ // PKCS7
+ //
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ PEMWriter pWrt = new PEMWriter(new OutputStreamWriter(bOut));
+
+ pWrt.writeObject(d);
+
+ pWrt.close();
+
+ pemRd = new PEMParser(new InputStreamReader(new ByteArrayInputStream(bOut.toByteArray())));
+ d = (ContentInfo)pemRd.readObject();
+
+ if (!d.getContentType().equals(CMSObjectIdentifiers.envelopedData))
+ {
+ fail("failed envelopedData recode check");
+ }
+
+
+ // OpenSSL test cases (as embedded resources)
+ doOpenSslDsaTest("unencrypted");
+ doOpenSslRsaTest("unencrypted");
+
+ doOpenSslTests("aes128");
+ doOpenSslTests("aes192");
+ doOpenSslTests("aes256");
+ doOpenSslTests("blowfish");
+ doOpenSslTests("des1");
+ doOpenSslTests("des2");
+ doOpenSslTests("des3");
+ doOpenSslTests("rc2_128");
+
+ doOpenSslDsaTest("rc2_40_cbc");
+ doOpenSslRsaTest("rc2_40_cbc");
+ doOpenSslDsaTest("rc2_64_cbc");
+ doOpenSslRsaTest("rc2_64_cbc");
+
+ doDudPasswordTest("7fd98", 0, "corrupted stream - out of bounds length found");
+ doDudPasswordTest("ef677", 1, "corrupted stream - out of bounds length found");
+ doDudPasswordTest("800ce", 2, "unknown tag 26 encountered");
+ doDudPasswordTest("b6cd8", 3, "DEF length 81 object truncated by 56");
+ doDudPasswordTest("28ce09", 4, "DEF length 110 object truncated by 28");
+ doDudPasswordTest("2ac3b9", 5, "DER length more than 4 bytes: 11");
+ doDudPasswordTest("2cba96", 6, "DEF length 100 object truncated by 35");
+ doDudPasswordTest("2e3354", 7, "DEF length 42 object truncated by 9");
+ doDudPasswordTest("2f4142", 8, "DER length more than 4 bytes: 14");
+ doDudPasswordTest("2fe9bb", 9, "DER length more than 4 bytes: 65");
+ doDudPasswordTest("3ee7a8", 10, "DER length more than 4 bytes: 57");
+ doDudPasswordTest("41af75", 11, "unknown tag 16 encountered");
+ doDudPasswordTest("1704a5", 12, "corrupted stream detected");
+ doDudPasswordTest("1c5822", 13, "unknown object in getInstance: org.spongycastle.asn1.DERUTF8String");
+ doDudPasswordTest("5a3d16", 14, "corrupted stream detected");
+ doDudPasswordTest("8d0c97", 15, "corrupted stream detected");
+ doDudPasswordTest("bc0daf", 16, "corrupted stream detected");
+ doDudPasswordTest("aaf9c4d",17, "corrupted stream - out of bounds length found");
+
+ doNoPasswordTest();
+
+ // encrypted private key test
+ InputDecryptorProvider pkcs8Prov = new JceOpenSSLPKCS8DecryptorProviderBuilder().build("password".toCharArray());
+ pemRd = openPEMResource("enckey.pem");
+
+ PKCS8EncryptedPrivateKeyInfo encPrivKeyInfo = (PKCS8EncryptedPrivateKeyInfo)pemRd.readObject();
+ JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("SC");
+
+ RSAPrivateCrtKey privKey = (RSAPrivateCrtKey)converter.getPrivateKey(encPrivKeyInfo.decryptPrivateKeyInfo(pkcs8Prov));
+
+ if (!privKey.getPublicExponent().equals(new BigInteger("10001", 16)))
+ {
+ fail("decryption of private key data check failed");
+ }
+
+ // general PKCS8 test
+
+ pemRd = openPEMResource("pkcs8test.pem");
+
+ Object privInfo;
+
+ while ((privInfo = pemRd.readObject()) != null)
+ {
+ if (privInfo instanceof PrivateKeyInfo)
+ {
+ privKey = (RSAPrivateCrtKey)converter.getPrivateKey(PrivateKeyInfo.getInstance(privInfo));
+ }
+ else
+ {
+ privKey = (RSAPrivateCrtKey)converter.getPrivateKey(((PKCS8EncryptedPrivateKeyInfo)privInfo).decryptPrivateKeyInfo(pkcs8Prov));
+ }
+ if (!privKey.getPublicExponent().equals(new BigInteger("10001", 16)))
+ {
+ fail("decryption of private key data check failed");
+ }
+ }
+ }
+
+ private void keyPairTest(
+ String name,
+ KeyPair pair)
+ throws IOException
+ {
+ PEMParser pemRd;
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ PEMWriter pWrt = new PEMWriter(new OutputStreamWriter(bOut));
+
+ pWrt.writeObject(pair.getPublic());
+
+ pWrt.close();
+
+ pemRd = new PEMParser(new InputStreamReader(new ByteArrayInputStream(bOut.toByteArray())));
+
+ SubjectPublicKeyInfo pub = SubjectPublicKeyInfo.getInstance(pemRd.readObject());
+ JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("SC");
+
+ PublicKey k = converter.getPublicKey(pub);
+
+ if (!k.equals(pair.getPublic()))
+ {
+ fail("Failed public key read: " + name);
+ }
+
+ bOut = new ByteArrayOutputStream();
+ pWrt = new PEMWriter(new OutputStreamWriter(bOut));
+
+ pWrt.writeObject(pair.getPrivate());
+
+ pWrt.close();
+
+ pemRd = new PEMParser(new InputStreamReader(new ByteArrayInputStream(bOut.toByteArray())));
+
+ KeyPair kPair = converter.getKeyPair((PEMKeyPair)pemRd.readObject());
+ if (!kPair.getPrivate().equals(pair.getPrivate()))
+ {
+ fail("Failed private key read: " + name);
+ }
+
+ if (!kPair.getPublic().equals(pair.getPublic()))
+ {
+ fail("Failed private key public read: " + name);
+ }
+ }
+
+ private void doOpenSslTests(
+ String baseName)
+ throws IOException
+ {
+ doOpenSslDsaModesTest(baseName);
+ doOpenSslRsaModesTest(baseName);
+ }
+
+ private void doOpenSslDsaModesTest(
+ String baseName)
+ throws IOException
+ {
+ doOpenSslDsaTest(baseName + "_cbc");
+ doOpenSslDsaTest(baseName + "_cfb");
+ doOpenSslDsaTest(baseName + "_ecb");
+ doOpenSslDsaTest(baseName + "_ofb");
+ }
+
+ private void doOpenSslRsaModesTest(
+ String baseName)
+ throws IOException
+ {
+ doOpenSslRsaTest(baseName + "_cbc");
+ doOpenSslRsaTest(baseName + "_cfb");
+ doOpenSslRsaTest(baseName + "_ecb");
+ doOpenSslRsaTest(baseName + "_ofb");
+ }
+
+ private void doOpenSslDsaTest(
+ String name)
+ throws IOException
+ {
+ String fileName = "dsa/openssl_dsa_" + name + ".pem";
+
+ doOpenSslTestFile(fileName, DSAPrivateKey.class);
+ }
+
+ private void doOpenSslRsaTest(
+ String name)
+ throws IOException
+ {
+ String fileName = "rsa/openssl_rsa_" + name + ".pem";
+
+ doOpenSslTestFile(fileName, RSAPrivateKey.class);
+ }
+
+ private void doOpenSslTestFile(
+ String fileName,
+ Class expectedPrivKeyClass)
+ throws IOException
+ {
+ JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("SC");
+ PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().setProvider("SC").build("changeit".toCharArray());
+ PEMParser pr = openPEMResource("data/" + fileName);
+ Object o = pr.readObject();
+
+ if (o == null || !((o instanceof PEMKeyPair) || (o instanceof PEMEncryptedKeyPair)))
+ {
+ fail("Didn't find OpenSSL key");
+ }
+
+ KeyPair kp = (o instanceof PEMEncryptedKeyPair) ?
+ converter.getKeyPair(((PEMEncryptedKeyPair)o).decryptKeyPair(decProv)) : converter.getKeyPair((PEMKeyPair)o);
+
+ PrivateKey privKey = kp.getPrivate();
+
+ if (!expectedPrivKeyClass.isInstance(privKey))
+ {
+ fail("Returned key not of correct type");
+ }
+ }
+
+ private void doDudPasswordTest(String password, int index, String message)
+ {
+ // illegal state exception check - in this case the wrong password will
+ // cause an underlying class cast exception.
+ try
+ {
+ PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().setProvider("SC").build(password.toCharArray());
+
+ PEMParser pemRd = openPEMResource("test.pem");
+ Object o;
+
+ while ((o = pemRd.readObject()) != null)
+ {
+ if (o instanceof PEMEncryptedKeyPair)
+ {
+ ((PEMEncryptedKeyPair)o).decryptKeyPair(decProv);
+ }
+ }
+
+ fail("issue not detected: " + index);
+ }
+ catch (IOException e)
+ {
+ if (e.getCause() != null && !e.getCause().getMessage().endsWith(message))
+ {
+ fail("issue " + index + " exception thrown, but wrong message");
+ }
+ else if (e.getCause() == null && !e.getMessage().equals(message))
+ {
+ e.printStackTrace();
+ fail("issue " + index + " exception thrown, but wrong message");
+ }
+ }
+ }
+
+ private void doNoPasswordTest()
+ throws IOException
+ {
+ PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().setProvider("SC").build("".toCharArray());
+
+ PEMParser pemRd = openPEMResource("smimenopw.pem");
+ Object o;
+ PrivateKeyInfo key = null;
+
+ while ((o = pemRd.readObject()) != null)
+ {
+ key = (PrivateKeyInfo)o;
+ }
+
+ if (key == null)
+ {
+ fail("private key not detected");
+ }
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new ParserTest());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/openssl/test/WriterTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/openssl/test/WriterTest.java
new file mode 100644
index 000000000..ac67e6a0b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/openssl/test/WriterTest.java
@@ -0,0 +1,248 @@
+package org.spongycastle.openssl.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.util.List;
+
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.openssl.PEMEncryptedKeyPair;
+import org.spongycastle.openssl.PEMKeyPair;
+import org.spongycastle.openssl.PEMParser;
+import org.spongycastle.openssl.PEMWriter;
+import org.spongycastle.openssl.PasswordFinder;
+import org.spongycastle.openssl.jcajce.JcaMiscPEMGenerator;
+import org.spongycastle.openssl.jcajce.JcaPEMKeyConverter;
+import org.spongycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
+import org.spongycastle.openssl.jcajce.JcePEMEncryptorBuilder;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.io.pem.PemHeader;
+import org.spongycastle.util.io.pem.PemObject;
+import org.spongycastle.util.test.SimpleTest;
+
+public class WriterTest
+ extends SimpleTest
+{
+ private static final SecureRandom random = new SecureRandom();
+
+ // TODO Replace with a randomly generated key each test run?
+ private static final RSAPrivateCrtKeySpec testRsaKeySpec = 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));
+
+ private static final DSAParameterSpec testDsaParams = new DSAParameterSpec(
+ new BigInteger("7434410770759874867539421675728577177024889699586189000788950934679315164676852047058354758883833299702695428196962057871264685291775577130504050839126673"),
+ new BigInteger("1138656671590261728308283492178581223478058193247"),
+ new BigInteger("4182906737723181805517018315469082619513954319976782448649747742951189003482834321192692620856488639629011570381138542789803819092529658402611668375788410"));
+
+ private static final PKCS8EncodedKeySpec testEcDsaKeySpec = new PKCS8EncodedKeySpec(
+ Base64.decode("MIG/AgEAMBAGByqGSM49AgEGBSuBBAAiBIGnMIGkAgEBBDCSBU3vo7ieeKs0ABQamy/ynxlde7Ylr8HmyfLaNnMr" +
+ "jAwPp9R+KMUEhB7zxSAXv9KgBwYFK4EEACKhZANiAQQyyolMpg+TyB4o9kPWqafHIOe8o9K1glus+w2sY8OIPQQWGb5i5LdAyi" +
+ "/SscwU24rZM0yiL3BHodp9ccwyhLrFYgXJUOQcCN2dno1GMols5497in5gL5+zn0yMsRtyv5o=")
+ );
+
+ private static final char[] testPassword = "bouncy".toCharArray();
+
+ private static final String[] algorithms = new String[]
+ {
+ "AES-128-CBC", "AES-128-CFB", "AES-128-ECB", "AES-128-OFB",
+ "AES-192-CBC", "AES-192-CFB", "AES-192-ECB", "AES-192-OFB",
+ "AES-256-CBC", "AES-256-CFB", "AES-256-ECB", "AES-256-OFB",
+ "BF-CBC", "BF-CFB", "BF-ECB", "BF-OFB",
+ "DES-CBC", "DES-CFB", "DES-ECB", "DES-OFB",
+ "DES-EDE", "DES-EDE-CBC", "DES-EDE-CFB", "DES-EDE-ECB", "DES-EDE-OFB",
+ "DES-EDE3", "DES-EDE3-CBC", "DES-EDE3-CFB", "DES-EDE3-ECB", "DES-EDE3-OFB",
+ "RC2-CBC", "RC2-CFB", "RC2-ECB", "RC2-OFB",
+ "RC2-40-CBC",
+ "RC2-64-CBC",
+ };
+
+ private class Password
+ implements PasswordFinder
+ {
+ private final char[] password;
+
+ public Password(
+ char[] word)
+ {
+ this.password = (char[]) word.clone();
+ }
+
+ public char[] getPassword()
+ {
+ return (char[]) password.clone();
+ }
+ }
+
+ public String getName()
+ {
+ return "PEMWriterTest";
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ final String provider = "SC";
+
+ KeyPairGenerator dsaKpg = KeyPairGenerator.getInstance("DSA", provider);
+ dsaKpg.initialize(testDsaParams, random);
+
+ KeyPair dsaKp = dsaKpg.generateKeyPair();
+ PrivateKey testDsaKey = dsaKp.getPrivate();
+
+ doWriteReadTest(testDsaKey, provider);
+ doWriteReadTests(testDsaKey, provider, algorithms);
+
+ KeyFactory fact = KeyFactory.getInstance("RSA", provider);
+ PrivateKey testRsaKey = fact.generatePrivate(testRsaKeySpec);
+
+ doWriteReadTest(testRsaKey, provider);
+ doWriteReadTests(testRsaKey, provider, algorithms);
+
+ fact = KeyFactory.getInstance("ECDSA", provider);
+ PrivateKey testEcDsaKey = fact.generatePrivate(testEcDsaKeySpec);
+
+ doWriteReadTest(testEcDsaKey, provider);
+ doWriteReadTests(testEcDsaKey, provider, algorithms);
+
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("ECDSA", "SC");
+
+ kpGen.initialize(239);
+
+ PrivateKey privKey = kpGen.generateKeyPair().getPrivate();
+
+ doWriteReadTest(privKey, provider);
+ doWriteReadTests(privKey, "SC", algorithms);
+
+ // override test
+ PEMWriter pWrt = new PEMWriter(new OutputStreamWriter(new ByteArrayOutputStream()));
+
+ Object o = new PemObject("FRED", new byte[100]);
+ pWrt.writeObject(o);
+
+ pWrt.close();
+ }
+
+ private void doWriteReadTests(
+ PrivateKey akp,
+ String provider,
+ String[] algorithms)
+ throws IOException
+ {
+ for (int i = 0; i < algorithms.length; ++i)
+ {
+ doWriteReadTest(akp, provider, algorithms[i]);
+ }
+ }
+
+ private void doWriteReadTest(
+ PrivateKey akp,
+ String provider)
+ throws IOException
+ {
+ StringWriter sw = new StringWriter();
+ PEMWriter pw = new PEMWriter(sw);
+
+ pw.writeObject(akp);
+ pw.close();
+
+ String data = sw.toString();
+
+ PEMParser pr = new PEMParser(new StringReader(data));
+
+ Object o = pr.readObject();
+
+ if (o == null || !(o instanceof PEMKeyPair))
+ {
+ fail("Didn't find OpenSSL key");
+ }
+
+ KeyPair kp = new JcaPEMKeyConverter().setProvider("SC").getKeyPair((PEMKeyPair)o);
+ PrivateKey privKey = kp.getPrivate();
+
+ if (!akp.equals(privKey))
+ {
+ fail("Failed to read back test");
+ }
+ }
+
+ private void doWriteReadTest(
+ PrivateKey akp,
+ String provider,
+ String algorithm)
+ throws IOException
+ {
+ StringWriter sw = new StringWriter();
+ PEMWriter pw = new PEMWriter(sw);
+
+ pw.writeObject(new JcaMiscPEMGenerator(akp, new JcePEMEncryptorBuilder(algorithm).setSecureRandom(random).build(testPassword)));
+ pw.close();
+
+ String data = sw.toString();
+
+ PEMParser pRaw = new PEMParser(new StringReader(data));
+ PemObject pemObject = pRaw.readPemObject();
+
+ List headers = pemObject.getHeaders();
+
+ for (int i = 0; i != headers.size(); i++)
+ {
+ PemHeader pemH = (PemHeader)headers.get(i);
+
+ if (pemH.getName().equals("DEK-Info"))
+ {
+ String v = pemH.getValue();
+ for (int j = 0; j != v.length(); j++)
+ {
+ if (v.charAt(j) >= 'a' && v.charAt(j) <= 'f')
+ {
+ fail("lower case detected in DEK-Info: " + v);
+ }
+ }
+ }
+ }
+
+ PEMParser pr = new PEMParser(new StringReader(data));
+
+ Object o = pr.readObject();
+
+ if (o == null || !(o instanceof PEMEncryptedKeyPair))
+ {
+ fail("Didn't find OpenSSL key");
+ }
+
+ KeyPair kp = new JcaPEMKeyConverter().setProvider("SC").getKeyPair(((PEMEncryptedKeyPair)o).decryptKeyPair(new JcePEMDecryptorProviderBuilder().setProvider("SC").build(testPassword)));
+ PrivateKey privKey = kp.getPrivate();
+
+ if (!akp.equals(privKey))
+ {
+ fail("Failed to read back test key encoded with: " + algorithm);
+ }
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new WriterTest());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/pkcs/test/AllTests.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/pkcs/test/AllTests.java
new file mode 100644
index 000000000..6751bfa48
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/pkcs/test/AllTests.java
@@ -0,0 +1,24 @@
+package org.spongycastle.pkcs.test;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+public class AllTests
+ extends TestCase
+{
+ public static void main (String[] args)
+ {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite()
+ {
+ TestSuite suite = new TestSuite("PKCS Tests");
+
+ suite.addTestSuite(PfxPduTest.class);
+ suite.addTestSuite(PKCS10Test.class);
+
+ return new BCTestSetup(suite);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/pkcs/test/BCTestSetup.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/pkcs/test/BCTestSetup.java
new file mode 100644
index 000000000..c73d568f0
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/pkcs/test/BCTestSetup.java
@@ -0,0 +1,26 @@
+// Copyright (c) 2005 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
+package org.spongycastle.pkcs.test;
+
+import java.security.Security;
+
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+
+class BCTestSetup
+ extends TestSetup
+{
+ public BCTestSetup(Test test)
+ {
+ super(test);
+ }
+
+ protected void setUp()
+ {
+ Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider());
+ }
+
+ protected void tearDown()
+ {
+ Security.removeProvider("SC");
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/pkcs/test/PKCS10Test.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/pkcs/test/PKCS10Test.java
new file mode 100644
index 000000000..de50acbc1
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/pkcs/test/PKCS10Test.java
@@ -0,0 +1,78 @@
+package org.spongycastle.pkcs.test;
+
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.pkcs.CertificationRequest;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.pkcs.PKCS10CertificationRequest;
+import org.spongycastle.pkcs.PKCS10CertificationRequestBuilder;
+import org.spongycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
+
+public class PKCS10Test
+ extends TestCase
+{
+ //
+ // personal keys
+ //
+ private static final RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ private static final 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));
+
+ public void testLeaveOffEmpty()
+ throws Exception
+ {
+ KeyFactory keyFact = KeyFactory.getInstance("RSA", "SC");
+ PublicKey pubKey = keyFact.generatePublic(pubKeySpec);
+ PrivateKey privKey = keyFact.generatePrivate(privKeySpec);
+
+ PKCS10CertificationRequestBuilder pkcs10Builder = new JcaPKCS10CertificationRequestBuilder(new X500Name("CN=Test"), pubKey);
+
+ PKCS10CertificationRequest request = pkcs10Builder.build(new JcaContentSignerBuilder("SHA1withRSA").setProvider("SC").build(privKey));
+
+ assertEquals(0, request.getAttributes().length);
+ assertNotNull(CertificationRequest.getInstance(request.getEncoded()).getCertificationRequestInfo().getAttributes());
+
+ pkcs10Builder.setLeaveOffEmptyAttributes(true);
+
+ request = pkcs10Builder.build(new JcaContentSignerBuilder("SHA1withRSA").setProvider("SC").build(privKey));
+
+ assertEquals(0, request.getAttributes().length);
+ assertNull(CertificationRequest.getInstance(request.getEncoded()).getCertificationRequestInfo().getAttributes());
+
+ pkcs10Builder.setLeaveOffEmptyAttributes(false);
+
+ request = pkcs10Builder.build(new JcaContentSignerBuilder("SHA1withRSA").setProvider("SC").build(privKey));
+
+ assertEquals(0, request.getAttributes().length);
+ assertNotNull(CertificationRequest.getInstance(request.getEncoded()).getCertificationRequestInfo().getAttributes());
+ }
+
+ public static void main(String args[])
+ {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite()
+ {
+ return new BCTestSetup(new TestSuite(PKCS10Test.class));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/pkcs/test/PfxPduTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/pkcs/test/PfxPduTest.java
new file mode 100644
index 000000000..dfb971a9b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/pkcs/test/PfxPduTest.java
@@ -0,0 +1,1255 @@
+package org.spongycastle.pkcs.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.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 junit.framework.TestCase;
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.DERBMPString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.Attribute;
+import org.spongycastle.asn1.pkcs.ContentInfo;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.X500NameBuilder;
+import org.spongycastle.asn1.x500.style.BCStyle;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509v1CertificateBuilder;
+import org.spongycastle.cert.X509v3CertificateBuilder;
+import org.spongycastle.cert.jcajce.JcaX500NameUtil;
+import org.spongycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.spongycastle.cert.jcajce.JcaX509ExtensionUtils;
+import org.spongycastle.cert.jcajce.JcaX509v1CertificateBuilder;
+import org.spongycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.spongycastle.crypto.engines.DESedeEngine;
+import org.spongycastle.crypto.engines.RC2Engine;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.InputDecryptorProvider;
+import org.spongycastle.operator.OutputEncryptor;
+import org.spongycastle.operator.bc.BcDefaultDigestProvider;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.pkcs.PKCS12PfxPdu;
+import org.spongycastle.pkcs.PKCS12PfxPduBuilder;
+import org.spongycastle.pkcs.PKCS12SafeBag;
+import org.spongycastle.pkcs.PKCS12SafeBagBuilder;
+import org.spongycastle.pkcs.PKCS12SafeBagFactory;
+import org.spongycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
+import org.spongycastle.pkcs.PKCS8EncryptedPrivateKeyInfoBuilder;
+import org.spongycastle.pkcs.PKCSException;
+import org.spongycastle.pkcs.bc.BcPKCS12MacCalculatorBuilder;
+import org.spongycastle.pkcs.bc.BcPKCS12MacCalculatorBuilderProvider;
+import org.spongycastle.pkcs.bc.BcPKCS12PBEInputDecryptorProviderBuilder;
+import org.spongycastle.pkcs.bc.BcPKCS12PBEOutputEncryptorBuilder;
+import org.spongycastle.pkcs.jcajce.JcaPKCS12SafeBagBuilder;
+import org.spongycastle.pkcs.jcajce.JcaPKCS8EncryptedPrivateKeyInfoBuilder;
+import org.spongycastle.pkcs.jcajce.JcePKCS12MacCalculatorBuilder;
+import org.spongycastle.pkcs.jcajce.JcePKCS12MacCalculatorBuilderProvider;
+import org.spongycastle.pkcs.jcajce.JcePKCSPBEInputDecryptorProviderBuilder;
+import org.spongycastle.pkcs.jcajce.JcePKCSPBEOutputEncryptorBuilder;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.encoders.Base64;
+
+public class PfxPduTest
+ extends TestCase
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+ private static final char[] passwd = {'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'};
+
+ //
+ // personal keys
+ //
+ private static final RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ private static final 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.
+ //
+ private static final RSAPublicKeySpec intPubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("8de0d113c5e736969c8d2b047a243f8fe18edad64cde9e842d3669230ca486f7cfdde1f8eec54d1905fff04acc85e61093e180cadc6cea407f193d44bb0e9449b8dbb49784cd9e36260c39e06a947299978c6ed8300724e887198cfede20f3fbde658fa2bd078be946a392bd349f2b49c486e20c405588e306706c9017308e69", 16),
+ new BigInteger("ffff", 16));
+
+
+ private static final 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
+ //
+ private static final RSAPublicKeySpec caPubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16),
+ new BigInteger("11", 16));
+
+ private static final 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));
+
+ //
+ // pkcs-12 pfx-pdu
+ //
+ private String pkcs12Pass = "hello world";
+
+ private byte[] pkcs12 = Base64.decode(
+ "MIACAQMwgAYJKoZIhvcNAQcBoIAkgAQBMAQBgAQBMAQBgAQBBgQBCQQJKoZI"
+ + "hvcNAQcBBAGgBAGABAEkBAGABAEEBAEBBAEwBAEEBAEDBAOCAzQEAQQEAQEE"
+ + "ATAEAQQEAQMEA4IDMAQBBAQBAQQBBgQBBAQBAQQBCwQBBAQBCwQLKoZIhvcN"
+ + "AQwKAQIEAQQEAQEEAaAEAQQEAQMEA4ICpQQBBAQBAQQBMAQBBAQBAwQDggKh"
+ + "BAEEBAEBBAEwBAEEBAEBBAEbBAEEBAEBBAEGBAEEBAEBBAEKBAEEBAEKBAoq"
+ + "hkiG9w0BDAEDBAEEBAEPBA8wDQQIoagiwNZPJR4CAQEEAQQEAQEEAQQEAQQE"
+ + "AQMEA4ICgAQBBAQDggKABIICgEPG0XlhMFyrs4ZWDrvEzl51ICfXd6K2ql2l"
+ + "nnxhszUbigtSj6x49VEx4PfOB9fQFeidc5L5An+nKp646NBMIY0UwXGs8BLQ"
+ + "au59jtOs987+l7QYIvl6fdGUIuLPhVSnZZDyqD+HQjU/0/ccKFHRif4tlEQq"
+ + "aErvZbFeH0pg4ijf1HfgX6gBJGRKdO+msa4qKGnZdHCSLZehyyxvxAmURetg"
+ + "yhtEl7RmedTB+4TDs7atekqxkNlD9tfwDUX6sb0IH6qbEA6P/DlVMdaD54Cl"
+ + "QDxRzOfIIjklZhv5OMFWtPK0aYPcqyxzLpw1qRAyoTVXpidkj/hpIpgCVBP/"
+ + "k5s2+WdGbLgA/4/zSrF6feRCE5llzM2IGxiHVq4oPzzngl3R+Fi5VCPDMcuW"
+ + "NRuIOzJA+RNV2NPOE/P3knThDnwiImq+rfxmvZ1u6T06s20RmWK6cxp7fTEw"
+ + "lQ9BOsv+mmyV8dr6cYJq4IlRzHdFOyEUBDwfHThyribNKKobO50xh2f93xYj"
+ + "Rn5UMOQBJIe3b7OKZt5HOIMrJSZO02IZgvImi9yQWi96PnWa419D1cAsLWvM"
+ + "xiN0HqZMbDFfxVM2BZmsxiexLhkHWKwLqfQDzRjJfmVww8fnXpWZhFXKyut9"
+ + "gMGEyCNoba4RU3QI/wHKWYaK74qtJpsucuLWBH6UcsHsCry6VZkwRxWwC0lb"
+ + "/F3Bm5UKHax5n9JHJ2amQm9zW3WJ0S5stpPObfmg5ArhbPY+pVOsTqBRlop1"
+ + "bYJLD/X8Qbs468Bwzej0FhoEU59ZxFrbjLSBsMUYrVrwD83JE9kEazMLVchc"
+ + "uCB9WT1g0hxYb7VA0BhOrWhL8F5ZH72RMCYLPI0EAQQEAQEEATEEAQQEAQEE"
+ + "AXgEAQQEAQEEATAEAQQEAQEEAVEEAQQEAQEEAQYEAQQEAQEEAQkEAQQEAQkE"
+ + "CSqGSIb3DQEJFAQBBAQBAQQBMQQBBAQBAQQBRAQBBAQBAQQBHgQBBAQBAQQB"
+ + "QgQBBAQBQgRCAEQAYQB2AGkAZAAgAEcALgAgAEgAbwBvAGsAJwBzACAAVgBl"
+ + "AHIAaQBTAGkAZwBuACwAIABJAG4AYwAuACAASQBEBAEEBAEBBAEwBAEEBAEB"
+ + "BAEjBAEEBAEBBAEGBAEEBAEBBAEJBAEEBAEJBAkqhkiG9w0BCRUEAQQEAQEE"
+ + "ATEEAQQEAQEEARYEAQQEAQEEAQQEAQQEAQEEARQEAQQEARQEFKEcMJ798oZL"
+ + "FkH0OnpbUBnrTLgWBAIAAAQCAAAEAgAABAEwBAGABAEGBAEJBAkqhkiG9w0B"
+ + "BwYEAaAEAYAEATAEAYAEAQIEAQEEAQAEATAEAYAEAQYEAQkECSqGSIb3DQEH"
+ + "AQQBMAQBGwQBBgQBCgQKKoZIhvcNAQwBBgQPMA0ECEE7euvmxxwYAgEBBAGg"
+ + "BAGABAEEBAEIBAgQIWDGlBWxnwQBBAQBCAQI2WsMhavhSCcEAQQEAQgECPol"
+ + "uHJy9bm/BAEEBAEQBBCiRxtllKXkJS2anKD2q3FHBAEEBAEIBAjKy6BRFysf"
+ + "7gQBBAQDggMwBIIDMJWRGu2ZLZild3oz7UBdpBDUVMOA6eSoWiRIfVTo4++l"
+ + "RUBm8TpmmGrVkV32PEoLkoV+reqlyWCvqqSjRzi3epQiVwPQ6PV+ccLqxDhV"
+ + "pGWDRQ5UttDBC2+u4fUQVZi2Z1i1g2tsk6SzB3MKUCrjoWKvaDUUwXo5k9Vz"
+ + "qSLWCLTZCjs3RaY+jg3NbLZYtfMDdYovhCU2jMYV9adJ8MxxmJRz+zPWAJph"
+ + "LH8hhfkKG+wJOSszqk9BqGZUa/mnZyzeQSMTEFga1ZB/kt2e8SZFWrTZEBgJ"
+ + "oszsL5MObbwMDowNurnZsnS+Mf7xi01LeG0VT1fjd6rn9BzVwuMwhoqyoCNo"
+ + "ziUqSUyLEwnGTYYpvXLxzhNiYzW8546KdoEKDkEjhfYsc4XqSjm9NYy/BW/M"
+ + "qR+aL92j8hqnkrWkrWyvocUe3mWaiqt7/oOzNZiMTcV2dgjjh9HfnjSHjFGe"
+ + "CVhnEWzV7dQIVyc/qvNzOuND8X5IyJ28xb6a/i1vScwGuo/UDgPAaMjGw28f"
+ + "siOZBShzde0Kj82y8NilfYLHHeIGRW+N/grUFWhW25mAcBReXDd5JwOqM/eF"
+ + "y+4+zBzlO84ws88T1pkSifwtMldglN0APwr4hvUH0swfiqQOWtwyeM4t+bHd"
+ + "5buAlXOkSeF5rrLzZ2/Lx+JJmI2pJ/CQx3ej3bxPlx/BmarUGAxaI4le5go4"
+ + "KNfs4GV8U+dbEHQz+yDYL+ksYNs1eb+DjI2khbl28jhoeAFKBtu2gGOL5M9M"
+ + "CIP/JDOCHimu1YZRuOTAf6WISnG/0Ri3pYZsgQ0i4cXj+WfYwYVjhKX5AcDj"
+ + "UKnc4/Cxp+TbbgZqEKRcYVb2q0kOAxkeaNo3WCm+qvUYrwAmKp4nVB+/24rK"
+ + "khHiyYJQsETxtOEyvJkVxAS01djY4amuJ4jL0sYnXIhW3Ag93eavbzksGT7W"
+ + "Fg1ywpr1x1xpXWIIuVt1k4e+g9fy7Yx7rx0IK1qCSjNwU3QPWbaef1rp0Q/X"
+ + "P9IVXYkqo1g/T3SyXqrbZLO+sDjiG4IT3z3fJJqt81sRSVT0QN1ND8l93BG4"
+ + "QKzghYw8sZ4FwKPtLky1dDcVTgQBBAQBCAQIK/85VMKWDWYEAQQEAQgECGsO"
+ + "Q85CcFwPBAEEBAEIBAhaup6ot9XnQAQBBAQCgaAEgaCeCMadSm5fkLfhErYQ"
+ + "DgePZl/rrjP9FQ3VJZ13XrjTSjTRknAbXi0DEu2tvAbmCf0sdoVNuZIZ92W0"
+ + "iyaa2/A3RHA2RLPNQz5meTi1RE2N361yR0q181dC3ztkkJ8PLyd74nCtgPUX"
+ + "0JlsvLRrdSjPBpBQ14GiM8VjqeIY7EVFy3vte6IbPzodxaviuSc70iXM4Yko"
+ + "fQq6oaSjNBFRqkHrBAEEBAEIBAjlIvOf8SnfugQBBAQBCAQIutCF3Jovvl0E"
+ + "AQQEAQgECO7jxbucdp/3BAEEBAEIBAidxK3XDLj+BwQBBAQBCAQI3m/HMbd3"
+ + "TwwEAQQEA4ICOASCAjgtoCiMfTkjpCRuMhF5gNLRBiNv+xjg6GvZftR12qiJ"
+ + "dLeCERI5bvXbh9GD6U+DjTUfhEab/37TbiI7VOFzsI/R137sYy9Tbnu7qkSx"
+ + "u0bTvyXSSmio6sMRiWIcakmDbv+TDWR/xgtj7+7C6p+1jfUGXn/RjB3vlyjL"
+ + "Q9lFe5F84qkZjnADo66p9gor2a48fgGm/nkABIUeyzFWCiTp9v6FEzuBfeuP"
+ + "T9qoKSnCitaXRCru5qekF6L5LJHLNXLtIMSrbO0bS3hZK58FZAUVMaqawesJ"
+ + "e/sVfQip9x/aFQ6U3KlSpJkmZK4TAqp9jIfxBC8CclbuwmoXPMomiCH57ykr"
+ + "vkFHOGcxRcCxax5HySCwSyPDr8I4+6Kocty61i/1Xr4xJjb+3oyFStIpB24x"
+ + "+ALb0Mz6mUa1ls76o+iQv0VM2YFwnx+TC8KC1+O4cNOE/gKeh0ircenVX83h"
+ + "GNez8C5Ltg81g6p9HqZPc2pkwsneX2sJ4jMsjDhewV7TyyS3x3Uy3vTpZPek"
+ + "VdjYeVIcgAz8VLJOpsIjyHMB57AyT7Yj87hVVy//VODnE1T88tRXZb+D+fCg"
+ + "lj2weQ/bZtFzDX0ReiEQP6+yklGah59omeklIy9wctGV1o9GNZnGBSLvQ5NI"
+ + "61e9zmQTJD2iDjihvQA/6+edKswCjGRX6rMjRWXT5Jv436l75DVoUj09tgR9"
+ + "ytXSathCjQUL9MNXzUMtr7mgEUPETjM/kYBR7CNrsc+gWTWHYaSWuqKVBAEE"
+ + "BAEIBAh6slfZ6iqkqwQBBAQBCAQI9McJKl5a+UwEAQQEATgEOBelrmiYMay3"
+ + "q0OW2x2a8QQodYqdUs1TCUU4JhfFGFRy+g3yU1cP/9ZSI8gcI4skdPc31cFG"
+ + "grP7BAEEBAEIBAhzv/wSV+RBJQQBBAQBCAQI837ImVqqlr4EAQQEAQgECGeU"
+ + "gjULLnylBAEEBAEIBAjD3P4hlSBCvQQBBAQBCAQISP/qivIzf50EAQQEAQgE"
+ + "CKIDMX9PKxICBAEEBAOCBOgEggTocP5VVT1vWvpAV6koZupKN1btJ3C01dR6"
+ + "16g1zJ5FK5xL1PTdA0r6iAwVtgYdxQYnU8tht3bkNXdPJC1BdsC9oTkBg9Nr"
+ + "dqlF5cCzXWIezcR3ObjGLpXu49SAHvChH4emT5rytv81MYxZ7bGmlQfp8BNa"
+ + "0cMZz05A56LXw//WWDEzZcbKSk4tCsfMXBdGk/ngs7aILZ4FGM620PBPtD92"
+ + "pz2Ui/tUZqtQ0WKdLzwga1E/rl02a/x78/OdlVRNeaIYWJWLmLavX98w0PhY"
+ + "ha3Tbj/fqq+H3ua6Vv2Ff4VeXazkXpp4tTiqUxhc6aAGiRYckwZaP7OPSbos"
+ + "RKFlRLVofSGu1IVSKO+7faxV4IrVaAAzqRwLGkpJZLV7NkzkU1BwgvsAZAI4"
+ + "WClPDF228ygbhLwrSN2NK0s+5bKhTCNAR/LCUf3k7uip3ZSe18IwEkUMWiaZ"
+ + "ayktcTYn2ZjmfIfV7wIxHgWPkP1DeB+RMS7VZe9zEgJKOA16L+9SNBwJSSs9"
+ + "5Sb1+nmhquZmnAltsXMgwOrR12JLIgdfyyqGcNq997U0/KuHybqBVDVu0Fyr"
+ + "6O+q5oRmQZq6rju7h+Hb/ZUqRxRoTTSPjGD4Cu9vUqkoNVgwYOT+88FIMYun"
+ + "g9eChhio2kwPYwU/9BNGGzh+hAvAKcUpO016mGLImYin+FpQxodJXfpNCFpG"
+ + "4v4HhIwKh71OOfL6ocM/518dYwuU4Ds2/JrDhYYFsn+KprLftjrnTBnSsfYS"
+ + "t68b+Xr16qv9r6sseEkXbsaNbrGiZAhfHEVBOxQ4lchHrMp4zpduxG4crmpc"
+ + "+Jy4SadvS0uaJvADgI03DpsDYffUdriECUqAfOg/Hr7HHyr6Q9XMo1GfIarz"
+ + "eUHBgi1Ny0nDTWkdb7I3bIajG+Unr3KfK6dZz5Lb3g5NeclU5zintB1045Jr"
+ + "j9fvGGk0/2lG0n17QViBiOzGs2poTlhn7YxmiskwlkRKVafxPZNPxKILpN9s"
+ + "YaWGz93qER/pGMJarGJxu8sFi3+yt6FZ4pVPkvKE8JZMEPBBrmH41batS3sw"
+ + "sfnJ5CicAkwd8bluQpoc6qQd81HdNpS6u7djaRSDwPtYnZWu/8Hhj4DXisje"
+ + "FJBAjQdn2nK4MV7WKVwr+mNcVgOdc5IuOZbRLOfc3Sff6kYVuQFfcCGgAFpd"
+ + "nbprF/FnYXR/rghWE7fT1gfzSMNv+z5UjZ5Rtg1S/IQfUM/P7t0UqQ01/w58"
+ + "bTlMGihTxHiJ4Qf3o5GUzNmAyryLvID+nOFqxpr5es6kqSN4GPRHsmUIpB9t"
+ + "f9Nw952vhsXI9uVkhQap3JvmdAKJaIyDz6Qi7JBZvhxpghVIDh73BQTaAFP9"
+ + "5GUcPbYOYJzKaU5MeYEsorGoanSqPDeKDeZxjxJD4xFsqJCoutyssqIxnXUN"
+ + "Y3Uojbz26IJOhqIBLaUn6QVFX79buWYjJ5ZkDS7D8kq6DZeqZclt5711AO5U"
+ + "uz/eDSrx3d4iVHR+kSeopxFKsrK+KCH3CbBUMIFGX/GE9WPhDWCtjjNKEe8W"
+ + "PinQtxvv8MlqGXtv3v7ObJ2BmfIfLD0rh3EB5WuRNKL7Ssxaq14KZGEBvc7G"
+ + "Fx7jXLOW6ZV3SH+C3deJGlKM2kVhDdIVjjODvQzD8qw8a/ZKqDO5hGGKUTGD"
+ + "Psdd7O/k/Wfn+XdE+YuKIhcEAQQEAQgECJJCZNJdIshRBAEEBAEIBAiGGrlG"
+ + "HlKwrAQBBAQBCAQIkdvKinJYjJcEAQQEAUAEQBGiIgN/s1bvPQr+p1aQNh/X"
+ + "UQFmay6Vm5HIvPhoNrX86gmMjr6/sg28/WCRtSfyuYjwQkK91n7MwFLOBaU3"
+ + "RrsEAQQEAQgECLRqESFR50+zBAEEBAEIBAguqbAEWMTiPwQBBAQBGAQYKzUv"
+ + "EetQEAe3cXEGlSsY4a/MNTbzu1WbBAEEBAEIBAiVpOv1dOWZ1AQCAAAEAgAA"
+ + "BAIAAAQCAAAEAgAABAIAAAAAAAAAADA1MCEwCQYFKw4DAhoFAAQUvMkeVqe6"
+ + "D4UmMHGEQwcb8O7ZwhgEEGiX9DeqtRwQnVi+iY/6Re8AAA==");
+
+ private String sha256Pass = "D317F8D5191F2602C527F8E6E0E8855C4517EC9512F7A06A7A588ACF0B3A6325";
+
+ private byte[] sha256Pfx = Base64.decode(
+ "MIIFvwIBAzCCBXEGCSqGSIb3DQEHAaCCBWIEggVeMIIFWjCCBVYGCSqGSIb3"
+ + "DQEHAaCCBUcEggVDMIIFPzCCBTsGCyqGSIb3DQEMCgECoIIFKjCCBSYwUAYJ"
+ + "KoZIhvcNAQUNMEMwIgYJKoZIhvcNAQUMMBUEEFEZik5RaSrwXtrWCnaLzAQC"
+ + "AQEwHQYJYIZIAWUDBAEqBBBTqY5oFOjZxnBBtWchzf0TBIIE0Pcvwtwthm8d"
+ + "yR16f5yqtofxGzJ0aAbCF7JJ+XsL9QhNuqndTtnXits+E2WgNwwm24XyRhPA"
+ + "obAwqz+DvH+gdUbKoN/gCEp+/6xhlwMQZyjyqi5ePznwLQ/bJueqmXZDT+pO"
+ + "zTIeMXMF0YaSjcZZ4FJnZtBX7XQDEAPmialrknhcSZI5RoLjOzFv51FgYd9+"
+ + "nWdtWlRINS9LrGCVL+y8wwHp55tWEoCR2/o9YWFMYNrUkVUUzImHCN1fkbIH"
+ + "XQxPp5fUqP00kwYY4288JZrzHGWGmSVYm54ok5YRLpCs0yhB0ve//iH/fNNO"
+ + "esShfBTUcRCc086skxgoCVWBZERyVJHWkKl/Q4RVzYt70k2/Qfq/xBNwVCrw"
+ + "YiOB0TwSQJKpvRbtufPx2vODfAmhIKes08ZLJHsMJ+O3p99O2rWZslNY7nfx"
+ + "1vWXYLVkHg0q79ThgbP4p0qQQziIVZoF9ViisJTJWzZbfJLdaKPeHcduvXsR"
+ + "lRvfEpR6/lifcxvkloxjpYtM6JEjtvT1x442VRKJWZofkjCohpLSmEDt77FM"
+ + "ENvra7B9ojlY+0DkwNV34FlSRrwi/nVl2XhebI11DfQFEUN+krNoZ3U4n5Sb"
+ + "g0Heibg5mILPwVS5Zh2vEybXzFY6b1XPA7TlGQATm6xBaU+BNFiACp+7+6CZ"
+ + "PxofFKKlWq0+Apx43JDATerwlPBKxLqxxgo0xTJUtL8OKnt6oSFX4P6O6AgX"
+ + "D9Pz3dzdWW9ga65N2qEmqpeIsd6SB4eGRJ1Vf1ePDgdVBUD9DG/eWfpn8l1T"
+ + "neg7wsQOGDrX00uDfio/WrjRBOw37IfToqJ/j6y/Ybggg5tldvCNoxq/42rC"
+ + "RvP0GJH+LJAHgB9sOWbksR7tKizWeFEyHwrAQfYc8aIZocApObtsZp8O5nuI"
+ + "MNcSCc77WZfVacrJzssKki1YHPoZeTYb9q4DRm0F6Rk+bqyvd7vs2DyLN7jT"
+ + "bkWoSoyCw8PAOuc8Q/+X3jhs18RQGzsEpeTOHoYJWeTUxgPrPqDFNKNLhD+L"
+ + "7mvDM7EvB08tVfLTSMeVBY+RUW6eFCbdlHfqszvp9pFZPNxQHtgbAYplwK6J"
+ + "i24gCH2UMF+BNzdcN2Fw9vP3nao+mzjtY1HuYebDDNNxgBAEoUFS4jr1YLoa"
+ + "+li3A9T/NqSf+J5OwASsSsp0YttAJQ+VU19amwJ141U+04kVc2bUIvSxEyxu"
+ + "UzWfFs26J1FhKzacirtpNv21iH78NHWOgS3jlEZMirpCHtHDbwF0z3V0upJ7"
+ + "cZzMwHJPQIGP4Nk8ei20dEogc/D2ijXHGRKdRjstzi89YXs4iLWjy2lEqhlK"
+ + "IvmlbF/snra1He2En/TFYv7m1zMuEPtS/+DTcwzqoe10Lko+2bNlOikW58u/"
+ + "OdAlteo1IissecMjL6743ttt8SAwx9gpAn6XHaIfFL1jiGKUQPJ5Mx9RUzfB"
+ + "lsKzHLNWmrDCZtR4BC4A21aRUueDGgRbtiOCYLbVtoiTc2XWM5juahaWCNKm"
+ + "4+ENQNOPrB4rJUeWJquNOj9+Brhe6pWWfi4EYVBuWlbTQB7u3uP9lnYvQHSo"
+ + "nOjkhjwEhPZneaKctEqXx2LoYc8arY1LSSpaXORcOJc/LkgVCq3bBEDNCJrZ"
+ + "DBOUpcPXDj43MEUwMTANBglghkgBZQMEAgEFAAQgdWQUVEirOjgax8qJhjqC"
+ + "bArDHuZQQvCmtrjqyhWbI4MEENBoJ4T1+xY5fmdiwmoXPPM=");
+
+ private String pkcs5Pass = "hello";
+
+ private byte[] pkcs5Aes128Pfx = Base64.decode(
+ "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"
+ + "gw8dRrSS4gQISYYYgNAwxl0CAggA");
+
+ private byte[] pkcs5Aes192Pfx = Base64.decode(
+ "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"
+ + "4EPgRMGPtQQItR+KgKM/oRMCAggA");
+
+ private byte[] pkcs5Camellia128Pfx = Base64.decode(
+ "MIIFswIBAzCCBXkGCSqGSIb3DQEHAaCCBWoEggVmMIIFYjCCAxcGCSqGSIb3"
+ + "DQEHBqCCAwgwggMEAgEAMIIC/QYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYw"
+ + "DgQIq+wFOOOtSokCAggAgIIC0IWDRpk4L/tSSMfwWx0mN3ecbaL+m2XZWvN9"
+ + "hK1K5PghAYquCs36l603cYSV9pypOkGC5rn1d2fyZCFhUMOObSC7V/mpkitr"
+ + "OfOYpaW7tU1JJecpONgIHlbd8N4fbBtH73E7vdmi6X/tg4Tl7yJf40fruYVq"
+ + "yzqfJCO2aGJIFv6JWsFivjCwehBa+6ppCHBnNcj4SsVlozj1y2B0Wl2TVi3r"
+ + "joBIsK2RQ+RMjM55k3pS57mV+jXtd29wb2q9utDKogvpBCboTk8dPMFcFGWz"
+ + "2D41onJoEJKizAEIgXiS7UvqHddhIL9O/rSZ68j2d2GcFi1Oxer1PyZoCI61"
+ + "CpZdk2QeNeVaVFTPJ26We6J34w2ivZwHOhn+iUZ7q0Sm9gcYa1QRG79LA/AC"
+ + "nE3Xxzl4nEjRRi5AKb6IOnMKBbr0povesS8tL323x91uPZc0jMctC6Q+vegX"
+ + "tIZ7dZPuNxhqRHqb62LSm11cpYQWibj16rRQ0ulOFSQGIr514PvfbIig6oo8"
+ + "niwHuefp/ey/Zvl/dAl+um2UkVdR9Mwn8vTM8oMF+ptJfpWyZEIrP785Rpu3"
+ + "oyBMyEYA2djX7JsFvoCxKxGCC5VK3C/9EFv9xUGmiV0zrTPcHb1P4sK1AJyI"
+ + "vhSY+Tgv+Fjq5KoPCa4ZXP+Y+vSzkttcP8u7x0wt9cblvgzdBy9Ee1xqCdJd"
+ + "F67U6vbQ6ErDrdVAwtRqc0TsPKG1XH5NFtxTwILyCeh8XzdYMIaHkEnTuITQ"
+ + "eeICaUJ2YPZrADLxXTNHI9e6dVcDvhjf/JfBXZfiiqFH8XmbCIMqyGSGTmQr"
+ + "8uwb8cquLMS78RbXSHLNcv+f/DmPOClNjmWgVAYxaDuw5lZBaU+YDyZaKEy2"
+ + "Mdjd+lR/g2LZhvAEfcM3V4bzr17s0GOSwJ5/5yzczPKZZ8auMwML+Bcmoggt"
+ + "EJgubVFHg/3l11xVe2djfg78CTCCAkMGCSqGSIb3DQEHAaCCAjQEggIwMIIC"
+ + "LDCCAigGCyqGSIb3DQEMCgECoIIBtTCCAbEwSwYJKoZIhvcNAQUNMD4wGwYJ"
+ + "KoZIhvcNAQUMMA4ECInc03N3q5vSAgIIADAfBgsqgwiMmks9AQEBAgQQR+Uo"
+ + "WVvmSL5AcwwRq6vtOQSCAWD0Ms1i2wHGaFi6qUWLqA5EnmYFwqwQQlfz5To+"
+ + "FwVEpHQHrqd0pehOt1J9vyDVYwfjU8DUOJDovCiBIzRsopyf0Qp5hcZnaTDw"
+ + "YJSNd3pIAYiEUAzfdtC7tQw2v0aLt5X/7zthEcoRtTe061dK8DhbV4fALWa9"
+ + "VF2E91L35+wq52DblvpJHBw28PHTbuhfJZsNshXKO7qU7uk+UR6V/Pwc7rsp"
+ + "x/TQ35fVfm7v53rapdHlMVyY4Bx/4fdEWV9aK1cV3qOfiBMByxt8WD0xBLoc"
+ + "Yy3qo3+k/N7q6t4hqjus3LPVrmCbpgAe5S5EkDgnjy7Mpz19tf7hhzL957p2"
+ + "ecWregvR9rQHoWZNOaxS2e2hdOiZUPSxIJ46nOJyCnoZQHG0CFVEwwJkGcWf"
+ + "Thjz38U203IRzuCPgsO1f8wjSXXMp4xJQtJW2TqMm+5/aaDtuXAsUGqQzGiH"
+ + "DQfUs4z/PCKyMWAwIwYJKoZIhvcNAQkVMRYEFKm5GgFnzYtYLITaZeZPkaaT"
+ + "XG/4MDkGCSqGSIb3DQEJFDEsHioAdABlAHMAdABAAGIAbwB1AG4AYwB5AGMA"
+ + "YQBzAHQAbABlAC4AbwByAGcwMTAhMAkGBSsOAwIaBQAEFHIzAiyzoVOmPvLE"
+ + "XCD2HHG5MC23BAhhHlFnklHZYgICCAA=");
+
+ private byte[] pkcs5Camellia256Pfx = Base64.decode(
+ "MIIFswIBAzCCBXkGCSqGSIb3DQEHAaCCBWoEggVmMIIFYjCCAxcGCSqGSIb3"
+ + "DQEHBqCCAwgwggMEAgEAMIIC/QYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYw"
+ + "DgQIq+wFOOOtSokCAggAgIIC0IWDRpk4L/tSSMfwWx0mN3ecbaL+m2XZWvN9"
+ + "hK1K5PghAYquCs36l603cYSV9pypOkGC5rn1d2fyZCFhUMOObSC7V/mpkitr"
+ + "OfOYpaW7tU1JJecpONgIHlbd8N4fbBtH73E7vdmi6X/tg4Tl7yJf40fruYVq"
+ + "yzqfJCO2aGJIFv6JWsFivjCwehBa+6ppCHBnNcj4SsVlozj1y2B0Wl2TVi3r"
+ + "joBIsK2RQ+RMjM55k3pS57mV+jXtd29wb2q9utDKogvpBCboTk8dPMFcFGWz"
+ + "2D41onJoEJKizAEIgXiS7UvqHddhIL9O/rSZ68j2d2GcFi1Oxer1PyZoCI61"
+ + "CpZdk2QeNeVaVFTPJ26We6J34w2ivZwHOhn+iUZ7q0Sm9gcYa1QRG79LA/AC"
+ + "nE3Xxzl4nEjRRi5AKb6IOnMKBbr0povesS8tL323x91uPZc0jMctC6Q+vegX"
+ + "tIZ7dZPuNxhqRHqb62LSm11cpYQWibj16rRQ0ulOFSQGIr514PvfbIig6oo8"
+ + "niwHuefp/ey/Zvl/dAl+um2UkVdR9Mwn8vTM8oMF+ptJfpWyZEIrP785Rpu3"
+ + "oyBMyEYA2djX7JsFvoCxKxGCC5VK3C/9EFv9xUGmiV0zrTPcHb1P4sK1AJyI"
+ + "vhSY+Tgv+Fjq5KoPCa4ZXP+Y+vSzkttcP8u7x0wt9cblvgzdBy9Ee1xqCdJd"
+ + "F67U6vbQ6ErDrdVAwtRqc0TsPKG1XH5NFtxTwILyCeh8XzdYMIaHkEnTuITQ"
+ + "eeICaUJ2YPZrADLxXTNHI9e6dVcDvhjf/JfBXZfiiqFH8XmbCIMqyGSGTmQr"
+ + "8uwb8cquLMS78RbXSHLNcv+f/DmPOClNjmWgVAYxaDuw5lZBaU+YDyZaKEy2"
+ + "Mdjd+lR/g2LZhvAEfcM3V4bzr17s0GOSwJ5/5yzczPKZZ8auMwML+Bcmoggt"
+ + "EJgubVFHg/3l11xVe2djfg78CTCCAkMGCSqGSIb3DQEHAaCCAjQEggIwMIIC"
+ + "LDCCAigGCyqGSIb3DQEMCgECoIIBtTCCAbEwSwYJKoZIhvcNAQUNMD4wGwYJ"
+ + "KoZIhvcNAQUMMA4ECInc03N3q5vSAgIIADAfBgsqgwiMmks9AQEBAgQQR+Uo"
+ + "WVvmSL5AcwwRq6vtOQSCAWD0Ms1i2wHGaFi6qUWLqA5EnmYFwqwQQlfz5To+"
+ + "FwVEpHQHrqd0pehOt1J9vyDVYwfjU8DUOJDovCiBIzRsopyf0Qp5hcZnaTDw"
+ + "YJSNd3pIAYiEUAzfdtC7tQw2v0aLt5X/7zthEcoRtTe061dK8DhbV4fALWa9"
+ + "VF2E91L35+wq52DblvpJHBw28PHTbuhfJZsNshXKO7qU7uk+UR6V/Pwc7rsp"
+ + "x/TQ35fVfm7v53rapdHlMVyY4Bx/4fdEWV9aK1cV3qOfiBMByxt8WD0xBLoc"
+ + "Yy3qo3+k/N7q6t4hqjus3LPVrmCbpgAe5S5EkDgnjy7Mpz19tf7hhzL957p2"
+ + "ecWregvR9rQHoWZNOaxS2e2hdOiZUPSxIJ46nOJyCnoZQHG0CFVEwwJkGcWf"
+ + "Thjz38U203IRzuCPgsO1f8wjSXXMp4xJQtJW2TqMm+5/aaDtuXAsUGqQzGiH"
+ + "DQfUs4z/PCKyMWAwIwYJKoZIhvcNAQkVMRYEFKm5GgFnzYtYLITaZeZPkaaT"
+ + "XG/4MDkGCSqGSIb3DQEJFDEsHioAdABlAHMAdABAAGIAbwB1AG4AYwB5AGMA"
+ + "YQBzAHQAbABlAC4AbwByAGcwMTAhMAkGBSsOAwIaBQAEFHIzAiyzoVOmPvLE"
+ + "XCD2HHG5MC23BAhhHlFnklHZYgICCAA=");
+
+ private byte[] pkcs5Cast5Pfx = Base64.decode(
+ "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"
+ + "CKHZUIQsQX9hAgIIAA==");
+
+ private byte[] gostPfx = Base64.decode(
+ "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"
+ + "BAgY5sDtkrVeBQICCAA=");
+
+ private byte[] gostPfxFoo123 = Base64.decode(
+ "MIID6gIBAzCCA6MGCSqGSIb3DQEHAaCCA5QEggOQMIIDjDCCApQGCSqGSIb3"
+ + "DQEHBqCCAoUwggKBAgEAMIICegYJKoZIhvcNAQcBMFUGCSqGSIb3DQEFDTBI"
+ + "MCcGCSqGSIb3DQEFDDAaBAhIVrbUVNoQ2wICCAAwCgYGKoUDAgIKBQAwHQYG"
+ + "KoUDAgIVMBMECBLmAh+XCCYhBgcqhQMCAh8BgIICFP9hQLgDq5SORy2npOdo"
+ + "1bvoGl9Qdga1kV9s2c1/Y1kTGpuiYKfm5Il+PurzYdE5t/Wi2+SxoePm/AKA"
+ + "x1Ep5btK/002wnyRbUKdjgF1r7fMXRrd5Ioy8lYxB1v6qhHmzE5fz7FxY+iV"
+ + "Z70dSRS0JkTasI8MRsFLkJJfDb9twgoch8lYGFfYirHLcVy4xxA3JO9VSHm2"
+ + "8nuSWSnsmGN0ufPX14UpV2RFe3Rt0gZ0Jc8u2h2Mo0sIoVU6HVwdXzoe6LN7"
+ + "1NPZdRuhVtjxEvjDAvNJ8WHXQnBQMai2nVAj87uNr6OHLRs+foEccEY9WpPQ"
+ + "GPt4XbPt4MtmVctT2+Gsvf6Ws2UCx6hD4k8i28a6xS8lhTVam2g/2Z5cxtUV"
+ + "HxYt7j13HjuQVsuSNdgtrUnw3l43LnBxRZhlFz0r2zrvTB04ynenS+lGdVuG"
+ + "0TauIH+rdP1ubujw6lFdG9RNgUxWvS5IdwbFGX73a+ZrWiYJeERX11N/6r3g"
+ + "0EqVFNH9t/ROsdAtCCe2FycQoOSb+VxPU6I+SHjwe7Oa7R8Xxazh/eWTsV59"
+ + "QzPuLriUMbyYdQIf4xdclgcJoxFElopgl4orRfzH3XQsVbtTxN33lwjkE0j/"
+ + "686VtcO+b+dU7+BEB7O5yDcx1tupgre0ha/0KOlYfPvmbogGdDf0r6MOwrS7"
+ + "QFXxKlHfp8vn4mNwoy7pjrzjmjclkbkwgfEGCSqGSIb3DQEHAaCB4wSB4DCB"
+ + "3TCB2gYLKoZIhvcNAQwKAQKggaMwgaAwVQYJKoZIhvcNAQUNMEgwJwYJKoZI"
+ + "hvcNAQUMMBoECLD6Ld7TqurqAgIIADAKBgYqhQMCAgoFADAdBgYqhQMCAhUw"
+ + "EwQIoYXV7LETOEAGByqFAwICHwEERyBQK9LuYnOO0ELrge+a6JFeAVwPL85V"
+ + "ip2Kj/GfD3nzZR4tPzCwAt79RriKQklNqa3uCc9o0C9Zk5Qcj36SqiXxD1tz"
+ + "Ea63MSUwIwYJKoZIhvcNAQkVMRYEFKjg5gKM+i+vFhSwaga8YGaZ5thVMD4w"
+ + "LjAKBgYqhQMCAgkFAAQgIwD0CRCwva2Bjdlv5g970H2bCB1aafBNr/hxJLZE"
+ + "Ey4ECAW3VYXJzJpYAgIIAA==");
+
+ /**
+ * we generate the CA's certificate
+ */
+ public static X509Certificate 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
+ //
+ X509v1CertificateBuilder v1CertBuilder = new JcaX509v1CertificateBuilder(
+ new X500Name(issuer),
+ BigInteger.valueOf(1),
+ new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30),
+ new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 30)),
+ new X500Name(subject),
+ pubKey);
+
+ X509CertificateHolder cert = v1CertBuilder.build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(privKey));
+
+ return new JcaX509CertificateConverter().setProvider(BC).getCertificate(cert);
+ }
+
+ /**
+ * we generate an intermediate certificate signed by our CA
+ */
+ public static X509Certificate createIntermediateCert(
+ PublicKey pubKey,
+ PrivateKey caPrivKey,
+ X509Certificate caCert)
+ throws Exception
+ {
+ //
+ // subject name builder.
+ //
+ X500NameBuilder subjectBuilder = new X500NameBuilder(BCStyle.INSTANCE);
+
+ subjectBuilder.addRDN(BCStyle.C, "AU");
+ subjectBuilder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ subjectBuilder.addRDN(BCStyle.OU, "Bouncy Intermediate Certificate");
+ subjectBuilder.addRDN(BCStyle.EmailAddress, "feedback-crypto@bouncycastle.org");
+
+ //
+ // create the certificate - version 3
+ //
+ X509v3CertificateBuilder v3CertBuilder = new JcaX509v3CertificateBuilder(
+ JcaX500NameUtil.getIssuer(caCert),
+ BigInteger.valueOf(2),
+ new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30),
+ new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 30)),
+ subjectBuilder.build(),
+ pubKey);
+
+
+ //
+ // extensions
+ //
+ JcaX509ExtensionUtils utils = new JcaX509ExtensionUtils();
+
+ v3CertBuilder.addExtension(
+ Extension.subjectKeyIdentifier,
+ false,
+ utils.createSubjectKeyIdentifier(pubKey));
+
+ v3CertBuilder.addExtension(
+ Extension.authorityKeyIdentifier,
+ false,
+ utils.createAuthorityKeyIdentifier(caCert));
+
+ v3CertBuilder.addExtension(
+ Extension.basicConstraints,
+ true,
+ new BasicConstraints(0));
+
+ X509CertificateHolder cert = v3CertBuilder.build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(caPrivKey));
+
+ return new JcaX509CertificateConverter().setProvider(BC).getCertificate(cert);
+ }
+
+ /**
+ * we generate a certificate signed by our CA's intermediate certficate
+ */
+ public static X509Certificate createCert(
+ PublicKey pubKey,
+ PrivateKey caPrivKey,
+ PublicKey caPubKey)
+ throws Exception
+ {
+ //
+ // signer name builder.
+ //
+ X500NameBuilder issuerBuilder = new X500NameBuilder(BCStyle.INSTANCE);
+
+ issuerBuilder.addRDN(BCStyle.C, "AU");
+ issuerBuilder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ issuerBuilder.addRDN(BCStyle.OU, "Bouncy Intermediate Certificate");
+ issuerBuilder.addRDN(BCStyle.EmailAddress, "feedback-crypto@bouncycastle.org");
+
+ //
+ // subject name builder
+ //
+ X500NameBuilder subjectBuilder = new X500NameBuilder(BCStyle.INSTANCE);
+
+ subjectBuilder.addRDN(BCStyle.C, "AU");
+ subjectBuilder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ subjectBuilder.addRDN(BCStyle.L, "Melbourne");
+ subjectBuilder.addRDN(BCStyle.CN, "Eric H. Echidna");
+ subjectBuilder.addRDN(BCStyle.EmailAddress, "feedback-crypto@bouncycastle.org");
+
+ //
+ // create the certificate - version 3
+ //
+ //
+ // create the certificate - version 3
+ //
+ X509v3CertificateBuilder v3CertBuilder = new JcaX509v3CertificateBuilder(
+ issuerBuilder.build(),
+ BigInteger.valueOf(3),
+ new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30),
+ new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 30)),
+ subjectBuilder.build(),
+ pubKey);
+
+
+ //
+ // add the extensions
+ //
+ JcaX509ExtensionUtils utils = new JcaX509ExtensionUtils();
+
+ v3CertBuilder.addExtension(
+ Extension.subjectKeyIdentifier,
+ false,
+ utils.createSubjectKeyIdentifier(pubKey));
+
+ v3CertBuilder.addExtension(
+ Extension.authorityKeyIdentifier,
+ false,
+ utils.createAuthorityKeyIdentifier(caPubKey));
+
+ X509CertificateHolder cert = v3CertBuilder.build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(caPrivKey));
+
+ return new JcaX509CertificateConverter().setProvider(BC).getCertificate(cert);
+ }
+
+ public void setUp()
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ public void testPfxPdu()
+ throws Exception
+ {
+ //
+ // set up the keys
+ //
+ KeyFactory fact = KeyFactory.getInstance("RSA", BC);
+ PrivateKey privKey = fact.generatePrivate(privKeySpec);
+ PublicKey pubKey = fact.generatePublic(pubKeySpec);
+
+ X509Certificate[] chain = createCertChain(fact, pubKey);
+
+ PKCS12PfxPdu pfx = createPfx(privKey, pubKey, chain);
+
+ //
+ // now try reading our object
+ //
+ KeyStore store = KeyStore.getInstance("PKCS12", "SC");
+
+ store.load(new ByteArrayInputStream(pfx.toASN1Structure().getEncoded()), passwd);
+
+ PrivateKey recPrivKey = (PrivateKey)store.getKey("Eric's Key", passwd);
+
+ if (!privKey.equals(recPrivKey))
+ {
+ fail("private key extraction failed");
+ }
+
+ Certificate[] certChain = store.getCertificateChain("Eric's Key");
+
+ for (int i = 0; i != certChain.length; i++)
+ {
+ if (!certChain[i].equals(chain[i]))
+ {
+ fail("certificate recovery failed");
+ }
+ }
+ }
+
+ public void testPfxPduMac()
+ throws Exception
+ {
+ //
+ // set up the keys
+ //
+ KeyFactory fact = KeyFactory.getInstance("RSA", BC);
+ PrivateKey privKey = fact.generatePrivate(privKeySpec);
+ PublicKey pubKey = fact.generatePublic(pubKeySpec);
+
+ X509Certificate[] chain = createCertChain(fact, pubKey);
+
+ PKCS12PfxPdu pfx = createPfx(privKey, pubKey, chain);
+
+ assertTrue(pfx.hasMac());
+ assertTrue(pfx.isMacValid(new BcPKCS12MacCalculatorBuilderProvider(BcDefaultDigestProvider.INSTANCE), passwd));
+ assertFalse(pfx.isMacValid(new BcPKCS12MacCalculatorBuilderProvider(BcDefaultDigestProvider.INSTANCE), "not right".toCharArray()));
+ }
+
+ public void testBcEncryptedPrivateKeyInfo()
+ throws Exception
+ {
+ KeyFactory fact = KeyFactory.getInstance("RSA", BC);
+ PrivateKey privKey = fact.generatePrivate(privKeySpec);
+
+ PKCS8EncryptedPrivateKeyInfoBuilder builder = new JcaPKCS8EncryptedPrivateKeyInfoBuilder(privKey);
+
+ PKCS8EncryptedPrivateKeyInfo priv = builder.build(new BcPKCS12PBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, new CBCBlockCipher(new DESedeEngine())).build(passwd));
+
+ PrivateKeyInfo info = priv.decryptPrivateKeyInfo(new BcPKCS12PBEInputDecryptorProviderBuilder().build(passwd));
+
+ assertTrue(Arrays.areEqual(info.getEncoded(), privKey.getEncoded()));
+ }
+
+ public void testEncryptedPrivateKeyInfo()
+ throws Exception
+ {
+ KeyFactory fact = KeyFactory.getInstance("RSA", BC);
+ PrivateKey privKey = fact.generatePrivate(privKeySpec);
+
+ PKCS8EncryptedPrivateKeyInfoBuilder builder = new JcaPKCS8EncryptedPrivateKeyInfoBuilder(privKey);
+
+ PKCS8EncryptedPrivateKeyInfo priv = builder.build(new JcePKCSPBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC).build(passwd));
+
+ PrivateKeyInfo info = priv.decryptPrivateKeyInfo(new JcePKCSPBEInputDecryptorProviderBuilder().build(passwd));
+
+ assertTrue(Arrays.areEqual(info.getEncoded(), privKey.getEncoded()));
+ }
+
+ public void testEncryptedPrivateKeyInfoPKCS5()
+ throws Exception
+ {
+ KeyFactory fact = KeyFactory.getInstance("RSA", BC);
+ PrivateKey privKey = fact.generatePrivate(privKeySpec);
+
+ PKCS8EncryptedPrivateKeyInfoBuilder builder = new JcaPKCS8EncryptedPrivateKeyInfoBuilder(privKey);
+
+ PKCS8EncryptedPrivateKeyInfo priv = builder.build(new JcePKCSPBEOutputEncryptorBuilder(NISTObjectIdentifiers.id_aes256_CBC).build(passwd));
+
+ PrivateKeyInfo info = priv.decryptPrivateKeyInfo(new JcePKCSPBEInputDecryptorProviderBuilder().build(passwd));
+
+ assertTrue(Arrays.areEqual(info.getEncoded(), privKey.getEncoded()));
+ }
+
+ public void testKeyBag()
+ throws Exception
+ {
+ OutputEncryptor encOut = new BcPKCS12PBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, new CBCBlockCipher(new DESedeEngine())).build(passwd);
+ InputDecryptorProvider inputDecryptorProvider = new BcPKCS12PBEInputDecryptorProviderBuilder().build(passwd);
+ KeyFactory fact = KeyFactory.getInstance("RSA", BC);
+ PrivateKey privKey = fact.generatePrivate(privKeySpec);
+ PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder(privKey);
+
+ keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Eric's Key"));
+
+ PKCS12PfxPduBuilder builder = new PKCS12PfxPduBuilder();
+
+ builder.addEncryptedData(encOut, keyBagBuilder.build());
+
+ PKCS12PfxPdu pfx = builder.build(new BcPKCS12MacCalculatorBuilder(), passwd);
+ assertTrue(pfx.hasMac());
+ assertTrue(pfx.isMacValid(new BcPKCS12MacCalculatorBuilderProvider(BcDefaultDigestProvider.INSTANCE), passwd));
+
+ ContentInfo[] infos = pfx.getContentInfos();
+
+ for (int i = 0; i != infos.length; i++)
+ {
+ if (infos[i].getContentType().equals(PKCSObjectIdentifiers.encryptedData))
+ {
+ PKCS12SafeBagFactory dataFact = new PKCS12SafeBagFactory(infos[i], inputDecryptorProvider);
+
+ PKCS12SafeBag[] bags = dataFact.getSafeBags();
+
+ assertEquals(1, bags.length);
+ assertEquals(PKCSObjectIdentifiers.keyBag, bags[0].getType());
+
+ assertTrue(Arrays.areEqual(privKey.getEncoded(), ((PrivateKeyInfo)bags[0].getBagValue()).getEncoded()));
+
+ Attribute[] attributes = bags[0].getAttributes();
+
+ assertEquals(1, attributes.length);
+
+ assertEquals(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, attributes[0].getAttrType());
+
+ ASN1Encodable[] attrValues = attributes[0].getAttributeValues();
+
+ assertEquals(1, attrValues.length);
+ assertEquals(new DERBMPString("Eric's Key"), attrValues[0]);
+ }
+ else
+ {
+ fail("unknown bag encountered");
+ }
+ }
+ }
+
+ public void testSafeBagRecovery()
+ throws Exception
+ {
+ InputDecryptorProvider inputDecryptorProvider = new BcPKCS12PBEInputDecryptorProviderBuilder().build(passwd);
+ KeyFactory fact = KeyFactory.getInstance("RSA", BC);
+ PrivateKey privKey = fact.generatePrivate(privKeySpec);
+ PublicKey pubKey = fact.generatePublic(pubKeySpec);
+
+ X509Certificate[] chain = createCertChain(fact, pubKey);
+
+ PKCS12PfxPdu pfx = createPfx(privKey, pubKey, chain);
+
+ ContentInfo[] infos = pfx.getContentInfos();
+
+ for (int i = 0; i != infos.length; i++)
+ {
+ if (infos[i].getContentType().equals(PKCSObjectIdentifiers.encryptedData))
+ {
+ PKCS12SafeBagFactory dataFact = new PKCS12SafeBagFactory(infos[i], inputDecryptorProvider);
+
+ PKCS12SafeBag[] bags = dataFact.getSafeBags();
+
+ assertEquals(3, bags.length);
+ assertEquals(PKCSObjectIdentifiers.certBag, bags[0].getType());
+
+ for (int j = 0; j != bags.length; j++)
+ {
+ assertTrue(Arrays.areEqual(chain[j].getEncoded(), ((X509CertificateHolder)bags[j].getBagValue()).getEncoded()));
+ }
+ }
+ else
+ {
+ PKCS12SafeBagFactory dataFact = new PKCS12SafeBagFactory(infos[i]);
+
+ PKCS12SafeBag[] bags = dataFact.getSafeBags();
+
+ assertEquals(1, bags.length);
+ assertEquals(PKCSObjectIdentifiers.pkcs8ShroudedKeyBag, bags[0].getType());
+
+ PKCS8EncryptedPrivateKeyInfo encInfo = (PKCS8EncryptedPrivateKeyInfo)bags[0].getBagValue();
+ PrivateKeyInfo info = encInfo.decryptPrivateKeyInfo(inputDecryptorProvider);
+
+ assertTrue(Arrays.areEqual(info.getEncoded(), privKey.getEncoded()));
+ }
+ }
+ }
+
+ public void testExceptions()
+ throws Exception
+ {
+ PKCS12SafeBagFactory dataFact;
+
+ try
+ {
+ dataFact = new PKCS12SafeBagFactory(new ContentInfo(PKCSObjectIdentifiers.data, new DERSequence()), null);
+ }
+ catch (IllegalArgumentException e)
+ {
+
+ }
+
+ try
+ {
+ dataFact = new PKCS12SafeBagFactory(new ContentInfo(PKCSObjectIdentifiers.encryptedData, new DERSequence()));
+ }
+ catch (IllegalArgumentException e)
+ {
+
+ }
+ }
+
+ public void testBasicPKCS12()
+ throws Exception
+ {
+ InputDecryptorProvider inputDecryptorProvider = new JcePKCSPBEInputDecryptorProviderBuilder()
+ .setProvider("SC").build(pkcs12Pass.toCharArray());
+ PKCS12PfxPdu pfx = new PKCS12PfxPdu(pkcs12);
+
+ ContentInfo[] infos = pfx.getContentInfos();
+
+ for (int i = 0; i != infos.length; i++)
+ {
+ if (infos[i].getContentType().equals(PKCSObjectIdentifiers.encryptedData))
+ {
+ PKCS12SafeBagFactory dataFact = new PKCS12SafeBagFactory(infos[i], inputDecryptorProvider);
+
+ PKCS12SafeBag[] bags = dataFact.getSafeBags();
+
+ // TODO: finish!
+// assertEquals(3, bags.length);
+// assertEquals(PKCSObjectIdentifiers.certBag, bags[0].getType());
+ }
+ else
+ {
+ PKCS12SafeBagFactory dataFact = new PKCS12SafeBagFactory(infos[i]);
+
+ PKCS12SafeBag[] bags = dataFact.getSafeBags();
+
+ assertEquals(1, bags.length);
+ assertEquals(PKCSObjectIdentifiers.pkcs8ShroudedKeyBag, bags[0].getType());
+
+ PKCS8EncryptedPrivateKeyInfo encInfo = (PKCS8EncryptedPrivateKeyInfo)bags[0].getBagValue();
+ PrivateKeyInfo info = encInfo.decryptPrivateKeyInfo(inputDecryptorProvider);
+ }
+ }
+ }
+
+ public void testSHA256withPKCS5()
+ throws Exception
+ {
+ InputDecryptorProvider inputDecryptorProvider = new JcePKCSPBEInputDecryptorProviderBuilder()
+ .setProvider("SC").build(sha256Pass.toCharArray());
+ PKCS12PfxPdu pfx = new PKCS12PfxPdu(sha256Pfx);
+
+ ContentInfo[] infos = pfx.getContentInfos();
+
+ for (int i = 0; i != infos.length; i++)
+ {
+ if (infos[i].getContentType().equals(PKCSObjectIdentifiers.encryptedData))
+ {
+ PKCS12SafeBagFactory dataFact = new PKCS12SafeBagFactory(infos[i], inputDecryptorProvider);
+
+ PKCS12SafeBag[] bags = dataFact.getSafeBags();
+
+ // TODO: finish!
+// assertEquals(3, bags.length);
+// assertEquals(PKCSObjectIdentifiers.certBag, bags[0].getType());
+ }
+ else
+ {
+ PKCS12SafeBagFactory dataFact = new PKCS12SafeBagFactory(infos[i]);
+
+ PKCS12SafeBag[] bags = dataFact.getSafeBags();
+
+ assertEquals(1, bags.length);
+ assertEquals(PKCSObjectIdentifiers.pkcs8ShroudedKeyBag, bags[0].getType());
+
+ PKCS8EncryptedPrivateKeyInfo encInfo = (PKCS8EncryptedPrivateKeyInfo)bags[0].getBagValue();
+ PrivateKeyInfo info = encInfo.decryptPrivateKeyInfo(inputDecryptorProvider);
+ }
+ }
+ }
+
+ public void testCreateAES256andSHA256()
+ throws Exception
+ {
+ OutputEncryptor encOut = new JcePKCSPBEOutputEncryptorBuilder(NISTObjectIdentifiers.id_aes256_CBC).setProvider("SC").build(passwd);
+
+ KeyFactory fact = KeyFactory.getInstance("RSA", BC);
+ PrivateKey privKey = fact.generatePrivate(privKeySpec);
+ PublicKey pubKey = fact.generatePublic(pubKeySpec);
+
+ X509Certificate[] chain = createCertChain(fact, pubKey);
+
+ PKCS12SafeBagBuilder taCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[2]);
+
+ taCertBagBuilder.addBagAttribute(PKCS12SafeBag.friendlyNameAttribute, new DERBMPString("Bouncy Primary Certificate"));
+
+ PKCS12SafeBagBuilder caCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[1]);
+
+ caCertBagBuilder.addBagAttribute(PKCS12SafeBag.friendlyNameAttribute, new DERBMPString("Bouncy Intermediate Certificate"));
+
+ JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
+ PKCS12SafeBagBuilder eeCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[0]);
+
+ eeCertBagBuilder.addBagAttribute(PKCS12SafeBag.friendlyNameAttribute, new DERBMPString("Eric's Key"));
+ SubjectKeyIdentifier pubKeyId = extUtils.createSubjectKeyIdentifier(chain[0].getPublicKey());
+ eeCertBagBuilder.addBagAttribute(PKCS12SafeBag.localKeyIdAttribute, pubKeyId);
+
+ PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder(privKey, encOut);
+
+ keyBagBuilder.addBagAttribute(PKCS12SafeBag.friendlyNameAttribute, new DERBMPString("Eric's Key"));
+ keyBagBuilder.addBagAttribute(PKCS12SafeBag.localKeyIdAttribute, pubKeyId);
+
+ PKCS12PfxPduBuilder builder = new PKCS12PfxPduBuilder();
+
+ builder.addData(keyBagBuilder.build());
+
+ builder.addEncryptedData(new JcePKCSPBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC).setProvider("SC").build(passwd), new PKCS12SafeBag[] { eeCertBagBuilder.build(), caCertBagBuilder.build(), taCertBagBuilder.build() });
+
+ PKCS12PfxPdu pfx = builder.build(new JcePKCS12MacCalculatorBuilder(NISTObjectIdentifiers.id_sha256), passwd);
+
+ assertTrue(pfx.hasMac());
+ assertTrue(pfx.isMacValid(new JcePKCS12MacCalculatorBuilderProvider().setProvider("SC"), passwd));
+
+ InputDecryptorProvider inputDecryptorProvider = new JcePKCSPBEInputDecryptorProviderBuilder()
+ .setProvider("SC").build(passwd);
+
+ pfx = new PKCS12PfxPdu(pfx.toASN1Structure().getEncoded());
+
+ ContentInfo[] infos = pfx.getContentInfos();
+ boolean encDataFound = false;
+ boolean pkcs8Found = false;
+
+ for (int i = 0; i != infos.length; i++)
+ {
+ if (infos[i].getContentType().equals(PKCSObjectIdentifiers.encryptedData))
+ {
+ encDataFound = true;
+ PKCS12SafeBagFactory dataFact = new PKCS12SafeBagFactory(infos[i], inputDecryptorProvider);
+
+ PKCS12SafeBag[] bags = dataFact.getSafeBags();
+
+ assertEquals(3, bags.length);
+ assertEquals(PKCSObjectIdentifiers.certBag, bags[0].getType());
+ }
+ else
+ {
+ pkcs8Found = true;
+ PKCS12SafeBagFactory dataFact = new PKCS12SafeBagFactory(infos[i]);
+
+ PKCS12SafeBag[] bags = dataFact.getSafeBags();
+
+ assertEquals(1, bags.length);
+ assertEquals(PKCSObjectIdentifiers.pkcs8ShroudedKeyBag, bags[0].getType());
+
+ PKCS8EncryptedPrivateKeyInfo encInfo = (PKCS8EncryptedPrivateKeyInfo)bags[0].getBagValue();
+ PrivateKeyInfo info = encInfo.decryptPrivateKeyInfo(inputDecryptorProvider);
+ }
+ }
+
+ assertTrue(encDataFound);
+ assertTrue(pkcs8Found);
+
+ KeyStore ks = KeyStore.getInstance("PKCS12", "SC");
+
+ ks.load(new ByteArrayInputStream(pfx.getEncoded(ASN1Encoding.DL)), passwd);
+
+ assertTrue(ks.containsAlias("Eric's Key"));
+ }
+
+ public void testPKCS5()
+ throws Exception
+ {
+ doPKCS5Test(pkcs5Aes128Pfx);
+ doPKCS5Test(pkcs5Aes192Pfx);
+ doPKCS5Test(pkcs5Camellia128Pfx);
+ doPKCS5Test(pkcs5Camellia256Pfx);
+ doPKCS5Test(pkcs5Cast5Pfx);
+ }
+
+ private void doPKCS5Test(byte[] keyStore)
+ throws Exception
+ {
+ InputDecryptorProvider inputDecryptorProvider = new JcePKCSPBEInputDecryptorProviderBuilder()
+ .setProvider("SC").build(pkcs5Pass.toCharArray());
+ PKCS12PfxPdu pfx = new PKCS12PfxPdu(keyStore);
+
+ ContentInfo[] infos = pfx.getContentInfos();
+
+ for (int i = 0; i != infos.length; i++)
+ {
+ if (infos[i].getContentType().equals(PKCSObjectIdentifiers.encryptedData))
+ {
+ PKCS12SafeBagFactory dataFact = new PKCS12SafeBagFactory(infos[i], inputDecryptorProvider);
+
+ PKCS12SafeBag[] bags = dataFact.getSafeBags();
+
+ // TODO: finish!
+// assertEquals(3, bags.length);
+// assertEquals(PKCSObjectIdentifiers.certBag, bags[0].getType());
+ }
+ else
+ {
+ PKCS12SafeBagFactory dataFact = new PKCS12SafeBagFactory(infos[i]);
+
+ PKCS12SafeBag[] bags = dataFact.getSafeBags();
+
+ assertEquals(1, bags.length);
+ assertEquals(PKCSObjectIdentifiers.pkcs8ShroudedKeyBag, bags[0].getType());
+
+ PKCS8EncryptedPrivateKeyInfo encInfo = (PKCS8EncryptedPrivateKeyInfo)bags[0].getBagValue();
+ PrivateKeyInfo info = encInfo.decryptPrivateKeyInfo(inputDecryptorProvider);
+ }
+ }
+ }
+
+ public void testGOST1()
+ throws Exception
+ {
+ char[] password = "1".toCharArray();
+
+ InputDecryptorProvider inputDecryptorProvider = new JcePKCSPBEInputDecryptorProviderBuilder()
+ .setProvider("SC").build(password);
+ PKCS12PfxPdu pfx = new PKCS12PfxPdu(gostPfx);
+
+ assertTrue(pfx.hasMac());
+ assertTrue(pfx.isMacValid(new JcePKCS12MacCalculatorBuilderProvider().setProvider("SC"), password));
+
+ ContentInfo[] infos = pfx.getContentInfos();
+
+ for (int i = 0; i != infos.length; i++)
+ {
+ if (infos[i].getContentType().equals(PKCSObjectIdentifiers.encryptedData))
+ {
+ PKCS12SafeBagFactory dataFact = new PKCS12SafeBagFactory(infos[i], inputDecryptorProvider);
+
+ PKCS12SafeBag[] bags = dataFact.getSafeBags();
+
+ // TODO: finish!
+// assertEquals(3, bags.length);
+// assertEquals(PKCSObjectIdentifiers.certBag, bags[0].getType());
+ }
+ else
+ {
+ PKCS12SafeBagFactory dataFact = new PKCS12SafeBagFactory(infos[i]);
+
+ PKCS12SafeBag[] bags = dataFact.getSafeBags();
+
+ assertEquals(1, bags.length);
+ assertEquals(PKCSObjectIdentifiers.pkcs8ShroudedKeyBag, bags[0].getType());
+
+ PKCS8EncryptedPrivateKeyInfo encInfo = (PKCS8EncryptedPrivateKeyInfo)bags[0].getBagValue();
+ PrivateKeyInfo info = encInfo.decryptPrivateKeyInfo(inputDecryptorProvider);
+ assertEquals(CryptoProObjectIdentifiers.gostR3410_2001, info.getPrivateKeyAlgorithm().getAlgorithm());
+ }
+ }
+ }
+
+ public void testGOST2()
+ throws Exception
+ {
+ char[] password = "foo123".toCharArray();
+
+ InputDecryptorProvider inputDecryptorProvider = new JcePKCSPBEInputDecryptorProviderBuilder()
+ .setProvider("SC").build(password);
+ PKCS12PfxPdu pfx = new PKCS12PfxPdu(gostPfxFoo123);
+
+ assertTrue(pfx.hasMac());
+ assertTrue(pfx.isMacValid(new JcePKCS12MacCalculatorBuilderProvider().setProvider("SC"), password));
+
+ ContentInfo[] infos = pfx.getContentInfos();
+
+ for (int i = 0; i != infos.length; i++)
+ {
+ if (infos[i].getContentType().equals(PKCSObjectIdentifiers.encryptedData))
+ {
+ PKCS12SafeBagFactory dataFact = new PKCS12SafeBagFactory(infos[i], inputDecryptorProvider);
+
+ PKCS12SafeBag[] bags = dataFact.getSafeBags();
+
+ // TODO: finish!
+// assertEquals(3, bags.length);
+// assertEquals(PKCSObjectIdentifiers.certBag, bags[0].getType());
+ }
+ else
+ {
+ PKCS12SafeBagFactory dataFact = new PKCS12SafeBagFactory(infos[i]);
+
+ PKCS12SafeBag[] bags = dataFact.getSafeBags();
+
+ assertEquals(1, bags.length);
+ assertEquals(PKCSObjectIdentifiers.pkcs8ShroudedKeyBag, bags[0].getType());
+
+ PKCS8EncryptedPrivateKeyInfo encInfo = (PKCS8EncryptedPrivateKeyInfo)bags[0].getBagValue();
+ PrivateKeyInfo info = encInfo.decryptPrivateKeyInfo(inputDecryptorProvider);
+ assertEquals(CryptoProObjectIdentifiers.gostR3410_2001, info.getPrivateKeyAlgorithm().getAlgorithm());
+ }
+ }
+ }
+
+ private X509Certificate[] createCertChain(KeyFactory fact, PublicKey pubKey)
+ throws Exception
+ {
+ PrivateKey caPrivKey = fact.generatePrivate(caPrivKeySpec);
+ PublicKey caPubKey = fact.generatePublic(caPubKeySpec);
+ PrivateKey intPrivKey = fact.generatePrivate(intPrivKeySpec);
+ PublicKey intPubKey = fact.generatePublic(intPubKeySpec);
+
+ X509Certificate[] chain = new X509Certificate[3];
+
+ chain[2] = createMasterCert(caPubKey, caPrivKey);
+ chain[1] = createIntermediateCert(intPubKey, caPrivKey, chain[2]);
+ chain[0] = createCert(pubKey, intPrivKey, intPubKey);
+ return chain;
+ }
+
+ private PKCS12PfxPdu createPfx(PrivateKey privKey, PublicKey pubKey, X509Certificate[] chain)
+ throws NoSuchAlgorithmException, IOException, PKCSException
+ {
+ JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
+
+ PKCS12SafeBagBuilder taCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[2]);
+
+ taCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Bouncy Primary Certificate"));
+
+ PKCS12SafeBagBuilder caCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[1]);
+
+ caCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Bouncy Intermediate Certificate"));
+
+ PKCS12SafeBagBuilder eeCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[0]);
+
+ eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Eric's Key"));
+ eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, extUtils.createSubjectKeyIdentifier(pubKey));
+
+ PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder(privKey, new BcPKCS12PBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, new CBCBlockCipher(new DESedeEngine())).build(passwd));
+
+ keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Eric's Key"));
+ keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, extUtils.createSubjectKeyIdentifier(pubKey));
+
+ //
+ // construct the actual key store
+ //
+ PKCS12PfxPduBuilder pfxPduBuilder = new PKCS12PfxPduBuilder();
+
+ PKCS12SafeBag[] certs = new PKCS12SafeBag[3];
+
+ certs[0] = eeCertBagBuilder.build();
+ certs[1] = caCertBagBuilder.build();
+ certs[2] = taCertBagBuilder.build();
+
+ pfxPduBuilder.addEncryptedData(new BcPKCS12PBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, new CBCBlockCipher(new RC2Engine())).build(passwd), certs);
+
+ pfxPduBuilder.addData(keyBagBuilder.build());
+
+ return pfxPduBuilder.build(new BcPKCS12MacCalculatorBuilder(), passwd);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/GenTimeAccuracyUnitTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/GenTimeAccuracyUnitTest.java
new file mode 100644
index 000000000..ba4ca49ee
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/GenTimeAccuracyUnitTest.java
@@ -0,0 +1,105 @@
+package org.spongycastle.tsp;
+
+import junit.framework.TestCase;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.tsp.Accuracy;
+
+public class GenTimeAccuracyUnitTest
+ extends TestCase
+{
+ private static final ASN1Integer ZERO_VALUE = new ASN1Integer(0);
+ private static final ASN1Integer ONE_VALUE = new ASN1Integer(1);
+ private static final ASN1Integer TWO_VALUE = new ASN1Integer(2);
+ private static final ASN1Integer THREE_VALUE = new ASN1Integer(3);
+
+ public void testOneTwoThree()
+ {
+ GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(ONE_VALUE, TWO_VALUE, THREE_VALUE));
+
+ checkValues(accuracy, ONE_VALUE, TWO_VALUE, THREE_VALUE);
+
+ checkToString(accuracy, "1.002003");
+ }
+
+ public void testThreeTwoOne()
+ {
+ GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(THREE_VALUE, TWO_VALUE, ONE_VALUE));
+
+ checkValues(accuracy, THREE_VALUE, TWO_VALUE, ONE_VALUE);
+
+ checkToString(accuracy, "3.002001");
+ }
+
+ public void testTwoThreeTwo()
+ {
+ GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(TWO_VALUE, THREE_VALUE, TWO_VALUE));
+
+ checkValues(accuracy, TWO_VALUE, THREE_VALUE, TWO_VALUE);
+
+ checkToString(accuracy, "2.003002");
+ }
+
+
+ public void testZeroTwoThree()
+ {
+ GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(ZERO_VALUE, TWO_VALUE, THREE_VALUE));
+
+ checkValues(accuracy, ZERO_VALUE, TWO_VALUE, THREE_VALUE);
+
+ checkToString(accuracy, "0.002003");
+ }
+
+ public void testThreeTwoNull()
+ {
+ GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(THREE_VALUE, TWO_VALUE, null));
+
+ checkValues(accuracy, THREE_VALUE, TWO_VALUE, ZERO_VALUE);
+
+ checkToString(accuracy, "3.002000");
+ }
+
+ public void testOneNullOne()
+ {
+ GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(ONE_VALUE, null, ONE_VALUE));
+
+ checkValues(accuracy, ONE_VALUE, ZERO_VALUE, ONE_VALUE);
+
+ checkToString(accuracy, "1.000001");
+ }
+
+ public void testZeroNullNull()
+ {
+ GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(ZERO_VALUE, null, null));
+
+ checkValues(accuracy, ZERO_VALUE, ZERO_VALUE, ZERO_VALUE);
+
+ checkToString(accuracy, "0.000000");
+ }
+
+ public void testNullNullNull()
+ {
+ GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(null, null, null));
+
+ checkValues(accuracy, ZERO_VALUE, ZERO_VALUE, ZERO_VALUE);
+
+ checkToString(accuracy, "0.000000");
+ }
+
+ private void checkValues(
+ GenTimeAccuracy accuracy,
+ ASN1Integer secs,
+ ASN1Integer millis,
+ ASN1Integer micros)
+ {
+ assertEquals(secs.getValue().intValue(), accuracy.getSeconds());
+ assertEquals(millis.getValue().intValue(), accuracy.getMillis());
+ assertEquals(micros.getValue().intValue(), accuracy.getMicros());
+ }
+
+ private void checkToString(
+ GenTimeAccuracy accuracy,
+ String expected)
+ {
+ assertEquals(expected, accuracy.toString());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/TimeStampTokenInfoUnitTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/TimeStampTokenInfoUnitTest.java
new file mode 100644
index 000000000..39e7285d4
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/TimeStampTokenInfoUnitTest.java
@@ -0,0 +1,144 @@
+package org.spongycastle.tsp;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import junit.framework.TestCase;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.tsp.TSTInfo;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.encoders.Hex;
+
+public class TimeStampTokenInfoUnitTest
+ extends TestCase
+{
+ private static final byte[] tstInfo1 = Hex.decode(
+ "303e02010106022a033021300906052b0e03021a050004140000000000000000000000000000000000000000"
+ + "020118180f32303035313130313038313732315a");
+
+ private static final byte[] tstInfo2 = Hex.decode(
+ "304c02010106022a033021300906052b0e03021a05000414ffffffffffffffffffffffffffffffffffffffff"
+ + "020117180f32303035313130313038323934355a3009020103800101810102020164");
+
+ private static final byte[] tstInfo3 = Hex.decode(
+ "304f02010106022a033021300906052b0e03021a050004140000000000000000000000000000000000000000"
+ + "020117180f32303035313130313038343733355a30090201038001018101020101ff020164");
+
+ private static final byte[] tstInfoDudDate = Hex.decode(
+ "303e02010106022a033021300906052b0e03021a050004140000000000000000000000000000000000000000"
+ + "020118180f32303056313130313038313732315a");
+
+ public void testTstInfo1()
+ throws Exception
+ {
+ TimeStampTokenInfo tstInfo = getTimeStampTokenInfo(tstInfo1);
+
+ //
+ // verify
+ //
+ GenTimeAccuracy accuracy = tstInfo.getGenTimeAccuracy();
+
+ assertNull(accuracy);
+
+ assertEquals(new BigInteger("24"), tstInfo.getSerialNumber());
+
+ assertEquals(1130833041000L, tstInfo.getGenTime().getTime());
+
+ assertEquals("1.2.3", tstInfo.getPolicy().getId());
+
+ assertEquals(false, tstInfo.isOrdered());
+
+ assertNull(tstInfo.getNonce());
+
+ assertEquals(TSPAlgorithms.SHA1, tstInfo.getMessageImprintAlgOID());
+
+ assertTrue(Arrays.areEqual(new byte[20], tstInfo.getMessageImprintDigest()));
+
+ assertTrue(Arrays.areEqual(tstInfo1, tstInfo.getEncoded()));
+ }
+
+ public void testTstInfo2()
+ throws Exception
+ {
+ TimeStampTokenInfo tstInfo = getTimeStampTokenInfo(tstInfo2);
+
+ //
+ // verify
+ //
+ GenTimeAccuracy accuracy = tstInfo.getGenTimeAccuracy();
+
+ assertEquals(3, accuracy.getSeconds());
+ assertEquals(1, accuracy.getMillis());
+ assertEquals(2, accuracy.getMicros());
+
+ assertEquals(new BigInteger("23"), tstInfo.getSerialNumber());
+
+ assertEquals(1130833785000L, tstInfo.getGenTime().getTime());
+
+ assertEquals("1.2.3", tstInfo.getPolicy().getId());
+
+ assertEquals(false, tstInfo.isOrdered());
+
+ assertEquals(tstInfo.getNonce(), BigInteger.valueOf(100));
+
+ assertTrue(Arrays.areEqual(Hex.decode("ffffffffffffffffffffffffffffffffffffffff"), tstInfo.getMessageImprintDigest()));
+
+ assertTrue(Arrays.areEqual(tstInfo2, tstInfo.getEncoded()));
+ }
+
+ public void testTstInfo3()
+ throws Exception
+ {
+ TimeStampTokenInfo tstInfo = getTimeStampTokenInfo(tstInfo3);
+
+ //
+ // verify
+ //
+ GenTimeAccuracy accuracy = tstInfo.getGenTimeAccuracy();
+
+ assertEquals(3, accuracy.getSeconds());
+ assertEquals(1, accuracy.getMillis());
+ assertEquals(2, accuracy.getMicros());
+
+ assertEquals(new BigInteger("23"), tstInfo.getSerialNumber());
+
+ assertEquals(1130834855000L, tstInfo.getGenTime().getTime());
+
+ assertEquals("1.2.3", tstInfo.getPolicy().getId());
+
+ assertEquals(true, tstInfo.isOrdered());
+
+ assertEquals(tstInfo.getNonce(), BigInteger.valueOf(100));
+
+ assertEquals(TSPAlgorithms.SHA1, tstInfo.getMessageImprintAlgOID());
+
+ assertTrue(Arrays.areEqual(new byte[20], tstInfo.getMessageImprintDigest()));
+
+ assertTrue(Arrays.areEqual(tstInfo3, tstInfo.getEncoded()));
+ }
+
+ public void testTstInfoDudDate()
+ throws Exception
+ {
+ try
+ {
+ getTimeStampTokenInfo(tstInfoDudDate);
+
+ fail("dud date not detected.");
+ }
+ catch (TSPException e)
+ {
+ // expected
+ }
+ }
+
+ private TimeStampTokenInfo getTimeStampTokenInfo(
+ byte[] tstInfo)
+ throws IOException, TSPException
+ {
+ ASN1InputStream aIn = new ASN1InputStream(tstInfo);
+ TSTInfo info = TSTInfo.getInstance(aIn.readObject());
+
+ return new TimeStampTokenInfo(info);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/AllTests.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/AllTests.java
new file mode 100644
index 000000000..5a9907722
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/AllTests.java
@@ -0,0 +1,32 @@
+package org.spongycastle.tsp.test;
+
+import java.security.Security;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public class AllTests
+ extends TestCase
+{
+ public static void main (String[] args)
+ {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite()
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ TestSuite suite = new TestSuite("TSP Tests");
+
+ suite.addTestSuite(ParseTest.class);
+ suite.addTestSuite(NewTSPTest.class);
+ suite.addTestSuite(CMSTimeStampedDataTest.class);
+ suite.addTestSuite(CMSTimeStampedDataParserTest.class);
+ suite.addTestSuite(CMSTimeStampedDataGeneratorTest.class);
+
+ return suite;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/CMSTimeStampedDataGeneratorTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/CMSTimeStampedDataGeneratorTest.java
new file mode 100644
index 000000000..2af0992a8
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/CMSTimeStampedDataGeneratorTest.java
@@ -0,0 +1,309 @@
+package org.spongycastle.tsp.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import junit.framework.TestCase;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.cert.jcajce.JcaCertStore;
+import org.spongycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.bc.BcDigestCalculatorProvider;
+import org.spongycastle.tsp.TSPAlgorithms;
+import org.spongycastle.tsp.TimeStampRequest;
+import org.spongycastle.tsp.TimeStampRequestGenerator;
+import org.spongycastle.tsp.TimeStampResponse;
+import org.spongycastle.tsp.TimeStampResponseGenerator;
+import org.spongycastle.tsp.TimeStampToken;
+import org.spongycastle.tsp.TimeStampTokenGenerator;
+import org.spongycastle.tsp.cms.CMSTimeStampedData;
+import org.spongycastle.tsp.cms.CMSTimeStampedDataGenerator;
+import org.spongycastle.tsp.cms.CMSTimeStampedDataParser;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Store;
+import org.spongycastle.util.io.Streams;
+
+public class CMSTimeStampedDataGeneratorTest
+ extends TestCase
+{
+
+ BouncyCastleProvider bouncyCastleProvider;
+ CMSTimeStampedDataGenerator cmsTimeStampedDataGenerator = null;
+ String fileInput = "FileDaFirmare.data";
+ byte[] baseData;
+
+ protected void setUp()
+ throws Exception
+ {
+ bouncyCastleProvider = new BouncyCastleProvider();
+ if (Security.getProvider(bouncyCastleProvider.getName()) == null)
+ {
+ Security.addProvider(bouncyCastleProvider);
+ }
+
+ cmsTimeStampedDataGenerator = new CMSTimeStampedDataGenerator();
+ ByteArrayOutputStream origStream = new ByteArrayOutputStream();
+ InputStream in = this.getClass().getResourceAsStream(fileInput);
+ int ch;
+
+ while ((ch = in.read()) >= 0)
+ {
+ origStream.write(ch);
+ }
+
+ origStream.close();
+
+ this.baseData = origStream.toByteArray();
+
+ }
+
+ protected void tearDown()
+ throws Exception
+ {
+ cmsTimeStampedDataGenerator = null;
+ Security.removeProvider(bouncyCastleProvider.getName());
+ }
+
+ public void testGenerate()
+ throws Exception
+ {
+ BcDigestCalculatorProvider calculatorProvider = new BcDigestCalculatorProvider();
+ ASN1ObjectIdentifier algOID = new ASN1ObjectIdentifier("2.16.840.1.101.3.4.2.1"); // SHA-256
+ DigestCalculator hashCalculator = calculatorProvider.get(new AlgorithmIdentifier(algOID));
+
+ cmsTimeStampedDataGenerator.initialiseMessageImprintDigestCalculator(hashCalculator);
+
+ hashCalculator.getOutputStream().write(baseData);
+ hashCalculator.getOutputStream().close();
+
+ TimeStampToken timeStampToken = createTimeStampToken(hashCalculator.getDigest(), NISTObjectIdentifiers.id_sha256);
+ CMSTimeStampedData cmsTimeStampedData = cmsTimeStampedDataGenerator.generate(timeStampToken, baseData);
+
+ for (int i = 0; i < 3; i++)
+ {
+ byte[] newRequestData = cmsTimeStampedData.calculateNextHash(hashCalculator);
+ TimeStampToken newTimeStampToken = createTimeStampToken(newRequestData, NISTObjectIdentifiers.id_sha256);
+ cmsTimeStampedData = cmsTimeStampedData.addTimeStamp(newTimeStampToken);
+ }
+ byte[] timeStampedData = cmsTimeStampedData.getEncoded();
+
+ // verify
+ DigestCalculatorProvider newCalculatorProvider = new BcDigestCalculatorProvider();
+ DigestCalculator imprintCalculator = cmsTimeStampedData.getMessageImprintDigestCalculator(newCalculatorProvider);
+ CMSTimeStampedData newCMSTimeStampedData = new CMSTimeStampedData(timeStampedData);
+ byte[] newContent = newCMSTimeStampedData.getContent();
+ assertEquals("Content expected and verified are different", true, Arrays.areEqual(newContent, baseData));
+
+ imprintCalculator.getOutputStream().write(newContent);
+
+ byte[] digest = imprintCalculator.getDigest();
+
+ TimeStampToken[] tokens = cmsTimeStampedData.getTimeStampTokens();
+ assertEquals("TimeStampToken expected and verified are different", 4, tokens.length);
+ for (int i = 0; i < tokens.length; i++)
+ {
+ cmsTimeStampedData.validate(newCalculatorProvider, digest, tokens[i]);
+ }
+ }
+
+ public void testGenerateWithMetadata()
+ throws Exception
+ {
+ cmsTimeStampedDataGenerator.setMetaData(true, fileInput, "TXT");
+
+ BcDigestCalculatorProvider calculatorProvider = new BcDigestCalculatorProvider();
+ ASN1ObjectIdentifier algOID = new ASN1ObjectIdentifier("2.16.840.1.101.3.4.2.1"); // SHA-256
+ DigestCalculator hashCalculator = calculatorProvider.get(new AlgorithmIdentifier(algOID));
+
+ cmsTimeStampedDataGenerator.initialiseMessageImprintDigestCalculator(hashCalculator);
+
+ hashCalculator.getOutputStream().write(baseData);
+ hashCalculator.getOutputStream().close();
+
+ TimeStampToken timeStampToken = createTimeStampToken(hashCalculator.getDigest(), NISTObjectIdentifiers.id_sha256);
+ CMSTimeStampedData cmsTimeStampedData = cmsTimeStampedDataGenerator.generate(timeStampToken, baseData);
+
+ for (int i = 0; i <= 3; i++)
+ {
+ byte[] newRequestData = cmsTimeStampedData.calculateNextHash(hashCalculator);
+ TimeStampToken newTimeStampToken = createTimeStampToken(newRequestData, NISTObjectIdentifiers.id_sha256);
+ cmsTimeStampedData = cmsTimeStampedData.addTimeStamp(newTimeStampToken);
+ }
+ byte[] timeStampedData = cmsTimeStampedData.getEncoded();
+
+ metadataCheck(timeStampedData);
+ metadataParserCheck(timeStampedData);
+ }
+
+ public void testGenerateWithMetadataAndDifferentAlgorithmIdentifier()
+ throws Exception
+ {
+ cmsTimeStampedDataGenerator.setMetaData(true, fileInput, "TXT");
+
+ BcDigestCalculatorProvider calculatorProvider = new BcDigestCalculatorProvider();
+
+ ASN1ObjectIdentifier algIdentifier = NISTObjectIdentifiers.id_sha224;
+
+ DigestCalculator hashCalculator = calculatorProvider.get(new AlgorithmIdentifier(algIdentifier));
+ cmsTimeStampedDataGenerator.initialiseMessageImprintDigestCalculator(hashCalculator);
+ hashCalculator.getOutputStream().write(baseData);
+ hashCalculator.getOutputStream().close();
+
+ byte[] requestData = hashCalculator.getDigest();
+ TimeStampToken timeStampToken = createTimeStampToken(requestData, algIdentifier);
+
+ CMSTimeStampedData cmsTimeStampedData = cmsTimeStampedDataGenerator.generate(timeStampToken, baseData);
+
+ for (int i = 0; i <= 3; i++) {
+ switch (i) {
+ case 0:
+ algIdentifier = NISTObjectIdentifiers.id_sha224;
+ break;
+ case 1:
+ algIdentifier = NISTObjectIdentifiers.id_sha256;
+ break;
+ case 2:
+ algIdentifier = NISTObjectIdentifiers.id_sha384;
+ break;
+ case 3:
+ algIdentifier = NISTObjectIdentifiers.id_sha512;
+ break;
+ }
+ hashCalculator = calculatorProvider.get(new AlgorithmIdentifier(algIdentifier));
+ byte[] newRequestData = cmsTimeStampedData.calculateNextHash(hashCalculator);
+ TimeStampToken newTimeStampToken = createTimeStampToken(newRequestData, algIdentifier);
+ cmsTimeStampedData = cmsTimeStampedData.addTimeStamp(newTimeStampToken);
+ }
+ byte[] timeStampedData = cmsTimeStampedData.getEncoded();
+
+ metadataCheck(timeStampedData);
+ metadataParserCheck(timeStampedData);
+
+ }
+
+
+ private void metadataCheck(byte[] timeStampedData)
+ throws Exception
+ {
+ CMSTimeStampedData cmsTspData = new CMSTimeStampedData(timeStampedData);
+ DigestCalculatorProvider newCalculatorProvider = new BcDigestCalculatorProvider();
+ DigestCalculator imprintCalculator = cmsTspData.getMessageImprintDigestCalculator(newCalculatorProvider);
+
+ byte[] newContent = cmsTspData.getContent();
+ assertEquals("Content expected and verified are different", true, Arrays.areEqual(newContent, baseData));
+
+ imprintCalculator.getOutputStream().write(newContent);
+
+ assertEquals(fileInput, cmsTspData.getFileName());
+ assertEquals("TXT", cmsTspData.getMediaType());
+
+ byte[] digest = imprintCalculator.getDigest();
+
+ TimeStampToken[] tokens = cmsTspData.getTimeStampTokens();
+ assertEquals("TimeStampToken expected and verified are different", 5, tokens.length);
+ for (int i = 0; i < tokens.length; i++)
+ {
+ cmsTspData.validate(newCalculatorProvider, digest, tokens[i]);
+ }
+ }
+
+ private void metadataParserCheck(byte[] timeStampedData)
+ throws Exception
+ {
+ CMSTimeStampedDataParser cmsTspData = new CMSTimeStampedDataParser(timeStampedData);
+ DigestCalculatorProvider newCalculatorProvider = new BcDigestCalculatorProvider();
+
+ InputStream input = cmsTspData.getContent();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ Streams.pipeAll(input, bOut);
+
+ assertEquals("Content expected and verified are different", true, Arrays.areEqual(bOut.toByteArray(), baseData));
+
+ DigestCalculator imprintCalculator = cmsTspData.getMessageImprintDigestCalculator(newCalculatorProvider);
+
+ Streams.pipeAll(new ByteArrayInputStream(bOut.toByteArray()), imprintCalculator.getOutputStream());
+
+ assertEquals(fileInput, cmsTspData.getFileName());
+ assertEquals("TXT", cmsTspData.getMediaType());
+
+ byte[] digest = imprintCalculator.getDigest();
+
+ TimeStampToken[] tokens = cmsTspData.getTimeStampTokens();
+ assertEquals("TimeStampToken expected and verified are different", 5, tokens.length);
+ for (int i = 0; i < tokens.length; i++)
+ {
+ cmsTspData.validate(newCalculatorProvider, digest, tokens[i]);
+ }
+ }
+
+ private TimeStampToken createTimeStampToken(byte[] hash, ASN1ObjectIdentifier hashAlg)
+ throws Exception
+ {
+ String algorithmName = null;
+ if (hashAlg.equals(NISTObjectIdentifiers.id_sha224))
+ {
+ algorithmName = "SHA224withRSA";
+ }
+ else if (hashAlg.equals(NISTObjectIdentifiers.id_sha256))
+ {
+ algorithmName = "SHA256withRSA";
+ }
+ else if (hashAlg.equals(NISTObjectIdentifiers.id_sha384))
+ {
+ algorithmName = "SHA384withRSA";
+ }
+ else if (hashAlg.equals(NISTObjectIdentifiers.id_sha512))
+ {
+ algorithmName = "SHA512withRSA";
+ }
+
+ String signDN = "O=Bouncy Castle, C=AU";
+ KeyPair signKP = TSPTestUtil.makeKeyPair();
+ X509Certificate signCert = TSPTestUtil.makeCACertificate(signKP,
+ signDN, signKP, signDN);
+
+ String origDN = "CN=Eric H. Echidna, E=eric@bouncycastle.org, O=Bouncy Castle, C=AU";
+ KeyPair origKP = TSPTestUtil.makeKeyPair();
+ X509Certificate cert = TSPTestUtil.makeCertificate(origKP,
+ origDN, signKP, signDN);
+
+ PrivateKey privateKey = origKP.getPrivate();
+
+ List certList = new ArrayList();
+ certList.add(cert);
+ certList.add(signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+ new JcaSimpleSignerInfoGeneratorBuilder().build(algorithmName, privateKey, cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
+
+ tsTokenGen.addCertificates(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(hashAlg, hash);
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date());
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ return tsResp.getTimeStampToken();
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/CMSTimeStampedDataParserTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/CMSTimeStampedDataParserTest.java
new file mode 100644
index 000000000..5fa14db71
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/CMSTimeStampedDataParserTest.java
@@ -0,0 +1,91 @@
+package org.spongycastle.tsp.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.bc.BcDigestCalculatorProvider;
+import org.spongycastle.tsp.TimeStampToken;
+import org.spongycastle.tsp.cms.CMSTimeStampedDataParser;
+import org.spongycastle.util.io.Streams;
+
+public class CMSTimeStampedDataParserTest
+ extends TestCase
+{
+
+ CMSTimeStampedDataParser cmsTimeStampedData = null;
+ String fileInput = "FileDaFirmare.txt.tsd.der";
+ private byte[] baseData;
+
+ protected void setUp()
+ throws Exception
+ {
+ ByteArrayOutputStream origStream = new ByteArrayOutputStream();
+ InputStream in = this.getClass().getResourceAsStream(fileInput);
+ int ch;
+
+ while ((ch = in.read()) >= 0)
+ {
+ origStream.write(ch);
+ }
+
+ origStream.close();
+
+ this.baseData = origStream.toByteArray();
+
+ cmsTimeStampedData = new CMSTimeStampedDataParser(baseData);
+ }
+
+ protected void tearDown()
+ throws Exception
+ {
+ cmsTimeStampedData = null;
+ }
+
+ public void testGetTimeStampTokens()
+ throws Exception
+ {
+ TimeStampToken[] tokens = cmsTimeStampedData.getTimeStampTokens();
+ assertEquals(3, tokens.length);
+ }
+
+ public void testValidateAllTokens()
+ throws Exception
+ {
+ DigestCalculatorProvider digestCalculatorProvider = new BcDigestCalculatorProvider();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ Streams.pipeAll(cmsTimeStampedData.getContent(), bOut);
+
+ DigestCalculator imprintCalculator = cmsTimeStampedData.getMessageImprintDigestCalculator(digestCalculatorProvider);
+
+ Streams.pipeAll(new ByteArrayInputStream(bOut.toByteArray()), imprintCalculator.getOutputStream());
+
+ byte[] digest = imprintCalculator.getDigest();
+
+ TimeStampToken[] tokens = cmsTimeStampedData.getTimeStampTokens();
+ for (int i = 0; i < tokens.length; i++)
+ {
+ cmsTimeStampedData.validate(digestCalculatorProvider, digest, tokens[i]);
+ }
+ }
+
+ public void testValidate()
+ throws Exception
+ {
+ DigestCalculatorProvider digestCalculatorProvider = new BcDigestCalculatorProvider();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ Streams.pipeAll(cmsTimeStampedData.getContent(), bOut);
+
+ DigestCalculator imprintCalculator = cmsTimeStampedData.getMessageImprintDigestCalculator(digestCalculatorProvider);
+
+ Streams.pipeAll(new ByteArrayInputStream(bOut.toByteArray()), imprintCalculator.getOutputStream());
+
+ cmsTimeStampedData.validate(digestCalculatorProvider, imprintCalculator.getDigest());
+ }
+
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/CMSTimeStampedDataTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/CMSTimeStampedDataTest.java
new file mode 100644
index 000000000..7f97dccb5
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/CMSTimeStampedDataTest.java
@@ -0,0 +1,84 @@
+package org.spongycastle.tsp.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.DigestCalculatorProvider;
+import org.spongycastle.operator.bc.BcDigestCalculatorProvider;
+import org.spongycastle.tsp.TimeStampToken;
+import org.spongycastle.tsp.cms.CMSTimeStampedData;
+
+public class CMSTimeStampedDataTest
+ extends TestCase
+{
+
+ CMSTimeStampedData cmsTimeStampedData = null;
+ String fileInput = "FileDaFirmare.txt.tsd.der";
+ String fileOutput = fileInput.substring(0, fileInput.indexOf(".tsd"));
+ private byte[] baseData;
+
+ protected void setUp()
+ throws Exception
+ {
+ ByteArrayOutputStream origStream = new ByteArrayOutputStream();
+ InputStream in = this.getClass().getResourceAsStream(fileInput);
+ int ch;
+
+ while ((ch = in.read()) >= 0)
+ {
+ origStream.write(ch);
+ }
+
+ origStream.close();
+
+ this.baseData = origStream.toByteArray();
+
+ cmsTimeStampedData = new CMSTimeStampedData(baseData);
+ }
+
+ protected void tearDown()
+ throws Exception
+ {
+ cmsTimeStampedData = null;
+ }
+
+ public void testGetTimeStampTokens()
+ throws Exception
+ {
+ TimeStampToken[] tokens = cmsTimeStampedData.getTimeStampTokens();
+ assertEquals(3, tokens.length);
+ }
+
+ public void testValidateAllTokens()
+ throws Exception
+ {
+ DigestCalculatorProvider digestCalculatorProvider = new BcDigestCalculatorProvider();
+
+ DigestCalculator imprintCalculator = cmsTimeStampedData.getMessageImprintDigestCalculator(digestCalculatorProvider);
+
+ imprintCalculator.getOutputStream().write(cmsTimeStampedData.getContent());
+
+ byte[] digest = imprintCalculator.getDigest();
+
+ TimeStampToken[] tokens = cmsTimeStampedData.getTimeStampTokens();
+ for (int i = 0; i < tokens.length; i++)
+ {
+ cmsTimeStampedData.validate(digestCalculatorProvider, digest, tokens[i]);
+ }
+ }
+
+ public void testValidate()
+ throws Exception
+ {
+ DigestCalculatorProvider digestCalculatorProvider = new BcDigestCalculatorProvider();
+
+ DigestCalculator imprintCalculator = cmsTimeStampedData.getMessageImprintDigestCalculator(digestCalculatorProvider);
+
+ imprintCalculator.getOutputStream().write(cmsTimeStampedData.getContent());
+
+ cmsTimeStampedData.validate(digestCalculatorProvider, imprintCalculator.getDigest());
+ }
+
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/NewTSPTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/NewTSPTest.java
new file mode 100644
index 000000000..e40ae0fc4
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/NewTSPTest.java
@@ -0,0 +1,833 @@
+package org.spongycastle.tsp.test;
+
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cmp.PKIFailureInfo;
+import org.spongycastle.asn1.cmp.PKIStatus;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.ess.ESSCertID;
+import org.spongycastle.asn1.ess.ESSCertIDv2;
+import org.spongycastle.asn1.ess.SigningCertificate;
+import org.spongycastle.asn1.ess.SigningCertificateV2;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.IssuerSerial;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.jcajce.JcaCertStore;
+import org.spongycastle.cms.CMSAttributeTableGenerationException;
+import org.spongycastle.cms.CMSAttributeTableGenerator;
+import org.spongycastle.cms.DefaultSignedAttributeTableGenerator;
+import org.spongycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
+import org.spongycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder;
+import org.spongycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.DigestCalculator;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.spongycastle.tsp.GenTimeAccuracy;
+import org.spongycastle.tsp.TSPAlgorithms;
+import org.spongycastle.tsp.TSPException;
+import org.spongycastle.tsp.TSPValidationException;
+import org.spongycastle.tsp.TimeStampRequest;
+import org.spongycastle.tsp.TimeStampRequestGenerator;
+import org.spongycastle.tsp.TimeStampResponse;
+import org.spongycastle.tsp.TimeStampResponseGenerator;
+import org.spongycastle.tsp.TimeStampToken;
+import org.spongycastle.tsp.TimeStampTokenGenerator;
+import org.spongycastle.tsp.TimeStampTokenInfo;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Store;
+
+public class NewTSPTest
+ extends TestCase
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ public void setUp()
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ public void testGeneral()
+ throws Exception
+ {
+ String signDN = "O=Bouncy Castle, C=AU";
+ KeyPair signKP = TSPTestUtil.makeKeyPair();
+ X509Certificate signCert = TSPTestUtil.makeCACertificate(signKP,
+ signDN, signKP, signDN);
+
+ String origDN = "CN=Eric H. Echidna, E=eric@bouncycastle.org, O=Bouncy Castle, C=AU";
+ KeyPair origKP = TSPTestUtil.makeKeyPair();
+ X509Certificate origCert = TSPTestUtil.makeCertificate(origKP,
+ origDN, signKP, signDN);
+
+
+
+ List certList = new ArrayList();
+ certList.add(origCert);
+ certList.add(signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ basicTest(origKP.getPrivate(), origCert, certs);
+ basicSha256Test(origKP.getPrivate(), origCert, certs);
+ basicTestWithTSA(origKP.getPrivate(), origCert, certs);
+ overrideAttrsTest(origKP.getPrivate(), origCert, certs);
+ responseValidationTest(origKP.getPrivate(), origCert, certs);
+ incorrectHashTest(origKP.getPrivate(), origCert, certs);
+ badAlgorithmTest(origKP.getPrivate(), origCert, certs);
+ timeNotAvailableTest(origKP.getPrivate(), origCert, certs);
+ badPolicyTest(origKP.getPrivate(), origCert, certs);
+ tokenEncodingTest(origKP.getPrivate(), origCert, certs);
+ certReqTest(origKP.getPrivate(), origCert, certs);
+ testAccuracyZeroCerts(origKP.getPrivate(), origCert, certs);
+ testAccuracyWithCertsAndOrdering(origKP.getPrivate(), origCert, certs);
+ testNoNonse(origKP.getPrivate(), origCert, certs);
+ }
+
+ private void basicTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ Store certs)
+ throws Exception
+ {
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+ new JcaSimpleSignerInfoGeneratorBuilder().build("SHA1withRSA", privateKey, cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
+
+ tsTokenGen.addCertificates(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date());
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert));
+
+ AttributeTable table = tsToken.getSignedAttributes();
+
+ assertNotNull("no signingCertificate attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificate));
+ }
+
+ private void basicSha256Test(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ Store certs)
+ throws Exception
+ {
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+ new JcaSimpleSignerInfoGeneratorBuilder().build("SHA256withRSA", privateKey, cert), new SHA256DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
+
+ tsTokenGen.addCertificates(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA256, new byte[32], BigInteger.valueOf(100));
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date());
+
+ assertEquals(PKIStatus.GRANTED, tsResp.getStatus());
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert));
+
+ AttributeTable table = tsToken.getSignedAttributes();
+
+ assertNotNull("no signingCertificate attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificateV2));
+
+ DigestCalculator digCalc = new SHA256DigestCalculator();
+
+ OutputStream dOut = digCalc.getOutputStream();
+
+ dOut.write(cert.getEncoded());
+
+ dOut.close();
+
+ byte[] certHash = digCalc.getDigest();
+
+ SigningCertificateV2 sigCertV2 = SigningCertificateV2.getInstance(table.get(PKCSObjectIdentifiers.id_aa_signingCertificateV2).getAttributeValues()[0]);
+
+ assertTrue(Arrays.areEqual(certHash, sigCertV2.getCerts()[0].getCertHash()));
+ }
+
+ private void overrideAttrsTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ Store certs)
+ throws Exception
+ {
+ JcaSimpleSignerInfoGeneratorBuilder signerInfoGenBuilder = new JcaSimpleSignerInfoGeneratorBuilder().setProvider("SC");
+
+ IssuerSerial issuerSerial = new IssuerSerial(new GeneralNames(new GeneralName(new X509CertificateHolder(cert.getEncoded()).getIssuer())), cert.getSerialNumber());
+
+ DigestCalculator digCalc = new SHA1DigestCalculator();
+
+ OutputStream dOut = digCalc.getOutputStream();
+
+ dOut.write(cert.getEncoded());
+
+ dOut.close();
+
+ byte[] certHash = digCalc.getDigest();
+
+ digCalc = new SHA256DigestCalculator();
+
+ dOut = digCalc.getOutputStream();
+
+ dOut.write(cert.getEncoded());
+
+ dOut.close();
+
+ byte[] certHash256 = digCalc.getDigest();
+
+ final ESSCertID essCertid = new ESSCertID(certHash, issuerSerial);
+ final ESSCertIDv2 essCertidV2 = new ESSCertIDv2(certHash256, issuerSerial);
+
+ signerInfoGenBuilder.setSignedAttributeGenerator(new CMSAttributeTableGenerator()
+ {
+ public AttributeTable getAttributes(Map parameters)
+ throws CMSAttributeTableGenerationException
+ {
+ CMSAttributeTableGenerator attrGen = new DefaultSignedAttributeTableGenerator();
+
+ AttributeTable table = attrGen.getAttributes(parameters);
+ table = table.add(PKCSObjectIdentifiers.id_aa_signingCertificate, new SigningCertificate(essCertid));
+ table = table.add(PKCSObjectIdentifiers.id_aa_signingCertificateV2, new SigningCertificateV2(new ESSCertIDv2[]{essCertidV2}));
+
+ return table;
+ }
+ });
+
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(signerInfoGenBuilder.build("SHA1withRSA", privateKey, cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
+
+ tsTokenGen.addCertificates(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date());
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert));
+
+ AttributeTable table = tsToken.getSignedAttributes();
+
+ assertNotNull("no signingCertificate attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificate));
+ assertNotNull("no signingCertificateV2 attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificateV2));
+
+ SigningCertificate sigCert = SigningCertificate.getInstance(table.get(PKCSObjectIdentifiers.id_aa_signingCertificate).getAttributeValues()[0]);
+
+ assertEquals(new X509CertificateHolder(cert.getEncoded()).getIssuer(), sigCert.getCerts()[0].getIssuerSerial().getIssuer().getNames()[0].getName());
+ assertEquals(cert.getSerialNumber(), sigCert.getCerts()[0].getIssuerSerial().getSerial().getValue());
+ assertTrue(Arrays.areEqual(certHash, sigCert.getCerts()[0].getCertHash()));
+
+ SigningCertificateV2 sigCertV2 = SigningCertificateV2.getInstance(table.get(PKCSObjectIdentifiers.id_aa_signingCertificateV2).getAttributeValues()[0]);
+
+ assertEquals(new X509CertificateHolder(cert.getEncoded()).getIssuer(), sigCertV2.getCerts()[0].getIssuerSerial().getIssuer().getNames()[0].getName());
+ assertEquals(cert.getSerialNumber(), sigCertV2.getCerts()[0].getIssuerSerial().getSerial().getValue());
+ assertTrue(Arrays.areEqual(certHash256, sigCertV2.getCerts()[0].getCertHash()));
+ }
+
+ private void basicTestWithTSA(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ Store certs)
+ throws Exception
+ {
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+ new JcaSimpleSignerInfoGeneratorBuilder().build("SHA1withRSA", privateKey, cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
+
+ tsTokenGen.addCertificates(certs);
+ tsTokenGen.setTSA(new GeneralName(new X500Name("CN=Test")));
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date());
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert));
+
+ AttributeTable table = tsToken.getSignedAttributes();
+
+ assertNotNull("no signingCertificate attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificate));
+ }
+
+ private void responseValidationTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ Store certs)
+ throws Exception
+ {
+ JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+ infoGeneratorBuilder.build(new JcaContentSignerBuilder("MD5withRSA").setProvider(BC).build(privateKey), cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
+
+ tsTokenGen.addCertificates(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date());
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider("SC").build(cert));
+
+ //
+ // check validation
+ //
+ tsResp.validate(request);
+
+ try
+ {
+ request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(101));
+
+ tsResp.validate(request);
+
+ fail("response validation failed on invalid nonce.");
+ }
+ catch (TSPValidationException e)
+ {
+ // ignore
+ }
+
+ try
+ {
+ request = reqGen.generate(TSPAlgorithms.SHA1, new byte[22], BigInteger.valueOf(100));
+
+ tsResp.validate(request);
+
+ fail("response validation failed on wrong digest.");
+ }
+ catch (TSPValidationException e)
+ {
+ // ignore
+ }
+
+ try
+ {
+ request = reqGen.generate(TSPAlgorithms.MD5, new byte[20], BigInteger.valueOf(100));
+
+ tsResp.validate(request);
+
+ fail("response validation failed on wrong digest.");
+ }
+ catch (TSPValidationException e)
+ {
+ // ignore
+ }
+ }
+
+ private void incorrectHashTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ Store certs)
+ throws Exception
+ {
+ JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(infoGeneratorBuilder.build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(privateKey), cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
+
+ tsTokenGen.addCertificates(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[16]);
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date());
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ if (tsToken != null)
+ {
+ fail("incorrectHash - token not null.");
+ }
+
+ PKIFailureInfo failInfo = tsResp.getFailInfo();
+
+ if (failInfo == null)
+ {
+ fail("incorrectHash - failInfo set to null.");
+ }
+
+ if (failInfo.intValue() != PKIFailureInfo.badDataFormat)
+ {
+ fail("incorrectHash - wrong failure info returned.");
+ }
+ }
+
+ private void badAlgorithmTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ Store certs)
+ throws Exception
+ {
+ JcaSimpleSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSimpleSignerInfoGeneratorBuilder().setProvider(BC);
+
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(infoGeneratorBuilder.build("SHA1withRSA", privateKey, cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
+
+ tsTokenGen.addCertificates(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(new ASN1ObjectIdentifier("1.2.3.4.5"), new byte[20]);
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date());
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ if (tsToken != null)
+ {
+ fail("badAlgorithm - token not null.");
+ }
+
+ PKIFailureInfo failInfo = tsResp.getFailInfo();
+
+ if (failInfo == null)
+ {
+ fail("badAlgorithm - failInfo set to null.");
+ }
+
+ if (failInfo.intValue() != PKIFailureInfo.badAlg)
+ {
+ fail("badAlgorithm - wrong failure info returned.");
+ }
+ }
+
+ private void timeNotAvailableTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ Store certs)
+ throws Exception
+ {
+ JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(infoGeneratorBuilder.build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(privateKey), cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
+
+ tsTokenGen.addCertificates(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(new ASN1ObjectIdentifier("1.2.3.4.5"), new byte[20]);
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp;
+
+ try
+ {
+ tsResp = tsRespGen.generateGrantedResponse(request, new BigInteger("23"), null);
+ }
+ catch (TSPException e)
+ {
+ tsResp = tsRespGen.generateRejectedResponse(e);
+ }
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ if (tsToken != null)
+ {
+ fail("timeNotAvailable - token not null.");
+ }
+
+ PKIFailureInfo failInfo = tsResp.getFailInfo();
+
+ if (failInfo == null)
+ {
+ fail("timeNotAvailable - failInfo set to null.");
+ }
+
+ if (failInfo.intValue() != PKIFailureInfo.timeNotAvailable)
+ {
+ fail("timeNotAvailable - wrong failure info returned.");
+ }
+ }
+
+ private void badPolicyTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ Store certs)
+ throws Exception
+ {
+ JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(infoGeneratorBuilder.build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(privateKey), cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
+
+ tsTokenGen.addCertificates(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+
+ reqGen.setReqPolicy(new ASN1ObjectIdentifier("1.1"));
+
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20]);
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED, new HashSet());
+
+ TimeStampResponse tsResp;
+
+ try
+ {
+ tsResp = tsRespGen.generateGrantedResponse(request, new BigInteger("23"), new Date());
+ }
+ catch (TSPException e)
+ {
+ tsResp = tsRespGen.generateRejectedResponse(e);
+ }
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ if (tsToken != null)
+ {
+ fail("badPolicy - token not null.");
+ }
+
+ PKIFailureInfo failInfo = tsResp.getFailInfo();
+
+ if (failInfo == null)
+ {
+ fail("badPolicy - failInfo set to null.");
+ }
+
+ if (failInfo.intValue() != PKIFailureInfo.unacceptedPolicy)
+ {
+ fail("badPolicy - wrong failure info returned.");
+ }
+ }
+
+ private void certReqTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ Store certs)
+ throws Exception
+ {
+ JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(infoGeneratorBuilder.build(new JcaContentSignerBuilder("MD5withRSA").setProvider(BC).build(privateKey), cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
+
+ tsTokenGen.addCertificates(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+
+ //
+ // request with certReq false
+ //
+ reqGen.setCertReq(false);
+
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generateGrantedResponse(request, new BigInteger("23"), new Date());
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ assertNull(tsToken.getTimeStampInfo().getGenTimeAccuracy()); // check for abscence of accuracy
+
+ assertEquals("1.2", tsToken.getTimeStampInfo().getPolicy().getId());
+
+ try
+ {
+ tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert));
+ }
+ catch (TSPValidationException e)
+ {
+ fail("certReq(false) verification of token failed.");
+ }
+
+ Store respCerts = tsToken.getCertificates();
+
+ Collection certsColl = respCerts.getMatches(null);
+
+ if (!certsColl.isEmpty())
+ {
+ fail("certReq(false) found certificates in response.");
+ }
+ }
+
+
+ private void tokenEncodingTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ Store certs)
+ throws Exception
+ {
+ JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(infoGeneratorBuilder.build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(privateKey), cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2.3.4.5.6"));
+
+ tsTokenGen.addCertificates(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date());
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampResponse tsResponse = new TimeStampResponse(tsResp.getEncoded());
+
+ if (!Arrays.areEqual(tsResponse.getEncoded(), tsResp.getEncoded())
+ || !Arrays.areEqual(tsResponse.getTimeStampToken().getEncoded(),
+ tsResp.getTimeStampToken().getEncoded()))
+ {
+ fail();
+ }
+ }
+
+ private void testAccuracyZeroCerts(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ Store certs)
+ throws Exception
+ {
+ JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(infoGeneratorBuilder.build(new JcaContentSignerBuilder("MD5withRSA").setProvider(BC).build(privateKey), cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2"));
+
+ tsTokenGen.addCertificates(certs);
+
+ tsTokenGen.setAccuracySeconds(1);
+ tsTokenGen.setAccuracyMillis(2);
+ tsTokenGen.setAccuracyMicros(3);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date());
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider("SC").build(cert));
+
+ //
+ // check validation
+ //
+ tsResp.validate(request);
+
+ //
+ // check tstInfo
+ //
+ TimeStampTokenInfo tstInfo = tsToken.getTimeStampInfo();
+
+ //
+ // check accuracy
+ //
+ GenTimeAccuracy accuracy = tstInfo.getGenTimeAccuracy();
+
+ assertEquals(1, accuracy.getSeconds());
+ assertEquals(2, accuracy.getMillis());
+ assertEquals(3, accuracy.getMicros());
+
+ assertEquals(new BigInteger("23"), tstInfo.getSerialNumber());
+
+ assertEquals("1.2", tstInfo.getPolicy().getId());
+
+ //
+ // test certReq
+ //
+ Store store = tsToken.getCertificates();
+
+ Collection certificates = store.getMatches(null);
+
+ assertEquals(0, certificates.size());
+ }
+
+ private void testAccuracyWithCertsAndOrdering(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ Store certs)
+ throws Exception
+ {
+ JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(infoGeneratorBuilder.build(new JcaContentSignerBuilder("MD5withRSA").setProvider(BC).build(privateKey), cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2.3"));
+
+ tsTokenGen.addCertificates(certs);
+
+ tsTokenGen.setAccuracySeconds(3);
+ tsTokenGen.setAccuracyMillis(1);
+ tsTokenGen.setAccuracyMicros(2);
+
+ tsTokenGen.setOrdering(true);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+
+ reqGen.setCertReq(true);
+
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+
+ assertTrue(request.getCertReq());
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp;
+
+ try
+ {
+ tsResp = tsRespGen.generateGrantedResponse(request, new BigInteger("23"), new Date());
+ }
+ catch (TSPException e)
+ {
+ tsResp = tsRespGen.generateRejectedResponse(e);
+ }
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider("SC").build(cert));
+
+ //
+ // check validation
+ //
+ tsResp.validate(request);
+
+ //
+ // check tstInfo
+ //
+ TimeStampTokenInfo tstInfo = tsToken.getTimeStampInfo();
+
+ //
+ // check accuracy
+ //
+ GenTimeAccuracy accuracy = tstInfo.getGenTimeAccuracy();
+
+ assertEquals(3, accuracy.getSeconds());
+ assertEquals(1, accuracy.getMillis());
+ assertEquals(2, accuracy.getMicros());
+
+ assertEquals(new BigInteger("23"), tstInfo.getSerialNumber());
+
+ assertEquals("1.2.3", tstInfo.getPolicy().getId());
+
+ assertEquals(true, tstInfo.isOrdered());
+
+ assertEquals(tstInfo.getNonce(), BigInteger.valueOf(100));
+
+ //
+ // test certReq
+ //
+ Store store = tsToken.getCertificates();
+
+ Collection certificates = store.getMatches(null);
+
+ assertEquals(2, certificates.size());
+ }
+
+ private void testNoNonse(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ Store certs)
+ throws Exception
+ {
+ JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build());
+
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(infoGeneratorBuilder.build(new JcaContentSignerBuilder("MD5withRSA").setProvider(BC).build(privateKey), cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2.3"));
+
+ tsTokenGen.addCertificates(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20]);
+
+ assertFalse(request.getCertReq());
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("24"), new Date());
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ tsToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider("SC").build(cert));
+
+ //
+ // check validation
+ //
+ tsResp.validate(request);
+
+ //
+ // check tstInfo
+ //
+ TimeStampTokenInfo tstInfo = tsToken.getTimeStampInfo();
+
+ //
+ // check accuracy
+ //
+ GenTimeAccuracy accuracy = tstInfo.getGenTimeAccuracy();
+
+ assertNull(accuracy);
+
+ assertEquals(new BigInteger("24"), tstInfo.getSerialNumber());
+
+ assertEquals("1.2.3", tstInfo.getPolicy().getId());
+
+ assertEquals(false, tstInfo.isOrdered());
+
+ assertNull(tstInfo.getNonce());
+
+ //
+ // test certReq
+ //
+ Store store = tsToken.getCertificates();
+
+ Collection certificates = store.getMatches(null);
+
+ assertEquals(0, certificates.size());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/ParseTest.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/ParseTest.java
new file mode 100644
index 000000000..4bc4c9853
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/ParseTest.java
@@ -0,0 +1,417 @@
+package org.spongycastle.tsp.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.Security;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+import junit.framework.TestCase;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cmp.PKIFailureInfo;
+import org.spongycastle.asn1.cmp.PKIStatus;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.tsp.TSPAlgorithms;
+import org.spongycastle.tsp.TimeStampRequest;
+import org.spongycastle.tsp.TimeStampResponse;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Store;
+import org.spongycastle.util.encoders.Base64;
+
+/**
+ * Test Cases
+ */
+public class ParseTest
+ extends TestCase
+{
+ private byte[] sha1Request = Base64.decode(
+ "MDACAQEwITAJBgUrDgMCGgUABBT5UbEBmJssO3RxcQtOePxNvfoMpgIIC+Gv"
+ + "YW2mtZQ=");
+
+
+ private byte[] sha1noNonse = Base64.decode(
+ "MCYCAQEwITAJBgUrDgMCGgUABBT5UbEBmJssO3RxcQtOePxNvfoMpg==");
+
+ private byte[] md5Request = Base64.decode(
+ "MDoCAQEwIDAMBggqhkiG9w0CBQUABBDIl9FBCvjyx0+6EbHbUR6eBgkrBgEE"
+ + "AakHBQECCDQluayIxIzn");
+
+ private byte[] ripemd160Request = Base64.decode(
+ "MD8CAQEwITAJBgUrJAMCAQUABBSq03a/mk50Yd9lMF+BSqOp/RHGQQYJKwYB"
+ + "BAGpBwUBAgkA4SZs9NfqISMBAf8=");
+
+ private byte[] sha1Response = Base64.decode(
+ "MIICbDADAgEAMIICYwYJKoZIhvcNAQcCoIICVDCCAlACAQMxCzAJBgUrDgMC"
+ + "GgUAMIHaBgsqhkiG9w0BCRABBKCBygSBxzCBxAIBAQYEKgMEATAhMAkGBSsO"
+ + "AwIaBQAEFPlRsQGYmyw7dHFxC054/E29+gymAgEEGA8yMDA0MTIwOTA3NTIw"
+ + "NVowCgIBAYACAfSBAWQBAf8CCAvhr2FtprWUoGmkZzBlMRgwFgYDVQQDEw9F"
+ + "cmljIEguIEVjaGlkbmExJDAiBgkqhkiG9w0BCQEWFWVyaWNAYm91bmN5Y2Fz"
+ + "dGxlLm9yZzEWMBQGA1UEChMNQm91bmN5IENhc3RsZTELMAkGA1UEBhMCQVUx"
+ + "ggFfMIIBWwIBATAqMCUxFjAUBgNVBAoTDUJvdW5jeSBDYXN0bGUxCzAJBgNV"
+ + "BAYTAkFVAgECMAkGBSsOAwIaBQCggYwwGgYJKoZIhvcNAQkDMQ0GCyqGSIb3"
+ + "DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0wNDEyMDkwNzUyMDVaMCMGCSqGSIb3"
+ + "DQEJBDEWBBTGR1cbm94tWbcpDWrH+bD8UYePsTArBgsqhkiG9w0BCRACDDEc"
+ + "MBowGDAWBBS37aLzFcheqeJ5cla0gjNWHGKbRzANBgkqhkiG9w0BAQEFAASB"
+ + "gBrc9CJ3xlcTQuWQXJUqPEn6f6vfJAINKsn22z8LIfS/2p/CTFU6+W/bz8j8"
+ + "j+8uWEJe8okTsI0FflljIsspqOPTB/RrnXteajbkuk/rLmz1B2g/qWBGAzPI"
+ + "D214raBc1a7Bpd76PkvSSdjqrEaaskd+7JJiPr9l9yeSoh1AIt0N");
+
+ private byte[] sha1noNonseResponse = Base64.decode(
+ "MIICYjADAgEAMIICWQYJKoZIhvcNAQcCoIICSjCCAkYCAQMxCzAJBgUrDgMC"
+ + "GgUAMIHQBgsqhkiG9w0BCRABBKCBwASBvTCBugIBAQYEKgMEATAhMAkGBSsO"
+ + "AwIaBQAEFPlRsQGYmyw7dHFxC054/E29+gymAgECGA8yMDA0MTIwOTA3MzQx"
+ + "MlowCgIBAYACAfSBAWQBAf+gaaRnMGUxGDAWBgNVBAMTD0VyaWMgSC4gRWNo"
+ + "aWRuYTEkMCIGCSqGSIb3DQEJARYVZXJpY0Bib3VuY3ljYXN0bGUub3JnMRYw"
+ + "FAYDVQQKEw1Cb3VuY3kgQ2FzdGxlMQswCQYDVQQGEwJBVTGCAV8wggFbAgEB"
+ + "MCowJTEWMBQGA1UEChMNQm91bmN5IENhc3RsZTELMAkGA1UEBhMCQVUCAQIw"
+ + "CQYFKw4DAhoFAKCBjDAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJ"
+ + "KoZIhvcNAQkFMQ8XDTA0MTIwOTA3MzQxMlowIwYJKoZIhvcNAQkEMRYEFMNA"
+ + "xlscHYiByHL9DIEh3FewIhgSMCsGCyqGSIb3DQEJEAIMMRwwGjAYMBYEFLft"
+ + "ovMVyF6p4nlyVrSCM1YcYptHMA0GCSqGSIb3DQEBAQUABIGAaj46Tarrg7V7"
+ + "z13bbetrGv+xy159eE8kmIW9nPegru3DuK/GmbMx9W3l0ydx0zdXRwYi6NZc"
+ + "nNqbEZQZ2L1biJVTflgWq4Nxu4gPGjH/BGHKdH/LyW4eDcXZR39AkNBMnDAK"
+ + "EmhhJo1/Tc+S/WkV9lnHJCPIn+TAijBUO6EiTik=");
+
+ private byte[] md5Response = Base64.decode(
+ "MIICcDADAgEAMIICZwYJKoZIhvcNAQcCoIICWDCCAlQCAQMxCzAJBgUrDgMC"
+ + "GgUAMIHeBgsqhkiG9w0BCRABBKCBzgSByzCByAIBAQYJKwYBBAGpBwUBMCAw"
+ + "DAYIKoZIhvcNAgUFAAQQyJfRQQr48sdPuhGx21EengIBAxgPMjAwNDEyMDkw"
+ + "NzQ2MTZaMAoCAQGAAgH0gQFkAQH/Agg0JbmsiMSM56BppGcwZTEYMBYGA1UE"
+ + "AxMPRXJpYyBILiBFY2hpZG5hMSQwIgYJKoZIhvcNAQkBFhVlcmljQGJvdW5j"
+ + "eWNhc3RsZS5vcmcxFjAUBgNVBAoTDUJvdW5jeSBDYXN0bGUxCzAJBgNVBAYT"
+ + "AkFVMYIBXzCCAVsCAQEwKjAlMRYwFAYDVQQKEw1Cb3VuY3kgQ2FzdGxlMQsw"
+ + "CQYDVQQGEwJBVQIBAjAJBgUrDgMCGgUAoIGMMBoGCSqGSIb3DQEJAzENBgsq"
+ + "hkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMDQxMjA5MDc0NjE2WjAjBgkq"
+ + "hkiG9w0BCQQxFgQUFpRpaiRUUjiY7EbefbWLKDIY0XMwKwYLKoZIhvcNAQkQ"
+ + "AgwxHDAaMBgwFgQUt+2i8xXIXqnieXJWtIIzVhxim0cwDQYJKoZIhvcNAQEB"
+ + "BQAEgYBTwKsLLrQm+bvKV7Jwto/cMQh0KsVB5RoEeGn5CI9XyF2Bm+JRcvQL"
+ + "Nm7SgSOBVt4A90TqujxirNeyQnXRiSnFvXd09Wet9WIQNpwpiGlE7lCrAhuq"
+ + "/TAUe79VIpoQZDtyhbh0Vzxl24yRoechabC0zuPpOWOzrA4YC3Hv1J2tAA==");
+
+ private byte[] signingCert = Base64.decode(
+ "MIICWjCCAcOgAwIBAgIBAjANBgkqhkiG9w0BAQQFADAlMRYwFAYDVQQKEw1Cb3Vu"
+ + "Y3kgQ2FzdGxlMQswCQYDVQQGEwJBVTAeFw0wNDEyMDkwNzEzMTRaFw0wNTAzMTkw"
+ + "NzEzMTRaMGUxGDAWBgNVBAMTD0VyaWMgSC4gRWNoaWRuYTEkMCIGCSqGSIb3DQEJ"
+ + "ARYVZXJpY0Bib3VuY3ljYXN0bGUub3JnMRYwFAYDVQQKEw1Cb3VuY3kgQ2FzdGxl"
+ + "MQswCQYDVQQGEwJBVTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqGAFO3dK"
+ + "jB7Ca7u5Z3CabsbGr2Exg+3sztSPiRCIba03es4295EhtDF5bXQvrW2R1Bg72vED"
+ + "5tWaQjVDetvDfCzVC3ErHLTVk3OgpLIP1gf2T0LcOH2pTh2LP9c5Ceta+uggK8zK"
+ + "9sYUUnzGPSAZxrqHIIAlPIgqk0BMV+KApyECAwEAAaNaMFgwHQYDVR0OBBYEFO4F"
+ + "YoqogtB9MjD0NB5x5HN3TrGUMB8GA1UdIwQYMBaAFPXAecuwLqNkCxYVLE/ngFQR"
+ + "7RLIMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMA0GCSqGSIb3DQEBBAUAA4GBADGi"
+ + "D5/qmGvcBgswEM/z2dF4lOxbTNKUW31ZHiU8CXlN0IkFtNbBLBTbJOQIAUnNEabL"
+ + "T7aYgj813OZKUbJTx4MuGChhot/TEP7hKo/xz9OnXLsqYDKbqbo8iLOode+SI7II"
+ + "+yYghOtqvx32cL2Qmffi1LaMbhJP+8NbsIxowdRC");
+
+ private byte[] unacceptablePolicy = Base64.decode(
+ "MDAwLgIBAjAkDCJSZXF1ZXN0ZWQgcG9saWN5IGlzIG5vdCBzdXBwb3J0ZWQu"
+ + "AwMAAAE=");
+
+ private byte[] generalizedTime = Base64.decode(
+ "MIIKPTADAgEAMIIKNAYJKoZIhvcNAQcCoIIKJTCCCiECAQMxCzAJBgUrDgMC"
+ + "GgUAMIIBGwYLKoZIhvcNAQkQAQSgggEKBIIBBjCCAQICAQEGCisGAQQBhFkK"
+ + "AwEwITAJBgUrDgMCGgUABBQAAAAAAAAAAAAAAAAAAAAAAAAAAAICUC8YEzIw"
+ + "MDUwMzEwMTA1ODQzLjkzM1owBIACAfQBAf8CAWSggaikgaUwgaIxCzAJBgNV"
+ + "BAYTAkdCMRcwFQYDVQQIEw5DYW1icmlkZ2VzaGlyZTESMBAGA1UEBxMJQ2Ft"
+ + "YnJpZGdlMSQwIgYDVQQKExtuQ2lwaGVyIENvcnBvcmF0aW9uIExpbWl0ZWQx"
+ + "JzAlBgNVBAsTHm5DaXBoZXIgRFNFIEVTTjozMjJBLUI1REQtNzI1QjEXMBUG"
+ + "A1UEAxMOZGVtby1kc2UyMDAtMDGgggaFMIID2TCCA0KgAwIBAgICAIswDQYJ"
+ + "KoZIhvcNAQEFBQAwgYwxCzAJBgNVBAYTAkdCMRcwFQYDVQQIEw5DYW1icmlk"
+ + "Z2VzaGlyZTESMBAGA1UEBxMJQ2FtYnJpZGdlMSQwIgYDVQQKExtuQ2lwaGVy"
+ + "IENvcnBvcmF0aW9uIExpbWl0ZWQxGDAWBgNVBAsTD1Byb2R1Y3Rpb24gVEVT"
+ + "VDEQMA4GA1UEAxMHVEVTVCBDQTAeFw0wNDA2MTQxNDIzNTlaFw0wNTA2MTQx"
+ + "NDIzNTlaMIGiMQswCQYDVQQGEwJHQjEXMBUGA1UECBMOQ2FtYnJpZGdlc2hp"
+ + "cmUxEjAQBgNVBAcTCUNhbWJyaWRnZTEkMCIGA1UEChMbbkNpcGhlciBDb3Jw"
+ + "b3JhdGlvbiBMaW1pdGVkMScwJQYDVQQLEx5uQ2lwaGVyIERTRSBFU046MzIy"
+ + "QS1CNURELTcyNUIxFzAVBgNVBAMTDmRlbW8tZHNlMjAwLTAxMIGfMA0GCSqG"
+ + "SIb3DQEBAQUAA4GNADCBiQKBgQC7zUamCeLIApddx1etW5YEFrL1WXnlCd7j"
+ + "mMFI6RpSq056LBkF1z5LgucLY+e/c3u2Nw+XJuS3a2fKuBD7I1s/6IkVtIb/"
+ + "KLDjjafOnottKhprH8K41siJUeuK3PRzfZ5kF0vwB3rNvWPCBJmp7kHtUQw3"
+ + "RhIsJTYs7Wy8oVFHVwIDAQABo4IBMDCCASwwCQYDVR0TBAIwADAWBgNVHSUB"
+ + "Af8EDDAKBggrBgEFBQcDCDAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5l"
+ + "cmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFDlEe9Pd0WwQrtnEmFRI2Vmt"
+ + "b+lCMIG5BgNVHSMEgbEwga6AFNy1VPweOQLC65bs6/0RcUYB19vJoYGSpIGP"
+ + "MIGMMQswCQYDVQQGEwJHQjEXMBUGA1UECBMOQ2FtYnJpZGdlc2hpcmUxEjAQ"
+ + "BgNVBAcTCUNhbWJyaWRnZTEkMCIGA1UEChMbbkNpcGhlciBDb3Jwb3JhdGlv"
+ + "biBMaW1pdGVkMRgwFgYDVQQLEw9Qcm9kdWN0aW9uIFRFU1QxEDAOBgNVBAMT"
+ + "B1RFU1QgQ0GCAQAwDQYJKoZIhvcNAQEFBQADgYEASEMlrpRE1RYZPxP3530e"
+ + "hOYUDjgQbw0dwpPjQtLWkeJrePMzDBAbuWwpRI8dOzKP3Rnrm5rxJ7oLY2S0"
+ + "A9ZfV+iwFKagEHFytfnPm2Y9AeNR7a3ladKd7NFMw+5Tbk7Asbetbb+NJfCl"
+ + "9YzHwxLGiQbpKxgc+zYOjq74eGLKtcKhggKkMIICDQIBATCB0qGBqKSBpTCB"
+ + "ojELMAkGA1UEBhMCR0IxFzAVBgNVBAgTDkNhbWJyaWRnZXNoaXJlMRIwEAYD"
+ + "VQQHEwlDYW1icmlkZ2UxJDAiBgNVBAoTG25DaXBoZXIgQ29ycG9yYXRpb24g"
+ + "TGltaXRlZDEnMCUGA1UECxMebkNpcGhlciBEU0UgRVNOOjMyMkEtQjVERC03"
+ + "MjVCMRcwFQYDVQQDEw5kZW1vLWRzZTIwMC0wMaIlCgEBMAkGBSsOAwIaBQAD"
+ + "FQDaLe88TQvM+iMKmIXMmDSyPCZ/+KBmMGSkYjBgMQswCQYDVQQGEwJVUzEk"
+ + "MCIGA1UEChMbbkNpcGhlciBDb3Jwb3JhdGlvbiBMaW1pdGVkMRgwFgYDVQQL"
+ + "Ew9Qcm9kdWN0aW9uIFRlc3QxETAPBgNVBAMTCFRlc3QgVE1DMA0GCSqGSIb3"
+ + "DQEBBQUAAgjF2jVbAAAAADAiGA8yMDA1MDMxMDAyNTQxOVoYDzIwMDUwMzEz"
+ + "MDI1NDE5WjCBjTBLBgorBgEEAYRZCgQBMT0wOzAMAgTF2jVbAgQAAAAAMA8C"
+ + "BAAAAAACBAAAaLkCAf8wDAIEAAAAAAIEAAKV/DAMAgTF3inbAgQAAAAAMD4G"
+ + "CisGAQQBhFkKBAIxMDAuMAwGCisGAQQBhFkKAwGgDjAMAgQAAAAAAgQAB6Eg"
+ + "oQ4wDAIEAAAAAAIEAAPQkDANBgkqhkiG9w0BAQUFAAOBgQB1q4d3GNWk7oAT"
+ + "WkpYmZaTFvapMhTwAmAtSGgFmNOZhs21iHWl/X990/HEBsduwxohfrd8Pz64"
+ + "hV/a76rpeJCVUfUNmbRIrsurFx6uKwe2HUHKW8grZWeCD1L8Y1pKQdrD41gu"
+ + "v0msfOXzLWW+xe5BcJguKclN8HmT7s2odtgiMTGCAmUwggJhAgEBMIGTMIGM"
+ + "MQswCQYDVQQGEwJHQjEXMBUGA1UECBMOQ2FtYnJpZGdlc2hpcmUxEjAQBgNV"
+ + "BAcTCUNhbWJyaWRnZTEkMCIGA1UEChMbbkNpcGhlciBDb3Jwb3JhdGlvbiBM"
+ + "aW1pdGVkMRgwFgYDVQQLEw9Qcm9kdWN0aW9uIFRFU1QxEDAOBgNVBAMTB1RF"
+ + "U1QgQ0ECAgCLMAkGBSsOAwIaBQCgggEnMBoGCSqGSIb3DQEJAzENBgsqhkiG"
+ + "9w0BCRABBDAjBgkqhkiG9w0BCQQxFgQUi1iYx5H3ACnvngWZTPfdxGswkSkw"
+ + "geMGCyqGSIb3DQEJEAIMMYHTMIHQMIHNMIGyBBTaLe88TQvM+iMKmIXMmDSy"
+ + "PCZ/+DCBmTCBkqSBjzCBjDELMAkGA1UEBhMCR0IxFzAVBgNVBAgTDkNhbWJy"
+ + "aWRnZXNoaXJlMRIwEAYDVQQHEwlDYW1icmlkZ2UxJDAiBgNVBAoTG25DaXBo"
+ + "ZXIgQ29ycG9yYXRpb24gTGltaXRlZDEYMBYGA1UECxMPUHJvZHVjdGlvbiBU"
+ + "RVNUMRAwDgYDVQQDEwdURVNUIENBAgIAizAWBBSpS/lH6bN/wf3E2z2X29vF"
+ + "2U7YHTANBgkqhkiG9w0BAQUFAASBgGvDVsgsG5I5WKjEDVHvdRwUx+8Cp10l"
+ + "zGF8o1h7aK5O3zQ4jLayYHea54E5+df35gG7Z3eoOy8E350J7BvHiwDLTqe8"
+ + "SoRlGs9VhL6LMmCcERfGSlSn61Aa15iXZ8eHMSc5JTeJl+kqy4I3FPP4m2ai"
+ + "8wy2fQhn7hUM8Ntg7Y2s");
+
+ private byte[] v2SigningCertResponse = Base64.decode(
+ "MIIPPTADAgEAMIIPNAYJKoZIhvcNAQcCoIIPJTCCDyECAQMxDzANBglghkgBZQMEAgEFADCB6QYL"
+ + "KoZIhvcNAQkQAQSggdkEgdYwgdMCAQEGBgQAj2cBATAxMA0GCWCGSAFlAwQCAQUABCBcU0GN08TA"
+ + "LUFi7AAwQwVkSXqGu9tAzvJ7EXW7SMXHHQIRAM7Fa7g6tMvZI3dgllwMfpcYDzIwMDcxMjExMTAy"
+ + "MTU5WjADAgEBAgYBFsi5OlmgYqRgMF4xCzAJBgNVBAYTAkRFMSQwIgYDVQQKDBtEZXV0c2NoZSBS"
+ + "ZW50ZW52ZXJzaWNoZXJ1bmcxEzARBgNVBAsMClFDIFJvb3QgQ0ExFDASBgNVBAMMC1FDIFJvb3Qg"
+ + "VFNQoIILQjCCBwkwggXxoAMCAQICAwN1pjANBgkqhkiG9w0BAQsFADBIMQswCQYDVQQGEwJERTEk"
+ + "MCIGA1UECgwbRGV1dHNjaGUgUmVudGVudmVyc2ljaGVydW5nMRMwEQYDVQQLDApRQyBSb290IENB"
+ + "MB4XDTA3MTEyMDE2MDcyMFoXDTEyMDcyNzIwMjExMVowXjELMAkGA1UEBhMCREUxJDAiBgNVBAoM"
+ + "G0RldXRzY2hlIFJlbnRlbnZlcnNpY2hlcnVuZzETMBEGA1UECwwKUUMgUm9vdCBDQTEUMBIGA1UE"
+ + "AwwLUUMgUm9vdCBUU1AwggEkMA0GCSqGSIb3DQEBAQUAA4IBEQAwggEMAoIBAQCv1vO+EtGnJNs0"
+ + "atv76BAJXs4bmO8yzVwe3RUtgeu5z9iefh8P46i1g3EL2CD15NcTfoHksr5KudNY30olfjHG7lIu"
+ + "MO3R5sAcrGDPP7riZJnaI6VD/e6kVR569VBid5z105fJAB7mID7+Bn7pdRwDW3Fy2CzfofXGuvrO"
+ + "GPNEWq8x8kqqf75DB5nAs5QP8H41obkdkap2ttHkkPZCiMghTs8iHfpJ0STn47MKq+QrUmuATMZi"
+ + "XrdEfb7f3TBMjO0UVJF64Mh+kC9GtUEHlcm0Tq2Pk5XIUxWEyL94rZ4UWcVdSVE7IjggV2MifMNx"
+ + "geZO3SwsDZk71AhDBy30CSzBAgUAx3HB5aOCA+IwggPeMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMI"
+ + "MBMGA1UdIwQMMAqACECefuBmflfeMBgGCCsGAQUFBwEDBAwwCjAIBgYEAI5GAQEwUAYIKwYBBQUH"
+ + "AQEERDBCMEAGCCsGAQUFBzABhjRodHRwOi8vb2NzcC1yb290cWMudGMuZGV1dHNjaGUtcmVudGVu"
+ + "dmVyc2ljaGVydW5nLmRlMHcGA1UdIARwMG4wbAYNKwYBBAGBrTwBCAEBAzBbMFkGCCsGAQUFBwIB"
+ + "Fk1odHRwOi8vd3d3LmRldXRzY2hlLXJlbnRlbnZlcnNpY2hlcnVuZy1idW5kLmRlL3N0YXRpYy90"
+ + "cnVzdGNlbnRlci9wb2xpY3kuaHRtbDCCATwGA1UdHwSCATMwggEvMHygeqB4hnZsZGFwOi8vZGly"
+ + "LnRjLmRldXRzY2hlLXJlbnRlbnZlcnNpY2hlcnVuZy5kZS9vdT1RQyUyMFJvb3QlMjBDQSxjbj1Q"
+ + "dWJsaWMsbz1EUlYsYz1ERT9hdHRybmFtZT1jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0MIGuoIGr"
+ + "oIGohoGlaHR0cDovL2Rpci50Yy5kZXV0c2NoZS1yZW50ZW52ZXJzaWNoZXJ1bmcuZGU6ODA4OS9z"
+ + "ZXJ2bGV0L0Rpclh3ZWIvQ2EveC5jcmw/ZG49b3UlM0RRQyUyMFJvb3QlMjBDQSUyQ2NuJTNEUHVi"
+ + "bGljJTJDbyUzRERSViUyQ2MlM0RERSZhdHRybmFtZT1jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0"
+ + "MIIBLQYDVR0SBIIBJDCCASCGdGxkYXA6Ly9kaXIudGMuZGV1dHNjaGUtcmVudGVudmVyc2ljaGVy"
+ + "dW5nLmRlL2NuPTE0NTUxOCxvdT1RQyUyMFJvb3QlMjBDQSxjbj1QdWJsaWMsbz1EUlYsYz1ERT9h"
+ + "dHRybmFtZT1jQUNlcnRpZmljYXRlhoGnaHR0cDovL2Rpci50Yy5kZXV0c2NoZS1yZW50ZW52ZXJz"
+ + "aWNoZXJ1bmcuZGU6ODA4OS9zZXJ2bGV0L0Rpclh3ZWIvQ2EveC5jZXI/ZG49Y24lM0QxNDU1MTgl"
+ + "MkNvdSUzRFFDJTIwUm9vdCUyMENBJTJDY24lM0RQdWJsaWMlMkNvJTNERFJWJTJDYyUzRERFJmF0"
+ + "dHJuYW1lPWNBQ2VydGlmaWNhdGUwDgYDVR0PAQH/BAQDAgZAMDsGA1UdCQQ0MDIwMAYDVQQDMSkT"
+ + "J1FDIFRTUCBEZXV0c2NoZSBSZW50ZW52ZXJzaWNoZXJ1bmcgMTpQTjAMBgNVHRMBAf8EAjAAMA0G"
+ + "CSqGSIb3DQEBCwUAA4IBAQCCrWe3Pd3ioX7d8phXvVAa859Rvgf0k3pZ6R4GMj8h/k6MNjNIrdAs"
+ + "wgUVkBbXMLLBk0smsvTdFIVtTBdp1urb9l7vXjDA4MckXBOXPcz4fN8Oswk92d+fM9XU1jKVPsFG"
+ + "PV6j8lAqfq5jwaRxOnS96UBGLKG+NdcrEyiMp/ZkpqnEQZZfu2mkeq6CPahnbBTZqsE0jgY351gU"
+ + "9T6SFVvLIFH7cOxJqsoxPqv5YEcgiXPpOyyu2rpQqKYBYcnerF6/zx5hmWHxTd7MWaTHm0gJI/Im"
+ + "d8esbW+xyaJuAVUcBA+sDmSe8AAoRVxwBRY+xi9ApaJHpmwT+0n2K2GsL3wIMIIEMTCCAxmgAwIB"
+ + "AgIDAjhuMA0GCSqGSIb3DQEBCwUAMEgxCzAJBgNVBAYTAkRFMSQwIgYDVQQKDBtEZXV0c2NoZSBS"
+ + "ZW50ZW52ZXJzaWNoZXJ1bmcxEzARBgNVBAsMClFDIFJvb3QgQ0EwHhcNMDcwNzI3MjAyMTExWhcN"
+ + "MTIwNzI3MjAyMTExWjBIMQswCQYDVQQGEwJERTEkMCIGA1UECgwbRGV1dHNjaGUgUmVudGVudmVy"
+ + "c2ljaGVydW5nMRMwEQYDVQQLDApRQyBSb290IENBMIIBJDANBgkqhkiG9w0BAQEFAAOCAREAMIIB"
+ + "DAKCAQEAzuhBdo9c84DdzsggjWOgfC4jJ2jYqpsOpBo3DVyem+5R26QK4feZdyFnaGvyG+TLcdLO"
+ + "iCecGmrRGD+ey4IhjCONb7hsQQhJWTyDEtBblzYB0yjY8+9fnNeR61W+M/KlMgC6Rw/w+zwzklTM"
+ + "MWwIbxLHm8l9jTSKFjAWTwjE8bCzpUCwN8+4JbFTwjwOJ5lsVA5Xa34wpgr6lgL3WrVTV1NSprqR"
+ + "ZYDWg477tht0KkyOJt3guF3RONKBBuTO2qCbpUeI8m4v3tznoopYbV5Gp5wu5gqd6lTfgju3ldql"
+ + "bxtuCLZd0nAI5rLEOPItDKl4vPXllmmtGIrtDZlwr86cbwIFAJvMJpGjggEgMIIBHDAPBgNVHRMB"
+ + "Af8EBTADAQH/MBEGA1UdDgQKBAhAnn7gZn5X3jB3BgNVHSAEcDBuMGwGDSsGAQQBga08AQgBAQEw"
+ + "WzBZBggrBgEFBQcCARZNaHR0cDovL3d3dy5kZXV0c2NoZS1yZW50ZW52ZXJzaWNoZXJ1bmctYnVu"
+ + "ZC5kZS9zdGF0aWMvdHJ1c3RjZW50ZXIvcG9saWN5Lmh0bWwwUwYDVR0JBEwwSjBIBgNVBAMxQRM/"
+ + "UUMgV3VyemVsemVydGlmaXppZXJ1bmdzc3RlbGxlIERldXRzY2hlIFJlbnRlbnZlcnNpY2hlcnVu"
+ + "ZyAxOlBOMBgGCCsGAQUFBwEDBAwwCjAIBgYEAI5GAQEwDgYDVR0PAQH/BAQDAgIEMA0GCSqGSIb3"
+ + "DQEBCwUAA4IBAQBNGs7Dnc1yzzpZrkuC+oLv+NhbORTEYNgpaOetB1JQ1EbUBoPuNN4ih0ngy/uJ"
+ + "D2O+h4JsNkmELgaehLWyFwATqCYZY4cTAGVoEwgn93x3aW8JbMDQf+YEJDSDsXcm4oIDFPqv5M6o"
+ + "HZUWfsPka3mxKivfKtWhooTz1/+BEGReVQ2oOAvlwXlkEab9e3GOqXQUcLPYDTl8BQxiYhtQtf3d"
+ + "kORiUkuGiGX1YJ5JnZnG3ElMjPgOl8rOiYU7oj9uv1HVb5sdAwuVw0BR/eiMVDBT8DNyfoJmPeQQ"
+ + "A9pXtoAYO0Ya7wNNmCY2Y63YfBlRCF+9VQv2RZ4TdO1KGWwxR98OMYIC1zCCAtMCAQEwTzBIMQsw"
+ + "CQYDVQQGEwJERTEkMCIGA1UECgwbRGV1dHNjaGUgUmVudGVudmVyc2ljaGVydW5nMRMwEQYDVQQL"
+ + "DApRQyBSb290IENBAgMDdaYwDQYJYIZIAWUDBAIBBQCgggFZMBoGCSqGSIb3DQEJAzENBgsqhkiG"
+ + "9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQgO7FFODWWwF5RUjo6wjIkgkD5u7dH+NICiCpSgRRqd/Aw"
+ + "ggEIBgsqhkiG9w0BCRACLzGB+DCB9TCB8jB3BCAMMZqK/5pZxOb3ruCbcgxStaTDwDHaf2glEo6P"
+ + "+89t8TBTMEykSjBIMQswCQYDVQQGEwJERTEkMCIGA1UECgwbRGV1dHNjaGUgUmVudGVudmVyc2lj"
+ + "aGVydW5nMRMwEQYDVQQLDApRQyBSb290IENBAgMDdaYwdwQgl7vwI+P47kpxhWLoIdEco7UfGwZ2"
+ + "X4el3jaZ67q5/9IwUzBMpEowSDELMAkGA1UEBhMCREUxJDAiBgNVBAoMG0RldXRzY2hlIFJlbnRl"
+ + "bnZlcnNpY2hlcnVuZzETMBEGA1UECwwKUUMgUm9vdCBDQQIDAjhuMA0GCSqGSIb3DQEBCwUABIIB"
+ + "AIOYgpDI0BaeG4RF/EB5QzkUqAZ9nX6w895+m2hHyRKrAKdj3913j5QI+aEVIG3DVbFaAfdKeKfn"
+ + "xsTW48aWs6aARtPAc+1OXwoGUSYElOFqqVpSeTaXe+kjY5bsLSQeETB+EPvXl8EcKTaxTRCNOqJU"
+ + "XbnyYRgWTI55A2jH6IsQQVHc5DaIcmbdI8iATaRTHY5eUeVuI+Q/3RMVBFAb5qRhM61Ddcrjq058"
+ + "C0uiH9G2IB5QRyu6RsCUgrkeMTMBqlIBlnDBy+EgLouDU4Dehxy5uzEl5DBKZEewZpQZOTO/kAgL"
+ + "WruAAg/Lj4r0f9vN12wRlHoS2UKDjrE1DnUBbrM=");
+
+ /* (non-Javadoc)
+ * @see org.spongycastle.util.test.Test#getName()
+ */
+ public String getName()
+ {
+ return "ParseTest";
+ }
+
+ private void requestParse(
+ byte[] request,
+ ASN1ObjectIdentifier algorithm)
+ throws IOException
+ {
+ TimeStampRequest req = new TimeStampRequest(request);
+
+ if (!req.getMessageImprintAlgOID().equals(algorithm))
+ {
+ fail("failed to get expected algorithm - got "
+ + req.getMessageImprintAlgOID() + " not " + algorithm);
+ }
+
+ if (request != sha1Request && request != sha1noNonse)
+ {
+ if (!req.getReqPolicy().equals(TSPTestUtil.EuroPKI_TSA_Test_Policy))
+ {
+ fail("" + algorithm + " failed policy check.");
+ }
+
+ if (request == ripemd160Request)
+ {
+ if (!req.getCertReq())
+ {
+ fail("" + algorithm + " failed certReq check.");
+ }
+ }
+ }
+
+ assertEquals("version not 1", 1, req.getVersion());
+
+ assertEquals("critical extensions found when none expected", 0, req.getCriticalExtensionOIDs().size());
+
+ assertEquals("non-critical extensions found when none expected", 0, req.getNonCriticalExtensionOIDs().size());
+
+ if (request != sha1noNonse)
+ {
+ if (req.getNonce() == null)
+ {
+ fail("" + algorithm + " nonse not found when one expected.");
+ }
+ }
+ else
+ {
+ if (req.getNonce() != null)
+ {
+ fail("" + algorithm + " nonse not found when one not expected.");
+ }
+ }
+
+ try
+ {
+ req.validate(TSPAlgorithms.ALLOWED, null, null);
+ }
+ catch (Exception e)
+ {
+ fail("validation exception.");
+ }
+
+ if (!Arrays.areEqual(req.getEncoded(), request))
+ {
+ fail("" + algorithm + " failed encode check.");
+ }
+ }
+
+ private void responseParse(
+ byte[] request,
+ byte[] response,
+ ASN1ObjectIdentifier algorithm)
+ throws Exception
+ {
+ TimeStampRequest req = new TimeStampRequest(request);
+ TimeStampResponse resp = new TimeStampResponse(response);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+
+ X509Certificate cert = (X509Certificate)fact.generateCertificate(new ByteArrayInputStream(signingCert));
+
+ resp.validate(req);
+
+ resp.getTimeStampToken().validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider("SC").build(cert));
+ }
+
+ private void unacceptableResponseParse(
+ byte[] response)
+ throws Exception
+ {
+ TimeStampResponse resp = new TimeStampResponse(response);
+
+ if (resp.getStatus() != PKIStatus.REJECTION)
+ {
+ fail("request not rejected.");
+ }
+
+ if (resp.getFailInfo().intValue() != PKIFailureInfo.unacceptedPolicy)
+ {
+ fail("request not rejected.");
+ }
+ }
+
+ private void generalizedTimeParse(
+ byte[] response)
+ throws Exception
+ {
+ TimeStampResponse resp = new TimeStampResponse(response);
+
+ if (resp.getStatus() != PKIStatus.GRANTED)
+ {
+ fail("request not rejected.");
+ }
+ }
+
+ public void setUp()
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ public void testParsing()
+ throws Exception
+ {
+ requestParse(sha1Request, TSPAlgorithms.SHA1);
+
+ requestParse(sha1noNonse, TSPAlgorithms.SHA1);
+
+ requestParse(md5Request, TSPAlgorithms.MD5);
+
+ requestParse(ripemd160Request, TSPAlgorithms.RIPEMD160);
+
+ responseParse(sha1Request, sha1Response, TSPAlgorithms.SHA1);
+
+ responseParse(sha1noNonse, sha1noNonseResponse, TSPAlgorithms.SHA1);
+
+ responseParse(md5Request, md5Response, TSPAlgorithms.MD5);
+
+ unacceptableResponseParse(unacceptablePolicy);
+
+ generalizedTimeParse(generalizedTime);
+
+ v2SigningResponseParse(v2SigningCertResponse);
+ }
+
+ private void v2SigningResponseParse(
+ byte[] encoded)
+ throws Exception
+ {
+ TimeStampResponse response = new TimeStampResponse(encoded);
+
+ Store store = response.getTimeStampToken().getCertificates();
+ X509CertificateHolder cert = (X509CertificateHolder)store.getMatches(response.getTimeStampToken().getSID()).iterator().next();
+
+ response.getTimeStampToken().validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider("SC").build(cert));
+ }
+
+ public void parse(
+ byte[] encoded,
+ boolean tokenPresent)
+ throws Exception
+ {
+ TimeStampResponse response = new TimeStampResponse(encoded);
+
+ if (tokenPresent && response.getTimeStampToken() == null)
+ {
+ fail("token not found when expected.");
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/SHA1DigestCalculator.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/SHA1DigestCalculator.java
new file mode 100644
index 000000000..9d53e933b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/SHA1DigestCalculator.java
@@ -0,0 +1,44 @@
+package org.spongycastle.tsp.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.operator.DigestCalculator;
+
+
+class SHA1DigestCalculator
+ implements DigestCalculator
+{
+ private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1);
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return bOut;
+ }
+
+ public byte[] getDigest()
+ {
+ byte[] bytes = bOut.toByteArray();
+
+ bOut.reset();
+
+ Digest sha1 = new SHA1Digest();
+
+ sha1.update(bytes, 0, bytes.length);
+
+ byte[] digest = new byte[sha1.getDigestSize()];
+
+ sha1.doFinal(digest, 0);
+
+ return digest;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/SHA256DigestCalculator.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/SHA256DigestCalculator.java
new file mode 100644
index 000000000..ee5fc3d9b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/SHA256DigestCalculator.java
@@ -0,0 +1,44 @@
+package org.spongycastle.tsp.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.operator.DigestCalculator;
+
+
+class SHA256DigestCalculator
+ implements DigestCalculator
+{
+ private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ public AlgorithmIdentifier getAlgorithmIdentifier()
+ {
+ return new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256);
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return bOut;
+ }
+
+ public byte[] getDigest()
+ {
+ byte[] bytes = bOut.toByteArray();
+
+ bOut.reset();
+
+ Digest sha256 = new SHA256Digest();
+
+ sha256.update(bytes, 0, bytes.length);
+
+ byte[] digest = new byte[sha256.getDigestSize()];
+
+ sha256.doFinal(digest, 0);
+
+ return digest;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/TSPTestUtil.java b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/TSPTestUtil.java
new file mode 100644
index 000000000..51ba4591d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/java/org/spongycastle/tsp/test/TSPTestUtil.java
@@ -0,0 +1,229 @@
+package org.spongycastle.tsp.test;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.ExtendedKeyUsage;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.KeyPurposeId;
+import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.cert.jcajce.JcaX509ExtensionUtils;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.x509.X509V3CertificateGenerator;
+
+public class TSPTestUtil
+{
+
+ public static SecureRandom rand = new SecureRandom();
+
+ public static KeyPairGenerator kpg;
+
+ public static KeyGenerator desede128kg;
+
+ public static KeyGenerator desede192kg;
+
+ public static KeyGenerator rc240kg;
+
+ public static KeyGenerator rc264kg;
+
+ public static KeyGenerator rc2128kg;
+
+ public static BigInteger serialNumber = BigInteger.ONE;
+
+ public static final boolean DEBUG = true;
+
+ public static DERObjectIdentifier EuroPKI_TSA_Test_Policy = new DERObjectIdentifier(
+ "1.3.6.1.4.1.5255.5.1");
+
+ public static JcaX509ExtensionUtils extUtils;
+
+ static
+ {
+ try
+ {
+ rand = new SecureRandom();
+
+ kpg = KeyPairGenerator.getInstance("RSA", "SC");
+ kpg.initialize(1024, rand);
+
+ desede128kg = KeyGenerator.getInstance("DESEDE", "SC");
+ desede128kg.init(112, rand);
+
+ desede192kg = KeyGenerator.getInstance("DESEDE", "SC");
+ desede192kg.init(168, rand);
+
+ rc240kg = KeyGenerator.getInstance("RC2", "SC");
+ rc240kg.init(40, rand);
+
+ rc264kg = KeyGenerator.getInstance("RC2", "SC");
+ rc264kg.init(64, rand);
+
+ rc2128kg = KeyGenerator.getInstance("RC2", "SC");
+ rc2128kg.init(128, rand);
+
+ serialNumber = new BigInteger("1");
+
+ extUtils = new JcaX509ExtensionUtils();
+
+ }
+ catch (Exception ex)
+ {
+ throw new RuntimeException(ex.toString());
+ }
+ }
+
+ public static String dumpBase64(byte[] data)
+ {
+ StringBuffer buf = new StringBuffer();
+
+ data = Base64.encode(data);
+
+ for (int i = 0; i < data.length; i += 64)
+ {
+ if (i + 64 < data.length)
+ {
+ buf.append(new String(data, i, 64));
+ }
+ else
+ {
+ buf.append(new String(data, i, data.length - i));
+ }
+ buf.append('\n');
+ }
+
+ return buf.toString();
+ }
+
+ public static KeyPair makeKeyPair()
+ {
+ return kpg.generateKeyPair();
+ }
+
+ public static SecretKey makeDesede128Key()
+ {
+ return desede128kg.generateKey();
+ }
+
+ public static SecretKey makeDesede192Key()
+ {
+ return desede192kg.generateKey();
+ }
+
+ public static SecretKey makeRC240Key()
+ {
+ return rc240kg.generateKey();
+ }
+
+ public static SecretKey makeRC264Key()
+ {
+ return rc264kg.generateKey();
+ }
+
+ public static SecretKey makeRC2128Key()
+ {
+ return rc2128kg.generateKey();
+ }
+
+ public static X509Certificate makeCertificate(KeyPair _subKP,
+ String _subDN, KeyPair _issKP, String _issDN)
+ throws GeneralSecurityException, IOException
+ {
+
+ return makeCertificate(_subKP, _subDN, _issKP, _issDN, false);
+ }
+
+ public static X509Certificate makeCACertificate(KeyPair _subKP,
+ String _subDN, KeyPair _issKP, String _issDN)
+ throws GeneralSecurityException, IOException
+ {
+
+ return makeCertificate(_subKP, _subDN, _issKP, _issDN, true);
+ }
+
+ public static X509Certificate makeCertificate(KeyPair _subKP,
+ String _subDN, KeyPair _issKP, String _issDN, boolean _ca)
+ throws GeneralSecurityException, IOException
+ {
+
+ PublicKey _subPub = _subKP.getPublic();
+ PrivateKey _issPriv = _issKP.getPrivate();
+ PublicKey _issPub = _issKP.getPublic();
+
+ X509V3CertificateGenerator _v3CertGen = new X509V3CertificateGenerator();
+
+ _v3CertGen.reset();
+ _v3CertGen.setSerialNumber(allocateSerialNumber());
+ _v3CertGen.setIssuerDN(new X509Name(_issDN));
+ _v3CertGen.setNotBefore(new Date(System.currentTimeMillis()));
+ _v3CertGen.setNotAfter(new Date(System.currentTimeMillis()
+ + (1000L * 60 * 60 * 24 * 100)));
+ _v3CertGen.setSubjectDN(new X509Name(_subDN));
+ _v3CertGen.setPublicKey(_subPub);
+ _v3CertGen.setSignatureAlgorithm("MD5WithRSAEncryption");
+
+ _v3CertGen.addExtension(Extension.subjectKeyIdentifier, false,
+ createSubjectKeyId(_subPub));
+
+ _v3CertGen.addExtension(Extension.authorityKeyIdentifier, false,
+ createAuthorityKeyId(_issPub));
+
+ if (_ca)
+ {
+ _v3CertGen.addExtension(Extension.basicConstraints, false,
+ new BasicConstraints(_ca));
+ }
+ else
+ {
+ _v3CertGen.addExtension(Extension.extendedKeyUsage, true,
+ new ExtendedKeyUsage(KeyPurposeId.id_kp_timeStamping));
+ }
+
+ X509Certificate _cert = _v3CertGen.generate(_issPriv);
+
+ _cert.checkValidity(new Date());
+ _cert.verify(_issPub);
+
+ return _cert;
+ }
+
+ /*
+ *
+ * INTERNAL METHODS
+ *
+ */
+
+
+ private static AuthorityKeyIdentifier createAuthorityKeyId(PublicKey _pubKey)
+ throws IOException
+ {
+ return extUtils.createAuthorityKeyIdentifier(_pubKey);
+ }
+
+ private static SubjectKeyIdentifier createSubjectKeyId(PublicKey _pubKey)
+ throws IOException
+ {
+ return extUtils.createSubjectKeyIdentifier(_pubKey);
+ }
+
+ private static BigInteger allocateSerialNumber()
+ {
+ BigInteger _tmp = serialNumber;
+ serialNumber = serialNumber.add(BigInteger.ONE);
+ return _tmp;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/jdk1.1/org/spongycastle/cert/path/test/CertPathTest.java b/libraries/spongycastle/pkix/src/test/jdk1.1/org/spongycastle/cert/path/test/CertPathTest.java
new file mode 100644
index 000000000..4d5f8521b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/jdk1.1/org/spongycastle/cert/path/test/CertPathTest.java
@@ -0,0 +1,370 @@
+package org.spongycastle.cert.path.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectOutputStream;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.SignatureException;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathBuilder;
+import java.security.cert.CertPathBuilderException;
+import java.security.cert.CertPathBuilderResult;
+import java.security.cert.CertStore;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CollectionCertStoreParameters;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.Vector;
+
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.test.SimpleTest;
+
+public class CertPathTest
+ extends SimpleTest
+{
+ public static byte[] rootCertBin = Base64.decode(
+ "MIIBqzCCARQCAQEwDQYJKoZIhvcNAQEFBQAwHjEcMBoGA1UEAxMTVGVzdCBDQSBDZXJ0aWZpY2F0ZTAeFw0wODA5MDQwNDQ1MDhaFw0wODA5MTEwNDQ1MDhaMB4xHDAaBgNVBAMTE1Rlc3QgQ0EgQ2VydGlmaWNhdGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMRLUjhPe4YUdLo6EcjKcWUOG7CydFTH53Pr1lWjOkbmszYDpkhCTT9LOsI+disk18nkBxSl8DAHTqV+VxtuTPt64iyi10YxyDeep+DwZG/f8cVQv97U3hA9cLurZ2CofkMLGr6JpSGCMZ9FcstcTdHB4lbErIJ54YqfF4pNOs4/AgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAgyrTEFY7ALpeY59jL6xFOLpuPqoBOWrUWv6O+zy5BCU0qiX71r3BpigtxRj+DYcfLIM9FNERDoHu3TthD3nwYWUBtFX8N0QUJIdJabxqAMhLjSC744koiFpCYse5Ye3ZvEdFwDzgAQsJTp5eFGgTZPkPzcdhkFJ2p9+OWs+cb24=");
+
+
+ static byte[] interCertBin = Base64.decode(
+ "MIICSzCCAbSgAwIBAgIBATANBgkqhkiG9w0BAQUFADAeMRwwGgYDVQQDExNUZXN0IENBIENlcnRpZmljYXRlMB4XDTA4MDkwNDA0NDUwOFoXDTA4MDkxMTA0NDUwOFowKDEmMCQGA1UEAxMdVGVzdCBJbnRlcm1lZGlhdGUgQ2VydGlmaWNhdGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAISS9OOZ2wxzdWny9aVvk4Joq+dwSJ+oqvHUxX3PflZyuiLiCBUOUE4q59dGKdtNX5fIfwyK3cpV0e73Y/0fwfM3m9rOWFrCKOhfeswNTes0w/2PqPVVDDsF/nj7NApuqXwioeQlgTL251RDF4sVoxXqAU7lRkcqwZt3mwqS4KTJAgMBAAGjgY4wgYswRgYDVR0jBD8wPYAUhv8BOT27EB9JaCccJD4YASPP5XWhIqQgMB4xHDAaBgNVBAMTE1Rlc3QgQ0EgQ2VydGlmaWNhdGWCAQEwHQYDVR0OBBYEFL/IwAGOkHzaQyPZegy79CwM5oTFMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4GBAE4TRgUz4sUvZyVdZxqV+XyNRnqXAeLOOqFGYv2D96tQrS+zjd0elVlT6lFrtchZdOmmX7R6/H/tjMWMcTBICZyRYrvK8cCAmDOI+EIdq5p6lj2Oq6Pbw/wruojAqNrpaR6IkwNpWtdOSSupv4IJL+YU9q2YFTh4R1j3tOkPoFGr");
+
+ static byte[] finalCertBin = Base64.decode(
+ "MIICRjCCAa+gAwIBAgIBATANBgkqhkiG9w0BAQUFADAoMSYwJAYDVQQDEx1UZXN0IEludGVybWVkaWF0ZSBDZXJ0aWZpY2F0ZTAeFw0wODA5MDQwNDQ1MDhaFw0wODA5MTEwNDQ1MDhaMB8xHTAbBgNVBAMTFFRlc3QgRW5kIENlcnRpZmljYXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChpUeo0tPYywWKiLlbWKNJBcCpSaLSlaZ+4+yer1AxI5yJIVHP6SAlBghlbD5Qne5ImnN/15cz1xwYAiul6vGKJkVPlFEe2Mr+g/J/WJPQQPsjbZ1G+vxbAwXEDA4KaQrnpjRZFq+CdKHwOjuPLYS/MYQNgdIvDVEQcTbPQ8GaiQIDAQABo4GIMIGFMEYGA1UdIwQ/MD2AFL/IwAGOkHzaQyPZegy79CwM5oTFoSKkIDAeMRwwGgYDVQQDExNUZXN0IENBIENlcnRpZmljYXRlggEBMB0GA1UdDgQWBBSVkw+VpqBf3zsLc/9GdkK9TzHPwDAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIFoDANBgkqhkiG9w0BAQUFAAOBgQBLv/0bVDjzTs/y1vN3FUiZNknEbzupIZduTuXJjqv/vBX+LDPjUfu/+iOCXOSKoRn6nlOWhwB1z6taG2usQkFG8InMkRcPREi2uVgFdhJ/1C3dAWhsdlubjdL926bftXvxnx/koDzyrePW5U96RlOQM2qLvbaky2Giz6hrc3Wl+w==");
+ public static byte[] rootCrlBin = Base64.decode(
+ "MIIBYjCBzAIBATANBgkqhkiG9w0BAQsFADAeMRwwGgYDVQQDExNUZXN0IENBIENlcnRpZmljYXRlFw0wODA5MDQwNDQ1MDhaFw0wODA5MDQwNzMxNDhaMCIwIAIBAhcNMDgwOTA0MDQ0NTA4WjAMMAoGA1UdFQQDCgEJoFYwVDBGBgNVHSMEPzA9gBSG/wE5PbsQH0loJxwkPhgBI8/ldaEipCAwHjEcMBoGA1UEAxMTVGVzdCBDQSBDZXJ0aWZpY2F0ZYIBATAKBgNVHRQEAwIBATANBgkqhkiG9w0BAQsFAAOBgQCAbaFCo0BNG4AktVf6jjBLeawP1u0ELYkOCEGvYZE0mBpQ+OvFg7subZ6r3lRIj030nUli28sPFtu5ZQMBNcpE4nS1ziF44RfT3Lp5UgHx9x17Krz781iEyV+7zU8YxYMY9wULD+DCuK294kGKIssVNbmTYXZatBNoXQN5CLIocA==");
+ static byte[] interCrlBin = Base64.decode(
+ "MIIBbDCB1gIBATANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQDEx1UZXN0IEludGVybWVkaWF0ZSBDZXJ0aWZpY2F0ZRcNMDgwOTA0MDQ0NTA4WhcNMDgwOTA0MDczMTQ4WjAiMCACAQIXDTA4MDkwNDA0NDUwOFowDDAKBgNVHRUEAwoBCaBWMFQwRgYDVR0jBD8wPYAUv8jAAY6QfNpDI9l6DLv0LAzmhMWhIqQgMB4xHDAaBgNVBAMTE1Rlc3QgQ0EgQ2VydGlmaWNhdGWCAQEwCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQADgYEAEVCr5TKs5yguGgLH+dBzmSPoeSIWJFLsgWwJEit/iUDJH3dgYmaczOcGxIDtbYYHLWIHM+P2YRyQz3MEkCXEgm/cx4y7leAmux5l+xQWgmxFPz+197vaphPeCZo+B7V1CWtm518gcq4mrs9ovfgNqgyFj7KGjcBpWdJE32KMt50=");
+
+ /*
+ * certpath with a circular reference
+ */
+ static byte[] certA = Base64.decode(
+ "MIIC6jCCAlOgAwIBAgIBBTANBgkqhkiG9w0BAQUFADCBjTEPMA0GA1UEAxMGSW50"
+ + "ZXIzMQswCQYDVQQGEwJDSDEPMA0GA1UEBxMGWnVyaWNoMQswCQYDVQQIEwJaSDEX"
+ + "MBUGA1UEChMOUHJpdmFzcGhlcmUgQUcxEDAOBgNVBAsTB1Rlc3RpbmcxJDAiBgkq"
+ + "hkiG9w0BCQEWFWFybWluQHByaXZhc3BoZXJlLmNvbTAeFw0wNzA0MDIwODQ2NTda"
+ + "Fw0xNzAzMzAwODQ0MDBaMIGlMScwJQYDVQQDHh4AQQByAG0AaQBuACAASADkAGIA"
+ + "ZQByAGwAaQBuAGcxCzAJBgNVBAYTAkNIMQ8wDQYDVQQHEwZadXJpY2gxCzAJBgNV"
+ + "BAgTAlpIMRcwFQYDVQQKEw5Qcml2YXNwaGVyZSBBRzEQMA4GA1UECxMHVGVzdGlu"
+ + "ZzEkMCIGCSqGSIb3DQEJARYVYXJtaW5AcHJpdmFzcGhlcmUuY29tMIGfMA0GCSqG"
+ + "SIb3DQEBAQUAA4GNADCBiQKBgQCfHfyVs5dbxG35H/Thd29qR4NZU88taCu/OWA1"
+ + "GdACI02lXWYpmLWiDgnU0ULP+GG8OnVp1IES9fz2zcrXKQ19xZzsen/To3h5sNte"
+ + "cJpS00XMM24q/jDwy5NvkBP9YIfFKQ1E/0hFHXcqwlw+b/y/v6YGsZCU2h6QDzc4"
+ + "5m0+BwIDAQABo0AwPjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIE8DAeBglg"
+ + "hkgBhvhCAQ0EERYPeGNhIGNlcnRpZmljYXRlMA0GCSqGSIb3DQEBBQUAA4GBAJEu"
+ + "KiSfIwsY7SfobMLrv2v/BtLhGLi4RnmjiwzBhuv5rn4rRfBpq1ppmqQMJ2pmA67v"
+ + "UWCY+mNwuyjHyivpCCyJGsZ9d5H09g2vqxzkDBMz7X9VNMZYFH8j/R3/Cfvqks31"
+ + "z0OFslJkeKLa1I0P/dfVHsRKNkLRT3Ws5LKksErQ");
+
+ static byte[] certB = Base64.decode(
+ "MIICtTCCAh6gAwIBAgIBBDANBgkqhkiG9w0BAQQFADCBjTEPMA0GA1UEAxMGSW50"
+ + "ZXIyMQswCQYDVQQGEwJDSDEPMA0GA1UEBxMGWnVyaWNoMQswCQYDVQQIEwJaSDEX"
+ + "MBUGA1UEChMOUHJpdmFzcGhlcmUgQUcxEDAOBgNVBAsTB1Rlc3RpbmcxJDAiBgkq"
+ + "hkiG9w0BCQEWFWFybWluQHByaXZhc3BoZXJlLmNvbTAeFw0wNzA0MDIwODQ2Mzha"
+ + "Fw0xNzAzMzAwODQ0MDBaMIGNMQ8wDQYDVQQDEwZJbnRlcjMxCzAJBgNVBAYTAkNI"
+ + "MQ8wDQYDVQQHEwZadXJpY2gxCzAJBgNVBAgTAlpIMRcwFQYDVQQKEw5Qcml2YXNw"
+ + "aGVyZSBBRzEQMA4GA1UECxMHVGVzdGluZzEkMCIGCSqGSIb3DQEJARYVYXJtaW5A"
+ + "cHJpdmFzcGhlcmUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxCXIB"
+ + "QRnmVvl2h7Q+0SsRxDLnyM1dJG9jMa+UCCmHy0k/ZHs5VirSbjEJSjkQ9BGeh9SC"
+ + "7JwbMpXO7UE+gcVc2RnWUY+MA+fWIeTV4KtkYA8WPu8wVGCXbN8wwh/StOocszxb"
+ + "g+iLvGeh8CYSRqg6QN3S/02etH3o8H4e7Z0PZwIDAQABoyMwITAPBgNVHRMBAf8E"
+ + "BTADAQH/MA4GA1UdDwEB/wQEAwIB9jANBgkqhkiG9w0BAQQFAAOBgQCtWdirSsmt"
+ + "+CBBCNn6ZnbU3QqQfiiQIomjenNEHESJgaS/+PvPE5i3xWFXsunTHLW321/Km16I"
+ + "7+ZvT8Su1cqHg79NAT8QB0yke1saKSy2C0Pic4HwrNqVBWFNSxMU0hQzpx/ZXDbZ"
+ + "DqIXAp5EfyRYBy2ul+jm6Rot6aFgzuopKg==");
+
+ static byte[] certC = Base64.decode(
+ "MIICtTCCAh6gAwIBAgIBAjANBgkqhkiG9w0BAQQFADCBjTEPMA0GA1UEAxMGSW50"
+ + "ZXIxMQswCQYDVQQGEwJDSDEPMA0GA1UEBxMGWnVyaWNoMQswCQYDVQQIEwJaSDEX"
+ + "MBUGA1UEChMOUHJpdmFzcGhlcmUgQUcxEDAOBgNVBAsTB1Rlc3RpbmcxJDAiBgkq"
+ + "hkiG9w0BCQEWFWFybWluQHByaXZhc3BoZXJlLmNvbTAeFw0wNzA0MDIwODQ0Mzla"
+ + "Fw0xNzAzMzAwODQ0MDBaMIGNMQ8wDQYDVQQDEwZJbnRlcjIxCzAJBgNVBAYTAkNI"
+ + "MQ8wDQYDVQQHEwZadXJpY2gxCzAJBgNVBAgTAlpIMRcwFQYDVQQKEw5Qcml2YXNw"
+ + "aGVyZSBBRzEQMA4GA1UECxMHVGVzdGluZzEkMCIGCSqGSIb3DQEJARYVYXJtaW5A"
+ + "cHJpdmFzcGhlcmUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD0rLr6"
+ + "f2/ONeJzTb0q9M/NNX+MnAFMSqiQGVBkT76u5nOH4KLkpHXkzI82JI7GuQMzoT3a"
+ + "+RP1hO6FneO92ms2soC6xiOFb4EC69Dfhh87Nww5O35JxVF0bzmbmIAWd6P/7zGh"
+ + "nd2S4tKkaZcubps+C0j9Fgi0hipVicAOUVVoDQIDAQABoyMwITAPBgNVHRMBAf8E"
+ + "BTADAQH/MA4GA1UdDwEB/wQEAwIB9jANBgkqhkiG9w0BAQQFAAOBgQCLPvc1IMA4"
+ + "YP+PmnEldyUoRWRnvPWjBGeu0WheBP7fdcnGBf93Nmc5j68ZN+eTZ5VMuZ99YdvH"
+ + "CXGNX6oodONLU//LlFKdLl5xjLAS5X9p1RbOEGytnalqeiEpjk4+C/7rIBG1kllO"
+ + "dItmI6LlEMV09Hkpg6ZRAUmRkb8KrM4X7A==");
+
+ static byte[] certD = Base64.decode(
+ "MIICtTCCAh6gAwIBAgIBBjANBgkqhkiG9w0BAQQFADCBjTEPMA0GA1UEAxMGSW50"
+ + "ZXIzMQswCQYDVQQGEwJDSDEPMA0GA1UEBxMGWnVyaWNoMQswCQYDVQQIEwJaSDEX"
+ + "MBUGA1UEChMOUHJpdmFzcGhlcmUgQUcxEDAOBgNVBAsTB1Rlc3RpbmcxJDAiBgkq"
+ + "hkiG9w0BCQEWFWFybWluQHByaXZhc3BoZXJlLmNvbTAeFw0wNzA0MDIwODQ5NTNa"
+ + "Fw0xNzAzMzAwODQ0MDBaMIGNMQ8wDQYDVQQDEwZJbnRlcjExCzAJBgNVBAYTAkNI"
+ + "MQ8wDQYDVQQHEwZadXJpY2gxCzAJBgNVBAgTAlpIMRcwFQYDVQQKEw5Qcml2YXNw"
+ + "aGVyZSBBRzEQMA4GA1UECxMHVGVzdGluZzEkMCIGCSqGSIb3DQEJARYVYXJtaW5A"
+ + "cHJpdmFzcGhlcmUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCae3TP"
+ + "jIVKeASqvNabaiUHAMGUgFxB7L0yUsIj39azLcLtUj4S7XkDf7SMGtYV0JY1XNaQ"
+ + "sHJAsnJivDZc50oiYvqDYfgFZx5+AsN5l5X5rjRzs/OX+Jo+k1OgsIyu6+mf9Kfb"
+ + "5IdWOVB2EcOg4f9tPjLM8CIj9Pp7RbKLyqUUgwIDAQABoyMwITAPBgNVHRMBAf8E"
+ + "BTADAQH/MA4GA1UdDwEB/wQEAwIB9jANBgkqhkiG9w0BAQQFAAOBgQCgr9kUdWUT"
+ + "Lt9UcztSzR3pnHRsyvS0E/z850OKQKS5/VxLEalpFvhj+3EcZ7Y6mFxaaS2B7vXg"
+ + "2YWyqV1PRb6iF7/u9EXkpSTKGrJahwANirCa3V/HTUuPdCE2GITlnWI8h3eVA+xQ"
+ + "D4LF0PXHOkXbwmhXRSb10lW1bSGkUxE9jg==");
+
+ private void testExceptions()
+ throws Exception
+ {
+ byte[] enc = { (byte)0, (byte)2, (byte)3, (byte)4, (byte)5 };
+ MyCertPath mc = new MyCertPath(enc);
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ ByteArrayInputStream is;
+ byte[] arr;
+
+ ObjectOutputStream oOut = new ObjectOutputStream(os);
+ oOut.writeObject(mc);
+ oOut.flush();
+ oOut.close();
+
+ try
+ {
+ CertificateFactory cFac = CertificateFactory.getInstance("X.509",
+ "SC");
+ arr = os.toByteArray();
+ is = new ByteArrayInputStream(arr);
+ cFac.generateCertPath(is);
+ }
+ catch (CertificateException e)
+ {
+ // ignore okay
+ }
+
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ List certCol = new ArrayList();
+
+ certCol.add(cf.generateCertificate(new ByteArrayInputStream(certA)));
+ certCol.add(cf.generateCertificate(new ByteArrayInputStream(certB)));
+ certCol.add(cf.generateCertificate(new ByteArrayInputStream(certC)));
+ certCol.add(cf.generateCertificate(new ByteArrayInputStream(certD)));
+
+ CertPathBuilder pathBuilder = CertPathBuilder.getInstance("PKIX", "SC");
+ X509CertSelector select = new X509CertSelector();
+ select.setSubject(PrincipalUtil.getSubjectX509Principal(((X509Certificate)certCol.get(0))).getEncoded());
+
+ Set trustanchors = new HashSet();
+ trustanchors.add(new TrustAnchor((X509Certificate)cf.generateCertificate(new ByteArrayInputStream(rootCertBin)), null));
+
+ CertStore certStore = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certCol));
+
+ PKIXBuilderParameters params = new PKIXBuilderParameters(trustanchors, select);
+ params.addCertStore(certStore);
+
+ try
+ {
+ CertPathBuilderResult result = pathBuilder.build(params);
+ CertPath path = result.getCertPath();
+ fail("found cert path in circular set");
+ }
+ catch (CertPathBuilderException e)
+ {
+ // expected
+ }
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509", "SC");
+
+ X509Certificate rootCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(rootCertBin));
+ X509Certificate interCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(interCertBin));
+ X509Certificate finalCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(finalCertBin));
+
+ //Testing CertPath generation from List
+ List list = new ArrayList();
+ list.add(interCert);
+ CertPath certPath1 = cf.generateCertPath(list);
+
+ //Testing CertPath encoding as PkiPath
+ byte[] encoded = certPath1.getEncoded("PkiPath");
+
+ //Testing CertPath generation from InputStream
+ ByteArrayInputStream inStream = new ByteArrayInputStream(encoded);
+ CertPath certPath2 = cf.generateCertPath(inStream, "PkiPath");
+
+ //Comparing both CertPathes
+ if (!certPath2.equals(certPath1))
+ {
+ fail("CertPath differ after encoding and decoding.");
+ }
+
+ encoded = certPath1.getEncoded("PKCS7");
+
+ //Testing CertPath generation from InputStream
+ inStream = new ByteArrayInputStream(encoded);
+ certPath2 = cf.generateCertPath(inStream, "PKCS7");
+
+ //Comparing both CertPathes
+ if (!certPath2.equals(certPath1))
+ {
+ fail("CertPath differ after encoding and decoding.");
+ }
+
+ encoded = certPath1.getEncoded("PEM");
+
+ //Testing CertPath generation from InputStream
+ inStream = new ByteArrayInputStream(encoded);
+ certPath2 = cf.generateCertPath(inStream, "PEM");
+
+ //Comparing both CertPathes
+ if (!certPath2.equals(certPath1))
+ {
+ fail("CertPath differ after encoding and decoding.");
+ }
+
+ //
+ // empty list test
+ //
+ list = new ArrayList();
+
+ CertPath certPath = CertificateFactory.getInstance("X.509","SC").generateCertPath(list);
+ if (certPath.getCertificates().size() != 0)
+ {
+ fail("list wrong size.");
+ }
+
+ //
+ // exception tests
+ //
+ testExceptions();
+ }
+
+ public String getName()
+ {
+ return "CertPath";
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new CertPathTest());
+ }
+
+ private static class MyCertificate extends Certificate
+ {
+ private final byte[] encoding;
+
+ public MyCertificate(String type, byte[] encoding)
+ {
+ super(type);
+ // don't copy to allow null parameter in test
+ this.encoding = encoding;
+ }
+
+ public byte[] getEncoded() throws CertificateEncodingException
+ {
+ // do copy to force NPE in test
+ return (byte[])encoding.clone();
+ }
+
+ public void verify(PublicKey key) throws CertificateException,
+ NoSuchAlgorithmException, InvalidKeyException,
+ NoSuchProviderException, SignatureException
+ {
+ }
+
+ public void verify(PublicKey key, String sigProvider)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException,
+ SignatureException
+ {
+ }
+
+ public String toString()
+ {
+ return "[My test Certificate, type: " + getType() + "]";
+ }
+
+ public PublicKey getPublicKey()
+ {
+ return new PublicKey()
+ {
+ public String getAlgorithm()
+ {
+ return "TEST";
+ }
+
+ public byte[] getEncoded()
+ {
+ return new byte[] { (byte)1, (byte)2, (byte)3 };
+ }
+
+ public String getFormat()
+ {
+ return "TEST_FORMAT";
+ }
+ };
+ }
+ }
+
+ private static class MyCertPath extends CertPath
+ {
+ private final List certificates;
+
+ private final List encodingNames;
+
+ private final byte[] encoding;
+
+ public MyCertPath(byte[] encoding)
+ {
+ super("MyEncoding");
+ this.encoding = encoding;
+ certificates = new ArrayList();
+ certificates.add(new MyCertificate("MyEncoding", encoding));
+ encodingNames = new ArrayList();
+ encodingNames.add("MyEncoding");
+ }
+
+ public List getCertificates()
+ {
+ return Collections.unmodifiableList(certificates);
+ }
+
+ public byte[] getEncoded() throws CertificateEncodingException
+ {
+ return (byte[])encoding.clone();
+ }
+
+ public byte[] getEncoded(String encoding)
+ throws CertificateEncodingException
+ {
+ if (getType().equals(encoding))
+ {
+ return (byte[])this.encoding.clone();
+ }
+ throw new CertificateEncodingException("Encoding not supported: "
+ + encoding);
+ }
+
+ public Iterator getEncodings()
+ {
+ return Collections.unmodifiableCollection(encodingNames).iterator();
+ }
+ }
+}
+
diff --git a/libraries/spongycastle/pkix/src/test/jdk1.1/org/spongycastle/cert/test/CertTest.java b/libraries/spongycastle/pkix/src/test/jdk1.1/org/spongycastle/cert/test/CertTest.java
new file mode 100644
index 000000000..9bb2c7073
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/jdk1.1/org/spongycastle/cert/test/CertTest.java
@@ -0,0 +1,2812 @@
+package org.spongycastle.cert.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Signature;
+import java.security.cert.CRL;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Vector;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Enumerated;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DEREnumerated;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSAPublicKey;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.X500NameBuilder;
+import org.spongycastle.asn1.x500.style.BCStyle;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.ExtensionsGenerator;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.IssuingDistributionPoint;
+import org.spongycastle.asn1.x509.KeyPurposeId;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509CertificateStructure;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.cert.X509CRLEntryHolder;
+import org.spongycastle.cert.X509CRLHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509v1CertificateBuilder;
+import org.spongycastle.cert.X509v2CRLBuilder;
+import org.spongycastle.cert.X509v3CertificateBuilder;
+import org.spongycastle.cert.jcajce.JcaX509CRLConverter;
+import org.spongycastle.cert.jcajce.JcaX509CRLHolder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.cert.jcajce.JcaX509v1CertificateBuilder;
+import org.spongycastle.cert.jcajce.JcaX509v2CRLBuilder;
+import org.spongycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.jce.X509KeyUsage;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPrivateKeySpec;
+import org.spongycastle.jce.spec.ECPublicKeySpec;
+import org.spongycastle.jce.spec.GOST3410ParameterSpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.bc.BcRSAContentSignerBuilder;
+import org.spongycastle.operator.bc.BcRSAContentVerifierProviderBuilder;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.encoders.Hex;
+import org.spongycastle.util.test.SimpleTest;
+import org.spongycastle.x509.extension.AuthorityKeyIdentifierStructure;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+
+public class CertTest
+ extends SimpleTest
+{
+ private static final String BC = org.spongycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
+
+ // test CA
+ byte[] testCAp12 = Base64.decode(
+ "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"
+ + "HLhcYQcQ1R+RucctAgIEAAAA");
+
+ //
+ // server.crt
+ //
+ byte[] cert1 = Base64.decode(
+ "MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx"
+ + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY"
+ + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB"
+ + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ"
+ + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2"
+ + "MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW"
+ + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM"
+ + "dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l"
+ + "Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv"
+ + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re"
+ + "Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO"
+ + "Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE"
+ + "7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy"
+ + "QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0"
+ + "ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw"
+ + "DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL"
+ + "iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4"
+ + "yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF"
+ + "5/8=");
+
+ //
+ // ca.crt
+ //
+ byte[] cert2 = Base64.decode(
+ "MIIDbDCCAtWgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx"
+ + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY"
+ + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB"
+ + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ"
+ + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU1MzNaFw0wMTA2"
+ + "MDIwNzU1MzNaMIG3MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW"
+ + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM"
+ + "dGQxHjAcBgNVBAsTFUNlcnRpZmljYXRlIEF1dGhvcml0eTEVMBMGA1UEAxMMQ29u"
+ + "bmVjdCA0IENBMSgwJgYJKoZIhvcNAQkBFhl3ZWJtYXN0ZXJAY29ubmVjdDQuY29t"
+ + "LmF1MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgs5ptNG6Qv1ZpCDuUNGmv"
+ + "rhjqMDPd3ri8JzZNRiiFlBA4e6/ReaO1U8ASewDeQMH6i9R6degFdQRLngbuJP0s"
+ + "xcEE+SksEWNvygfzLwV9J/q+TQDyJYK52utb++lS0b48A1KPLwEsyL6kOAgelbur"
+ + "ukwxowprKUIV7Knf1ajetQIDAQABo4GFMIGCMCQGA1UdEQQdMBuBGXdlYm1hc3Rl"
+ + "ckBjb25uZWN0NC5jb20uYXUwDwYDVR0TBAgwBgEB/wIBADA2BglghkgBhvhCAQ0E"
+ + "KRYnbW9kX3NzbCBnZW5lcmF0ZWQgY3VzdG9tIENBIGNlcnRpZmljYXRlMBEGCWCG"
+ + "SAGG+EIBAQQEAwICBDANBgkqhkiG9w0BAQQFAAOBgQCsGvfdghH8pPhlwm1r3pQk"
+ + "msnLAVIBb01EhbXm2861iXZfWqGQjrGAaA0ZpXNk9oo110yxoqEoSJSzniZa7Xtz"
+ + "soTwNUpE0SLHvWf/SlKdFWlzXA+vOZbzEv4UmjeelekTm7lc01EEa5QRVzOxHFtQ"
+ + "DhkaJ8VqOMajkQFma2r9iA==");
+
+ //
+ // testx509.pem
+ //
+ byte[] cert3 = Base64.decode(
+ "MIIBWzCCAQYCARgwDQYJKoZIhvcNAQEEBQAwODELMAkGA1UEBhMCQVUxDDAKBgNV"
+ + "BAgTA1FMRDEbMBkGA1UEAxMSU1NMZWF5L3JzYSB0ZXN0IENBMB4XDTk1MDYxOTIz"
+ + "MzMxMloXDTk1MDcxNzIzMzMxMlowOjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA1FM"
+ + "RDEdMBsGA1UEAxMUU1NMZWF5L3JzYSB0ZXN0IGNlcnQwXDANBgkqhkiG9w0BAQEF"
+ + "AANLADBIAkEAqtt6qS5GTxVxGZYWa0/4u+IwHf7p2LNZbcPBp9/OfIcYAXBQn8hO"
+ + "/Re1uwLKXdCjIoaGs4DLdG88rkzfyK5dPQIDAQABMAwGCCqGSIb3DQIFBQADQQAE"
+ + "Wc7EcF8po2/ZO6kNCwK/ICH6DobgLekA5lSLr5EvuioZniZp5lFzAw4+YzPQ7XKJ"
+ + "zl9HYIMxATFyqSiD9jsx");
+
+ //
+ // v3-cert1.pem
+ //
+ byte[] cert4 = Base64.decode(
+ "MIICjTCCAfigAwIBAgIEMaYgRzALBgkqhkiG9w0BAQQwRTELMAkGA1UEBhMCVVMx"
+ + "NjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFuZCBTcGFjZSBBZG1pbmlz"
+ + "dHJhdGlvbjAmFxE5NjA1MjgxMzQ5MDUrMDgwMBcROTgwNTI4MTM0OTA1KzA4MDAw"
+ + "ZzELMAkGA1UEBhMCVVMxNjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFu"
+ + "ZCBTcGFjZSBBZG1pbmlzdHJhdGlvbjEgMAkGA1UEBRMCMTYwEwYDVQQDEwxTdGV2"
+ + "ZSBTY2hvY2gwWDALBgkqhkiG9w0BAQEDSQAwRgJBALrAwyYdgxmzNP/ts0Uyf6Bp"
+ + "miJYktU/w4NG67ULaN4B5CnEz7k57s9o3YY3LecETgQ5iQHmkwlYDTL2fTgVfw0C"
+ + "AQOjgaswgagwZAYDVR0ZAQH/BFowWDBWMFQxCzAJBgNVBAYTAlVTMTYwNAYDVQQK"
+ + "Ey1OYXRpb25hbCBBZXJvbmF1dGljcyBhbmQgU3BhY2UgQWRtaW5pc3RyYXRpb24x"
+ + "DTALBgNVBAMTBENSTDEwFwYDVR0BAQH/BA0wC4AJODMyOTcwODEwMBgGA1UdAgQR"
+ + "MA8ECTgzMjk3MDgyM4ACBSAwDQYDVR0KBAYwBAMCBkAwCwYJKoZIhvcNAQEEA4GB"
+ + "AH2y1VCEw/A4zaXzSYZJTTUi3uawbbFiS2yxHvgf28+8Js0OHXk1H1w2d6qOHH21"
+ + "X82tZXd/0JtG0g1T9usFFBDvYK8O0ebgz/P5ELJnBL2+atObEuJy1ZZ0pBDWINR3"
+ + "WkDNLCGiTkCKp0F5EWIrVDwh54NNevkCQRZita+z4IBO");
+
+ //
+ // v3-cert2.pem
+ //
+ byte[] cert5 = Base64.decode(
+ "MIICiTCCAfKgAwIBAgIEMeZfHzANBgkqhkiG9w0BAQQFADB9MQswCQYDVQQGEwJD"
+ + "YTEPMA0GA1UEBxMGTmVwZWFuMR4wHAYDVQQLExVObyBMaWFiaWxpdHkgQWNjZXB0"
+ + "ZWQxHzAdBgNVBAoTFkZvciBEZW1vIFB1cnBvc2VzIE9ubHkxHDAaBgNVBAMTE0Vu"
+ + "dHJ1c3QgRGVtbyBXZWIgQ0EwHhcNOTYwNzEyMTQyMDE1WhcNOTYxMDEyMTQyMDE1"
+ + "WjB0MSQwIgYJKoZIhvcNAQkBExVjb29rZUBpc3NsLmF0bC5ocC5jb20xCzAJBgNV"
+ + "BAYTAlVTMScwJQYDVQQLEx5IZXdsZXR0IFBhY2thcmQgQ29tcGFueSAoSVNTTCkx"
+ + "FjAUBgNVBAMTDVBhdWwgQS4gQ29va2UwXDANBgkqhkiG9w0BAQEFAANLADBIAkEA"
+ + "6ceSq9a9AU6g+zBwaL/yVmW1/9EE8s5you1mgjHnj0wAILuoB3L6rm6jmFRy7QZT"
+ + "G43IhVZdDua4e+5/n1ZslwIDAQABo2MwYTARBglghkgBhvhCAQEEBAMCB4AwTAYJ"
+ + "YIZIAYb4QgENBD8WPVRoaXMgY2VydGlmaWNhdGUgaXMgb25seSBpbnRlbmRlZCBm"
+ + "b3IgZGVtb25zdHJhdGlvbiBwdXJwb3Nlcy4wDQYJKoZIhvcNAQEEBQADgYEAi8qc"
+ + "F3zfFqy1sV8NhjwLVwOKuSfhR/Z8mbIEUeSTlnH3QbYt3HWZQ+vXI8mvtZoBc2Fz"
+ + "lexKeIkAZXCesqGbs6z6nCt16P6tmdfbZF3I3AWzLquPcOXjPf4HgstkyvVBn0Ap"
+ + "jAFN418KF/Cx4qyHB4cjdvLrRjjQLnb2+ibo7QU=");
+
+ //
+ // pem encoded pkcs7
+ //
+ byte[] cert6 = Base64.decode(
+ "MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIJbzCCAj0w"
+ + "ggGmAhEAzbp/VvDf5LxU/iKss3KqVTANBgkqhkiG9w0BAQIFADBfMQswCQYDVQQGEwJVUzEXMBUG"
+ + "A1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGljIFByaW1hcnkgQ2Vy"
+ + "dGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNOTYwMTI5MDAwMDAwWhcNMjgwODAxMjM1OTU5WjBfMQsw"
+ + "CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVi"
+ + "bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwgZ8wDQYJKoZIhvcNAQEBBQADgY0A"
+ + "MIGJAoGBAOUZv22jVmEtmUhx9mfeuY3rt56GgAqRDvo4Ja9GiILlc6igmyRdDR/MZW4MsNBWhBiH"
+ + "mgabEKFz37RYOWtuwfYV1aioP6oSBo0xrH+wNNePNGeICc0UEeJORVZpH3gCgNrcR5EpuzbJY1zF"
+ + "4Ncth3uhtzKwezC6Ki8xqu6jZ9rbAgMBAAEwDQYJKoZIhvcNAQECBQADgYEATD+4i8Zo3+5DMw5d"
+ + "6abLB4RNejP/khv0Nq3YlSI2aBFsfELM85wuxAc/FLAPT/+Qknb54rxK6Y/NoIAK98Up8YIiXbix"
+ + "3YEjo3slFUYweRb46gVLlH8dwhzI47f0EEA8E8NfH1PoSOSGtHuhNbB7Jbq4046rPzidADQAmPPR"
+ + "cZQwggMuMIICl6ADAgECAhEA0nYujRQMPX2yqCVdr+4NdTANBgkqhkiG9w0BAQIFADBfMQswCQYD"
+ + "VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGlj"
+ + "IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNOTgwNTEyMDAwMDAwWhcNMDgwNTEy"
+ + "MjM1OTU5WjCBzDEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy"
+ + "dXN0IE5ldHdvcmsxRjBEBgNVBAsTPXd3dy52ZXJpc2lnbi5jb20vcmVwb3NpdG9yeS9SUEEgSW5j"
+ + "b3JwLiBCeSBSZWYuLExJQUIuTFREKGMpOTgxSDBGBgNVBAMTP1ZlcmlTaWduIENsYXNzIDEgQ0Eg"
+ + "SW5kaXZpZHVhbCBTdWJzY3JpYmVyLVBlcnNvbmEgTm90IFZhbGlkYXRlZDCBnzANBgkqhkiG9w0B"
+ + "AQEFAAOBjQAwgYkCgYEAu1pEigQWu1X9A3qKLZRPFXg2uA1Ksm+cVL+86HcqnbnwaLuV2TFBcHqB"
+ + "S7lIE1YtxwjhhEKrwKKSq0RcqkLwgg4C6S/7wju7vsknCl22sDZCM7VuVIhPh0q/Gdr5FegPh7Yc"
+ + "48zGmo5/aiSS4/zgZbqnsX7vyds3ashKyAkG5JkCAwEAAaN8MHowEQYJYIZIAYb4QgEBBAQDAgEG"
+ + "MEcGA1UdIARAMD4wPAYLYIZIAYb4RQEHAQEwLTArBggrBgEFBQcCARYfd3d3LnZlcmlzaWduLmNv"
+ + "bS9yZXBvc2l0b3J5L1JQQTAPBgNVHRMECDAGAQH/AgEAMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0B"
+ + "AQIFAAOBgQCIuDc73dqUNwCtqp/hgQFxHpJqbS/28Z3TymQ43BuYDAeGW4UVag+5SYWklfEXfWe0"
+ + "fy0s3ZpCnsM+tI6q5QsG3vJWKvozx74Z11NMw73I4xe1pElCY+zCphcPXVgaSTyQXFWjZSAA/Rgg"
+ + "5V+CprGoksVYasGNAzzrw80FopCubjCCA/gwggNhoAMCAQICEBbbn/1G1zppD6KsP01bwywwDQYJ"
+ + "KoZIhvcNAQEEBQAwgcwxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln"
+ + "biBUcnVzdCBOZXR3b3JrMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvUlBB"
+ + "IEluY29ycC4gQnkgUmVmLixMSUFCLkxURChjKTk4MUgwRgYDVQQDEz9WZXJpU2lnbiBDbGFzcyAx"
+ + "IENBIEluZGl2aWR1YWwgU3Vic2NyaWJlci1QZXJzb25hIE5vdCBWYWxpZGF0ZWQwHhcNMDAxMDAy"
+ + "MDAwMDAwWhcNMDAxMjAxMjM1OTU5WjCCAQcxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYD"
+ + "VQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3Jl"
+ + "cG9zaXRvcnkvUlBBIEluY29ycC4gYnkgUmVmLixMSUFCLkxURChjKTk4MR4wHAYDVQQLExVQZXJz"
+ + "b25hIE5vdCBWYWxpZGF0ZWQxJzAlBgNVBAsTHkRpZ2l0YWwgSUQgQ2xhc3MgMSAtIE1pY3Jvc29m"
+ + "dDETMBEGA1UEAxQKRGF2aWQgUnlhbjElMCMGCSqGSIb3DQEJARYWZGF2aWRAbGl2ZW1lZGlhLmNv"
+ + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqxBsdeNmSvFqhMNwhQgNzM8mdjX9eSXb"
+ + "DawpHtQHjmh0AKJSa3IwUY0VIsyZHuXWktO/CgaMBVPt6OVf/n0R2sQigMP6Y+PhEiS0vCJBL9aK"
+ + "0+pOo2qXrjVBmq+XuCyPTnc+BOSrU26tJsX0P9BYorwySiEGxGanBNATdVL4NdUCAwEAAaOBnDCB"
+ + "mTAJBgNVHRMEAjAAMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQgwKjAoBggrBgEFBQcCARYcaHR0"
+ + "cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYTARBglghkgBhvhCAQEEBAMCB4AwMwYDVR0fBCwwKjAo"
+ + "oCagJIYiaHR0cDovL2NybC52ZXJpc2lnbi5jb20vY2xhc3MxLmNybDANBgkqhkiG9w0BAQQFAAOB"
+ + "gQBC8yIIdVGpFTf8/YiL14cMzcmL0nIRm4kGR3U59z7UtcXlfNXXJ8MyaeI/BnXwG/gD5OKYqW6R"
+ + "yca9vZOxf1uoTBl82gInk865ED3Tej6msCqFzZffnSUQvOIeqLxxDlqYRQ6PmW2nAnZeyjcnbI5Y"
+ + "syQSM2fmo7n6qJFP+GbFezGCAkUwggJBAgEBMIHhMIHMMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5j"
+ + "LjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazFGMEQGA1UECxM9d3d3LnZlcmlzaWdu"
+ + "LmNvbS9yZXBvc2l0b3J5L1JQQSBJbmNvcnAuIEJ5IFJlZi4sTElBQi5MVEQoYyk5ODFIMEYGA1UE"
+ + "AxM/VmVyaVNpZ24gQ2xhc3MgMSBDQSBJbmRpdmlkdWFsIFN1YnNjcmliZXItUGVyc29uYSBOb3Qg"
+ + "VmFsaWRhdGVkAhAW25/9Rtc6aQ+irD9NW8MsMAkGBSsOAwIaBQCggbowGAYJKoZIhvcNAQkDMQsG"
+ + "CSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMDAxMDAyMTczNTE4WjAjBgkqhkiG9w0BCQQxFgQU"
+ + "gZjSaBEY2oxGvlQUIMnxSXhivK8wWwYJKoZIhvcNAQkPMU4wTDAKBggqhkiG9w0DBzAOBggqhkiG"
+ + "9w0DAgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwBwYFKw4DAh0w"
+ + "DQYJKoZIhvcNAQEBBQAEgYAzk+PU91/ZFfoiuKOECjxEh9fDYE2jfDCheBIgh5gdcCo+sS1WQs8O"
+ + "HreQ9Nop/JdJv1DQMBK6weNBBDoP0EEkRm1XCC144XhXZC82jBZohYmi2WvDbbC//YN58kRMYMyy"
+ + "srrfn4Z9I+6kTriGXkrpGk9Q0LSGjmG2BIsqiF0dvwAAAAAAAA==");
+
+ //
+ // dsaWithSHA1 cert
+ //
+ byte[] cert7 = Base64.decode(
+ "MIIEXAYJKoZIhvcNAQcCoIIETTCCBEkCAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+ + "SIb3DQEHAaCCAsMwggK/MIIB4AIBADCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7"
+ + "d8miwTMN55CUSmo3TO8WGCxgY61TX5k+7NU4XPf1TULjw3GobwaJX13kquPh"
+ + "fVXk+gVy46n4Iw3hAhUBSe/QF4BUj+pJOF9ROBM4u+FEWA8CQQD4mSJbrABj"
+ + "TUWrlnAte8pS22Tq4/FPO7jHSqjijUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/z"
+ + "m8Q12PFp/PjOhh+nMA4xDDAKBgNVBAMTA0lEMzAeFw05NzEwMDEwMDAwMDBa"
+ + "Fw0zODAxMDEwMDAwMDBaMA4xDDAKBgNVBAMTA0lEMzCB8DCBpwYFKw4DAhsw"
+ + "gZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxgY61TX5k+7NU4XPf1TULj"
+ + "w3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/QF4BUj+pJOF9ROBM4u+FE"
+ + "WA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jHSqjijUHfXKTrHL1OEqV3"
+ + "SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nA0QAAkEAkYkXLYMtGVGWj9OnzjPn"
+ + "sB9sefSRPrVegZJCZbpW+Iv0/1RP1u04pHG9vtRpIQLjzUiWvLMU9EKQTThc"
+ + "eNMmWDCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxg"
+ + "Y61TX5k+7NU4XPf1TULjw3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/Q"
+ + "F4BUj+pJOF9ROBM4u+FEWA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jH"
+ + "SqjijUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nAy8AMCwC"
+ + "FBY3dBSdeprGcqpr6wr3xbG+6WW+AhRMm/facKJNxkT3iKgJbp7R8Xd3QTGC"
+ + "AWEwggFdAgEBMBMwDjEMMAoGA1UEAxMDSUQzAgEAMAkGBSsOAwIaBQCgXTAY"
+ + "BgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0wMjA1"
+ + "MjQyMzEzMDdaMCMGCSqGSIb3DQEJBDEWBBS4WMsoJhf7CVbZYCFcjoTRzPkJ"
+ + "xjCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxgY61T"
+ + "X5k+7NU4XPf1TULjw3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/QF4BU"
+ + "j+pJOF9ROBM4u+FEWA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jHSqji"
+ + "jUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nBC8wLQIVALID"
+ + "dt+MHwawrDrwsO1Z6sXBaaJsAhRaKssrpevmLkbygKPV07XiAKBG02Zvb2Jh"
+ + "cg==");
+
+ //
+ // testcrl.pem
+ //
+ byte[] crl1 = Base64.decode(
+ "MIICjTCCAfowDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoT"
+ + "F1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVy"
+ + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5Fw05NTA1MDIwMjEyMjZaFw05NTA2MDEw"
+ + "MDAxNDlaMIIBaDAWAgUCQQAABBcNOTUwMjAxMTcyNDI2WjAWAgUCQQAACRcNOTUw"
+ + "MjEwMDIxNjM5WjAWAgUCQQAADxcNOTUwMjI0MDAxMjQ5WjAWAgUCQQAADBcNOTUw"
+ + "MjI1MDA0NjQ0WjAWAgUCQQAAGxcNOTUwMzEzMTg0MDQ5WjAWAgUCQQAAFhcNOTUw"
+ + "MzE1MTkxNjU0WjAWAgUCQQAAGhcNOTUwMzE1MTk0MDQxWjAWAgUCQQAAHxcNOTUw"
+ + "MzI0MTk0NDMzWjAWAgUCcgAABRcNOTUwMzI5MjAwNzExWjAWAgUCcgAAERcNOTUw"
+ + "MzMwMDIzNDI2WjAWAgUCQQAAIBcNOTUwNDA3MDExMzIxWjAWAgUCcgAAHhcNOTUw"
+ + "NDA4MDAwMjU5WjAWAgUCcgAAQRcNOTUwNDI4MTcxNzI0WjAWAgUCcgAAOBcNOTUw"
+ + "NDI4MTcyNzIxWjAWAgUCcgAATBcNOTUwNTAyMDIxMjI2WjANBgkqhkiG9w0BAQIF"
+ + "AAN+AHqOEJXSDejYy0UwxxrH/9+N2z5xu/if0J6qQmK92W0hW158wpJg+ovV3+wQ"
+ + "wvIEPRL2rocL0tKfAsVq1IawSJzSNgxG0lrcla3MrJBnZ4GaZDu4FutZh72MR3Gt"
+ + "JaAL3iTJHJD55kK2D/VoyY1djlsPuNh6AEgdVwFAyp0v");
+
+ //
+ // ecdsa cert with extra octet string.
+ //
+ byte[] oldEcdsa = Base64.decode(
+ "MIICljCCAkCgAwIBAgIBATALBgcqhkjOPQQBBQAwgY8xCzAJBgNVBAYTAkFVMSgwJ"
+ + "gYDVQQKEx9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIwEAYDVQQHEw"
+ + "lNZWxib3VybmUxETAPBgNVBAgTCFZpY3RvcmlhMS8wLQYJKoZIhvcNAQkBFiBmZWV"
+ + "kYmFjay1jcnlwdG9AYm91bmN5Y2FzdGxlLm9yZzAeFw0wMTEyMDcwMTAwMDRaFw0w"
+ + "MTEyMDcwMTAxNDRaMIGPMQswCQYDVQQGEwJBVTEoMCYGA1UEChMfVGhlIExlZ2lvb"
+ + "iBvZiB0aGUgQm91bmN5IENhc3RsZTESMBAGA1UEBxMJTWVsYm91cm5lMREwDwYDVQ"
+ + "QIEwhWaWN0b3JpYTEvMC0GCSqGSIb3DQEJARYgZmVlZGJhY2stY3J5cHRvQGJvdW5"
+ + "jeWNhc3RsZS5vcmcwgeQwgb0GByqGSM49AgEwgbECAQEwKQYHKoZIzj0BAQIef///"
+ + "////////////f///////gAAAAAAAf///////MEAEHn///////////////3///////"
+ + "4AAAAAAAH///////AQeawFsO9zxiUHQ1lSSFHXKcanbL7J9HTd5YYXClCwKBB8CD/"
+ + "qWPNyogWzMM7hkK+35BcPTWFc9Pyf7vTs8uaqvAh5///////////////9///+eXpq"
+ + "fXZBx+9FSJoiQnQsDIgAEHwJbbcU7xholSP+w9nFHLebJUhqdLSU05lq/y9X+DHAw"
+ + "CwYHKoZIzj0EAQUAA0MAMEACHnz6t4UNoVROp74ma4XNDjjGcjaqiIWPZLK8Bdw3G"
+ + "QIeLZ4j3a6ividZl344UH+UPUE7xJxlYGuy7ejTsqRR");
+
+ byte[] uncompressedPtEC = Base64.decode(
+ "MIIDKzCCAsGgAwIBAgICA+kwCwYHKoZIzj0EAQUAMGYxCzAJBgNVBAYTAkpQ"
+ + "MRUwEwYDVQQKEwxuaXRlY2guYWMuanAxDjAMBgNVBAsTBWFpbGFiMQ8wDQYD"
+ + "VQQDEwZ0ZXN0Y2ExHzAdBgkqhkiG9w0BCQEWEHRlc3RjYUBsb2NhbGhvc3Qw"
+ + "HhcNMDExMDEzMTE1MzE3WhcNMjAxMjEyMTE1MzE3WjBmMQswCQYDVQQGEwJK"
+ + "UDEVMBMGA1UEChMMbml0ZWNoLmFjLmpwMQ4wDAYDVQQLEwVhaWxhYjEPMA0G"
+ + "A1UEAxMGdGVzdGNhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0Y2FAbG9jYWxob3N0"
+ + "MIIBczCCARsGByqGSM49AgEwggEOAgEBMDMGByqGSM49AQECKEdYWnajFmnZ"
+ + "tzrukK2XWdle2v+GsD9l1ZiR6g7ozQDbhFH/bBiMDQcwVAQoJ5EQKrI54/CT"
+ + "xOQ2pMsd/fsXD+EX8YREd8bKHWiLz8lIVdD5cBNeVwQoMKSc6HfI7vKZp8Q2"
+ + "zWgIFOarx1GQoWJbMcSt188xsl30ncJuJT2OoARRBAqJ4fD+q6hbqgNSjTQ7"
+ + "htle1KO3eiaZgcJ8rrnyN8P+5A8+5K+H9aQ/NbBR4Gs7yto5PXIUZEUgodHA"
+ + "TZMSAcSq5ZYt4KbnSYaLY0TtH9CqAigEwZ+hglbT21B7ZTzYX2xj0x+qooJD"
+ + "hVTLtIPaYJK2HrMPxTw6/zfrAgEPA1IABAnvfFcFDgD/JicwBGn6vR3N8MIn"
+ + "mptZf/mnJ1y649uCF60zOgdwIyI7pVSxBFsJ7ohqXEHW0x7LrGVkdSEiipiH"
+ + "LYslqh3xrqbAgPbl93GUo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB"
+ + "/wQEAwIBxjAdBgNVHQ4EFgQUAEo62Xm9H6DcsE0zUDTza4BRG90wCwYHKoZI"
+ + "zj0EAQUAA1cAMFQCKAQsCHHSNOqfJXLgt3bg5+k49hIBGVr/bfG0B9JU3rNt"
+ + "Ycl9Y2zfRPUCKAK2ccOQXByAWfsasDu8zKHxkZv7LVDTFjAIffz3HaCQeVhD"
+ + "z+fauEg=");
+
+ byte[] keyUsage = Base64.decode(
+ "MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UE"
+ + "BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50"
+ + "cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBs"
+ + "aW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExp"
+ + "bWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0"
+ + "aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBa"
+ + "MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNV"
+ + "BAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3Jw"
+ + "LiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50"
+ + "cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50"
+ + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GL"
+ + "ADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSv"
+ + "x1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHV"
+ + "iTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173"
+ + "iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkw"
+ + "ggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50"
+ + "cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0Ff"
+ + "SW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UE"
+ + "CxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50"
+ + "cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYD"
+ + "VQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9D"
+ + "bGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkx"
+ + "MDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW"
+ + "/O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwG"
+ + "A1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI"
+ + "hvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQ"
+ + "OokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkU"
+ + "ODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapE"
+ + "PHayXOw=");
+
+ byte[] nameCert = Base64.decode(
+ "MIIEFjCCA3+gAwIBAgIEdS8BozANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJE"+
+ "RTERMA8GA1UEChQIREFURVYgZUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRQ0Eg"+
+ "REFURVYgRDAzIDE6UE4wIhgPMjAwMTA1MTAxMDIyNDhaGA8yMDA0MDUwOTEwMjI0"+
+ "OFowgYQxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIFAZCYXllcm4xEjAQBgNVBAcUCU7I"+
+ "dXJuYmVyZzERMA8GA1UEChQIREFURVYgZUcxHTAbBgNVBAUTFDAwMDAwMDAwMDA4"+
+ "OTU3NDM2MDAxMR4wHAYDVQQDFBVEaWV0bWFyIFNlbmdlbmxlaXRuZXIwgaEwDQYJ"+
+ "KoZIhvcNAQEBBQADgY8AMIGLAoGBAJLI/LJLKaHoMk8fBECW/od8u5erZi6jI8Ug"+
+ "C0a/LZyQUO/R20vWJs6GrClQtXB+AtfiBSnyZOSYzOdfDI8yEKPEv8qSuUPpOHps"+
+ "uNCFdLZF1vavVYGEEWs2+y+uuPmg8q1oPRyRmUZ+x9HrDvCXJraaDfTEd9olmB/Z"+
+ "AuC/PqpjAgUAwAAAAaOCAcYwggHCMAwGA1UdEwEB/wQCMAAwDwYDVR0PAQH/BAUD"+
+ "AwdAADAxBgNVHSAEKjAoMCYGBSskCAEBMB0wGwYIKwYBBQUHAgEWD3d3dy56cy5k"+
+ "YXRldi5kZTApBgNVHREEIjAggR5kaWV0bWFyLnNlbmdlbmxlaXRuZXJAZGF0ZXYu"+
+ "ZGUwgYQGA1UdIwR9MHuhc6RxMG8xCzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1"+
+ "bGllcnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0"+
+ "MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjVSLUNBIDE6UE6CBACm8LkwDgYHAoIG"+
+ "AQoMAAQDAQEAMEcGA1UdHwRAMD4wPKAUoBKGEHd3dy5jcmwuZGF0ZXYuZGWiJKQi"+
+ "MCAxCzAJBgNVBAYTAkRFMREwDwYDVQQKFAhEQVRFViBlRzAWBgUrJAgDBAQNMAsT"+
+ "A0VVUgIBBQIBATAdBgNVHQ4EFgQUfv6xFP0xk7027folhy+ziZvBJiwwLAYIKwYB"+
+ "BQUHAQEEIDAeMBwGCCsGAQUFBzABhhB3d3cuZGlyLmRhdGV2LmRlMA0GCSqGSIb3"+
+ "DQEBBQUAA4GBAEOVX6uQxbgtKzdgbTi6YLffMftFr2mmNwch7qzpM5gxcynzgVkg"+
+ "pnQcDNlm5AIbS6pO8jTCLfCd5TZ5biQksBErqmesIl3QD+VqtB+RNghxectZ3VEs"+
+ "nCUtcE7tJ8O14qwCb3TxS9dvIUFiVi4DjbxX46TdcTbTaK8/qr6AIf+l");
+
+ byte[] probSelfSignedCert = Base64.decode(
+ "MIICxTCCAi6gAwIBAgIQAQAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQUFADBF"
+ + "MScwJQYDVQQKEx4gRElSRUNUSU9OIEdFTkVSQUxFIERFUyBJTVBPVFMxGjAYBgNV"
+ + "BAMTESBBQyBNSU5FRkkgQiBURVNUMB4XDTA0MDUwNzEyMDAwMFoXDTE0MDUwNzEy"
+ + "MDAwMFowRTEnMCUGA1UEChMeIERJUkVDVElPTiBHRU5FUkFMRSBERVMgSU1QT1RT"
+ + "MRowGAYDVQQDExEgQUMgTUlORUZJIEIgVEVTVDCBnzANBgkqhkiG9w0BAQEFAAOB"
+ + "jQAwgYkCgYEAveoCUOAukZdcFCs2qJk76vSqEX0ZFzHqQ6faBPZWjwkgUNwZ6m6m"
+ + "qWvvyq1cuxhoDvpfC6NXILETawYc6MNwwxsOtVVIjuXlcF17NMejljJafbPximEt"
+ + "DQ4LcQeSp4K7FyFlIAMLyt3BQ77emGzU5fjFTvHSUNb3jblx0sV28c0CAwEAAaOB"
+ + "tTCBsjAfBgNVHSMEGDAWgBSEJ4bLbvEQY8cYMAFKPFD1/fFXlzAdBgNVHQ4EFgQU"
+ + "hCeGy27xEGPHGDABSjxQ9f3xV5cwDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIB"
+ + "AQQEAwIBBjA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vYWRvbmlzLnBrNy5jZXJ0"
+ + "cGx1cy5uZXQvZGdpLXRlc3QuY3JsMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN"
+ + "AQEFBQADgYEAmToHJWjd3+4zknfsP09H6uMbolHNGG0zTS2lrLKpzcmkQfjhQpT9"
+ + "LUTBvfs1jdjo9fGmQLvOG+Sm51Rbjglb8bcikVI5gLbclOlvqLkm77otjl4U4Z2/"
+ + "Y0vP14Aov3Sn3k+17EfReYUZI4liuB95ncobC4e8ZM++LjQcIM0s+Vs=");
+
+
+ byte[] gost34102001base = Base64.decode(
+ "MIIB1DCCAYECEEjpVKXP6Wn1yVz3VeeDQa8wCgYGKoUDAgIDBQAwbTEfMB0G"
+ + "A1UEAwwWR29zdFIzNDEwLTIwMDEgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRv"
+ + "UHJvMQswCQYDVQQGEwJSVTEpMCcGCSqGSIb3DQEJARYaR29zdFIzNDEwLTIw"
+ + "MDFAZXhhbXBsZS5jb20wHhcNMDUwMjAzMTUxNjQ2WhcNMTUwMjAzMTUxNjQ2"
+ + "WjBtMR8wHQYDVQQDDBZHb3N0UjM0MTAtMjAwMSBleGFtcGxlMRIwEAYDVQQK"
+ + "DAlDcnlwdG9Qcm8xCzAJBgNVBAYTAlJVMSkwJwYJKoZIhvcNAQkBFhpHb3N0"
+ + "UjM0MTAtMjAwMUBleGFtcGxlLmNvbTBjMBwGBiqFAwICEzASBgcqhQMCAiQA"
+ + "BgcqhQMCAh4BA0MABECElWh1YAIaQHUIzROMMYks/eUFA3pDXPRtKw/nTzJ+"
+ + "V4/rzBa5lYgD0Jp8ha4P5I3qprt+VsfLsN8PZrzK6hpgMAoGBiqFAwICAwUA"
+ + "A0EAHw5dw/aw/OiNvHyOE65kvyo4Hp0sfz3csM6UUkp10VO247ofNJK3tsLb"
+ + "HOLjUaqzefrlGb11WpHYrvWFg+FcLA==");
+
+ byte[] gost341094base = Base64.decode(
+ "MIICDzCCAbwCEBcxKsIb0ghYvAQeUjfQdFAwCgYGKoUDAgIEBQAwaTEdMBsG"
+ + "A1UEAwwUR29zdFIzNDEwLTk0IGV4YW1wbGUxEjAQBgNVBAoMCUNyeXB0b1By"
+ + "bzELMAkGA1UEBhMCUlUxJzAlBgkqhkiG9w0BCQEWGEdvc3RSMzQxMC05NEBl"
+ + "eGFtcGxlLmNvbTAeFw0wNTAyMDMxNTE2NTFaFw0xNTAyMDMxNTE2NTFaMGkx"
+ + "HTAbBgNVBAMMFEdvc3RSMzQxMC05NCBleGFtcGxlMRIwEAYDVQQKDAlDcnlw"
+ + "dG9Qcm8xCzAJBgNVBAYTAlJVMScwJQYJKoZIhvcNAQkBFhhHb3N0UjM0MTAt"
+ + "OTRAZXhhbXBsZS5jb20wgaUwHAYGKoUDAgIUMBIGByqFAwICIAIGByqFAwIC"
+ + "HgEDgYQABIGAu4Rm4XmeWzTYLIB/E6gZZnFX/oxUJSFHbzALJ3dGmMb7R1W+"
+ + "t7Lzk2w5tUI3JoTiDRCKJA4fDEJNKzsRK6i/ZjkyXJSLwaj+G2MS9gklh8x1"
+ + "G/TliYoJgmjTXHemD7aQEBON4z58nJHWrA0ILD54wbXCtrcaqCqLRYGTMjJ2"
+ + "+nswCgYGKoUDAgIEBQADQQBxKNhOmjgz/i5CEgLOyKyz9pFGkDcaymsWYQWV"
+ + "v7CZ0pTM8IzMzkUBW3GHsUjCFpanFZDfg2zuN+3kT+694n9B");
+
+ byte[] gost341094A = Base64.decode(
+ "MIICSDCCAfWgAwIBAgIBATAKBgYqhQMCAgQFADCBgTEXMBUGA1UEAxMOZGVmYXVsdDM0MTAtOTQx"
+ + "DTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1vbGExDDAKBgNVBAgT"
+ + "A01FTDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAzMjkx"
+ + "MzExNTdaFw0wNjAzMjkxMzExNTdaMIGBMRcwFQYDVQQDEw5kZWZhdWx0MzQxMC05NDENMAsGA1UE"
+ + "ChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLW9sYTEMMAoGA1UECBMDTUVMMQsw"
+ + "CQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MIGlMBwGBiqFAwICFDASBgcq"
+ + "hQMCAiACBgcqhQMCAh4BA4GEAASBgIQACDLEuxSdRDGgdZxHmy30g/DUYkRxO9Mi/uSHX5NjvZ31"
+ + "b7JMEMFqBtyhql1HC5xZfUwZ0aT3UnEFDfFjLP+Bf54gA+LPkQXw4SNNGOj+klnqgKlPvoqMGlwa"
+ + "+hLPKbS561WpvB2XSTgbV+pqqXR3j6j30STmybelEV3RdS2Now8wDTALBgNVHQ8EBAMCB4AwCgYG"
+ + "KoUDAgIEBQADQQBCFy7xWRXtNVXflKvDs0pBdBuPzjCMeZAXVxK8vUxsxxKu76d9CsvhgIFknFRi"
+ + "wWTPiZenvNoJ4R1uzeX+vREm");
+
+ byte[] gost341094B = Base64.decode(
+ "MIICSDCCAfWgAwIBAgIBATAKBgYqhQMCAgQFADCBgTEXMBUGA1UEAxMOcGFyYW0xLTM0MTAtOTQx"
+ + "DTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1PbGExDDAKBgNVBAgT"
+ + "A01lbDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAzMjkx"
+ + "MzEzNTZaFw0wNjAzMjkxMzEzNTZaMIGBMRcwFQYDVQQDEw5wYXJhbTEtMzQxMC05NDENMAsGA1UE"
+ + "ChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLU9sYTEMMAoGA1UECBMDTWVsMQsw"
+ + "CQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MIGlMBwGBiqFAwICFDASBgcq"
+ + "hQMCAiADBgcqhQMCAh4BA4GEAASBgEa+AAcZmijWs1M9x5Pn9efE8D9ztG1NMoIt0/hNZNqln3+j"
+ + "lMZjyqPt+kTLIjtmvz9BRDmIDk6FZz+4LhG2OTL7yGpWfrMxMRr56nxomTN9aLWRqbyWmn3brz9Y"
+ + "AUD3ifnwjjIuW7UM84JNlDTOdxx0XRUfLQIPMCXe9cO02Xskow8wDTALBgNVHQ8EBAMCB4AwCgYG"
+ + "KoUDAgIEBQADQQBzFcnuYc/639OTW+L5Ecjw9KxGr+dwex7lsS9S1BUgKa3m1d5c+cqI0B2XUFi5"
+ + "4iaHHJG0dCyjtQYLJr0OZjRw");
+
+ byte[] gost34102001A = Base64.decode(
+ "MIICCzCCAbigAwIBAgIBATAKBgYqhQMCAgMFADCBhDEaMBgGA1UEAxMRZGVmYXVsdC0zNDEwLTIw"
+ + "MDExDTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1PbGExDDAKBgNV"
+ + "BAgTA01lbDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAz"
+ + "MjkxMzE4MzFaFw0wNjAzMjkxMzE4MzFaMIGEMRowGAYDVQQDExFkZWZhdWx0LTM0MTAtMjAwMTEN"
+ + "MAsGA1UEChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLU9sYTEMMAoGA1UECBMD"
+ + "TWVsMQswCQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MGMwHAYGKoUDAgIT"
+ + "MBIGByqFAwICIwEGByqFAwICHgEDQwAEQG/4c+ZWb10IpeHfmR+vKcbpmSOClJioYmCVgnojw0Xn"
+ + "ned0KTg7TJreRUc+VX7vca4hLQaZ1o/TxVtfEApK/O6jDzANMAsGA1UdDwQEAwIHgDAKBgYqhQMC"
+ + "AgMFAANBAN8y2b6HuIdkD3aWujpfQbS1VIA/7hro4vLgDhjgVmev/PLzFB8oTh3gKhExpDo82IEs"
+ + "ZftGNsbbyp1NFg7zda0=");
+
+ byte[] gostCA1 = Base64.decode(
+ "MIIDNDCCAuGgAwIBAgIQZLcKDcWcQopF+jp4p9jylDAKBgYqhQMCAgQFADBm"
+ + "MQswCQYDVQQGEwJSVTEPMA0GA1UEBxMGTW9zY293MRcwFQYDVQQKEw5PT08g"
+ + "Q3J5cHRvLVBybzEUMBIGA1UECxMLRGV2ZWxvcG1lbnQxFzAVBgNVBAMTDkNQ"
+ + "IENTUCBUZXN0IENBMB4XDTAyMDYwOTE1NTIyM1oXDTA5MDYwOTE1NTkyOVow"
+ + "ZjELMAkGA1UEBhMCUlUxDzANBgNVBAcTBk1vc2NvdzEXMBUGA1UEChMOT09P"
+ + "IENyeXB0by1Qcm8xFDASBgNVBAsTC0RldmVsb3BtZW50MRcwFQYDVQQDEw5D"
+ + "UCBDU1AgVGVzdCBDQTCBpTAcBgYqhQMCAhQwEgYHKoUDAgIgAgYHKoUDAgIe"
+ + "AQOBhAAEgYAYglywKuz1nMc9UiBYOaulKy53jXnrqxZKbCCBSVaJ+aCKbsQm"
+ + "glhRFrw6Mwu8Cdeabo/ojmea7UDMZd0U2xhZFRti5EQ7OP6YpqD0alllo7za"
+ + "4dZNXdX+/ag6fOORSLFdMpVx5ganU0wHMPk67j+audnCPUj/plbeyccgcdcd"
+ + "WaOCASIwggEeMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud"
+ + "DgQWBBTe840gTo4zt2twHilw3PD9wJaX0TCBygYDVR0fBIHCMIG/MDygOqA4"
+ + "hjYtaHR0cDovL2ZpZXdhbGwvQ2VydEVucm9sbC9DUCUyMENTUCUyMFRlc3Ql"
+ + "MjBDQSgzKS5jcmwwRKBCoECGPmh0dHA6Ly93d3cuY3J5cHRvcHJvLnJ1L0Nl"
+ + "cnRFbnJvbGwvQ1AlMjBDU1AlMjBUZXN0JTIwQ0EoMykuY3JsMDmgN6A1hjMt"
+ + "ZmlsZTovL1xcZmlld2FsbFxDZXJ0RW5yb2xsXENQIENTUCBUZXN0IENBKDMp"
+ + "LmNybC8wEgYJKwYBBAGCNxUBBAUCAwMAAzAKBgYqhQMCAgQFAANBAIJi7ni7"
+ + "9rwMR5rRGTFftt2k70GbqyUEfkZYOzrgdOoKiB4IIsIstyBX0/ne6GsL9Xan"
+ + "G2IN96RB7KrowEHeW+k=");
+
+ byte[] gostCA2 = Base64.decode(
+ "MIIC2DCCAoWgAwIBAgIQe9ZCugm42pRKNcHD8466zTAKBgYqhQMCAgMFADB+"
+ + "MRowGAYJKoZIhvcNAQkBFgtzYmFAZGlndC5ydTELMAkGA1UEBhMCUlUxDDAK"
+ + "BgNVBAgTA01FTDEUMBIGA1UEBxMLWW9zaGthci1PbGExDTALBgNVBAoTBERp"
+ + "Z3QxDzANBgNVBAsTBkNyeXB0bzEPMA0GA1UEAxMGc2JhLUNBMB4XDTA0MDgw"
+ + "MzEzMzE1OVoXDTE0MDgwMzEzNDAxMVowfjEaMBgGCSqGSIb3DQEJARYLc2Jh"
+ + "QGRpZ3QucnUxCzAJBgNVBAYTAlJVMQwwCgYDVQQIEwNNRUwxFDASBgNVBAcT"
+ + "C1lvc2hrYXItT2xhMQ0wCwYDVQQKEwREaWd0MQ8wDQYDVQQLEwZDcnlwdG8x"
+ + "DzANBgNVBAMTBnNiYS1DQTBjMBwGBiqFAwICEzASBgcqhQMCAiMBBgcqhQMC"
+ + "Ah4BA0MABEDMSy10CuOH+i8QKG2UWA4XmCt6+BFrNTZQtS6bOalyDY8Lz+G7"
+ + "HybyipE3PqdTB4OIKAAPsEEeZOCZd2UXGQm5o4HaMIHXMBMGCSsGAQQBgjcU"
+ + "AgQGHgQAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud"
+ + "DgQWBBRJJl3LcNMxkZI818STfoi3ng1xoDBxBgNVHR8EajBoMDGgL6Athito"
+ + "dHRwOi8vc2JhLmRpZ3QubG9jYWwvQ2VydEVucm9sbC9zYmEtQ0EuY3JsMDOg"
+ + "MaAvhi1maWxlOi8vXFxzYmEuZGlndC5sb2NhbFxDZXJ0RW5yb2xsXHNiYS1D"
+ + "QS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwCgYGKoUDAgIDBQADQQA+BRJHbc/p"
+ + "q8EYl6iJqXCuR+ozRmH7hPAP3c4KqYSC38TClCgBloLapx/3/WdatctFJW/L"
+ + "mcTovpq088927shE");
+
+ byte[] inDirectCrl = Base64.decode(
+ "MIIdXjCCHMcCAQEwDQYJKoZIhvcNAQEFBQAwdDELMAkGA1UEBhMCREUxHDAaBgNV"
+ +"BAoUE0RldXRzY2hlIFRlbGVrb20gQUcxFzAVBgNVBAsUDlQtVGVsZVNlYyBUZXN0"
+ +"MS4wDAYHAoIGAQoHFBMBMTAeBgNVBAMUF1QtVGVsZVNlYyBUZXN0IERJUiA4OlBO"
+ +"Fw0wNjA4MDQwODQ1MTRaFw0wNjA4MDQxNDQ1MTRaMIIbfzB+AgQvrj/pFw0wMzA3"
+ +"MjIwNTQxMjhaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+ +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+ +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP+oXDTAzMDcyMjA1NDEyOFowZzBlBgNV"
+ +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+ +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+ +"UE4wfgIEL64/5xcNMDQwNDA1MTMxODE3WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+ +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC"
+ +"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/oFw0wNDA0"
+ +"MDUxMzE4MTdaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+ +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+ +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP+UXDTAzMDExMzExMTgxMVowZzBlBgNV"
+ +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+ +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+ +"UE4wfgIEL64/5hcNMDMwMTEzMTExODExWjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+ +"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");
+
+ byte[] directCRL = Base64.decode(
+ "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"
+ +"MQ==");
+
+ private final byte[] pkcs7CrlProblem = Base64.decode(
+ "MIIwSAYJKoZIhvcNAQcCoIIwOTCCMDUCAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+ + "SIb3DQEHAaCCEsAwggP4MIIC4KADAgECAgF1MA0GCSqGSIb3DQEBBQUAMEUx"
+ + "CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR4wHAYDVQQD"
+ + "ExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUwHhcNMDQxMjAyMjEyNTM5WhcNMDYx"
+ + "MjMwMjEyNTM5WjBMMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMR2VvVHJ1c3Qg"
+ + "SW5jMSYwJAYDVQQDEx1HZW9UcnVzdCBBZG9iZSBPQ1NQIFJlc3BvbmRlcjCB"
+ + "nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4gnNYhtw7U6QeVXZODnGhHMj"
+ + "+OgZ0DB393rEk6a2q9kq129IA2e03yKBTfJfQR9aWKc2Qj90dsSqPjvTDHFG"
+ + "Qsagm2FQuhnA3fb1UWhPzeEIdm6bxDsnQ8nWqKqxnWZzELZbdp3I9bBLizIq"
+ + "obZovzt60LNMghn/unvvuhpeVSsCAwEAAaOCAW4wggFqMA4GA1UdDwEB/wQE"
+ + "AwIE8DCB5QYDVR0gAQH/BIHaMIHXMIHUBgkqhkiG9y8BAgEwgcYwgZAGCCsG"
+ + "AQUFBwICMIGDGoGAVGhpcyBjZXJ0aWZpY2F0ZSBoYXMgYmVlbiBpc3N1ZWQg"
+ + "aW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBBY3JvYmF0IENyZWRlbnRpYWxzIENQ"
+ + "UyBsb2NhdGVkIGF0IGh0dHA6Ly93d3cuZ2VvdHJ1c3QuY29tL3Jlc291cmNl"
+ + "cy9jcHMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2VvdHJ1c3QuY29tL3Jl"
+ + "c291cmNlcy9jcHMwEwYDVR0lBAwwCgYIKwYBBQUHAwkwOgYDVR0fBDMwMTAv"
+ + "oC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9hZG9iZWNhMS5j"
+ + "cmwwHwYDVR0jBBgwFoAUq4BZw2WDbR19E70Zw+wajw1HaqMwDQYJKoZIhvcN"
+ + "AQEFBQADggEBAENJf1BD7PX5ivuaawt90q1OGzXpIQL/ClzEeFVmOIxqPc1E"
+ + "TFRq92YuxG5b6+R+k+tGkmCwPLcY8ipg6ZcbJ/AirQhohzjlFuT6YAXsTfEj"
+ + "CqEZfWM2sS7crK2EYxCMmKE3xDfPclYtrAoz7qZvxfQj0TuxHSstHZv39wu2"
+ + "ZiG1BWiEcyDQyTgqTOXBoZmfJtshuAcXmTpgkrYSrS37zNlPTGh+pMYQ0yWD"
+ + "c8OQRJR4OY5ZXfdna01mjtJTOmj6/6XPoLPYTq2gQrc2BCeNJ4bEhLb7sFVB"
+ + "PbwPrpzTE/HRbQHDrzj0YimDxeOUV/UXctgvYwHNtEkcBLsOm/uytMYwggSh"
+ + "MIIDiaADAgECAgQ+HL0oMA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNVBAYTAlVT"
+ + "MSMwIQYDVQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UE"
+ + "CxMUQWRvYmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3Qg"
+ + "Q0EwHhcNMDMwMTA4MjMzNzIzWhcNMjMwMTA5MDAwNzIzWjBpMQswCQYDVQQG"
+ + "EwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQxHTAb"
+ + "BgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYwFAYDVQQDEw1BZG9iZSBS"
+ + "b290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzE9UhPen"
+ + "ouczU38/nBKIayyZR2d+Dx65rRSI+cMQ2B3w8NWfaQovWTWwzGypTJwVoJ/O"
+ + "IL+gz1Ti4CBmRT85hjh+nMSOByLGJPYBErA131XqaZCw24U3HuJOB7JCoWoT"
+ + "aaBm6oCREVkqmwh5WiBELcm9cziLPC/gQxtdswvwrzUaKf7vppLdgUydPVmO"
+ + "rTE8QH6bkTYG/OJcjdGNJtVcRc+vZT+xqtJilvSoOOq6YEL09BxKNRXO+E4i"
+ + "Vg+VGMX4lp+f+7C3eCXpgGu91grwxnSUnfMPUNuad85LcIMjjaDKeCBEXDxU"
+ + "ZPHqojAZn+pMBk0GeEtekt8i0slns3rSAQIDAQABo4IBTzCCAUswEQYJYIZI"
+ + "AYb4QgEBBAQDAgAHMIGOBgNVHR8EgYYwgYMwgYCgfqB8pHoweDELMAkGA1UE"
+ + "BhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMgSW5jb3Jwb3JhdGVkMR0w"
+ + "GwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEWMBQGA1UEAxMNQWRvYmUg"
+ + "Um9vdCBDQTENMAsGA1UEAxMEQ1JMMTArBgNVHRAEJDAigA8yMDAzMDEwODIz"
+ + "MzcyM1qBDzIwMjMwMTA5MDAwNzIzWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgw"
+ + "FoAUgrc4SpOqmxDvgLvZVOLxD/uAnN4wHQYDVR0OBBYEFIK3OEqTqpsQ74C7"
+ + "2VTi8Q/7gJzeMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjYu"
+ + "MDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQAy2p9DdcH6b8lv26sdNjc+"
+ + "vGEZNrcCPB0jWZhsnu5NhedUyCAfp9S74r8Ad30ka3AvXME6dkm10+AjhCpx"
+ + "aiLzwScpmBX2NZDkBEzDjbyfYRzn/SSM0URDjBa6m02l1DUvvBHOvfdRN42f"
+ + "kOQU8Rg/vulZEjX5M5LznuDVa5pxm5lLyHHD4bFhCcTl+pHwQjo3fTT5cujN"
+ + "qmIcIenV9IIQ43sFti1oVgt+fpIsb01yggztVnSynbmrLSsdEF/bJ3Vwj/0d"
+ + "1+ICoHnlHOX/r2RAUS2em0fbQqV8H8KmSLDXvpJpTaT2KVfFeBEY3IdRyhOy"
+ + "Yp1PKzK9MaXB+lKrBYjIMIIEyzCCA7OgAwIBAgIEPhy9tTANBgkqhkiG9w0B"
+ + "AQUFADBpMQswCQYDVQQGEwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJ"
+ + "bmNvcnBvcmF0ZWQxHTAbBgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYw"
+ + "FAYDVQQDEw1BZG9iZSBSb290IENBMB4XDTA0MDExNzAwMDMzOVoXDTE1MDEx"
+ + "NTA4MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu"
+ + "Yy4xHjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTCCASIwDQYJKoZI"
+ + "hvcNAQEBBQADggEPADCCAQoCggEBAKfld+BkeFrnOYW8r9L1WygTDlTdSfrO"
+ + "YvWS/Z6Ye5/l+HrBbOHqQCXBcSeCpz7kB2WdKMh1FOE4e9JlmICsHerBLdWk"
+ + "emU+/PDb69zh8E0cLoDfxukF6oVPXj6WSThdSG7H9aXFzRr6S3XGCuvgl+Qw"
+ + "DTLiLYW+ONF6DXwt3TQQtKReJjOJZk46ZZ0BvMStKyBaeB6DKZsmiIo89qso"
+ + "13VDZINH2w1KvXg0ygDizoNtbvgAPFymwnsINS1klfQlcvn0x0RJm9bYQXK3"
+ + "5GNZAgL3M7Lqrld0jMfIUaWvuHCLyivytRuzq1dJ7E8rmidjDEk/G+27pf13"
+ + "fNZ7vR7M+IkCAwEAAaOCAZ0wggGZMBIGA1UdEwEB/wQIMAYBAf8CAQEwUAYD"
+ + "VR0gBEkwRzBFBgkqhkiG9y8BAgEwODA2BggrBgEFBQcCARYqaHR0cHM6Ly93"
+ + "d3cuYWRvYmUuY29tL21pc2MvcGtpL2Nkc19jcC5odG1sMBQGA1UdJQQNMAsG"
+ + "CSqGSIb3LwEBBTCBsgYDVR0fBIGqMIGnMCKgIKAehhxodHRwOi8vY3JsLmFk"
+ + "b2JlLmNvbS9jZHMuY3JsMIGAoH6gfKR6MHgxCzAJBgNVBAYTAlVTMSMwIQYD"
+ + "VQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRv"
+ + "YmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0ExDTAL"
+ + "BgNVBAMTBENSTDEwCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFIK3OEqTqpsQ"
+ + "74C72VTi8Q/7gJzeMB0GA1UdDgQWBBSrgFnDZYNtHX0TvRnD7BqPDUdqozAZ"
+ + "BgkqhkiG9n0HQQAEDDAKGwRWNi4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA"
+ + "PzlZLqIAjrFeEWEs0uC29YyJhkXOE9mf3YSaFGsITF+Gl1j0pajTjyH4R35Q"
+ + "r3floW2q3HfNzTeZ90Jnr1DhVERD6zEMgJpCtJqVuk0sixuXJHghS/KicKf4"
+ + "YXJJPx9epuIRF1siBRnznnF90svmOJMXApc0jGnYn3nQfk4kaShSnDaYaeYR"
+ + "DJKcsiWhl6S5zfwS7Gg8hDeyckhMQKKWnlG1CQrwlSFisKCduoodwRtWgft8"
+ + "kx13iyKK3sbalm6vnVc+5nufS4vI+TwMXoV63NqYaSroafBWk0nL53zGXPEy"
+ + "+A69QhzEViJKn2Wgqt5gt++jMMNImbRObIqgfgF1VjCCBUwwggQ0oAMCAQIC"
+ + "AgGDMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1H"
+ + "ZW9UcnVzdCBJbmMuMR4wHAYDVQQDExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUw"
+ + "HhcNMDYwMzI0MTU0MjI5WhcNMDkwNDA2MTQ0MjI5WjBzMQswCQYDVQQGEwJV"
+ + "UzELMAkGA1UECBMCTUExETAPBgNVBAoTCEdlb1RydXN0MR0wGwYDVQQDExRN"
+ + "YXJrZXRpbmcgRGVwYXJ0bWVudDElMCMGCSqGSIb3DQEJARYWbWFya2V0aW5n"
+ + "QGdlb3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB"
+ + "ANmvajTO4XJvAU2nVcLmXeCnAQX7RZt+7+ML3InmqQ3LCGo1weop09zV069/"
+ + "1x/Nmieol7laEzeXxd2ghjGzwfXafqQEqHn6+vBCvqdNPoSi63fSWhnuDVWp"
+ + "KVDOYgxOonrXl+Cc43lu4zRSq+Pi5phhrjDWcH74a3/rdljUt4c4GFezFXfa"
+ + "w2oTzWkxj2cTSn0Szhpr17+p66UNt8uknlhmu4q44Speqql2HwmCEnpLYJrK"
+ + "W3fOq5D4qdsvsLR2EABLhrBezamLI3iGV8cRHOUTsbTMhWhv/lKfHAyf4XjA"
+ + "z9orzvPN5jthhIfICOFq/nStTgakyL4Ln+nFAB/SMPkCAwEAAaOCAhYwggIS"
+ + "MA4GA1UdDwEB/wQEAwIF4DCB5QYDVR0gAQH/BIHaMIHXMIHUBgkqhkiG9y8B"
+ + "AgEwgcYwgZAGCCsGAQUFBwICMIGDGoGAVGhpcyBjZXJ0aWZpY2F0ZSBoYXMg"
+ + "YmVlbiBpc3N1ZWQgaW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBBY3JvYmF0IENy"
+ + "ZWRlbnRpYWxzIENQUyBsb2NhdGVkIGF0IGh0dHA6Ly93d3cuZ2VvdHJ1c3Qu"
+ + "Y29tL3Jlc291cmNlcy9jcHMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2Vv"
+ + "dHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwOgYDVR0fBDMwMTAvoC2gK4YpaHR0"
+ + "cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9hZG9iZWNhMS5jcmwwHwYDVR0j"
+ + "BBgwFoAUq4BZw2WDbR19E70Zw+wajw1HaqMwRAYIKwYBBQUHAQEEODA2MDQG"
+ + "CCsGAQUFBzABhihodHRwOi8vYWRvYmUtb2NzcC5nZW90cnVzdC5jb20vcmVz"
+ + "cG9uZGVyMBQGA1UdJQQNMAsGCSqGSIb3LwEBBTA8BgoqhkiG9y8BAQkBBC4w"
+ + "LAIBAYYnaHR0cDovL2Fkb2JlLXRpbWVzdGFtcC5nZW90cnVzdC5jb20vdHNh"
+ + "MBMGCiqGSIb3LwEBCQIEBTADAgEBMAwGA1UdEwQFMAMCAQAwDQYJKoZIhvcN"
+ + "AQEFBQADggEBAAOhy6QxOo+i3h877fvDvTa0plGD2bIqK7wMdNqbMDoSWied"
+ + "FIcgcBOIm2wLxOjZBAVj/3lDq59q2rnVeNnfXM0/N0MHI9TumHRjU7WNk9e4"
+ + "+JfJ4M+c3anrWOG3NE5cICDVgles+UHjXetHWql/LlP04+K2ZOLb6LE2xGnI"
+ + "YyLW9REzCYNAVF+/WkYdmyceHtaBZdbyVAJq0NAJPsfgY1pWcBo31Mr1fpX9"
+ + "WrXNTYDCqMyxMImJTmN3iI68tkXlNrhweQoArKFqBysiBkXzG/sGKYY6tWKU"
+ + "pzjLc3vIp/LrXC5zilROes8BSvwu1w9qQrJNcGwo7O4uijoNtyYil1Exgh1Q"
+ + "MIIdTAIBATBLMEUxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJ"
+ + "bmMuMR4wHAYDVQQDExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUCAgGDMAkGBSsO"
+ + "AwIaBQCgggxMMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwIwYJKoZIhvcN"
+ + "AQkEMRYEFP4R6qIdpQJzWyzrqO8X1ZfJOgChMIIMCQYJKoZIhvcvAQEIMYIL"
+ + "+jCCC/agggZ5MIIGdTCCA6gwggKQMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV"
+ + "BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR4wHAYDVQQDExVHZW9U"
+ + "cnVzdCBDQSBmb3IgQWRvYmUXDTA2MDQwNDE3NDAxMFoXDTA2MDQwNTE3NDAx"
+ + "MFowggIYMBMCAgC5Fw0wNTEwMTEyMDM2MzJaMBICAVsXDTA0MTEwNDE1MDk0"
+ + "MVowEwICALgXDTA1MTIxMjIyMzgzOFowEgIBWhcNMDQxMTA0MTUwOTMzWjAT"
+ + "AgIA5hcNMDUwODI3MDQwOTM4WjATAgIAtxcNMDYwMTE2MTc1NTEzWjATAgIA"
+ + "hhcNMDUxMjEyMjIzODU1WjATAgIAtRcNMDUwNzA2MTgzODQwWjATAgIA4BcN"
+ + "MDYwMzIwMDc0ODM0WjATAgIAgRcNMDUwODAyMjIzMTE1WjATAgIA3xcNMDUx"
+ + "MjEyMjIzNjUwWjASAgFKFw0wNDExMDQxNTA5MTZaMBICAUQXDTA0MTEwNDE1"
+ + "MDg1M1owEgIBQxcNMDQxMDAzMDEwMDQwWjASAgFsFw0wNDEyMDYxOTQ0MzFa"
+ + "MBMCAgEoFw0wNjAzMDkxMjA3MTJaMBMCAgEkFw0wNjAxMTYxNzU1MzRaMBIC"
+ + "AWcXDTA1MDMxODE3NTYxNFowEwICAVEXDTA2MDEzMTExMjcxMVowEgIBZBcN"
+ + "MDQxMTExMjI0ODQxWjATAgIA8RcNMDUwOTE2MTg0ODAxWjATAgIBThcNMDYw"
+ + "MjIxMjAxMDM2WjATAgIAwRcNMDUxMjEyMjIzODE2WjASAgFiFw0wNTAxMTAx"
+ + "NjE5MzRaMBICAWAXDTA1MDExMDE5MDAwNFowEwICAL4XDTA1MDUxNzE0NTYx"
+ + "MFowDQYJKoZIhvcNAQEFBQADggEBAEKhRMS3wVho1U3EvEQJZC8+JlUngmZQ"
+ + "A78KQbHPWNZWFlNvPuf/b0s7Lu16GfNHXh1QAW6Y5Hi1YtYZ3YOPyMd4Xugt"
+ + "gCdumbB6xtKsDyN5RvTht6ByXj+CYlYqsL7RX0izJZ6mJn4fjMkqzPKNOjb8"
+ + "kSn5T6rn93BjlATtCE8tPVOM8dnqGccRE0OV59+nDBXc90UMt5LdEbwaUOap"
+ + "snVB0oLcNm8d/HnlVH6RY5LnDjrT4vwfe/FApZtTecEWsllVUXDjSpwfcfD/"
+ + "476/lpGySB2otALqzImlA9R8Ok3hJ8dnF6hhQ5Oe6OJMnGYgdhkKbxsKkdib"
+ + "tTVl3qmH5QAwggLFMIIBrQIBATANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQG"
+ + "EwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQxHTAb"
+ + "BgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYwFAYDVQQDEw1BZG9iZSBS"
+ + "b290IENBFw0wNjAxMjcxODMzMzFaFw0wNzAxMjcwMDAwMDBaMIHeMCMCBD4c"
+ + "vUAXDTAzMDEyMTIzNDY1NlowDDAKBgNVHRUEAwoBBDAjAgQ+HL1BFw0wMzAx"
+ + "MjEyMzQ3MjJaMAwwCgYDVR0VBAMKAQQwIwIEPhy9YhcNMDMwMTIxMjM0NzQy"
+ + "WjAMMAoGA1UdFQQDCgEEMCMCBD4cvWEXDTA0MDExNzAxMDg0OFowDDAKBgNV"
+ + "HRUEAwoBBDAjAgQ+HL2qFw0wNDAxMTcwMTA5MDVaMAwwCgYDVR0VBAMKAQQw"
+ + "IwIEPhy9qBcNMDQwMTE3MDEzOTI5WjAMMAoGA1UdFQQDCgEEoC8wLTAKBgNV"
+ + "HRQEAwIBDzAfBgNVHSMEGDAWgBSCtzhKk6qbEO+Au9lU4vEP+4Cc3jANBgkq"
+ + "hkiG9w0BAQUFAAOCAQEAwtXF9042wG39icUlsotn5tpE3oCusLb/hBpEONhx"
+ + "OdfEQOq0w5hf/vqaxkcf71etA+KpbEUeSVaHMHRPhx/CmPrO9odE139dJdbt"
+ + "9iqbrC9iZokFK3h/es5kg73xujLKd7C/u5ngJ4mwBtvhMLjFjF2vJhPKHL4C"
+ + "IgMwdaUAhrcNzy16v+mw/VGJy3Fvc6oCESW1K9tvFW58qZSNXrMlsuidgunM"
+ + "hPKG+z0SXVyCqL7pnqKiaGddcgujYGOSY4S938oVcfZeZQEODtSYGlzldojX"
+ + "C1U1hCK5+tHAH0Ox/WqRBIol5VCZQwJftf44oG8oviYq52aaqSejXwmfT6zb"
+ + "76GCBXUwggVxMIIFbQoBAKCCBWYwggViBgkrBgEFBQcwAQEEggVTMIIFTzCB"
+ + "taIWBBS+8EpykfXdl4h3z7m/NZfdkAQQERgPMjAwNjA0MDQyMDIwMTVaMGUw"
+ + "YzA7MAkGBSsOAwIaBQAEFEb4BuZYkbjBjOjT6VeA/00fBvQaBBT3fTSQniOp"
+ + "BbHBSkz4xridlX0bsAICAYOAABgPMjAwNjA0MDQyMDIwMTVaoBEYDzIwMDYw"
+ + "NDA1MDgyMDE1WqEjMCEwHwYJKwYBBQUHMAECBBIEEFqooq/R2WltD7TposkT"
+ + "BhMwDQYJKoZIhvcNAQEFBQADgYEAMig6lty4b0JDsT/oanfQG5x6jVKPACpp"
+ + "1UA9SJ0apJJa7LeIdDFmu5C2S/CYiKZm4A4P9cAu0YzgLHxE4r6Op+HfVlAG"
+ + "6bzUe1P/hi1KCJ8r8wxOZAktQFPSzs85RAZwkHMfB0lP2e/h666Oye+Zf8VH"
+ + "RaE+/xZ7aswE89HXoumgggQAMIID/DCCA/gwggLgoAMCAQICAXUwDQYJKoZI"
+ + "hvcNAQEFBQAwRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu"
+ + "Yy4xHjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTAeFw0wNDEyMDIy"
+ + "MTI1MzlaFw0wNjEyMzAyMTI1MzlaMEwxCzAJBgNVBAYTAlVTMRUwEwYDVQQK"
+ + "EwxHZW9UcnVzdCBJbmMxJjAkBgNVBAMTHUdlb1RydXN0IEFkb2JlIE9DU1Ag"
+ + "UmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDiCc1iG3Dt"
+ + "TpB5Vdk4OcaEcyP46BnQMHf3esSTprar2SrXb0gDZ7TfIoFN8l9BH1pYpzZC"
+ + "P3R2xKo+O9MMcUZCxqCbYVC6GcDd9vVRaE/N4Qh2bpvEOydDydaoqrGdZnMQ"
+ + "tlt2ncj1sEuLMiqhtmi/O3rQs0yCGf+6e++6Gl5VKwIDAQABo4IBbjCCAWow"
+ + "DgYDVR0PAQH/BAQDAgTwMIHlBgNVHSABAf8EgdowgdcwgdQGCSqGSIb3LwEC"
+ + "ATCBxjCBkAYIKwYBBQUHAgIwgYMagYBUaGlzIGNlcnRpZmljYXRlIGhhcyBi"
+ + "ZWVuIGlzc3VlZCBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIEFjcm9iYXQgQ3Jl"
+ + "ZGVudGlhbHMgQ1BTIGxvY2F0ZWQgYXQgaHR0cDovL3d3dy5nZW90cnVzdC5j"
+ + "b20vcmVzb3VyY2VzL2NwczAxBggrBgEFBQcCARYlaHR0cDovL3d3dy5nZW90"
+ + "cnVzdC5jb20vcmVzb3VyY2VzL2NwczATBgNVHSUEDDAKBggrBgEFBQcDCTA6"
+ + "BgNVHR8EMzAxMC+gLaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxz"
+ + "L2Fkb2JlY2ExLmNybDAfBgNVHSMEGDAWgBSrgFnDZYNtHX0TvRnD7BqPDUdq"
+ + "ozANBgkqhkiG9w0BAQUFAAOCAQEAQ0l/UEPs9fmK+5prC33SrU4bNekhAv8K"
+ + "XMR4VWY4jGo9zURMVGr3Zi7Eblvr5H6T60aSYLA8txjyKmDplxsn8CKtCGiH"
+ + "OOUW5PpgBexN8SMKoRl9YzaxLtysrYRjEIyYoTfEN89yVi2sCjPupm/F9CPR"
+ + "O7EdKy0dm/f3C7ZmIbUFaIRzINDJOCpM5cGhmZ8m2yG4BxeZOmCSthKtLfvM"
+ + "2U9MaH6kxhDTJYNzw5BElHg5jlld92drTWaO0lM6aPr/pc+gs9hOraBCtzYE"
+ + "J40nhsSEtvuwVUE9vA+unNMT8dFtAcOvOPRiKYPF45RX9Rdy2C9jAc20SRwE"
+ + "uw6b+7K0xjANBgkqhkiG9w0BAQEFAASCAQC7a4yICFGCEMPlJbydK5qLG3rV"
+ + "sip7Ojjz9TB4nLhC2DgsIHds8jjdq2zguInluH2nLaBCVS+qxDVlTjgbI2cB"
+ + "TaWS8nglC7nNjzkKAsa8vThA8FZUVXTW0pb74jNJJU2AA27bb4g+4WgunCrj"
+ + "fpYp+QjDyMmdrJVqRmt5eQN+dpVxMS9oq+NrhOSEhyIb4/rejgNg9wnVK1ms"
+ + "l5PxQ4x7kpm7+Ua41//owkJVWykRo4T1jo4eHEz1DolPykAaKie2VKH/sMqR"
+ + "Spjh4E5biKJLOV9fKivZWKAXByXfwUbbMsJvz4v/2yVHFy9xP+tqB5ZbRoDK"
+ + "k8PzUyCprozn+/22oYIPijCCD4YGCyqGSIb3DQEJEAIOMYIPdTCCD3EGCSqG"
+ + "SIb3DQEHAqCCD2Iwgg9eAgEDMQswCQYFKw4DAhoFADCB+gYLKoZIhvcNAQkQ"
+ + "AQSggeoEgecwgeQCAQEGAikCMCEwCQYFKw4DAhoFAAQUoT97qeCv3FXYaEcS"
+ + "gY8patCaCA8CAiMHGA8yMDA2MDQwNDIwMjA1N1owAwIBPAEB/wIIO0yRre3L"
+ + "8/6ggZCkgY0wgYoxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNl"
+ + "dHRzMRAwDgYDVQQHEwdOZWVkaGFtMRUwEwYDVQQKEwxHZW9UcnVzdCBJbmMx"
+ + "EzARBgNVBAsTClByb2R1Y3Rpb24xJTAjBgNVBAMTHGFkb2JlLXRpbWVzdGFt"
+ + "cC5nZW90cnVzdC5jb22gggzJMIIDUTCCAjmgAwIBAgICAI8wDQYJKoZIhvcN"
+ + "AQEFBQAwRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4x"
+ + "HjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTAeFw0wNTAxMTAwMTI5"
+ + "MTBaFw0xNTAxMTUwODAwMDBaMIGKMQswCQYDVQQGEwJVUzEWMBQGA1UECBMN"
+ + "TWFzc2FjaHVzZXR0czEQMA4GA1UEBxMHTmVlZGhhbTEVMBMGA1UEChMMR2Vv"
+ + "VHJ1c3QgSW5jMRMwEQYDVQQLEwpQcm9kdWN0aW9uMSUwIwYDVQQDExxhZG9i"
+ + "ZS10aW1lc3RhbXAuZ2VvdHJ1c3QuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GN"
+ + "ADCBiQKBgQDRbxJotLFPWQuuEDhKtOMaBUJepGxIvWxeahMbq1DVmqnk88+j"
+ + "w/5lfPICPzQZ1oHrcTLSAFM7Mrz3pyyQKQKMqUyiemzuG/77ESUNfBNSUfAF"
+ + "PdtHuDMU8Is8ABVnFk63L+wdlvvDIlKkE08+VTKCRdjmuBVltMpQ6QcLFQzm"
+ + "AQIDAQABo4GIMIGFMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly9jcmwuZ2Vv"
+ + "dHJ1c3QuY29tL2NybHMvYWRvYmVjYTEuY3JsMB8GA1UdIwQYMBaAFKuAWcNl"
+ + "g20dfRO9GcPsGo8NR2qjMA4GA1UdDwEB/wQEAwIGwDAWBgNVHSUBAf8EDDAK"
+ + "BggrBgEFBQcDCDANBgkqhkiG9w0BAQUFAAOCAQEAmnyXjdtX+F79Nf0KggTd"
+ + "6YC2MQD9s09IeXTd8TP3rBmizfM+7f3icggeCGakNfPRmIUMLoa0VM5Kt37T"
+ + "2X0TqzBWusfbKx7HnX4v1t/G8NJJlT4SShSHv+8bjjU4lUoCmW2oEcC5vXwP"
+ + "R5JfjCyois16npgcO05ZBT+LLDXyeBijE6qWmwLDfEpLyILzVRmyU4IE7jvm"
+ + "rgb3GXwDUvd3yQXGRRHbPCh3nj9hBGbuzyt7GnlqnEie3wzIyMG2ET/wvTX5"
+ + "4BFXKNe7lDLvZj/MXvd3V7gMTSVW0kAszKao56LfrVTgp1VX3UBQYwmQqaoA"
+ + "UwFezih+jEvjW6cYJo/ErDCCBKEwggOJoAMCAQICBD4cvSgwDQYJKoZIhvcN"
+ + "AQEFBQAwaTELMAkGA1UEBhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMg"
+ + "SW5jb3Jwb3JhdGVkMR0wGwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEW"
+ + "MBQGA1UEAxMNQWRvYmUgUm9vdCBDQTAeFw0wMzAxMDgyMzM3MjNaFw0yMzAx"
+ + "MDkwMDA3MjNaMGkxCzAJBgNVBAYTAlVTMSMwIQYDVQQKExpBZG9iZSBTeXN0"
+ + "ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRvYmUgVHJ1c3QgU2Vydmlj"
+ + "ZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUA"
+ + "A4IBDwAwggEKAoIBAQDMT1SE96ei5zNTfz+cEohrLJlHZ34PHrmtFIj5wxDY"
+ + "HfDw1Z9pCi9ZNbDMbKlMnBWgn84gv6DPVOLgIGZFPzmGOH6cxI4HIsYk9gES"
+ + "sDXfVeppkLDbhTce4k4HskKhahNpoGbqgJERWSqbCHlaIEQtyb1zOIs8L+BD"
+ + "G12zC/CvNRop/u+mkt2BTJ09WY6tMTxAfpuRNgb84lyN0Y0m1VxFz69lP7Gq"
+ + "0mKW9Kg46rpgQvT0HEo1Fc74TiJWD5UYxfiWn5/7sLd4JemAa73WCvDGdJSd"
+ + "8w9Q25p3zktwgyONoMp4IERcPFRk8eqiMBmf6kwGTQZ4S16S3yLSyWezetIB"
+ + "AgMBAAGjggFPMIIBSzARBglghkgBhvhCAQEEBAMCAAcwgY4GA1UdHwSBhjCB"
+ + "gzCBgKB+oHykejB4MQswCQYDVQQGEwJVUzEjMCEGA1UEChMaQWRvYmUgU3lz"
+ + "dGVtcyBJbmNvcnBvcmF0ZWQxHTAbBgNVBAsTFEFkb2JlIFRydXN0IFNlcnZp"
+ + "Y2VzMRYwFAYDVQQDEw1BZG9iZSBSb290IENBMQ0wCwYDVQQDEwRDUkwxMCsG"
+ + "A1UdEAQkMCKADzIwMDMwMTA4MjMzNzIzWoEPMjAyMzAxMDkwMDA3MjNaMAsG"
+ + "A1UdDwQEAwIBBjAfBgNVHSMEGDAWgBSCtzhKk6qbEO+Au9lU4vEP+4Cc3jAd"
+ + "BgNVHQ4EFgQUgrc4SpOqmxDvgLvZVOLxD/uAnN4wDAYDVR0TBAUwAwEB/zAd"
+ + "BgkqhkiG9n0HQQAEEDAOGwhWNi4wOjQuMAMCBJAwDQYJKoZIhvcNAQEFBQAD"
+ + "ggEBADLan0N1wfpvyW/bqx02Nz68YRk2twI8HSNZmGye7k2F51TIIB+n1Lvi"
+ + "vwB3fSRrcC9cwTp2SbXT4COEKnFqIvPBJymYFfY1kOQETMONvJ9hHOf9JIzR"
+ + "REOMFrqbTaXUNS+8Ec6991E3jZ+Q5BTxGD++6VkSNfkzkvOe4NVrmnGbmUvI"
+ + "ccPhsWEJxOX6kfBCOjd9NPly6M2qYhwh6dX0ghDjewW2LWhWC35+kixvTXKC"
+ + "DO1WdLKduastKx0QX9sndXCP/R3X4gKgeeUc5f+vZEBRLZ6bR9tCpXwfwqZI"
+ + "sNe+kmlNpPYpV8V4ERjch1HKE7JinU8rMr0xpcH6UqsFiMgwggTLMIIDs6AD"
+ + "AgECAgQ+HL21MA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNVBAYTAlVTMSMwIQYD"
+ + "VQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRv"
+ + "YmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0EwHhcN"
+ + "MDQwMTE3MDAwMzM5WhcNMTUwMTE1MDgwMDAwWjBFMQswCQYDVQQGEwJVUzEW"
+ + "MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgQ0Eg"
+ + "Zm9yIEFkb2JlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+V3"
+ + "4GR4Wuc5hbyv0vVbKBMOVN1J+s5i9ZL9nph7n+X4esFs4epAJcFxJ4KnPuQH"
+ + "ZZ0oyHUU4Th70mWYgKwd6sEt1aR6ZT788Nvr3OHwTRwugN/G6QXqhU9ePpZJ"
+ + "OF1Ibsf1pcXNGvpLdcYK6+CX5DANMuIthb440XoNfC3dNBC0pF4mM4lmTjpl"
+ + "nQG8xK0rIFp4HoMpmyaIijz2qyjXdUNkg0fbDUq9eDTKAOLOg21u+AA8XKbC"
+ + "ewg1LWSV9CVy+fTHREmb1thBcrfkY1kCAvczsuquV3SMx8hRpa+4cIvKK/K1"
+ + "G7OrV0nsTyuaJ2MMST8b7bul/Xd81nu9Hsz4iQIDAQABo4IBnTCCAZkwEgYD"
+ + "VR0TAQH/BAgwBgEB/wIBATBQBgNVHSAESTBHMEUGCSqGSIb3LwECATA4MDYG"
+ + "CCsGAQUFBwIBFipodHRwczovL3d3dy5hZG9iZS5jb20vbWlzYy9wa2kvY2Rz"
+ + "X2NwLmh0bWwwFAYDVR0lBA0wCwYJKoZIhvcvAQEFMIGyBgNVHR8Egaowgacw"
+ + "IqAgoB6GHGh0dHA6Ly9jcmwuYWRvYmUuY29tL2Nkcy5jcmwwgYCgfqB8pHow"
+ + "eDELMAkGA1UEBhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMgSW5jb3Jw"
+ + "b3JhdGVkMR0wGwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEWMBQGA1UE"
+ + "AxMNQWRvYmUgUm9vdCBDQTENMAsGA1UEAxMEQ1JMMTALBgNVHQ8EBAMCAQYw"
+ + "HwYDVR0jBBgwFoAUgrc4SpOqmxDvgLvZVOLxD/uAnN4wHQYDVR0OBBYEFKuA"
+ + "WcNlg20dfRO9GcPsGo8NR2qjMBkGCSqGSIb2fQdBAAQMMAobBFY2LjADAgSQ"
+ + "MA0GCSqGSIb3DQEBBQUAA4IBAQA/OVkuogCOsV4RYSzS4Lb1jImGRc4T2Z/d"
+ + "hJoUawhMX4aXWPSlqNOPIfhHflCvd+Whbarcd83NN5n3QmevUOFUREPrMQyA"
+ + "mkK0mpW6TSyLG5ckeCFL8qJwp/hhckk/H16m4hEXWyIFGfOecX3Sy+Y4kxcC"
+ + "lzSMadifedB+TiRpKFKcNphp5hEMkpyyJaGXpLnN/BLsaDyEN7JySExAopae"
+ + "UbUJCvCVIWKwoJ26ih3BG1aB+3yTHXeLIorextqWbq+dVz7me59Li8j5PAxe"
+ + "hXrc2phpKuhp8FaTScvnfMZc8TL4Dr1CHMRWIkqfZaCq3mC376Mww0iZtE5s"
+ + "iqB+AXVWMYIBgDCCAXwCAQEwSzBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN"
+ + "R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgQ0EgZm9yIEFkb2Jl"
+ + "AgIAjzAJBgUrDgMCGgUAoIGMMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRAB"
+ + "BDAcBgkqhkiG9w0BCQUxDxcNMDYwNDA0MjAyMDU3WjAjBgkqhkiG9w0BCQQx"
+ + "FgQUp7AnXBqoNcarvO7fMJut1og2U5AwKwYLKoZIhvcNAQkQAgwxHDAaMBgw"
+ + "FgQU1dH4eZTNhgxdiSABrat6zsPdth0wDQYJKoZIhvcNAQEBBQAEgYCinr/F"
+ + "rMiQz/MRm9ZD5YGcC0Qo2dRTPd0Aop8mZ4g1xAhKFLnp7lLsjCbkSDpVLDBh"
+ + "cnCk7CV+3FT5hlvt8OqZlR0CnkSnCswLFhrppiWle6cpxlwGqyAteC8uKtQu"
+ + "wjE5GtBKLcCOAzQYyyuNZZeB6oCZ+3mPhZ62FxrvvEGJCgAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==");
+
+ private final byte[] emptyDNCert = Base64.decode(
+ "MIICfTCCAeagAwIBAgIBajANBgkqhkiG9w0BAQQFADB8MQswCQYDVQQGEwJVUzEMMAoGA1UEChMD"
+ + "Q0RXMQkwBwYDVQQLEwAxCTAHBgNVBAcTADEJMAcGA1UECBMAMRowGAYDVQQDExFUZW1wbGFyIFRl"
+ + "c3QgMTAyNDEiMCAGCSqGSIb3DQEJARYTdGVtcGxhcnRlc3RAY2R3LmNvbTAeFw0wNjA1MjIwNTAw"
+ + "MDBaFw0xMDA1MjIwNTAwMDBaMHwxCzAJBgNVBAYTAlVTMQwwCgYDVQQKEwNDRFcxCTAHBgNVBAsT"
+ + "ADEJMAcGA1UEBxMAMQkwBwYDVQQIEwAxGjAYBgNVBAMTEVRlbXBsYXIgVGVzdCAxMDI0MSIwIAYJ"
+ + "KoZIhvcNAQkBFhN0ZW1wbGFydGVzdEBjZHcuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB"
+ + "gQDH3aJpJBfM+A3d84j5YcU6zEQaQ76u5xO9NSBmHjZykKS2kCcUqPpvVOPDA5WgV22dtKPh+lYV"
+ + "iUp7wyCVwAKibq8HIbihHceFqMKzjwC639rMoDJ7bi/yzQWz1Zg+075a4FGPlUKn7Yfu89wKkjdW"
+ + "wDpRPXc/agqBnrx5pJTXzQIDAQABow8wDTALBgNVHQ8EBAMCALEwDQYJKoZIhvcNAQEEBQADgYEA"
+ + "RRsRsjse3i2/KClFVd6YLZ+7K1BE0WxFyY2bbytkwQJSxvv3vLSuweFUbhNxutb68wl/yW4GLy4b"
+ + "1QdyswNxrNDXTuu5ILKhRDDuWeocz83aG2KGtr3JlFyr3biWGEyn5WUOE6tbONoQDJ0oPYgI6CAc"
+ + "EHdUp0lioOCt6UOw7Cs=");
+
+ private final byte[] gostRFC4491_94 = Base64.decode(
+ "MIICCzCCAboCECMO42BGlSTOxwvklBgufuswCAYGKoUDAgIEMGkxHTAbBgNVBAMM" +
+ "FEdvc3RSMzQxMC05NCBleGFtcGxlMRIwEAYDVQQKDAlDcnlwdG9Qcm8xCzAJBgNV" +
+ "BAYTAlJVMScwJQYJKoZIhvcNAQkBFhhHb3N0UjM0MTAtOTRAZXhhbXBsZS5jb20w" +
+ "HhcNMDUwODE2MTIzMjUwWhcNMTUwODE2MTIzMjUwWjBpMR0wGwYDVQQDDBRHb3N0" +
+ "UjM0MTAtOTQgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRvUHJvMQswCQYDVQQGEwJS" +
+ "VTEnMCUGCSqGSIb3DQEJARYYR29zdFIzNDEwLTk0QGV4YW1wbGUuY29tMIGlMBwG" +
+ "BiqFAwICFDASBgcqhQMCAiACBgcqhQMCAh4BA4GEAASBgLuEZuF5nls02CyAfxOo" +
+ "GWZxV/6MVCUhR28wCyd3RpjG+0dVvrey85NsObVCNyaE4g0QiiQOHwxCTSs7ESuo" +
+ "v2Y5MlyUi8Go/htjEvYJJYfMdRv05YmKCYJo01x3pg+2kBATjeM+fJyR1qwNCCw+" +
+ "eMG1wra3Gqgqi0WBkzIydvp7MAgGBiqFAwICBANBABHHCH4S3ALxAiMpR3aPRyqB" +
+ "g1DjB8zy5DEjiULIc+HeIveF81W9lOxGkZxnrFjXBSqnjLeFKgF1hffXOAP7zUM=");
+
+ private final byte[] gostRFC4491_2001 = Base64.decode(
+ "MIIB0DCCAX8CECv1xh7CEb0Xx9zUYma0LiEwCAYGKoUDAgIDMG0xHzAdBgNVBAMM" +
+ "Fkdvc3RSMzQxMC0yMDAxIGV4YW1wbGUxEjAQBgNVBAoMCUNyeXB0b1BybzELMAkG" +
+ "A1UEBhMCUlUxKTAnBgkqhkiG9w0BCQEWGkdvc3RSMzQxMC0yMDAxQGV4YW1wbGUu" +
+ "Y29tMB4XDTA1MDgxNjE0MTgyMFoXDTE1MDgxNjE0MTgyMFowbTEfMB0GA1UEAwwW" +
+ "R29zdFIzNDEwLTIwMDEgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRvUHJvMQswCQYD" +
+ "VQQGEwJSVTEpMCcGCSqGSIb3DQEJARYaR29zdFIzNDEwLTIwMDFAZXhhbXBsZS5j" +
+ "b20wYzAcBgYqhQMCAhMwEgYHKoUDAgIkAAYHKoUDAgIeAQNDAARAhJVodWACGkB1" +
+ "CM0TjDGJLP3lBQN6Q1z0bSsP508yfleP68wWuZWIA9CafIWuD+SN6qa7flbHy7Df" +
+ "D2a8yuoaYDAIBgYqhQMCAgMDQQA8L8kJRLcnqeyn1en7U23Sw6pkfEQu3u0xFkVP" +
+ "vFQ/3cHeF26NG+xxtZPz3TaTVXdoiYkXYiD02rEx1bUcM97i");
+
+ private PublicKey dudPublicKey = new PublicKey()
+ {
+ public String getAlgorithm()
+ {
+ return null;
+ }
+
+ public String getFormat()
+ {
+ return null;
+ }
+
+ public byte[] getEncoded()
+ {
+ return null;
+ }
+
+ };
+
+ public String getName()
+ {
+ return "CertTest";
+ }
+
+ public void checkCertificate(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+
+ Certificate cert = fact.generateCertificate(bIn);
+
+ PublicKey k = cert.getPublicKey();
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+ public void checkNameCertificate(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+
+ X509Certificate cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ PublicKey k = cert.getPublicKey();
+ if (!cert.getIssuerDN().toString().equals("C=DE,O=DATEV eG,0.2.262.1.10.7.20=1+CN=CA DATEV D03 1:PN"))
+ {
+ fail(id + " failed - name test.");
+ }
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+ public void checkKeyUsage(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+
+ X509Certificate cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ PublicKey k = cert.getPublicKey();
+
+ if (cert.getKeyUsage()[7])
+ {
+ fail("error generating cert - key usage wrong.");
+ }
+
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+
+ public void checkSelfSignedCertificate(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+
+ Certificate cert = fact.generateCertificate(bIn);
+
+ PublicKey k = cert.getPublicKey();
+
+ cert.verify(k);
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+
+ /**
+ * Test a generated certificate with the sun provider
+ */
+ private void sunProviderCheck(byte[] encoding)
+ throws CertificateException
+ {
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509");
+
+ certFact.generateCertificate(new ByteArrayInputStream(encoding));
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - RSA
+ */
+ public void checkCreation1()
+ throws Exception
+ {
+ //
+ // a sample key pair.
+ //
+ 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));
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory fact = KeyFactory.getInstance("RSA", "SC");
+
+ privKey = fact.generatePrivate(privKeySpec);
+ pubKey = fact.generatePublic(pubKeySpec);
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
+
+ builder.addRDN(BCStyle.C, "AU");
+ builder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ builder.addRDN(BCStyle.L, "Melbourne");
+ builder.addRDN(BCStyle.ST, "Victoria");
+ builder.addRDN(BCStyle.E, "feedback-crypto@bouncycastle.org");
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3 - without extensions
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider(BC).build(privKey);
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000),builder.build(), pubKey);
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ cert.verify(cert.getPublicKey());
+
+ Set dummySet = cert.getNonCriticalExtensionOIDs();
+ if (dummySet != null)
+ {
+ fail("non-critical oid set should be null");
+ }
+ dummySet = cert.getCriticalExtensionOIDs();
+ if (dummySet != null)
+ {
+ fail("critical oid set should be null");
+ }
+
+ //
+ // create the certificate - version 3 - with extensions
+ //
+ sigGen = new JcaContentSignerBuilder("MD5WithRSAEncryption").setProvider(BC).build(privKey);
+ certGen = new JcaX509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1)
+ , new Date(System.currentTimeMillis() - 50000)
+ , new Date(System.currentTimeMillis() + 50000)
+ , builder.build()
+ , pubKey)
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true,
+ new X509KeyUsage(X509KeyUsage.encipherOnly))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.37"), true,
+ new DERSequence(KeyPurposeId.anyExtendedKeyUsage))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true,
+ new GeneralNames(new GeneralName[]
+ {
+ new GeneralName(GeneralName.rfc822Name, "test@test.test"),
+ new GeneralName(GeneralName.dNSName, "dom.test.test")
+ }));
+
+ X509CertificateHolder certHolder = certGen.build(sigGen);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certHolder);
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+ cert.verify(cert.getPublicKey());
+
+ ContentVerifierProvider contentVerifierProvider = new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey);
+ if (!certHolder.isSignatureValid(contentVerifierProvider))
+ {
+ fail("signature test failed");
+ }
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", "SC");
+
+ cert = (X509Certificate)certFact.generateCertificate(bIn);
+
+ if (!cert.getKeyUsage()[7])
+ {
+ fail("error generating cert - key usage wrong.");
+ }
+
+/*
+ List l = cert.getExtendedKeyUsage();
+ if (!l.get(0).equals(KeyPurposeId.anyExtendedKeyUsage.getId()))
+ {
+ fail("failed extended key usage test");
+ }
+
+ Collection c = cert.getSubjectAlternativeNames();
+ Iterator it = c.iterator();
+ while (it.hasNext())
+ {
+ List gn = (List)it.next();
+ if (!gn.get(1).equals("test@test.test") && !gn.get(1).equals("dom.test.test"))
+ {
+ fail("failed subject alternative names test");
+ }
+ }
+*/
+
+ sunProviderCheck(certHolder.getEncoded());
+ sunProviderCheck(cert.getEncoded());
+
+ // System.out.println(cert);
+
+ //
+ // create the certificate - version 1
+ //
+ sigGen = new JcaContentSignerBuilder("MD5WithRSAEncryption").setProvider(BC).build(privKey);
+ X509v1CertificateBuilder certGen1 = new JcaX509v1CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen1.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+ cert.verify(cert.getPublicKey());
+
+ bIn = new ByteArrayInputStream(cert.getEncoded());
+ certFact = CertificateFactory.getInstance("X.509", "SC");
+
+ cert = (X509Certificate)certFact.generateCertificate(bIn);
+
+ // System.out.println(cert);
+ if (!cert.getIssuerDN().equals(cert.getSubjectDN()))
+ {
+ fail("name comparison fails");
+ }
+
+ sunProviderCheck(certHolder.getEncoded());
+ sunProviderCheck(cert.getEncoded());
+//
+ // a lightweight key pair.
+ //
+ RSAKeyParameters lwPubKey = new RSAKeyParameters(
+ false,
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ RSAPrivateCrtKeyParameters lwPrivKey = new RSAPrivateCrtKeyParameters(
+ 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));
+
+ //
+ // distinguished name table.
+ //
+ builder = new X500NameBuilder(BCStyle.INSTANCE);
+
+ builder.addRDN(BCStyle.C, "AU");
+ builder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ builder.addRDN(BCStyle.L, "Melbourne");
+ builder.addRDN(BCStyle.ST, "Victoria");
+ builder.addRDN(BCStyle.E, "feedback-crypto@bouncycastle.org");
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3 - without extensions
+ //
+ AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSAEncryption");
+ AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
+
+ sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(lwPrivKey);
+ SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPublicKey(lwPubKey.getModulus(), lwPubKey.getExponent()));
+ certGen = new X509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000), builder.build(), pubInfo);
+
+ certHolder = certGen.build(sigGen);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certHolder);
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ contentVerifierProvider = new BcRSAContentVerifierProviderBuilder(new DefaultDigestAlgorithmIdentifierFinder()).build(lwPubKey);
+
+ if (!certHolder.isSignatureValid(contentVerifierProvider))
+ {
+ fail("lw sig verification failed");
+ }
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - DSA
+ */
+ public void checkCreation2()
+ throws Exception
+ {
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ try
+ {
+ KeyPairGenerator g = KeyPairGenerator.getInstance("DSA", "SUN");
+
+ g.initialize(512, new SecureRandom());
+
+ KeyPair p = g.generateKeyPair();
+
+ privKey = p.getPrivate();
+ pubKey = p.getPublic();
+ }
+ catch (Exception e)
+ {
+ fail("error setting up keys - " + e.toString());
+ return;
+ }
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3
+ //
+
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA1withDSA").setProvider(BC).build(privKey);
+ JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ // System.out.println(cert);
+
+
+ //
+ // create the certificate - version 1
+ //
+ sigGen = new JcaContentSignerBuilder("SHA1withDSA").setProvider(BC).build(privKey);
+ JcaX509v1CertificateBuilder certGen1 = new JcaX509v1CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen1.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ bIn = new ByteArrayInputStream(cert.getEncoded());
+ fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ //System.out.println(cert);
+
+ //
+ // exception test
+ //
+ try
+ {
+ certGen1 = new JcaX509v1CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),dudPublicKey);
+
+
+ fail("key without encoding not detected in v1");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // expected
+ }
+ }
+
+ private X500NameBuilder createStdBuilder()
+ {
+ X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
+
+ builder.addRDN(BCStyle.C, "AU");
+ builder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ builder.addRDN(BCStyle.L, "Melbourne");
+ builder.addRDN(BCStyle.ST, "Victoria");
+ builder.addRDN(BCStyle.E, "feedback-crypto@bouncycastle.org");
+
+ return builder;
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - ECDSA
+ */
+ public void checkCreation3()
+ {
+ ECCurve curve = new ECCurve.Fp(
+ new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+ new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+ new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+
+ ECParameterSpec spec = new ECParameterSpec(
+ curve,
+ curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+ new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n
+
+
+ ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(
+ new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d
+ spec);
+
+ ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(
+ curve.decodePoint(Hex.decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q
+ spec);
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ try
+ {
+ KeyFactory fact = KeyFactory.getInstance("ECDSA", BC);
+
+ privKey = fact.generatePrivate(privKeySpec);
+ pubKey = fact.generatePublic(pubKeySpec);
+ }
+ catch (Exception e)
+ {
+ fail("error setting up keys - " + e.toString());
+ return;
+ }
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = createStdBuilder();
+
+
+ //
+ // toString test
+ //
+ X500Name p = builder.build();
+ String s = p.toString();
+
+ if (!s.equals("C=AU,O=The Legion of the Bouncy Castle,L=Melbourne,ST=Victoria,E=feedback-crypto@bouncycastle.org"))
+ {
+ fail("ordered X509Principal test failed - s = " + s + ".");
+ }
+
+// p = new X509Principal(attrs);
+// s = p.toString();
+//
+// //
+// // we need two of these as the hash code for strings changed...
+// //
+// if (!s.equals("O=The Legion of the Bouncy Castle,E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU") && !s.equals("ST=Victoria,L=Melbourne,C=AU,E=feedback-crypto@bouncycastle.org,O=The Legion of the Bouncy Castle"))
+// {
+// fail("unordered X509Principal test failed.");
+// }
+
+ //
+ // create the certificate - version 3
+ //
+ try
+ {
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA1withECDSA").setProvider(BC).build(privKey);
+ JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ //
+ // try with point compression turned off
+ //
+ ((ECPointEncoder)pubKey).setPointFormat("UNCOMPRESSED");
+
+ certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ bIn = new ByteArrayInputStream(cert.getEncoded());
+ fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail("error setting generating cert - " + e.toString());
+ }
+
+ X509Principal pr = new X509Principal("O=\"The Bouncy Castle, The Legion of\",E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU");
+
+ if (!pr.toString().equals("O=The Bouncy Castle\\, The Legion of,E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU"))
+ {
+ fail("string based X509Principal test failed.");
+ }
+
+ pr = new X509Principal("O=The Bouncy Castle\\, The Legion of,E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU");
+
+ if (!pr.toString().equals("O=The Bouncy Castle\\, The Legion of,E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU"))
+ {
+ fail("string based X509Principal test failed.");
+ }
+
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - SHA224withECDSA
+ */
+ private void createECCert(String algorithm, DERObjectIdentifier algOid)
+ throws Exception
+ {
+ ECCurve.Fp curve = new ECCurve.Fp(
+ new BigInteger("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"), // q (or p)
+ new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", 16), // a
+ new BigInteger("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", 16)); // b
+
+ ECParameterSpec spec = new ECParameterSpec(
+ curve,
+ curve.decodePoint(Hex.decode("0200C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")), // G
+ new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", 16)); // n
+
+ ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(
+ new BigInteger("5769183828869504557786041598510887460263120754767955773309066354712783118202294874205844512909370791582896372147797293913785865682804434049019366394746072023"), // d
+ spec);
+
+ ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(
+ curve.decodePoint(Hex.decode("02006BFDD2C9278B63C92D6624F151C9D7A822CC75BD983B17D25D74C26740380022D3D8FAF304781E416175EADF4ED6E2B47142D2454A7AC7801DD803CF44A4D1F0AC")), // Q
+ spec);
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory fact = KeyFactory.getInstance("ECDSA", BC);
+
+ privKey = fact.generatePrivate(privKeySpec);
+ pubKey = fact.generatePublic(pubKeySpec);
+
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // create the certificate - version 3
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey);
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)certFact.generateCertificate(bIn);
+
+ //
+ // try with point compression turned off
+ //
+ ((ECPointEncoder)pubKey).setPointFormat("UNCOMPRESSED");
+
+ certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ bIn = new ByteArrayInputStream(cert.getEncoded());
+ certFact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)certFact.generateCertificate(bIn);
+
+ if (!cert.getSigAlgOID().equals(algOid.toString()))
+ {
+ fail("ECDSA oid incorrect.");
+ }
+
+ if (cert.getSigAlgParams() != null)
+ {
+ fail("sig parameters present");
+ }
+
+ Signature sig = Signature.getInstance(algorithm, BC);
+
+ sig.initVerify(pubKey);
+
+ sig.update(cert.getTBSCertificate());
+
+ if (!sig.verify(cert.getSignature()))
+ {
+ fail("EC certificate signature not mapped correctly.");
+ }
+ // System.out.println(cert);
+ }
+
+ private void checkCRL(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
+
+ CRL cert = fact.generateCRL(bIn);
+
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+ public void checkCRLCreation1()
+ throws Exception
+ {
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", BC);
+ Date now = new Date();
+ KeyPair pair = kpGen.generateKeyPair();
+ X509v2CRLBuilder crlGen = new X509v2CRLBuilder(new X500Name("CN=Test CA"), now);
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ crlGen.addCRLEntry(BigInteger.valueOf(1), now, CRLReason.privilegeWithdrawn);
+
+ crlGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.getPublic()));
+
+ X509CRLHolder crl = crlGen.build(new JcaContentSignerBuilder("SHA256withRSAEncryption").setProvider(BC).build(pair.getPrivate()));
+
+ if (!crl.getIssuer().equals(new X500Name("CN=Test CA")))
+ {
+ fail("failed CRL issuer test");
+ }
+
+ Extension authExt = crl.getExtension(Extension.authorityKeyIdentifier);
+
+ if (authExt == null)
+ {
+ fail("failed to find CRL extension");
+ }
+
+ AuthorityKeyIdentifier authId = new AuthorityKeyIdentifierStructure(authExt);
+
+ X509CRLEntryHolder entry = crl.getRevokedCertificate(BigInteger.valueOf(1));
+
+ if (entry == null)
+ {
+ fail("failed to find CRL entry");
+ }
+
+ if (!entry.getSerialNumber().equals(BigInteger.valueOf(1)))
+ {
+ fail("CRL cert serial number does not match");
+ }
+
+ if (!entry.hasExtensions())
+ {
+ fail("CRL entry extension not found");
+ }
+
+ Extension ext = entry.getExtension(X509Extension.reasonCode);
+
+ if (ext != null)
+ {
+ ASN1Enumerated reasonCode = (ASN1Enumerated)ASN1Enumerated.getInstance(ext.getParsedValue());
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found");
+ }
+ }
+
+ public void checkCRLCreation2()
+ throws Exception
+ {
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ Date now = new Date();
+ KeyPair pair = kpGen.generateKeyPair();
+ X509v2CRLBuilder crlGen = new X509v2CRLBuilder(new X500Name("CN=Test CA"), now);
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ Vector extOids = new Vector();
+ Vector extValues = new Vector();
+
+ CRLReason crlReason = CRLReason.lookup(CRLReason.privilegeWithdrawn);
+
+ try
+ {
+ extOids.addElement(X509Extensions.ReasonCode);
+ extValues.addElement(new X509Extension(false, new DEROctetString(crlReason.getEncoded())));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("error encoding reason: " + e);
+ }
+
+ X509Extensions entryExtensions = new X509Extensions(extOids, extValues);
+
+ crlGen.addCRLEntry(BigInteger.valueOf(1), now, entryExtensions);
+
+ crlGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.getPublic()));
+
+ X509CRLHolder crlHolder = crlGen.build(new JcaContentSignerBuilder("SHA256withRSAEncryption").setProvider(BC).build(pair.getPrivate()));
+
+ X509CRL crl = new JcaX509CRLConverter().setProvider(BC).getCRL(crlHolder);
+
+ if (!PrincipalUtil.getIssuerX509Principal(crl).equals(new X509Principal("CN=Test CA")))
+ {
+ fail("failed CRL issuer test");
+ }
+
+ byte[] authExt = crl.getExtensionValue(X509Extensions.AuthorityKeyIdentifier.getId());
+
+ if (authExt == null)
+ {
+ fail("failed to find CRL extension");
+ }
+
+ AuthorityKeyIdentifier authId = new AuthorityKeyIdentifierStructure(authExt);
+
+ X509CRLEntry entry = crl.getRevokedCertificate(BigInteger.valueOf(1));
+
+ if (entry == null)
+ {
+ fail("failed to find CRL entry");
+ }
+
+ if (!entry.getSerialNumber().equals(BigInteger.valueOf(1)))
+ {
+ fail("CRL cert serial number does not match");
+ }
+
+ if (!entry.hasExtensions())
+ {
+ fail("CRL entry extension not found");
+ }
+
+ byte[] ext = entry.getExtensionValue(X509Extensions.ReasonCode.getId());
+
+ if (ext != null)
+ {
+ DEREnumerated reasonCode = (DEREnumerated)X509ExtensionUtil.fromExtensionValue(ext);
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found");
+ }
+ }
+
+ public void checkCRLCreation3()
+ throws Exception
+ {
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", BC);
+ Date now = new Date();
+ KeyPair pair = kpGen.generateKeyPair();
+ X509v2CRLBuilder crlGen = new JcaX509v2CRLBuilder(new X500Name("CN=Test CA"), now);
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ Vector extOids = new Vector();
+ Vector extValues = new Vector();
+
+ CRLReason crlReason = CRLReason.lookup(CRLReason.privilegeWithdrawn);
+
+ try
+ {
+ extOids.addElement(X509Extensions.ReasonCode);
+ extValues.addElement(new X509Extension(false, new DEROctetString(crlReason.getEncoded())));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("error encoding reason: " + e);
+ }
+
+ X509Extensions entryExtensions = new X509Extensions(extOids, extValues);
+
+ crlGen.addCRLEntry(BigInteger.valueOf(1), now, entryExtensions);
+
+ crlGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.getPublic()));
+
+ X509CRLHolder crlHolder = crlGen.build(new JcaContentSignerBuilder("SHA256withRSAEncryption").setProvider(BC).build(pair.getPrivate()));
+
+ X509CRL crl = new JcaX509CRLConverter().setProvider(BC).getCRL(crlHolder);
+
+ if (!PrincipalUtil.getIssuerX509Principal(crl).equals(new X509Principal("CN=Test CA")))
+ {
+ fail("failed CRL issuer test");
+ }
+
+ byte[] authExt = crl.getExtensionValue(X509Extensions.AuthorityKeyIdentifier.getId());
+
+ if (authExt == null)
+ {
+ fail("failed to find CRL extension");
+ }
+
+ AuthorityKeyIdentifier authId = new AuthorityKeyIdentifierStructure(authExt);
+
+ X509CRLEntry entry = crl.getRevokedCertificate(BigInteger.valueOf(1));
+
+ if (entry == null)
+ {
+ fail("failed to find CRL entry");
+ }
+
+ if (!entry.getSerialNumber().equals(BigInteger.valueOf(1)))
+ {
+ fail("CRL cert serial number does not match");
+ }
+
+ if (!entry.hasExtensions())
+ {
+ fail("CRL entry extension not found");
+ }
+
+ byte[] ext = entry.getExtensionValue(X509Extensions.ReasonCode.getId());
+
+ if (ext != null)
+ {
+ DEREnumerated reasonCode = (DEREnumerated)X509ExtensionUtil.fromExtensionValue(ext);
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found");
+ }
+
+ //
+ // check loading of existing CRL
+ //
+ now = new Date();
+ crlGen = new X509v2CRLBuilder(new X500Name("CN=Test CA"), now);
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ crlGen.addCRL(new JcaX509CRLHolder(crl));
+
+ crlGen.addCRLEntry(BigInteger.valueOf(2), now, entryExtensions);
+
+ crlGen.addExtension(X509Extension.authorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.getPublic()));
+
+ crlHolder = crlGen.build(new JcaContentSignerBuilder("SHA256withRSAEncryption").setProvider(BC).build(pair.getPrivate()));
+
+ int count = 0;
+ boolean oneFound = false;
+ boolean twoFound = false;
+
+ Iterator it = crlHolder.getRevokedCertificates().iterator();
+ while (it.hasNext())
+ {
+ X509CRLEntryHolder crlEnt = (X509CRLEntryHolder)it.next();
+
+ if (crlEnt.getSerialNumber().intValue() == 1)
+ {
+ oneFound = true;
+ Extension extn = crlEnt.getExtension(X509Extension.reasonCode);
+
+ if (extn != null)
+ {
+ ASN1Enumerated reasonCode = (ASN1Enumerated)ASN1Enumerated.getInstance(extn.getParsedValue());
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found");
+ }
+ }
+ else if (crlEnt.getSerialNumber().intValue() == 2)
+ {
+ twoFound = true;
+ }
+
+ count++;
+ }
+
+ if (count != 2)
+ {
+ fail("wrong number of CRLs found");
+ }
+
+ if (!oneFound || !twoFound)
+ {
+ fail("wrong CRLs found in copied list");
+ }
+
+ //
+ // check factory read back
+ //
+ CertificateFactory cFact = CertificateFactory.getInstance("X.509", BC);
+
+ X509CRL readCrl = (X509CRL)cFact.generateCRL(new ByteArrayInputStream(crlHolder.getEncoded()));
+
+ if (readCrl == null)
+ {
+ fail("crl not returned!");
+ }
+
+ Collection col = cFact.generateCRLs(new ByteArrayInputStream(crlHolder.getEncoded()));
+
+ if (col.size() != 1)
+ {
+ fail("wrong number of CRLs found in collection");
+ }
+ }
+
+ public void checkCreation5()
+ throws Exception
+ {
+ //
+ // a sample key pair.
+ //
+ 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));
+
+ //
+ // set up the keys
+ //
+ SecureRandom rand = new SecureRandom();
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory fact = KeyFactory.getInstance("RSA", BC);
+
+ privKey = fact.generatePrivate(privKeySpec);
+ pubKey = fact.generatePublic(pubKeySpec);
+
+ //
+ // distinguished name table.
+ //
+ Vector ord = new Vector();
+ Vector values = new Vector();
+
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // create base certificate - version 3
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder("MD5WithRSAEncryption").setProvider(BC).build(privKey);
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey)
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true,
+ new X509KeyUsage(X509KeyUsage.encipherOnly))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.37"), true,
+ new DERSequence(KeyPurposeId.anyExtendedKeyUsage))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true,
+ new GeneralNames(new GeneralName(GeneralName.rfc822Name, "test@test.test")));
+
+ X509Certificate baseCert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ //
+ // copy certificate
+ //
+
+ certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey)
+ .copyAndAddExtension(new ASN1ObjectIdentifier("2.5.29.15"), true, baseCert)
+ .copyAndAddExtension(new ASN1ObjectIdentifier("2.5.29.37"), false, baseCert);
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ if (!areEqual(baseCert.getExtensionValue("2.5.29.15"), cert.getExtensionValue("2.5.29.15")))
+ {
+ fail("2.5.29.15 differs");
+ }
+
+ if (!areEqual(baseCert.getExtensionValue("2.5.29.37"), cert.getExtensionValue("2.5.29.37")))
+ {
+ fail("2.5.29.37 differs");
+ }
+
+ //
+ // exception test
+ //
+
+ try
+ {
+ certGen.copyAndAddExtension(new ASN1ObjectIdentifier("2.5.99.99"), true, new JcaX509CertificateHolder(baseCert));
+
+ fail("exception not thrown on dud extension copy");
+ }
+ catch (NullPointerException e)
+ {
+ // expected
+ }
+
+// try
+// {
+// certGen.setPublicKey(dudPublicKey);
+//
+// certGen.generate(privKey, BC);
+//
+// fail("key without encoding not detected in v3");
+// }
+// catch (IllegalArgumentException e)
+// {
+// // expected
+// }
+
+ }
+
+ private void testForgedSignature()
+ throws Exception
+ {
+ String cert = "MIIBsDCCAVoCAQYwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCQVUxEzARBgNV"
+ + "BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMSMwIQYD"
+ + "VQQDExpTZXJ2ZXIgdGVzdCBjZXJ0ICg1MTIgYml0KTAeFw0wNjA5MTEyMzU4NTVa"
+ + "Fw0wNjEwMTEyMzU4NTVaMGMxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpRdWVlbnNs"
+ + "YW5kMRowGAYDVQQKExFDcnlwdFNvZnQgUHR5IEx0ZDEjMCEGA1UEAxMaU2VydmVy"
+ + "IHRlc3QgY2VydCAoNTEyIGJpdCkwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAn7PD"
+ + "hCeV/xIxUg8V70YRxK2A5jZbD92A12GN4PxyRQk0/lVmRUNMaJdq/qigpd9feP/u"
+ + "12S4PwTLb/8q/v657QIDAQABMA0GCSqGSIb3DQEBBQUAA0EAbynCRIlUQgaqyNgU"
+ + "DF6P14yRKUtX8akOP2TwStaSiVf/akYqfLFm3UGka5XbPj4rifrZ0/sOoZEEBvHQ"
+ + "e20sRA==";
+
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", BC);
+
+ X509Certificate x509 = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(Base64.decode(cert)));
+ try
+ {
+ x509.verify(x509.getPublicKey());
+
+ fail("forged RSA signature passed");
+ }
+ catch (Exception e)
+ {
+ // expected
+ }
+ }
+
+
+ private void pemTest()
+ throws Exception
+ {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509", BC);
+
+ Certificate cert = readPEMCert(cf, PEMData.CERTIFICATE_1);
+ if (cert == null)
+ {
+ fail("PEM cert not read");
+ }
+ cert = readPEMCert(cf, "-----BEGIN CERTIFICATE-----" + PEMData.CERTIFICATE_2);
+ if (cert == null)
+ {
+ fail("PEM cert with extraneous header not read");
+ }
+ CRL crl = cf.generateCRL(new ByteArrayInputStream(PEMData.CRL_1.getBytes("US-ASCII")));
+ if (crl == null)
+ {
+ fail("PEM crl not read");
+ }
+ Collection col = cf.generateCertificates(new ByteArrayInputStream(PEMData.CERTIFICATE_2.getBytes("US-ASCII")));
+ if (col.size() != 1 || !col.contains(cert))
+ {
+ fail("PEM cert collection not right");
+ }
+ col = cf.generateCRLs(new ByteArrayInputStream(PEMData.CRL_2.getBytes("US-ASCII")));
+ if (col.size() != 1 || !col.contains(crl))
+ {
+ fail("PEM crl collection not right");
+ }
+ }
+
+ private static Certificate readPEMCert(CertificateFactory cf, String pemData)
+ throws CertificateException, UnsupportedEncodingException
+ {
+ return cf.generateCertificate(new ByteArrayInputStream(pemData.getBytes("US-ASCII")));
+ }
+
+ private void pkcs7Test()
+ throws Exception
+ {
+ /*
+ ASN1EncodableVector certs = new ASN1EncodableVector();
+
+ certs.add(new ASN1InputStream(CertPathTest.rootCertBin).readObject());
+ certs.add(new DERTaggedObject(false, 2, new ASN1InputStream(AttrCertTest.attrCert).readObject()));
+
+ ASN1EncodableVector crls = new ASN1EncodableVector();
+
+ crls.add(new ASN1InputStream(CertPathTest.rootCrlBin).readObject());
+ SignedData sigData = new SignedData(new DERSet(), new ContentInfo(CMSObjectIdentifiers.data, null), new DERSet(certs), new DERSet(crls), new DERSet());
+
+ ContentInfo info = new ContentInfo(CMSObjectIdentifiers.signedData, sigData);
+
+ CertificateFactory cf = CertificateFactory.getInstance("X.509", BC);
+
+ X509Certificate cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(info.getEncoded()));
+ if (cert == null || !areEqual(cert.getEncoded(), certs.get(0).getDERObject().getEncoded()))
+ {
+ fail("PKCS7 cert not read");
+ }
+ X509CRL crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(info.getEncoded()));
+ if (crl == null || !areEqual(crl.getEncoded(), crls.get(0).getDERObject().getEncoded()))
+ {
+ fail("PKCS7 crl not read");
+ }
+ Collection col = cf.generateCertificates(new ByteArrayInputStream(info.getEncoded()));
+ if (col.size() != 1 || !col.contains(cert))
+ {
+ fail("PKCS7 cert collection not right");
+ }
+ col = cf.generateCRLs(new ByteArrayInputStream(info.getEncoded()));
+ if (col.size() != 1 || !col.contains(crl))
+ {
+ fail("PKCS7 crl collection not right");
+ }
+
+ // data with no certificates or CRLs
+
+ sigData = new SignedData(new DERSet(), new ContentInfo(CMSObjectIdentifiers.data, null), new DERSet(), new DERSet(), new DERSet());
+
+ info = new ContentInfo(CMSObjectIdentifiers.signedData, sigData);
+
+ cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(info.getEncoded()));
+ if (cert != null)
+ {
+ fail("PKCS7 cert present");
+ }
+ crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(info.getEncoded()));
+ if (crl != null)
+ {
+ fail("PKCS7 crl present");
+ }
+
+ // data with absent certificates and CRLS
+
+ sigData = new SignedData(new DERSet(), new ContentInfo(CMSObjectIdentifiers.data, null), null, null, new DERSet());
+
+ info = new ContentInfo(CMSObjectIdentifiers.signedData, sigData);
+
+ cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(info.getEncoded()));
+ if (cert != null)
+ {
+ fail("PKCS7 cert present");
+ }
+ crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(info.getEncoded()));
+ if (crl != null)
+ {
+ fail("PKCS7 crl present");
+ }
+
+ //
+ // sample message
+ //
+ InputStream in = new ByteArrayInputStream(pkcs7CrlProblem);
+ Collection certCol = cf.generateCertificates(in);
+ Collection crlCol = cf.generateCRLs(in);
+
+ if (crlCol.size() != 0)
+ {
+ fail("wrong number of CRLs: " + crlCol.size());
+ }
+
+ if (certCol.size() != 4)
+ {
+ fail("wrong number of Certs: " + certCol.size());
+ }
+ */
+ }
+
+ private void createPSSCert(String algorithm)
+ throws Exception
+ {
+ KeyPair pair = generateLongFixedKeys();
+
+ PrivateKey privKey = pair.getPrivate();
+ PublicKey pubKey = pair.getPublic();
+
+ //
+ // distinguished name table.
+ //
+
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // create base certificate - version 3
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey);
+ JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),
+ new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ certGen.addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true,
+ new X509KeyUsage(X509KeyUsage.encipherOnly));
+ certGen.addExtension(new ASN1ObjectIdentifier("2.5.29.37"), true,
+ new DERSequence(KeyPurposeId.anyExtendedKeyUsage));
+ certGen.addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true,
+ new GeneralNames(new GeneralName(GeneralName.rfc822Name, "test@test.test")));
+
+ X509Certificate baseCert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ baseCert.verify(pubKey);
+ }
+
+ private KeyPair generateLongFixedKeys()
+ throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException
+ {
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+ new BigInteger("010001",16));
+
+ RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec(
+ new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+ new BigInteger("010001",16),
+ new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16),
+ new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16),
+ new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16),
+ new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16),
+ new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16),
+ new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16));
+
+ KeyFactory fact = KeyFactory.getInstance("RSA", BC);
+
+ return new KeyPair(fact.generatePublic(pubKeySpec), fact.generatePrivate(privKeySpec));
+ }
+
+ private void rfc4491Test()
+ throws Exception
+ {
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", BC);
+
+ X509Certificate x509 = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(gostRFC4491_94));
+
+ x509.verify(x509.getPublicKey(), BC);
+
+ x509 = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(gostRFC4491_2001));
+
+ x509.verify(x509.getPublicKey(), BC);
+ }
+
+ private void testNullDerNullCert()
+ throws Exception
+ {
+ KeyPair pair = generateLongFixedKeys();
+ PublicKey pubKey = pair.getPublic();
+ PrivateKey privKey = pair.getPrivate();
+
+ ContentSigner sigGen = new JcaContentSignerBuilder("MD5WithRSAEncryption").setProvider(BC).build(privKey);
+ JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(new X500Name("CN=Test"),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),new X500Name("CN=Test"),pubKey);
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ X509CertificateStructure struct = X509CertificateStructure.getInstance(ASN1Primitive.fromByteArray(cert.getEncoded()));
+
+ ASN1Encodable tbsCertificate = struct.getTBSCertificate();
+ AlgorithmIdentifier sig = struct.getSignatureAlgorithm();
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCertificate);
+ v.add(new AlgorithmIdentifier(sig.getAlgorithm()));
+ v.add(struct.getSignature());
+
+ // verify
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(new DERSequence(v).getEncoded());
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ cert.verify(cert.getPublicKey());
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": testNullDerNull failed - exception " + e.toString(), e);
+ }
+ }
+
+ private void testDirect()
+ throws Exception
+ {
+ KeyStore keyStore = KeyStore.getInstance("PKCS12", "SC");
+
+ ByteArrayInputStream input = new ByteArrayInputStream(testCAp12);
+
+ keyStore.load(input, "test".toCharArray());
+
+ X509Certificate certificate = (X509Certificate) keyStore.getCertificate("ca");
+ PrivateKey privateKey = (PrivateKey) keyStore.getKey("ca", null);
+
+ X500Name issuer = X500Name.getInstance(PrincipalUtil.getIssuerX509Principal(certificate).getEncoded());
+
+ X509v2CRLBuilder builder = new X509v2CRLBuilder(issuer, new Date());
+
+ builder.addCRLEntry(certificate.getSerialNumber(), new Date(), CRLReason.cACompromise);
+
+ JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA256WithRSAEncryption");
+
+ contentSignerBuilder.setProvider("SC");
+
+ X509CRLHolder cRLHolder = builder.build(contentSignerBuilder.build(privateKey));
+
+ JcaX509CRLConverter converter = new JcaX509CRLConverter();
+
+ converter.setProvider("SC");
+
+ X509CRL crl = converter.getCRL(cRLHolder);
+
+ crl.verify(certificate.getPublicKey());
+
+ if (!crl.isRevoked(certificate))
+ {
+ fail("Certificate should be revoked");
+ }
+
+ // now encode the CRL and load the CRL with the JCE provider
+
+ CertificateFactory fac = CertificateFactory.getInstance("X.509");
+
+ X509CRL jceCRL = (X509CRL) fac.generateCRL(new ByteArrayInputStream(crl.getEncoded()));
+
+ jceCRL.verify(certificate.getPublicKey());
+
+ if (!jceCRL.isRevoked(certificate))
+ {
+ fail("This certificate should also be revoked");
+ }
+ }
+
+ private void testIndirect()
+ throws Exception
+ {
+ KeyStore keyStore = KeyStore.getInstance("PKCS12", "SC");
+
+ ByteArrayInputStream input = new ByteArrayInputStream(testCAp12);
+
+ keyStore.load(input, "test".toCharArray());
+
+ X509Certificate certificate = (X509Certificate) keyStore.getCertificate("ca");
+ PrivateKey privateKey = (PrivateKey) keyStore.getKey("ca", null);
+
+ X500Name crlIssuer = X500Name.getInstance(PrincipalUtil.getSubjectX509Principal(certificate).getEncoded());
+ X500Name caName = X500Name.getInstance(PrincipalUtil.getIssuerX509Principal(certificate).getEncoded());
+
+ X509v2CRLBuilder builder = new X509v2CRLBuilder(crlIssuer, new Date());
+
+ builder.addExtension(Extension.issuingDistributionPoint, true, new IssuingDistributionPoint(null, true, false));
+
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+
+ extGen.addExtension(Extension.reasonCode, false, CRLReason.lookup(CRLReason.cACompromise));
+ extGen.addExtension(Extension.certificateIssuer, true, new GeneralNames(new GeneralName(caName)));
+
+ builder.addCRLEntry(certificate.getSerialNumber(), new Date(), extGen.generate());
+
+ JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA256WithRSAEncryption");
+
+ contentSignerBuilder.setProvider("SC");
+
+ X509CRLHolder cRLHolder = builder.build(contentSignerBuilder.build(privateKey));
+
+ JcaX509CRLConverter converter = new JcaX509CRLConverter();
+
+ converter.setProvider("SC");
+
+ X509CRL crl = converter.getCRL(cRLHolder);
+
+ crl.verify(certificate.getPublicKey());
+
+ if (!crl.isRevoked(certificate))
+ {
+ fail("Certificate should be revoked");
+ }
+
+ // now encode the CRL and load the CRL with the JCE provider
+
+ CertificateFactory fac = CertificateFactory.getInstance("X.509");
+
+ X509CRL jceCRL = (X509CRL) fac.generateCRL(new ByteArrayInputStream(crl.getEncoded()));
+
+ jceCRL.verify(certificate.getPublicKey());
+
+ if (!jceCRL.isRevoked(certificate))
+ {
+ fail("This certificate should also be revoked");
+ }
+ }
+
+ // issuing distribution point must be set for an indirect CRL to be recognised
+ private void testMalformedIndirect()
+ throws Exception
+ {
+ KeyStore keyStore = KeyStore.getInstance("PKCS12", "SC");
+
+ ByteArrayInputStream input = new ByteArrayInputStream(testCAp12);
+
+ keyStore.load(input, "test".toCharArray());
+
+ X509Certificate certificate = (X509Certificate) keyStore.getCertificate("ca");
+ PrivateKey privateKey = (PrivateKey) keyStore.getKey("ca", null);
+
+ X500Name crlIssuer = X500Name.getInstance(PrincipalUtil.getSubjectX509Principal(certificate).getEncoded());
+ X500Name caName = X500Name.getInstance(PrincipalUtil.getIssuerX509Principal(certificate).getEncoded());
+
+ X509v2CRLBuilder builder = new X509v2CRLBuilder(crlIssuer, new Date());
+
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+
+ extGen.addExtension(Extension.reasonCode, false, CRLReason.lookup(CRLReason.cACompromise));
+ extGen.addExtension(Extension.certificateIssuer, true, new GeneralNames(new GeneralName(caName)));
+
+ builder.addCRLEntry(certificate.getSerialNumber(), new Date(), extGen.generate());
+
+ JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA256WithRSAEncryption");
+
+ contentSignerBuilder.setProvider("SC");
+
+ X509CRLHolder cRLHolder = builder.build(contentSignerBuilder.build(privateKey));
+
+ JcaX509CRLConverter converter = new JcaX509CRLConverter();
+
+ converter.setProvider("SC");
+
+ X509CRL crl = converter.getCRL(cRLHolder);
+
+ crl.verify(certificate.getPublicKey());
+
+ if (crl.isRevoked(certificate))
+ {
+ throw new Exception("Certificate should not be revoked");
+ }
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ testDirect();
+ testIndirect();
+ testMalformedIndirect();
+
+ checkCertificate(1, cert1);
+ checkCertificate(2, cert2);
+ checkCertificate(3, cert3);
+ checkCertificate(4, cert4);
+ checkCertificate(5, cert5);
+ checkCertificate(6, oldEcdsa);
+ checkCertificate(7, cert7);
+
+ checkKeyUsage(8, keyUsage);
+ checkSelfSignedCertificate(9, uncompressedPtEC);
+ checkNameCertificate(10, nameCert);
+
+ checkSelfSignedCertificate(11, probSelfSignedCert);
+ checkSelfSignedCertificate(12, gostCA1);
+ checkSelfSignedCertificate(13, gostCA2);
+ checkSelfSignedCertificate(14, gost341094base);
+ checkSelfSignedCertificate(15, gost34102001base);
+ checkSelfSignedCertificate(16, gost341094A);
+ checkSelfSignedCertificate(17, gost341094B);
+ checkSelfSignedCertificate(17, gost34102001A);
+
+ checkCRL(1, crl1);
+
+ checkCreation1();
+ checkCreation2();
+ checkCreation3();
+ checkCreation5();
+
+ createECCert("SHA1withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ createECCert("SHA224withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ createECCert("SHA256withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ createECCert("SHA384withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ createECCert("SHA512withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+
+ createPSSCert("SHA1withRSAandMGF1");
+ createPSSCert("SHA224withRSAandMGF1");
+ createPSSCert("SHA256withRSAandMGF1");
+ createPSSCert("SHA384withRSAandMGF1");
+
+ checkCRLCreation1();
+ checkCRLCreation2();
+ checkCRLCreation3();
+
+ pemTest();
+ pkcs7Test();
+ rfc4491Test();
+
+ testForgedSignature();
+
+ testNullDerNullCert();
+
+ checkCertificate(18, emptyDNCert);
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new CertTest());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/jdk1.1/org/spongycastle/cert/test/PKCS10Test.java b/libraries/spongycastle/pkix/src/test/jdk1.1/org/spongycastle/cert/test/PKCS10Test.java
new file mode 100644
index 000000000..659736b5f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/jdk1.1/org/spongycastle/cert/test/PKCS10Test.java
@@ -0,0 +1,420 @@
+package org.spongycastle.cert.test;
+
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Signature;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.Vector;
+
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.Attribute;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.X500NameBuilder;
+import org.spongycastle.asn1.x500.style.BCStyle;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.KeyUsage;
+import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jce.ECGOST3410NamedCurveTable;
+import org.spongycastle.jce.ECNamedCurveTable;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+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.jce.spec.ECPublicKeySpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+import org.spongycastle.pkcs.PKCS10CertificationRequest;
+import org.spongycastle.pkcs.PKCS10CertificationRequestBuilder;
+import org.spongycastle.pkcs.jcajce.JcaPKCS10CertificationRequest;
+import org.spongycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.encoders.Hex;
+import org.spongycastle.util.test.SimpleTest;
+import org.spongycastle.x509.extension.SubjectKeyIdentifierStructure;
+
+/**
+ **/
+public class PKCS10Test
+ extends SimpleTest
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ private byte[] gost3410EC_A = Base64.decode(
+ "MIIBOzCB6wIBADB/MQ0wCwYDVQQDEwR0ZXN0MRUwEwYDVQQKEwxEZW1vcyBDbyBMdGQxHjAcBgNV"
+ +"BAsTFUNyeXB0b2dyYXBoeSBkaXZpc2lvbjEPMA0GA1UEBxMGTW9zY293MQswCQYDVQQGEwJydTEZ"
+ +"MBcGCSqGSIb3DQEJARYKc2RiQGRvbC5ydTBjMBwGBiqFAwICEzASBgcqhQMCAiMBBgcqhQMCAh4B"
+ +"A0MABEBYx0P2D7YuuZo5HgdIAUKAXcLBDZ+4LYFgbKjrfStVfH59lc40BQ2FZ7M703hLpXK8GiBQ"
+ +"GEYpKaAuQZnMIpByoAAwCAYGKoUDAgIDA0EAgXMcTrhdOY2Er2tHOSAgnMezqrYxocZTWhxmW5Rl"
+ +"JY6lbXH5rndCn4swFzXU+YhgAsJv1wQBaoZEWRl5WV4/nA==");
+
+ private byte[] gost3410EC_B = Base64.decode(
+ "MIIBPTCB7QIBADCBgDENMAsGA1UEAxMEdGVzdDEWMBQGA1UEChMNRGVtb3MgQ28gTHRkLjEeMBwG"
+ +"A1UECxMVQ3J5cHRvZ3JhcGh5IGRpdmlzaW9uMQ8wDQYDVQQHEwZNb3Njb3cxCzAJBgNVBAYTAnJ1"
+ +"MRkwFwYJKoZIhvcNAQkBFgpzZGJAZG9sLnJ1MGMwHAYGKoUDAgITMBIGByqFAwICIwIGByqFAwIC"
+ +"HgEDQwAEQI5SLoWT7dZVilbV9j5B/fyIDuDs6x4pjqNC2TtFYbpRHrk/Wc5g/mcHvD80tsm5o1C7"
+ +"7cizNzkvAVUM4VT4Dz6gADAIBgYqhQMCAgMDQQAoT5TwJ8o+bSrxckymyo3diwG7ZbSytX4sRiKy"
+ +"wXPWRS9LlBvPO2NqwpS2HUnxSU8rzfL9fJcybATf7Yt1OEVq");
+
+ private byte[] gost3410EC_C = Base64.decode(
+ "MIIBRDCB9AIBADCBhzEVMBMGA1UEAxMMdGVzdCByZXF1ZXN0MRUwEwYDVQQKEwxEZW1vcyBDbyBM"
+ +"dGQxHjAcBgNVBAsTFUNyeXB0b2dyYXBoeSBkaXZpc2lvbjEPMA0GA1UEBxMGTW9zY293MQswCQYD"
+ +"VQQGEwJydTEZMBcGCSqGSIb3DQEJARYKc2RiQGRvbC5ydTBjMBwGBiqFAwICEzASBgcqhQMCAiMD"
+ +"BgcqhQMCAh4BA0MABEBcmGh7OmR4iqqj+ycYo1S1fS7r5PhisSQU2Ezuz8wmmmR2zeTZkdMYCOBa"
+ +"UTMNms0msW3wuYDho7nTDNscHTB5oAAwCAYGKoUDAgIDA0EAVoOMbfyo1Un4Ss7WQrUjHJoiaYW8"
+ +"Ime5LeGGU2iW3ieAv6es/FdMrwTKkqn5dhd3aL/itFg5oQbhyfXw5yw/QQ==");
+
+ private byte[] gost3410EC_ExA = Base64.decode(
+ "MIIBOzCB6wIBADB/MQ0wCwYDVQQDEwR0ZXN0MRUwEwYDVQQKEwxEZW1vcyBDbyBMdGQxHjAcBgNV"
+ + "BAsTFUNyeXB0b2dyYXBoeSBkaXZpc2lvbjEPMA0GA1UEBxMGTW9zY293MQswCQYDVQQGEwJydTEZ"
+ + "MBcGCSqGSIb3DQEJARYKc2RiQGRvbC5ydTBjMBwGBiqFAwICEzASBgcqhQMCAiQABgcqhQMCAh4B"
+ + "A0MABEDkqNT/3f8NHj6EUiWnK4JbVZBh31bEpkwq9z3jf0u8ZndG56Vt+K1ZB6EpFxLT7hSIos0w"
+ + "weZ2YuTZ4w43OgodoAAwCAYGKoUDAgIDA0EASk/IUXWxoi6NtcUGVF23VRV1L3undB4sRZLp4Vho"
+ + "gQ7m3CMbZFfJ2cPu6QyarseXGYHmazoirH5lGjEo535c1g==");
+
+ private byte[] gost3410EC_ExB = Base64.decode(
+ "MIIBPTCB7QIBADCBgDENMAsGA1UEAxMEdGVzdDEWMBQGA1UEChMNRGVtb3MgQ28gTHRkLjEeMBwG"
+ + "A1UECxMVQ3J5cHRvZ3JhcGh5IGRpdmlzaW9uMQ8wDQYDVQQHEwZNb3Njb3cxCzAJBgNVBAYTAnJ1"
+ + "MRkwFwYJKoZIhvcNAQkBFgpzZGJAZG9sLnJ1MGMwHAYGKoUDAgITMBIGByqFAwICJAEGByqFAwIC"
+ + "HgEDQwAEQMBWYUKPy/1Kxad9ChAmgoSWSYOQxRnXo7KEGLU5RNSXA4qMUvArWzvhav+EYUfTbWLh"
+ + "09nELDyHt2XQcvgQHnSgADAIBgYqhQMCAgMDQQAdaNhgH/ElHp64mbMaEo1tPCg9Q22McxpH8rCz"
+ + "E0QBpF4H5mSSQVGI5OAXHToetnNuh7gHHSynyCupYDEHTbkZ");
+
+ public String getName()
+ {
+ return "PKCS10CertRequest";
+ }
+
+ private void generationTest(int keySize, String keyName, String sigName, String provider)
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyName, "SC");
+
+ kpg.initialize(keySize);
+
+ KeyPair kp = kpg.generateKeyPair();
+
+
+ X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE);
+
+ x500NameBld.addRDN(BCStyle.C, "AU");
+ x500NameBld.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ x500NameBld.addRDN(BCStyle.L, "Melbourne");
+ x500NameBld.addRDN(BCStyle.ST, "Victoria");
+ x500NameBld.addRDN(BCStyle.EmailAddress, "feedback-crypto@bouncycastle.org");
+
+ X500Name subject = x500NameBld.build();
+
+ PKCS10CertificationRequestBuilder requestBuilder = new JcaPKCS10CertificationRequestBuilder(subject, kp.getPublic());
+
+ PKCS10CertificationRequest req1 = requestBuilder.build(new JcaContentSignerBuilder(sigName).setProvider(provider).build(kp.getPrivate()));
+
+ JcaPKCS10CertificationRequest req2 = new JcaPKCS10CertificationRequest(req1.getEncoded()).setProvider(provider);
+
+ if (!req2.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(provider).build(kp.getPublic())))
+ {
+ fail(sigName + ": Failed verify check.");
+ }
+
+ if (!Arrays.areEqual(req2.getPublicKey().getEncoded(), req1.getSubjectPublicKeyInfo().getEncoded()))
+ {
+ fail(keyName + ": Failed public key check.");
+ }
+ }
+
+ private void createECRequest(String algorithm, DERObjectIdentifier algOid)
+ throws Exception
+ {
+ ECCurve.Fp curve = new ECCurve.Fp(
+ new BigInteger("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"), // q (or p)
+ new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", 16), // a
+ new BigInteger("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", 16)); // b
+
+ ECParameterSpec spec = new ECParameterSpec(
+ curve,
+ curve.decodePoint(Hex.decode("0200C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")), // G
+ new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", 16)); // n
+
+ ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(
+ new BigInteger("5769183828869504557786041598510887460263120754767955773309066354712783118202294874205844512909370791582896372147797293913785865682804434049019366394746072023"), // d
+ spec);
+
+ ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(
+ curve.decodePoint(Hex.decode("02006BFDD2C9278B63C92D6624F151C9D7A822CC75BD983B17D25D74C26740380022D3D8FAF304781E416175EADF4ED6E2B47142D2454A7AC7801DD803CF44A4D1F0AC")), // Q
+ spec);
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory fact = KeyFactory.getInstance("ECDSA", "SC");
+
+ privKey = fact.generatePrivate(privKeySpec);
+ pubKey = fact.generatePublic(pubKeySpec);
+
+ PKCS10CertificationRequest req = new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("CN=XXX"), pubKey).build(new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey));
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("Failed verify check EC.");
+ }
+
+ req = new PKCS10CertificationRequest(req.getEncoded());
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("Failed verify check EC encoded.");
+ }
+
+ //
+ // try with point compression turned off
+ //
+ ((ECPointEncoder)pubKey).setPointFormat("UNCOMPRESSED");
+
+ req = new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("CN=XXX"), pubKey).build(new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey));
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("Failed verify check EC uncompressed.");
+ }
+
+ JcaPKCS10CertificationRequest jcaReq = new JcaPKCS10CertificationRequest(new PKCS10CertificationRequest(req.getEncoded()));
+ if (!jcaReq.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(jcaReq.getPublicKey())))
+ {
+ fail("Failed verify check EC uncompressed encoded.");
+ }
+
+ if (!jcaReq.getSignatureAlgorithm().getAlgorithm().equals(algOid))
+ {
+ fail("ECDSA oid incorrect.");
+ }
+
+ if (jcaReq.getSignatureAlgorithm().getParameters() != null)
+ {
+ fail("ECDSA parameters incorrect.");
+ }
+
+ Signature sig = Signature.getInstance(algorithm, BC);
+
+ sig.initVerify(pubKey);
+
+ sig.update(req.toASN1Structure().getCertificationRequestInfo().getEncoded());
+
+ if (!sig.verify(req.getSignature()))
+ {
+ fail("signature not mapped correctly.");
+ }
+ }
+
+ private void createPSSTest(String algorithm)
+ throws Exception
+ {
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+ new BigInteger("010001",16));
+
+ RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec(
+ new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+ new BigInteger("010001",16),
+ new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16),
+ new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16),
+ new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16),
+ new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16),
+ new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16),
+ new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16));
+
+ KeyFactory fact = KeyFactory.getInstance("RSA", "SC");
+
+ PrivateKey privKey = fact.generatePrivate(privKeySpec);
+ PublicKey pubKey = fact.generatePublic(pubKeySpec);
+
+ PKCS10CertificationRequest req = new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("CN=XXX"), pubKey).build(new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey));
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("Failed verify check PSS.");
+ }
+
+ JcaPKCS10CertificationRequest jcaReq = new JcaPKCS10CertificationRequest(req.getEncoded()).setProvider(BC);
+ if (!jcaReq.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(jcaReq.getPublicKey())))
+ {
+ fail("Failed verify check PSS encoded.");
+ }
+
+ if (!jcaReq.getSignatureAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ fail("PSS oid incorrect.");
+ }
+
+ if (jcaReq.getSignatureAlgorithm().getParameters() == null)
+ {
+ fail("PSS parameters incorrect.");
+ }
+
+ Signature sig = Signature.getInstance(algorithm, "SC");
+
+ sig.initVerify(pubKey);
+
+ sig.update(jcaReq.toASN1Structure().getCertificationRequestInfo().getEncoded());
+
+ if (!sig.verify(req.getSignature()))
+ {
+ fail("signature not mapped correctly.");
+ }
+ }
+
+ // previous code found to cause a NullPointerException
+ private void nullPointerTest()
+ throws Exception
+ {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA", "SC");
+ keyGen.initialize(1024, new SecureRandom());
+ KeyPair pair = keyGen.generateKeyPair();
+
+ Vector oids = new Vector();
+ Vector values = new Vector();
+ oids.addElement(X509Extension.basicConstraints);
+ values.addElement(new X509Extension(true, new DEROctetString(new BasicConstraints(true))));
+ oids.addElement(X509Extension.keyUsage);
+ values.addElement(new X509Extension(true, new DEROctetString(
+ new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign))));
+ SubjectKeyIdentifier subjectKeyIdentifier = new SubjectKeyIdentifierStructure(pair.getPublic());
+ X509Extension ski = new X509Extension(false, new DEROctetString(subjectKeyIdentifier));
+ oids.addElement(X509Extension.subjectKeyIdentifier);
+ values.addElement(ski);
+
+ PKCS10CertificationRequest p1 = new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("cn=csr"),
+ pair.getPublic())
+ .addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, new X509Extensions(oids, values))
+ .build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(pair.getPrivate()));
+ PKCS10CertificationRequest p2 = new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("cn=csr"),
+ pair.getPublic())
+ .addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, new X509Extensions(oids, values))
+ .build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(pair.getPrivate()));
+
+ if (!p1.equals(p2))
+ {
+ fail("cert request comparison failed");
+ }
+
+ Attribute[] attr1 = p1.getAttributes();
+ Attribute[] attr2 = p1.getAttributes();
+
+ checkAttrs(1, attr1, attr2);
+
+ attr1 = p1.getAttributes(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest);
+ attr2 = p1.getAttributes(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest);
+
+ checkAttrs(1, attr1, attr2);
+ }
+
+ private void checkAttrs(int expectedLength, Attribute[] attr1, Attribute[] attr2)
+ {
+ if (expectedLength != attr1.length)
+ {
+ fail("expected length mismatch");
+ }
+
+ if (attr1.length != attr2.length)
+ {
+ fail("atrribute length mismatch");
+ }
+
+ for (int i = 0; i != attr1.length; i++)
+ {
+ if (!attr1[i].equals(attr2[i]))
+ {
+ fail("atrribute mismatch");
+ }
+ }
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ generationTest(512, "RSA", "SHA1withRSA", "SC");
+ generationTest(512, "GOST3410", "GOST3411withGOST3410", "SC");
+
+ if (Security.getProvider("SunRsaSign") != null)
+ {
+ generationTest(512, "RSA", "SHA1withRSA", "SunRsaSign");
+ }
+
+ // elliptic curve GOST A parameter set
+ JcaPKCS10CertificationRequest req = new JcaPKCS10CertificationRequest(gost3410EC_A).setProvider(BC);
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(req.getPublicKey())))
+ {
+ fail("Failed verify check gost3410EC_A.");
+ }
+
+ // elliptic curve GOST B parameter set
+ req = new JcaPKCS10CertificationRequest(gost3410EC_B).setProvider(BC);
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(req.getPublicKey())))
+ {
+ fail("Failed verify check gost3410EC_B.");
+ }
+
+ // elliptic curve GOST C parameter set
+ req = new JcaPKCS10CertificationRequest(gost3410EC_C).setProvider(BC);
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(req.getPublicKey())))
+ {
+ fail("Failed verify check gost3410EC_C.");
+ }
+
+ // elliptic curve GOST ExA parameter set
+ req = new JcaPKCS10CertificationRequest(gost3410EC_ExA).setProvider(BC);
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(req.getPublicKey())))
+ {
+ fail("Failed verify check gost3410EC_ExA.");
+ }
+
+ // elliptic curve GOST ExB parameter set
+ req = new JcaPKCS10CertificationRequest(gost3410EC_ExB).setProvider(BC);
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(req.getPublicKey())))
+ {
+ fail("Failed verify check gost3410EC_ExA.");
+ }
+
+ createECRequest("SHA1withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ createECRequest("SHA224withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ createECRequest("SHA256withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ createECRequest("SHA384withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ createECRequest("SHA512withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+
+
+ createPSSTest("SHA1withRSAandMGF1");
+ createPSSTest("SHA224withRSAandMGF1");
+ createPSSTest("SHA256withRSAandMGF1");
+ createPSSTest("SHA384withRSAandMGF1");
+
+ nullPointerTest();
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new PKCS10Test());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/crmf/test/AllTests.java b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/crmf/test/AllTests.java
new file mode 100644
index 000000000..499953306
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/crmf/test/AllTests.java
@@ -0,0 +1,355 @@
+package org.spongycastle.cert.crmf.test;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Date;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.crmf.CRMFObjectIdentifiers;
+import org.spongycastle.asn1.crmf.EncKeyWithID;
+import org.spongycastle.asn1.crmf.EncryptedValue;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509v1CertificateBuilder;
+import org.spongycastle.cert.crmf.EncryptedValueBuilder;
+import org.spongycastle.cert.crmf.EncryptedValuePadder;
+import org.spongycastle.cert.crmf.EncryptedValueParser;
+import org.spongycastle.cert.crmf.FixedLengthMGF1Padder;
+import org.spongycastle.cert.crmf.PKIArchiveControl;
+import org.spongycastle.cert.crmf.PKMACBuilder;
+import org.spongycastle.cert.crmf.ValueDecryptorGenerator;
+import org.spongycastle.cert.crmf.jcajce.JcaCertificateRequestMessage;
+import org.spongycastle.cert.crmf.jcajce.JcaCertificateRequestMessageBuilder;
+import org.spongycastle.cert.crmf.jcajce.JcaEncryptedValueBuilder;
+import org.spongycastle.cert.crmf.jcajce.JcaPKIArchiveControlBuilder;
+import org.spongycastle.cert.crmf.jcajce.JceAsymmetricValueDecryptorGenerator;
+import org.spongycastle.cert.crmf.jcajce.JceCRMFEncryptorBuilder;
+import org.spongycastle.cert.crmf.jcajce.JcePKMACValuesCalculator;
+import org.spongycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.spongycastle.cert.jcajce.JcaX509v1CertificateBuilder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSEnvelopedDataGenerator;
+import org.spongycastle.cms.RecipientId;
+import org.spongycastle.cms.RecipientInformation;
+import org.spongycastle.cms.RecipientInformationStore;
+import org.spongycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
+import org.spongycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
+import org.spongycastle.cms.jcajce.JceKeyTransRecipientId;
+import org.spongycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.OperatorCreationException;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+import org.spongycastle.operator.jcajce.JceAsymmetricKeyWrapper;
+import org.spongycastle.util.Arrays;
+
+public class AllTests
+ extends TestCase
+{
+ private static final byte[] TEST_DATA = "Hello world!".getBytes();
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+ private static final String PASSPHRASE = "hello world";
+
+ /*
+ *
+ * INFRASTRUCTURE
+ *
+ */
+
+ public AllTests(String name)
+ {
+ super(name);
+ }
+
+ public static void main(String args[])
+ {
+ junit.textui.TestRunner.run(AllTests.class);
+ }
+
+ public static Test suite()
+ {
+ return new TestSuite(AllTests.class);
+ }
+
+ public void setUp()
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ public void tearDown()
+ {
+
+ }
+
+ public void testBasicMessageWithArchiveControl()
+ throws Exception
+ {
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(512);
+
+ KeyPair kp = kGen.generateKeyPair();
+ X509Certificate cert = makeV1Certificate(kp, "CN=Test", kp, "CN=Test");
+
+ JcaCertificateRequestMessageBuilder certReqBuild = new JcaCertificateRequestMessageBuilder(BigInteger.ONE);
+
+ certReqBuild.setPublicKey(kp.getPublic())
+ .setSubject(new X500Name("CN=Test"));
+
+ certReqBuild.addControl(new JcaPKIArchiveControlBuilder(kp.getPrivate(), new X500Name("CN=Test"))
+ .addRecipientGenerator(new JceKeyTransRecipientInfoGenerator(cert).setProvider(BC))
+ .build(new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier(CMSEnvelopedDataGenerator.AES128_CBC)).setProvider(BC).build()));
+
+ JcaCertificateRequestMessage certReqMsg = new JcaCertificateRequestMessage(certReqBuild.build());
+
+ assertEquals(new X500Name("CN=Test"), certReqMsg.getCertTemplate().getSubject());
+ assertEquals(kp.getPublic(), certReqMsg.getPublicKey());
+
+ PKIArchiveControl archiveControl = (PKIArchiveControl)certReqMsg.getControl(CRMFObjectIdentifiers.id_regCtrl_pkiArchiveOptions);
+
+ assertEquals(PKIArchiveControl.encryptedPrivKey, archiveControl.getArchiveType());
+
+ assertTrue(archiveControl.isEnvelopedData());
+
+ RecipientInformationStore recips = archiveControl.getEnvelopedData().getRecipientInfos();
+
+ RecipientId recipientId = new JceKeyTransRecipientId(cert);
+
+ RecipientInformation recipientInformation = recips.get(recipientId);
+
+ assertNotNull(recipientInformation);
+
+ EncKeyWithID encKeyWithID = EncKeyWithID.getInstance(recipientInformation.getContent(new JceKeyTransEnvelopedRecipient(kp.getPrivate()).setProvider(BC)));
+
+ assertTrue(encKeyWithID.hasIdentifier());
+ assertFalse(encKeyWithID.isIdentifierUTF8String());
+
+ assertEquals(new GeneralName(X500Name.getInstance(new X500Name("CN=Test").getEncoded())), encKeyWithID.getIdentifier());
+ assertTrue(Arrays.areEqual(kp.getPrivate().getEncoded(), encKeyWithID.getPrivateKey().getEncoded()));
+ }
+
+ public void testProofOfPossessionWithoutSender()
+ throws Exception
+ {
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(512);
+
+ KeyPair kp = kGen.generateKeyPair();
+ X509Certificate cert = makeV1Certificate(kp, "CN=Test", kp, "CN=Test");
+
+ JcaCertificateRequestMessageBuilder certReqBuild = new JcaCertificateRequestMessageBuilder(BigInteger.ONE);
+
+ certReqBuild.setPublicKey(kp.getPublic())
+ .setAuthInfoPKMAC(new PKMACBuilder(new JcePKMACValuesCalculator()), "fred".toCharArray())
+ .setProofOfPossessionSigningKeySigner(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(kp.getPrivate()));
+
+ certReqBuild.addControl(new JcaPKIArchiveControlBuilder(kp.getPrivate(), new X500Name("CN=test"))
+ .addRecipientGenerator(new JceKeyTransRecipientInfoGenerator(cert).setProvider(BC))
+ .build(new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier(CMSEnvelopedDataGenerator.AES128_CBC)).setProvider(BC).build()));
+
+ JcaCertificateRequestMessage certReqMsg = new JcaCertificateRequestMessage(certReqBuild.build());
+
+ // check that internal check on popo signing is working okay
+ try
+ {
+ certReqMsg.isValidSigningKeyPOP(new JcaContentVerifierProviderBuilder().setProvider(BC).build(kp.getPublic()));
+ fail("IllegalStateException not thrown");
+ }
+ catch (IllegalStateException e)
+ {
+ // ignore
+ }
+
+ assertTrue(certReqMsg.isValidSigningKeyPOP(new JcaContentVerifierProviderBuilder().setProvider(BC).build(kp.getPublic()), new PKMACBuilder(new JcePKMACValuesCalculator().setProvider(BC)), "fred".toCharArray()));
+
+ assertEquals(kp.getPublic(), certReqMsg.getPublicKey());
+ }
+
+ public void testProofOfPossessionWithSender()
+ throws Exception
+ {
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(512);
+
+ KeyPair kp = kGen.generateKeyPair();
+ X509Certificate cert = makeV1Certificate(kp, "CN=Test", kp, "CN=Test");
+
+ JcaCertificateRequestMessageBuilder certReqBuild = new JcaCertificateRequestMessageBuilder(BigInteger.ONE);
+
+ certReqBuild.setPublicKey(kp.getPublic())
+ .setAuthInfoSender(new X500Name("CN=Test"))
+ .setProofOfPossessionSigningKeySigner(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(kp.getPrivate()));
+
+ certReqBuild.addControl(new JcaPKIArchiveControlBuilder(kp.getPrivate(), new X500Name("CN=test"))
+ .addRecipientGenerator(new JceKeyTransRecipientInfoGenerator(cert).setProvider(BC))
+ .build(new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier(CMSEnvelopedDataGenerator.AES128_CBC)).setProvider(BC).build()));
+
+ JcaCertificateRequestMessage certReqMsg = new JcaCertificateRequestMessage(certReqBuild.build());
+
+ // check that internal check on popo signing is working okay
+ try
+ {
+ certReqMsg.isValidSigningKeyPOP(new JcaContentVerifierProviderBuilder().setProvider(BC).build(kp.getPublic()), new PKMACBuilder(new JcePKMACValuesCalculator().setProvider(BC)), "fred".toCharArray());
+
+ fail("IllegalStateException not thrown");
+ }
+ catch (IllegalStateException e)
+ {
+ // ignore
+ }
+
+
+ assertTrue(certReqMsg.isValidSigningKeyPOP(new JcaContentVerifierProviderBuilder().setProvider(BC).build(kp.getPublic())));
+
+ assertEquals(kp.getPublic(), certReqMsg.getPublicKey());
+ }
+
+ public void testEncryptedValue()
+ throws Exception
+ {
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(512);
+
+ KeyPair kp = kGen.generateKeyPair();
+ X509Certificate cert = makeV1Certificate(kp, "CN=Test", kp, "CN=Test");
+
+ JcaEncryptedValueBuilder build = new JcaEncryptedValueBuilder(new JceAsymmetricKeyWrapper(cert.getPublicKey()).setProvider(BC), new JceCRMFEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+ EncryptedValue value = build.build(cert);
+ ValueDecryptorGenerator decGen = new JceAsymmetricValueDecryptorGenerator(kp.getPrivate()).setProvider(BC);
+
+ // try direct
+ encryptedValueParserTest(value, decGen, cert);
+
+ // try indirect
+ encryptedValueParserTest(EncryptedValue.getInstance(value.getEncoded()), decGen, cert);
+ }
+
+ private void encryptedValueParserTest(EncryptedValue value, ValueDecryptorGenerator decGen, X509Certificate cert)
+ throws Exception
+ {
+ EncryptedValueParser parser = new EncryptedValueParser(value);
+
+ X509CertificateHolder holder = parser.readCertificateHolder(decGen);
+
+ assertTrue(Arrays.areEqual(cert.getEncoded(), holder.getEncoded()));
+ }
+
+ public void testEncryptedValuePassphrase()
+ throws Exception
+ {
+ char[] passphrase = PASSPHRASE.toCharArray();
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(512);
+
+ KeyPair kp = kGen.generateKeyPair();
+ X509Certificate cert = makeV1Certificate(kp, "CN=Test", kp, "CN=Test");
+
+ EncryptedValueBuilder build = new EncryptedValueBuilder(new JceAsymmetricKeyWrapper(cert.getPublicKey()).setProvider(BC), new JceCRMFEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+ EncryptedValue value = build.build(passphrase);
+ ValueDecryptorGenerator decGen = new JceAsymmetricValueDecryptorGenerator(kp.getPrivate()).setProvider(BC);
+
+ // try direct
+ encryptedValuePassphraseParserTest(value, null, decGen, cert);
+
+ // try indirect
+ encryptedValuePassphraseParserTest(EncryptedValue.getInstance(value.getEncoded()), null, decGen, cert);
+ }
+
+ public void testEncryptedValuePassphraseWithPadding()
+ throws Exception
+ {
+ char[] passphrase = PASSPHRASE.toCharArray();
+ KeyPairGenerator kGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ kGen.initialize(512);
+
+ KeyPair kp = kGen.generateKeyPair();
+ X509Certificate cert = makeV1Certificate(kp, "CN=Test", kp, "CN=Test");
+
+ FixedLengthMGF1Padder mgf1Padder = new FixedLengthMGF1Padder(200, new SecureRandom());
+ EncryptedValueBuilder build = new EncryptedValueBuilder(new JceAsymmetricKeyWrapper(cert.getPublicKey()).setProvider(BC), new JceCRMFEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build(), mgf1Padder);
+ EncryptedValue value = build.build(passphrase);
+ ValueDecryptorGenerator decGen = new JceAsymmetricValueDecryptorGenerator(kp.getPrivate()).setProvider(BC);
+
+ // try direct
+ encryptedValuePassphraseParserTest(value, mgf1Padder, decGen, cert);
+
+ // try indirect
+ encryptedValuePassphraseParserTest(EncryptedValue.getInstance(value.getEncoded()), mgf1Padder, decGen, cert);
+ }
+
+ private void encryptedValuePassphraseParserTest(EncryptedValue value, EncryptedValuePadder padder, ValueDecryptorGenerator decGen, X509Certificate cert)
+ throws Exception
+ {
+ EncryptedValueParser parser = new EncryptedValueParser(value, padder);
+
+ assertTrue(Arrays.areEqual(PASSPHRASE.toCharArray(), parser.readPassphrase(decGen)));
+ }
+
+ private static X509Certificate makeV1Certificate(KeyPair subKP, String _subDN, KeyPair issKP, String _issDN)
+ throws GeneralSecurityException, IOException, OperatorCreationException
+ {
+
+ PublicKey subPub = subKP.getPublic();
+ PrivateKey issPriv = issKP.getPrivate();
+ PublicKey issPub = issKP.getPublic();
+
+ X509v1CertificateBuilder v1CertGen = new JcaX509v1CertificateBuilder(
+ new X500Name(_issDN),
+ BigInteger.valueOf(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)),
+ new X500Name(_subDN),
+ subPub);
+
+ JcaContentSignerBuilder signerBuilder = null;
+
+ if (issPub instanceof RSAPublicKey)
+ {
+ signerBuilder = new JcaContentSignerBuilder("SHA1WithRSA");
+ }
+ else if (issPub.getAlgorithm().equals("DSA"))
+ {
+ signerBuilder = new JcaContentSignerBuilder("SHA1withDSA");
+ }
+ else if (issPub.getAlgorithm().equals("ECDSA"))
+ {
+ signerBuilder = new JcaContentSignerBuilder("SHA1withECDSA");
+ }
+ else if (issPub.getAlgorithm().equals("ECGOST3410"))
+ {
+ signerBuilder = new JcaContentSignerBuilder("GOST3411withECGOST3410");
+ }
+ else
+ {
+ signerBuilder = new JcaContentSignerBuilder("GOST3411WithGOST3410");
+ }
+
+ signerBuilder.setProvider(BC);
+
+ X509Certificate _cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(v1CertGen.build(signerBuilder.build(issPriv)));
+
+ _cert.checkValidity(new Date());
+ _cert.verify(issPub);
+
+ return _cert;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/AllTests.java b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/AllTests.java
new file mode 100644
index 000000000..d602d8fb5
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/AllTests.java
@@ -0,0 +1,56 @@
+package org.spongycastle.cert.test;
+
+import java.security.Security;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.test.SimpleTestResult;
+
+public class AllTests
+ extends TestCase
+{
+ public void testSimpleTests()
+ {
+ org.spongycastle.util.test.Test[] tests = new org.spongycastle.util.test.Test[] { new CertTest(), new PKCS10Test(), new AttrCertSelectorTest(), new AttrCertTest(), new X509ExtensionUtilsTest() };
+
+ for (int i = 0; i != tests.length; i++)
+ {
+ SimpleTestResult result = (SimpleTestResult)tests[i].perform();
+
+ if (!result.isSuccessful())
+ {
+ if (result.getException() != null)
+ {
+ result.getException().printStackTrace();
+ }
+ fail(result.toString());
+ }
+ }
+ }
+
+ public static void main (String[] args)
+ {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite()
+ {
+ TestSuite suite = new TestSuite("Cert Tests");
+
+ if (Security.getProvider("SC") == null)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ suite.addTestSuite(AllTests.class);
+ suite.addTestSuite(BcAttrCertSelectorTest.class);
+ suite.addTestSuite(BcAttrCertSelectorTest.class);
+ suite.addTestSuite(BcAttrCertTest.class);
+ suite.addTestSuite(BcPKCS10Test.class);
+ suite.addTest(ConverterTest.suite());
+
+ return suite;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/AttrCertTest.java b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/AttrCertTest.java
new file mode 100644
index 000000000..525971e6c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/AttrCertTest.java
@@ -0,0 +1,665 @@
+package org.spongycastle.cert.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+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.Attribute;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.cert.AttributeCertificateHolder;
+import org.spongycastle.cert.AttributeCertificateIssuer;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.cert.X509v2AttributeCertificateBuilder;
+import org.spongycastle.cert.jcajce.JcaCertStore;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+import org.spongycastle.util.Store;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.test.SimpleTest;
+
+public class AttrCertTest
+ extends SimpleTest
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ private static final RSAPrivateCrtKeySpec RSA_PRIVATE_KEY_SPEC = 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));
+
+ public static byte[] attrCert = Base64.decode(
+ "MIIHQDCCBqkCAQEwgZChgY2kgYowgYcxHDAaBgkqhkiG9w0BCQEWDW1sb3JjaEB2"
+ + "dC5lZHUxHjAcBgNVBAMTFU1hcmt1cyBMb3JjaCAobWxvcmNoKTEbMBkGA1UECxMS"
+ + "VmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAyMQswCQYDVQQKEwJ2"
+ + "dDELMAkGA1UEBhMCVVMwgYmkgYYwgYMxGzAZBgkqhkiG9w0BCQEWDHNzaGFoQHZ0"
+ + "LmVkdTEbMBkGA1UEAxMSU3VtaXQgU2hhaCAoc3NoYWgpMRswGQYDVQQLExJWaXJn"
+ + "aW5pYSBUZWNoIFVzZXIxEDAOBgNVBAsTB0NsYXNzIDExCzAJBgNVBAoTAnZ0MQsw"
+ + "CQYDVQQGEwJVUzANBgkqhkiG9w0BAQQFAAIBBTAiGA8yMDAzMDcxODE2MDgwMloY"
+ + "DzIwMDMwNzI1MTYwODAyWjCCBU0wggVJBgorBgEEAbRoCAEBMYIFORaCBTU8UnVs"
+ + "ZSBSdWxlSWQ9IkZpbGUtUHJpdmlsZWdlLVJ1bGUiIEVmZmVjdD0iUGVybWl0Ij4K"
+ + "IDxUYXJnZXQ+CiAgPFN1YmplY3RzPgogICA8U3ViamVjdD4KICAgIDxTdWJqZWN0"
+ + "TWF0Y2ggTWF0Y2hJZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5j"
+ + "dGlvbjpzdHJpbmctZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlw"
+ + "ZT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjc3RyaW5nIj4KICAg"
+ + "ICAgIENOPU1hcmt1cyBMb3JjaDwvQXR0cmlidXRlVmFsdWU+CiAgICAgPFN1Ympl"
+ + "Y3RBdHRyaWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFt"
+ + "ZXM6dGM6eGFjbWw6MS4wOnN1YmplY3Q6c3ViamVjdC1pZCIgRGF0YVR5cGU9Imh0"
+ + "dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hI3N0cmluZyIgLz4gCiAgICA8"
+ + "L1N1YmplY3RNYXRjaD4KICAgPC9TdWJqZWN0PgogIDwvU3ViamVjdHM+CiAgPFJl"
+ + "c291cmNlcz4KICAgPFJlc291cmNlPgogICAgPFJlc291cmNlTWF0Y2ggTWF0Y2hJ"
+ + "ZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5jdGlvbjpzdHJpbmct"
+ + "ZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlwZT0iaHR0cDovL3d3"
+ + "dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIj4KICAgICAgaHR0cDovL3p1"
+ + "bmkuY3MudnQuZWR1PC9BdHRyaWJ1dGVWYWx1ZT4KICAgICA8UmVzb3VyY2VBdHRy"
+ + "aWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6"
+ + "eGFjbWw6MS4wOnJlc291cmNlOnJlc291cmNlLWlkIiBEYXRhVHlwZT0iaHR0cDov"
+ + "L3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIiAvPiAKICAgIDwvUmVz"
+ + "b3VyY2VNYXRjaD4KICAgPC9SZXNvdXJjZT4KICA8L1Jlc291cmNlcz4KICA8QWN0"
+ + "aW9ucz4KICAgPEFjdGlvbj4KICAgIDxBY3Rpb25NYXRjaCBNYXRjaElkPSJ1cm46"
+ + "b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmZ1bmN0aW9uOnN0cmluZy1lcXVhbCI+"
+ + "CiAgICAgPEF0dHJpYnV0ZVZhbHVlIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9y"
+ + "Zy8yMDAxL1hNTFNjaGVtYSNzdHJpbmciPgpEZWxlZ2F0ZSBBY2Nlc3MgICAgIDwv"
+ + "QXR0cmlidXRlVmFsdWU+CgkgIDxBY3Rpb25BdHRyaWJ1dGVEZXNpZ25hdG9yIEF0"
+ + "dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmFjdGlvbjph"
+ + "Y3Rpb24taWQiIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNj"
+ + "aGVtYSNzdHJpbmciIC8+IAogICAgPC9BY3Rpb25NYXRjaD4KICAgPC9BY3Rpb24+"
+ + "CiAgPC9BY3Rpb25zPgogPC9UYXJnZXQ+CjwvUnVsZT4KMA0GCSqGSIb3DQEBBAUA"
+ + "A4GBAGiJSM48XsY90HlYxGmGVSmNR6ZW2As+bot3KAfiCIkUIOAqhcphBS23egTr"
+ + "6asYwy151HshbPNYz+Cgeqs45KkVzh7bL/0e1r8sDVIaaGIkjHK3CqBABnfSayr3"
+ + "Rd1yBoDdEv8Qb+3eEPH6ab9021AsLEnJ6LWTmybbOpMNZ3tv");
+
+ byte[] signCert = Base64.decode(
+ "MIIGjTCCBXWgAwIBAgICAPswDQYJKoZIhvcNAQEEBQAwaTEdMBsGCSqGSIb3DQEJ"
+ + "ARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZpcmdpbmlhIFRlY2ggQ2VydGlm"
+ + "aWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0MQswCQYDVQQGEwJVUzAeFw0w"
+ + "MzAxMzExMzUyMTRaFw0wNDAxMzExMzUyMTRaMIGDMRswGQYJKoZIhvcNAQkBFgxz"
+ + "c2hhaEB2dC5lZHUxGzAZBgNVBAMTElN1bWl0IFNoYWggKHNzaGFoKTEbMBkGA1UE"
+ + "CxMSVmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAxMQswCQYDVQQK"
+ + "EwJ2dDELMAkGA1UEBhMCVVMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPDc"
+ + "scgSKmsEp0VegFkuitD5j5PUkDuzLjlfaYONt2SN8WeqU4j2qtlCnsipa128cyKS"
+ + "JzYe9duUdNxquh5BPIkMkHBw4jHoQA33tk0J/sydWdN74/AHPpPieK5GHwhU7GTG"
+ + "rCCS1PJRxjXqse79ExAlul+gjQwHeldAC+d4A6oZAgMBAAGjggOmMIIDojAMBgNV"
+ + "HRMBAf8EAjAAMBEGCWCGSAGG+EIBAQQEAwIFoDAOBgNVHQ8BAf8EBAMCA/gwHQYD"
+ + "VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMB0GA1UdDgQWBBRUIoWAzlXbzBYE"
+ + "yVTjQFWyMMKo1jCBkwYDVR0jBIGLMIGIgBTgc3Fm+TGqKDhen+oKfbl+xVbj2KFt"
+ + "pGswaTEdMBsGCSqGSIb3DQEJARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZp"
+ + "cmdpbmlhIFRlY2ggQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0"
+ + "MQswCQYDVQQGEwJVU4IBADCBiwYJYIZIAYb4QgENBH4WfFZpcmdpbmlhIFRlY2gg"
+ + "Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgZGlnaXRhbCBjZXJ0aWZpY2F0ZXMgYXJl"
+ + "IHN1YmplY3QgdG8gcG9saWNpZXMgbG9jYXRlZCBhdCBodHRwOi8vd3d3LnBraS52"
+ + "dC5lZHUvY2EvY3BzLy4wFwYDVR0RBBAwDoEMc3NoYWhAdnQuZWR1MBkGA1UdEgQS"
+ + "MBCBDmlybWhlbHBAdnQuZWR1MEMGCCsGAQUFBwEBBDcwNTAzBggrBgEFBQcwAoYn"
+ + "aHR0cDovL2JveDE3Ny5jYy52dC5lZHUvY2EvaXNzdWVycy5odG1sMEQGA1UdHwQ9"
+ + "MDswOaA3oDWGM2h0dHA6Ly9ib3gxNzcuY2MudnQuZWR1L2h0ZG9jcy1wdWJsaWMv"
+ + "Y3JsL2NhY3JsLmNybDBUBgNVHSAETTBLMA0GCysGAQQBtGgFAQEBMDoGCysGAQQB"
+ + "tGgFAQEBMCswKQYIKwYBBQUHAgEWHWh0dHA6Ly93d3cucGtpLnZ0LmVkdS9jYS9j"
+ + "cHMvMD8GCWCGSAGG+EIBBAQyFjBodHRwOi8vYm94MTc3LmNjLnZ0LmVkdS9jZ2kt"
+ + "cHVibGljL2NoZWNrX3Jldl9jYT8wPAYJYIZIAYb4QgEDBC8WLWh0dHA6Ly9ib3gx"
+ + "NzcuY2MudnQuZWR1L2NnaS1wdWJsaWMvY2hlY2tfcmV2PzBLBglghkgBhvhCAQcE"
+ + "PhY8aHR0cHM6Ly9ib3gxNzcuY2MudnQuZWR1L35PcGVuQ0E4LjAxMDYzMC9jZ2kt"
+ + "cHVibGljL3JlbmV3YWw/MCwGCWCGSAGG+EIBCAQfFh1odHRwOi8vd3d3LnBraS52"
+ + "dC5lZHUvY2EvY3BzLzANBgkqhkiG9w0BAQQFAAOCAQEAHJ2ls9yjpZVcu5DqiE67"
+ + "r7BfkdMnm7IOj2v8cd4EAlPp6OPBmjwDMwvKRBb/P733kLBqFNWXWKTpT008R0KB"
+ + "8kehbx4h0UPz9vp31zhGv169+5iReQUUQSIwTGNWGLzrT8kPdvxiSAvdAJxcbRBm"
+ + "KzDic5I8PoGe48kSCkPpT1oNmnivmcu5j1SMvlx0IS2BkFMksr0OHiAW1elSnE/N"
+ + "RuX2k73b3FucwVxB3NRo3vgoHPCTnh9r4qItAHdxFlF+pPtbw2oHESKRfMRfOIHz"
+ + "CLQWSIa6Tvg4NIV3RRJ0sbCObesyg08lymalQMdkXwtRn5eGE00SHWwEUjSXP2gR"
+ + "3g==");
+
+ static byte[] certWithBaseCertificateID = Base64.decode(
+ "MIIBqzCCARQCAQEwSKBGMD6kPDA6MQswCQYDVQQGEwJJVDEOMAwGA1UEChMFVU5JVE4xDDAKBgNV"
+ + "BAsTA0RJVDENMAsGA1UEAxMEcm9vdAIEAVMVjqB6MHikdjB0MQswCQYDVQQGEwJBVTEoMCYGA1UE"
+ + "ChMfVGhlIExlZ2lvbiBvZiB0aGUgQm91bmN5IENhc3RsZTEjMCEGA1UECxMaQm91bmN5IFByaW1h"
+ + "cnkgQ2VydGlmaWNhdGUxFjAUBgNVBAMTDUJvdW5jeSBDYXN0bGUwDQYJKoZIhvcNAQEFBQACBQKW"
+ + "RhnHMCIYDzIwMDUxMjEyMTIwMDQyWhgPMjAwNTEyMTkxMjAxMzJaMA8wDQYDVRhIMQaBBGVWSVAw"
+ + "DQYJKoZIhvcNAQEFBQADgYEAUAVin9StDaA+InxtXq/av6rUQLI9p1X6louBcj4kYJnxRvTrHpsr"
+ + "N3+i9Uq/uk5lRdAqmPFvcmSbuE3TRAsjrXON5uFiBBKZ1AouLqcr8nHbwcdwjJ9TyUNO9I4hfpSH"
+ + "UHHXMtBKgp4MOkhhX8xTGyWg3hp23d3GaUeg/IYlXBI=");
+
+ byte[] holderCertWithBaseCertificateID = Base64.decode(
+ "MIIBwDCCASmgAwIBAgIEAVMVjjANBgkqhkiG9w0BAQUFADA6MQswCQYDVQQGEwJJVDEOMAwGA1UE"
+ + "ChMFVU5JVE4xDDAKBgNVBAsTA0RJVDENMAsGA1UEAxMEcm9vdDAeFw0wNTExMTExMjAxMzJaFw0w"
+ + "NjA2MTYxMjAxMzJaMD4xCzAJBgNVBAYTAklUMQ4wDAYDVQQKEwVVTklUTjEMMAoGA1UECxMDRElU"
+ + "MREwDwYDVQQDEwhMdWNhQm9yejBaMA0GCSqGSIb3DQEBAQUAA0kAMEYCQQC0p+RhcFdPFqlwgrIr"
+ + "5YtqKmKXmEGb4ShypL26Ymz66ZAPdqv7EhOdzl3lZWT6srZUMWWgQMYGiHQg4z2R7X7XAgERoxUw"
+ + "EzARBglghkgBhvhCAQEEBAMCBDAwDQYJKoZIhvcNAQEFBQADgYEAsX50VPQQCWmHvPq9y9DeCpmS"
+ + "4szcpFAhpZyn6gYRwY9CRZVtmZKH8713XhkGDWcIEMcG0u3oTz3tdKgPU5uyIPrDEWr6w8ClUj4x"
+ + "5aVz5c2223+dVY7KES//JSB2bE/KCIchN3kAioQ4K8O3e0OL6oDVjsqKGw5bfahgKuSIk/Q=");
+
+
+ public String getName()
+ {
+ return "AttrCertTest";
+ }
+
+ private void testCertWithBaseCertificateID()
+ throws Exception
+ {
+ X509AttributeCertificateHolder attrCert = new X509AttributeCertificateHolder(certWithBaseCertificateID);
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+ X509Certificate cert = (X509Certificate)fact.generateCertificate(new ByteArrayInputStream(holderCertWithBaseCertificateID));
+
+ AttributeCertificateHolder holder = attrCert.getHolder();
+
+ if (holder.getEntityNames() != null)
+ {
+ fail("entity names set when none expected");
+ }
+
+ if (!holder.getSerialNumber().equals(cert.getSerialNumber()))
+ {
+ fail("holder serial number doesn't match");
+ }
+
+ if (!holder.getIssuer()[0].equals(new JcaX509CertificateHolder(cert).getIssuer()))
+ {
+ fail("holder issuer doesn't match");
+ }
+
+ if (!holder.match(new JcaX509CertificateHolder(cert)))
+ {
+ fail("holder not matching holder certificate");
+ }
+
+ if (!holder.equals(holder.clone()))
+ {
+ fail("holder clone test failed");
+ }
+
+ if (!attrCert.getIssuer().equals(attrCert.getIssuer().clone()))
+ {
+ fail("issuer clone test failed");
+ }
+
+ //equalityAndHashCodeTest(attrCert, certWithBaseCertificateID);
+ }
+
+ private void equalityAndHashCodeTest(X509AttributeCertificateHolder attrCert, byte[] encoding)
+ throws IOException
+ {
+ if (!attrCert.equals(attrCert))
+ {
+ fail("same certificate not equal");
+ }
+
+ if (!attrCert.getHolder().equals(attrCert.getHolder()))
+ {
+ fail("same holder not equal");
+ }
+
+ if (!attrCert.getIssuer().equals(attrCert.getIssuer()))
+ {
+ fail("same issuer not equal");
+ }
+
+ if (attrCert.getHolder().equals(attrCert.getIssuer()))
+ {
+ fail("wrong holder equal");
+ }
+
+ if (attrCert.getIssuer().equals(attrCert.getHolder()))
+ {
+ fail("wrong issuer equal");
+ }
+
+ X509AttributeCertificateHolder attrCert2 = new X509AttributeCertificateHolder(encoding);
+
+ if (attrCert2.getHolder().hashCode() != attrCert.getHolder().hashCode())
+ {
+ fail("holder hashCode test failed");
+ }
+
+ if (!attrCert2.getHolder().equals(attrCert.getHolder()))
+ {
+ fail("holder equals test failed");
+ }
+
+ if (attrCert2.getIssuer().hashCode() != attrCert.getIssuer().hashCode())
+ {
+ fail("issuer hashCode test failed");
+ }
+
+ if (!attrCert2.getIssuer().equals(attrCert.getIssuer()))
+ {
+ fail("issuer equals test failed");
+ }
+ }
+
+ private void testGenerateWithCert()
+ throws Exception
+ {
+ CertificateFactory fact = CertificateFactory.getInstance("X.509","SC");
+ X509Certificate iCert = (X509Certificate)fact.generateCertificate(new ByteArrayInputStream(signCert));
+
+ //
+ // a sample key pair.
+ //
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory kFact = KeyFactory.getInstance("RSA", "SC");
+
+ privKey = kFact.generatePrivate(RSA_PRIVATE_KEY_SPEC);
+ pubKey = kFact.generatePublic(pubKeySpec);
+
+ X509v2AttributeCertificateBuilder gen = new X509v2AttributeCertificateBuilder(
+ new AttributeCertificateHolder(new JcaX509CertificateHolder(iCert)),
+ new AttributeCertificateIssuer(new X500Name("cn=test")),
+ BigInteger.valueOf(1),
+ new Date(System.currentTimeMillis() - 50000),
+ new Date(System.currentTimeMillis() + 50000));
+
+ // the actual attributes
+ GeneralName roleName = new GeneralName(GeneralName.rfc822Name, "DAU123456789");
+ ASN1EncodableVector roleSyntax = new ASN1EncodableVector();
+ roleSyntax.add(roleName);
+
+ // roleSyntax OID: 2.5.24.72;
+
+ gen.addAttribute(new ASN1ObjectIdentifier("2.5.24.72"), new DERSequence(roleSyntax));
+
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA1WithRSAEncryption").setProvider(BC).build(privKey);
+
+ X509AttributeCertificateHolder aCert = gen.build(sigGen);
+
+ if (!aCert.isValidOn(new Date()))
+ {
+ fail("certificate invalid");
+ }
+
+ if (!aCert.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("certificate signature not valid");
+ }
+
+ AttributeCertificateHolder holder = aCert.getHolder();
+
+ if (holder.getEntityNames() != null)
+ {
+ fail("entity names set when none expected");
+ }
+
+ if (!holder.getSerialNumber().equals(iCert.getSerialNumber()))
+ {
+ fail("holder serial number doesn't match");
+ }
+
+ if (!holder.getIssuer()[0].equals(new JcaX509CertificateHolder(iCert).getIssuer()))
+ {
+ fail("holder issuer doesn't match");
+ }
+
+ if (!holder.match(new JcaX509CertificateHolder(iCert)))
+ {
+ fail("generated holder not matching holder certificate");
+ }
+
+ Attribute[] attrs = aCert.getAttributes(new ASN1ObjectIdentifier("2.5.24.72"));
+
+ if (attrs == null)
+ {
+ fail("attributes related to 2.5.24.72 not found");
+ }
+
+ Attribute attr = attrs[0];
+
+ if (!attr.getAttrType().getId().equals("2.5.24.72"))
+ {
+ fail("attribute oid mismatch");
+ }
+
+ ASN1Encodable[] values = attr.getAttrValues().toArray();
+
+ GeneralName role = GeneralNames.getInstance(values[0]).getNames()[0];
+
+ if (role.getTagNo() != GeneralName.rfc822Name)
+ {
+ fail("wrong general name type found in role");
+ }
+
+ if (!((ASN1String)role.getName()).getString().equals("DAU123456789"))
+ {
+ fail("wrong general name value found in role");
+ }
+
+ X509Certificate sCert = (X509Certificate)fact.generateCertificate(new ByteArrayInputStream(holderCertWithBaseCertificateID));
+
+ if (holder.match(new JcaX509CertificateHolder(sCert)))
+ {
+ fail("generated holder matching wrong certificate");
+ }
+
+ equalityAndHashCodeTest(aCert, aCert.getEncoded());
+ }
+
+ private void testGenerateWithPrincipal()
+ throws Exception
+ {
+ CertificateFactory fact = CertificateFactory.getInstance("X.509","SC");
+ X509Certificate iCert = (X509Certificate)fact.generateCertificate(new ByteArrayInputStream(signCert));
+
+ //
+ // a sample key pair.
+ //
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory kFact = KeyFactory.getInstance("RSA", "SC");
+
+ privKey = kFact.generatePrivate(RSA_PRIVATE_KEY_SPEC);
+ pubKey = kFact.generatePublic(pubKeySpec);
+
+ X509v2AttributeCertificateBuilder gen = new X509v2AttributeCertificateBuilder(
+ new AttributeCertificateHolder(new JcaX509CertificateHolder(iCert).getSubject()),
+ new AttributeCertificateIssuer(new X500Name("cn=test")),
+ BigInteger.valueOf(1),
+ new Date(System.currentTimeMillis() - 50000),
+ new Date(System.currentTimeMillis() + 50000));
+
+ // the actual attributes
+ GeneralName roleName = new GeneralName(GeneralName.rfc822Name, "DAU123456789");
+ ASN1EncodableVector roleSyntax = new ASN1EncodableVector();
+ roleSyntax.add(roleName);
+
+ // roleSyntax OID: 2.5.24.72
+
+ gen.addAttribute(new ASN1ObjectIdentifier("2.5.24.72"), new DERSequence(roleSyntax));
+
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA1WithRSAEncryption").setProvider(BC).build(privKey);
+
+ X509AttributeCertificateHolder aCert = gen.build(sigGen);
+
+ if (!aCert.isValidOn(new Date()))
+ {
+ fail("certificate invalid");
+ }
+
+ if (!aCert.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("certificate signature not valid");
+ }
+
+ AttributeCertificateHolder holder = aCert.getHolder();
+
+ if (holder.getEntityNames() == null)
+ {
+ fail("entity names not set when expected");
+ }
+
+ if (holder.getSerialNumber() != null)
+ {
+ fail("holder serial number found when none expected");
+ }
+
+ if (holder.getIssuer() != null)
+ {
+ fail("holder issuer found when none expected");
+ }
+
+ if (!holder.match(new JcaX509CertificateHolder(iCert)))
+ {
+ fail("generated holder not matching holder certificate");
+ }
+
+ X509Certificate sCert = (X509Certificate)fact.generateCertificate(new ByteArrayInputStream(holderCertWithBaseCertificateID));
+
+ if (holder.match(sCert))
+ {
+ fail("principal generated holder matching wrong certificate");
+ }
+
+ equalityAndHashCodeTest(aCert, aCert.getEncoded());
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ X509AttributeCertificateHolder aCert = new X509AttributeCertificateHolder(attrCert);
+ CertificateFactory fact = CertificateFactory.getInstance("X.509","SC");
+ X509Certificate sCert = (X509Certificate)fact.generateCertificate(new ByteArrayInputStream(signCert));
+
+ if (!aCert.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(sCert)))
+ {
+ fail("certificate signature not valid");
+ }
+
+ //
+ // search test
+ //
+
+ List list = new ArrayList();
+
+ list.add(sCert);
+
+ Store store = new JcaCertStore(list);
+
+ Collection certs = store.getMatches(aCert.getIssuer());
+ if (certs.size() != 1 || !certs.contains(new JcaX509CertificateHolder(sCert)))
+ {
+ fail("sCert not found by issuer");
+ }
+
+ Attribute[] attrs = aCert.getAttributes(new ASN1ObjectIdentifier("1.3.6.1.4.1.6760.8.1.1"));
+ if (attrs == null || attrs.length != 1)
+ {
+ fail("attribute not found");
+ }
+
+ //
+ // reencode test
+ //
+ aCert = new X509AttributeCertificateHolder(aCert.getEncoded());
+
+ if (!aCert.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(sCert)))
+ {
+ fail("certificate signature not valid");
+ }
+
+ X509AttributeCertificateHolder saCert = new X509AttributeCertificateHolder(aCert.getEncoded());
+
+ if (!aCert.getNotAfter().equals(saCert.getNotAfter()))
+ {
+ fail("failed date comparison");
+ }
+
+ // base generator test
+
+ //
+ // a sample key pair.
+ //
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ RSAPrivateCrtKeySpec privKeySpec = RSA_PRIVATE_KEY_SPEC;
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory kFact = KeyFactory.getInstance("RSA", "SC");
+
+ privKey = kFact.generatePrivate(privKeySpec);
+ pubKey = kFact.generatePublic(pubKeySpec);
+
+ X509v2AttributeCertificateBuilder gen = new X509v2AttributeCertificateBuilder(
+ aCert.getHolder(),
+ aCert.getIssuer(),
+ aCert.getSerialNumber(),
+ new Date(System.currentTimeMillis() - 50000),
+ new Date(System.currentTimeMillis() + 50000));
+
+ gen.addAttribute(attrs[0].getAttrType(), attrs[0].getAttributeValues());
+
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA1WithRSAEncryption").setProvider(BC).build(privKey);
+
+ aCert = gen.build(sigGen);
+
+ if (!aCert.isValidOn(new Date()))
+ {
+ fail("certificate not valid");
+ }
+
+ if (!aCert.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("signature not valid");
+ }
+
+ // as the issuer is the same this should still work (even though it is not
+ // technically correct
+
+ certs = store.getMatches(aCert.getIssuer());
+ if (certs.size() != 1 || !certs.contains(new JcaX509CertificateHolder(sCert)))
+ {
+ fail("sCert not found by issuer");
+ }
+
+ attrs = aCert.getAttributes(new ASN1ObjectIdentifier("1.3.6.1.4.1.6760.8.1.1"));
+ if (attrs == null || attrs.length != 1)
+ {
+ fail("attribute not found");
+ }
+
+ //
+ // reencode test
+ //
+ aCert = new X509AttributeCertificateHolder(aCert.getEncoded());
+
+ if (!aCert.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("signature not valid");
+ }
+
+ AttributeCertificateIssuer issuer = aCert.getIssuer();
+
+ X500Name[] principals = issuer.getNames();
+
+ //
+ // test holder
+ //
+ AttributeCertificateHolder holder = aCert.getHolder();
+
+ if (holder.getEntityNames() == null)
+ {
+ fail("entity names not set");
+ }
+
+ if (holder.getSerialNumber() != null)
+ {
+ fail("holder serial number set when none expected");
+ }
+
+ if (holder.getIssuer() != null)
+ {
+ fail("holder issuer set when none expected");
+ }
+
+ principals = holder.getEntityNames();
+
+ // X500Principal principal0 = new X500Principal(principals[0].getEncoded());
+ // if (!principal0.toString().equals("C=US, O=vt, OU=Class 2, OU=Virginia Tech User, CN=Markus Lorch (mlorch), EMAILADDRESS=mlorch@vt.edu"))
+ // {
+ // fail("principal[0] for entity names don't match");
+ // }
+
+ //
+ // extension test
+ //
+
+ if (aCert.hasExtensions())
+ {
+ fail("hasExtensions true with no extensions");
+ }
+
+ gen.addExtension(new ASN1ObjectIdentifier("1.1"), true, new DEROctetString(new byte[10]));
+
+ gen.addExtension(new ASN1ObjectIdentifier("2.2"), false, new DEROctetString(new byte[20]));
+
+ aCert = gen.build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(privKey));
+
+ Set exts = aCert.getCriticalExtensionOIDs();
+
+ if (exts.size() != 1 || !exts.contains(new ASN1ObjectIdentifier("1.1")))
+ {
+ fail("critical extension test failed");
+ }
+
+ exts = aCert.getNonCriticalExtensionOIDs();
+
+ if (exts.size() != 1 || !exts.contains(new ASN1ObjectIdentifier("2.2")))
+ {
+ fail("non-critical extension test failed");
+ }
+
+ if (aCert.getCriticalExtensionOIDs().isEmpty())
+ {
+ fail("critical extensions not found");
+ }
+
+ Extension ext = aCert.getExtension(new ASN1ObjectIdentifier("1.1"));
+ ASN1Encodable extValue = ext.getParsedValue();
+
+ if (!extValue.equals(new DEROctetString(new byte[10])))
+ {
+ fail("wrong extension value found for 1.1");
+ }
+
+ testCertWithBaseCertificateID();
+ testGenerateWithCert();
+ testGenerateWithPrincipal();
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new AttrCertTest());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/CertTest.java b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/CertTest.java
new file mode 100644
index 000000000..14fd82108
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/CertTest.java
@@ -0,0 +1,2875 @@
+package org.spongycastle.cert.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Signature;
+import java.security.cert.CRL;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Vector;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Enumerated;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DEREnumerated;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSAPublicKey;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.X500NameBuilder;
+import org.spongycastle.asn1.x500.style.BCStyle;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.ExtensionsGenerator;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.IssuingDistributionPoint;
+import org.spongycastle.asn1.x509.KeyPurposeId;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509CertificateStructure;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.cert.X509CRLEntryHolder;
+import org.spongycastle.cert.X509CRLHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509v1CertificateBuilder;
+import org.spongycastle.cert.X509v2CRLBuilder;
+import org.spongycastle.cert.X509v3CertificateBuilder;
+import org.spongycastle.cert.jcajce.JcaX509CRLConverter;
+import org.spongycastle.cert.jcajce.JcaX509CRLHolder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.cert.jcajce.JcaX509v1CertificateBuilder;
+import org.spongycastle.cert.jcajce.JcaX509v2CRLBuilder;
+import org.spongycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.jce.X509KeyUsage;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPrivateKeySpec;
+import org.spongycastle.jce.spec.ECPublicKeySpec;
+import org.spongycastle.jce.spec.GOST3410ParameterSpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.bc.BcRSAContentSignerBuilder;
+import org.spongycastle.operator.bc.BcRSAContentVerifierProviderBuilder;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.encoders.Hex;
+import org.spongycastle.util.test.SimpleTest;
+import org.spongycastle.x509.extension.AuthorityKeyIdentifierStructure;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+
+public class CertTest
+ extends SimpleTest
+{
+ private static final String BC = org.spongycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
+
+ // test CA
+ byte[] testCAp12 = Base64.decode(
+ "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"
+ + "HLhcYQcQ1R+RucctAgIEAAAA");
+
+ //
+ // server.crt
+ //
+ byte[] cert1 = Base64.decode(
+ "MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx"
+ + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY"
+ + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB"
+ + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ"
+ + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2"
+ + "MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW"
+ + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM"
+ + "dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l"
+ + "Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv"
+ + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re"
+ + "Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO"
+ + "Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE"
+ + "7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy"
+ + "QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0"
+ + "ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw"
+ + "DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL"
+ + "iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4"
+ + "yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF"
+ + "5/8=");
+
+ //
+ // ca.crt
+ //
+ byte[] cert2 = Base64.decode(
+ "MIIDbDCCAtWgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx"
+ + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY"
+ + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB"
+ + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ"
+ + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU1MzNaFw0wMTA2"
+ + "MDIwNzU1MzNaMIG3MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW"
+ + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM"
+ + "dGQxHjAcBgNVBAsTFUNlcnRpZmljYXRlIEF1dGhvcml0eTEVMBMGA1UEAxMMQ29u"
+ + "bmVjdCA0IENBMSgwJgYJKoZIhvcNAQkBFhl3ZWJtYXN0ZXJAY29ubmVjdDQuY29t"
+ + "LmF1MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgs5ptNG6Qv1ZpCDuUNGmv"
+ + "rhjqMDPd3ri8JzZNRiiFlBA4e6/ReaO1U8ASewDeQMH6i9R6degFdQRLngbuJP0s"
+ + "xcEE+SksEWNvygfzLwV9J/q+TQDyJYK52utb++lS0b48A1KPLwEsyL6kOAgelbur"
+ + "ukwxowprKUIV7Knf1ajetQIDAQABo4GFMIGCMCQGA1UdEQQdMBuBGXdlYm1hc3Rl"
+ + "ckBjb25uZWN0NC5jb20uYXUwDwYDVR0TBAgwBgEB/wIBADA2BglghkgBhvhCAQ0E"
+ + "KRYnbW9kX3NzbCBnZW5lcmF0ZWQgY3VzdG9tIENBIGNlcnRpZmljYXRlMBEGCWCG"
+ + "SAGG+EIBAQQEAwICBDANBgkqhkiG9w0BAQQFAAOBgQCsGvfdghH8pPhlwm1r3pQk"
+ + "msnLAVIBb01EhbXm2861iXZfWqGQjrGAaA0ZpXNk9oo110yxoqEoSJSzniZa7Xtz"
+ + "soTwNUpE0SLHvWf/SlKdFWlzXA+vOZbzEv4UmjeelekTm7lc01EEa5QRVzOxHFtQ"
+ + "DhkaJ8VqOMajkQFma2r9iA==");
+
+ //
+ // testx509.pem
+ //
+ byte[] cert3 = Base64.decode(
+ "MIIBWzCCAQYCARgwDQYJKoZIhvcNAQEEBQAwODELMAkGA1UEBhMCQVUxDDAKBgNV"
+ + "BAgTA1FMRDEbMBkGA1UEAxMSU1NMZWF5L3JzYSB0ZXN0IENBMB4XDTk1MDYxOTIz"
+ + "MzMxMloXDTk1MDcxNzIzMzMxMlowOjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA1FM"
+ + "RDEdMBsGA1UEAxMUU1NMZWF5L3JzYSB0ZXN0IGNlcnQwXDANBgkqhkiG9w0BAQEF"
+ + "AANLADBIAkEAqtt6qS5GTxVxGZYWa0/4u+IwHf7p2LNZbcPBp9/OfIcYAXBQn8hO"
+ + "/Re1uwLKXdCjIoaGs4DLdG88rkzfyK5dPQIDAQABMAwGCCqGSIb3DQIFBQADQQAE"
+ + "Wc7EcF8po2/ZO6kNCwK/ICH6DobgLekA5lSLr5EvuioZniZp5lFzAw4+YzPQ7XKJ"
+ + "zl9HYIMxATFyqSiD9jsx");
+
+ //
+ // v3-cert1.pem
+ //
+ byte[] cert4 = Base64.decode(
+ "MIICjTCCAfigAwIBAgIEMaYgRzALBgkqhkiG9w0BAQQwRTELMAkGA1UEBhMCVVMx"
+ + "NjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFuZCBTcGFjZSBBZG1pbmlz"
+ + "dHJhdGlvbjAmFxE5NjA1MjgxMzQ5MDUrMDgwMBcROTgwNTI4MTM0OTA1KzA4MDAw"
+ + "ZzELMAkGA1UEBhMCVVMxNjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFu"
+ + "ZCBTcGFjZSBBZG1pbmlzdHJhdGlvbjEgMAkGA1UEBRMCMTYwEwYDVQQDEwxTdGV2"
+ + "ZSBTY2hvY2gwWDALBgkqhkiG9w0BAQEDSQAwRgJBALrAwyYdgxmzNP/ts0Uyf6Bp"
+ + "miJYktU/w4NG67ULaN4B5CnEz7k57s9o3YY3LecETgQ5iQHmkwlYDTL2fTgVfw0C"
+ + "AQOjgaswgagwZAYDVR0ZAQH/BFowWDBWMFQxCzAJBgNVBAYTAlVTMTYwNAYDVQQK"
+ + "Ey1OYXRpb25hbCBBZXJvbmF1dGljcyBhbmQgU3BhY2UgQWRtaW5pc3RyYXRpb24x"
+ + "DTALBgNVBAMTBENSTDEwFwYDVR0BAQH/BA0wC4AJODMyOTcwODEwMBgGA1UdAgQR"
+ + "MA8ECTgzMjk3MDgyM4ACBSAwDQYDVR0KBAYwBAMCBkAwCwYJKoZIhvcNAQEEA4GB"
+ + "AH2y1VCEw/A4zaXzSYZJTTUi3uawbbFiS2yxHvgf28+8Js0OHXk1H1w2d6qOHH21"
+ + "X82tZXd/0JtG0g1T9usFFBDvYK8O0ebgz/P5ELJnBL2+atObEuJy1ZZ0pBDWINR3"
+ + "WkDNLCGiTkCKp0F5EWIrVDwh54NNevkCQRZita+z4IBO");
+
+ //
+ // v3-cert2.pem
+ //
+ byte[] cert5 = Base64.decode(
+ "MIICiTCCAfKgAwIBAgIEMeZfHzANBgkqhkiG9w0BAQQFADB9MQswCQYDVQQGEwJD"
+ + "YTEPMA0GA1UEBxMGTmVwZWFuMR4wHAYDVQQLExVObyBMaWFiaWxpdHkgQWNjZXB0"
+ + "ZWQxHzAdBgNVBAoTFkZvciBEZW1vIFB1cnBvc2VzIE9ubHkxHDAaBgNVBAMTE0Vu"
+ + "dHJ1c3QgRGVtbyBXZWIgQ0EwHhcNOTYwNzEyMTQyMDE1WhcNOTYxMDEyMTQyMDE1"
+ + "WjB0MSQwIgYJKoZIhvcNAQkBExVjb29rZUBpc3NsLmF0bC5ocC5jb20xCzAJBgNV"
+ + "BAYTAlVTMScwJQYDVQQLEx5IZXdsZXR0IFBhY2thcmQgQ29tcGFueSAoSVNTTCkx"
+ + "FjAUBgNVBAMTDVBhdWwgQS4gQ29va2UwXDANBgkqhkiG9w0BAQEFAANLADBIAkEA"
+ + "6ceSq9a9AU6g+zBwaL/yVmW1/9EE8s5you1mgjHnj0wAILuoB3L6rm6jmFRy7QZT"
+ + "G43IhVZdDua4e+5/n1ZslwIDAQABo2MwYTARBglghkgBhvhCAQEEBAMCB4AwTAYJ"
+ + "YIZIAYb4QgENBD8WPVRoaXMgY2VydGlmaWNhdGUgaXMgb25seSBpbnRlbmRlZCBm"
+ + "b3IgZGVtb25zdHJhdGlvbiBwdXJwb3Nlcy4wDQYJKoZIhvcNAQEEBQADgYEAi8qc"
+ + "F3zfFqy1sV8NhjwLVwOKuSfhR/Z8mbIEUeSTlnH3QbYt3HWZQ+vXI8mvtZoBc2Fz"
+ + "lexKeIkAZXCesqGbs6z6nCt16P6tmdfbZF3I3AWzLquPcOXjPf4HgstkyvVBn0Ap"
+ + "jAFN418KF/Cx4qyHB4cjdvLrRjjQLnb2+ibo7QU=");
+
+ //
+ // pem encoded pkcs7
+ //
+ byte[] cert6 = Base64.decode(
+ "MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIJbzCCAj0w"
+ + "ggGmAhEAzbp/VvDf5LxU/iKss3KqVTANBgkqhkiG9w0BAQIFADBfMQswCQYDVQQGEwJVUzEXMBUG"
+ + "A1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGljIFByaW1hcnkgQ2Vy"
+ + "dGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNOTYwMTI5MDAwMDAwWhcNMjgwODAxMjM1OTU5WjBfMQsw"
+ + "CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVi"
+ + "bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwgZ8wDQYJKoZIhvcNAQEBBQADgY0A"
+ + "MIGJAoGBAOUZv22jVmEtmUhx9mfeuY3rt56GgAqRDvo4Ja9GiILlc6igmyRdDR/MZW4MsNBWhBiH"
+ + "mgabEKFz37RYOWtuwfYV1aioP6oSBo0xrH+wNNePNGeICc0UEeJORVZpH3gCgNrcR5EpuzbJY1zF"
+ + "4Ncth3uhtzKwezC6Ki8xqu6jZ9rbAgMBAAEwDQYJKoZIhvcNAQECBQADgYEATD+4i8Zo3+5DMw5d"
+ + "6abLB4RNejP/khv0Nq3YlSI2aBFsfELM85wuxAc/FLAPT/+Qknb54rxK6Y/NoIAK98Up8YIiXbix"
+ + "3YEjo3slFUYweRb46gVLlH8dwhzI47f0EEA8E8NfH1PoSOSGtHuhNbB7Jbq4046rPzidADQAmPPR"
+ + "cZQwggMuMIICl6ADAgECAhEA0nYujRQMPX2yqCVdr+4NdTANBgkqhkiG9w0BAQIFADBfMQswCQYD"
+ + "VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGlj"
+ + "IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNOTgwNTEyMDAwMDAwWhcNMDgwNTEy"
+ + "MjM1OTU5WjCBzDEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy"
+ + "dXN0IE5ldHdvcmsxRjBEBgNVBAsTPXd3dy52ZXJpc2lnbi5jb20vcmVwb3NpdG9yeS9SUEEgSW5j"
+ + "b3JwLiBCeSBSZWYuLExJQUIuTFREKGMpOTgxSDBGBgNVBAMTP1ZlcmlTaWduIENsYXNzIDEgQ0Eg"
+ + "SW5kaXZpZHVhbCBTdWJzY3JpYmVyLVBlcnNvbmEgTm90IFZhbGlkYXRlZDCBnzANBgkqhkiG9w0B"
+ + "AQEFAAOBjQAwgYkCgYEAu1pEigQWu1X9A3qKLZRPFXg2uA1Ksm+cVL+86HcqnbnwaLuV2TFBcHqB"
+ + "S7lIE1YtxwjhhEKrwKKSq0RcqkLwgg4C6S/7wju7vsknCl22sDZCM7VuVIhPh0q/Gdr5FegPh7Yc"
+ + "48zGmo5/aiSS4/zgZbqnsX7vyds3ashKyAkG5JkCAwEAAaN8MHowEQYJYIZIAYb4QgEBBAQDAgEG"
+ + "MEcGA1UdIARAMD4wPAYLYIZIAYb4RQEHAQEwLTArBggrBgEFBQcCARYfd3d3LnZlcmlzaWduLmNv"
+ + "bS9yZXBvc2l0b3J5L1JQQTAPBgNVHRMECDAGAQH/AgEAMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0B"
+ + "AQIFAAOBgQCIuDc73dqUNwCtqp/hgQFxHpJqbS/28Z3TymQ43BuYDAeGW4UVag+5SYWklfEXfWe0"
+ + "fy0s3ZpCnsM+tI6q5QsG3vJWKvozx74Z11NMw73I4xe1pElCY+zCphcPXVgaSTyQXFWjZSAA/Rgg"
+ + "5V+CprGoksVYasGNAzzrw80FopCubjCCA/gwggNhoAMCAQICEBbbn/1G1zppD6KsP01bwywwDQYJ"
+ + "KoZIhvcNAQEEBQAwgcwxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln"
+ + "biBUcnVzdCBOZXR3b3JrMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvUlBB"
+ + "IEluY29ycC4gQnkgUmVmLixMSUFCLkxURChjKTk4MUgwRgYDVQQDEz9WZXJpU2lnbiBDbGFzcyAx"
+ + "IENBIEluZGl2aWR1YWwgU3Vic2NyaWJlci1QZXJzb25hIE5vdCBWYWxpZGF0ZWQwHhcNMDAxMDAy"
+ + "MDAwMDAwWhcNMDAxMjAxMjM1OTU5WjCCAQcxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYD"
+ + "VQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3Jl"
+ + "cG9zaXRvcnkvUlBBIEluY29ycC4gYnkgUmVmLixMSUFCLkxURChjKTk4MR4wHAYDVQQLExVQZXJz"
+ + "b25hIE5vdCBWYWxpZGF0ZWQxJzAlBgNVBAsTHkRpZ2l0YWwgSUQgQ2xhc3MgMSAtIE1pY3Jvc29m"
+ + "dDETMBEGA1UEAxQKRGF2aWQgUnlhbjElMCMGCSqGSIb3DQEJARYWZGF2aWRAbGl2ZW1lZGlhLmNv"
+ + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqxBsdeNmSvFqhMNwhQgNzM8mdjX9eSXb"
+ + "DawpHtQHjmh0AKJSa3IwUY0VIsyZHuXWktO/CgaMBVPt6OVf/n0R2sQigMP6Y+PhEiS0vCJBL9aK"
+ + "0+pOo2qXrjVBmq+XuCyPTnc+BOSrU26tJsX0P9BYorwySiEGxGanBNATdVL4NdUCAwEAAaOBnDCB"
+ + "mTAJBgNVHRMEAjAAMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQgwKjAoBggrBgEFBQcCARYcaHR0"
+ + "cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYTARBglghkgBhvhCAQEEBAMCB4AwMwYDVR0fBCwwKjAo"
+ + "oCagJIYiaHR0cDovL2NybC52ZXJpc2lnbi5jb20vY2xhc3MxLmNybDANBgkqhkiG9w0BAQQFAAOB"
+ + "gQBC8yIIdVGpFTf8/YiL14cMzcmL0nIRm4kGR3U59z7UtcXlfNXXJ8MyaeI/BnXwG/gD5OKYqW6R"
+ + "yca9vZOxf1uoTBl82gInk865ED3Tej6msCqFzZffnSUQvOIeqLxxDlqYRQ6PmW2nAnZeyjcnbI5Y"
+ + "syQSM2fmo7n6qJFP+GbFezGCAkUwggJBAgEBMIHhMIHMMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5j"
+ + "LjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazFGMEQGA1UECxM9d3d3LnZlcmlzaWdu"
+ + "LmNvbS9yZXBvc2l0b3J5L1JQQSBJbmNvcnAuIEJ5IFJlZi4sTElBQi5MVEQoYyk5ODFIMEYGA1UE"
+ + "AxM/VmVyaVNpZ24gQ2xhc3MgMSBDQSBJbmRpdmlkdWFsIFN1YnNjcmliZXItUGVyc29uYSBOb3Qg"
+ + "VmFsaWRhdGVkAhAW25/9Rtc6aQ+irD9NW8MsMAkGBSsOAwIaBQCggbowGAYJKoZIhvcNAQkDMQsG"
+ + "CSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMDAxMDAyMTczNTE4WjAjBgkqhkiG9w0BCQQxFgQU"
+ + "gZjSaBEY2oxGvlQUIMnxSXhivK8wWwYJKoZIhvcNAQkPMU4wTDAKBggqhkiG9w0DBzAOBggqhkiG"
+ + "9w0DAgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwBwYFKw4DAh0w"
+ + "DQYJKoZIhvcNAQEBBQAEgYAzk+PU91/ZFfoiuKOECjxEh9fDYE2jfDCheBIgh5gdcCo+sS1WQs8O"
+ + "HreQ9Nop/JdJv1DQMBK6weNBBDoP0EEkRm1XCC144XhXZC82jBZohYmi2WvDbbC//YN58kRMYMyy"
+ + "srrfn4Z9I+6kTriGXkrpGk9Q0LSGjmG2BIsqiF0dvwAAAAAAAA==");
+
+ //
+ // dsaWithSHA1 cert
+ //
+ byte[] cert7 = Base64.decode(
+ "MIIEXAYJKoZIhvcNAQcCoIIETTCCBEkCAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+ + "SIb3DQEHAaCCAsMwggK/MIIB4AIBADCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7"
+ + "d8miwTMN55CUSmo3TO8WGCxgY61TX5k+7NU4XPf1TULjw3GobwaJX13kquPh"
+ + "fVXk+gVy46n4Iw3hAhUBSe/QF4BUj+pJOF9ROBM4u+FEWA8CQQD4mSJbrABj"
+ + "TUWrlnAte8pS22Tq4/FPO7jHSqjijUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/z"
+ + "m8Q12PFp/PjOhh+nMA4xDDAKBgNVBAMTA0lEMzAeFw05NzEwMDEwMDAwMDBa"
+ + "Fw0zODAxMDEwMDAwMDBaMA4xDDAKBgNVBAMTA0lEMzCB8DCBpwYFKw4DAhsw"
+ + "gZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxgY61TX5k+7NU4XPf1TULj"
+ + "w3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/QF4BUj+pJOF9ROBM4u+FE"
+ + "WA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jHSqjijUHfXKTrHL1OEqV3"
+ + "SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nA0QAAkEAkYkXLYMtGVGWj9OnzjPn"
+ + "sB9sefSRPrVegZJCZbpW+Iv0/1RP1u04pHG9vtRpIQLjzUiWvLMU9EKQTThc"
+ + "eNMmWDCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxg"
+ + "Y61TX5k+7NU4XPf1TULjw3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/Q"
+ + "F4BUj+pJOF9ROBM4u+FEWA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jH"
+ + "SqjijUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nAy8AMCwC"
+ + "FBY3dBSdeprGcqpr6wr3xbG+6WW+AhRMm/facKJNxkT3iKgJbp7R8Xd3QTGC"
+ + "AWEwggFdAgEBMBMwDjEMMAoGA1UEAxMDSUQzAgEAMAkGBSsOAwIaBQCgXTAY"
+ + "BgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0wMjA1"
+ + "MjQyMzEzMDdaMCMGCSqGSIb3DQEJBDEWBBS4WMsoJhf7CVbZYCFcjoTRzPkJ"
+ + "xjCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxgY61T"
+ + "X5k+7NU4XPf1TULjw3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/QF4BU"
+ + "j+pJOF9ROBM4u+FEWA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jHSqji"
+ + "jUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nBC8wLQIVALID"
+ + "dt+MHwawrDrwsO1Z6sXBaaJsAhRaKssrpevmLkbygKPV07XiAKBG02Zvb2Jh"
+ + "cg==");
+
+ //
+ // testcrl.pem
+ //
+ byte[] crl1 = Base64.decode(
+ "MIICjTCCAfowDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoT"
+ + "F1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVy"
+ + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5Fw05NTA1MDIwMjEyMjZaFw05NTA2MDEw"
+ + "MDAxNDlaMIIBaDAWAgUCQQAABBcNOTUwMjAxMTcyNDI2WjAWAgUCQQAACRcNOTUw"
+ + "MjEwMDIxNjM5WjAWAgUCQQAADxcNOTUwMjI0MDAxMjQ5WjAWAgUCQQAADBcNOTUw"
+ + "MjI1MDA0NjQ0WjAWAgUCQQAAGxcNOTUwMzEzMTg0MDQ5WjAWAgUCQQAAFhcNOTUw"
+ + "MzE1MTkxNjU0WjAWAgUCQQAAGhcNOTUwMzE1MTk0MDQxWjAWAgUCQQAAHxcNOTUw"
+ + "MzI0MTk0NDMzWjAWAgUCcgAABRcNOTUwMzI5MjAwNzExWjAWAgUCcgAAERcNOTUw"
+ + "MzMwMDIzNDI2WjAWAgUCQQAAIBcNOTUwNDA3MDExMzIxWjAWAgUCcgAAHhcNOTUw"
+ + "NDA4MDAwMjU5WjAWAgUCcgAAQRcNOTUwNDI4MTcxNzI0WjAWAgUCcgAAOBcNOTUw"
+ + "NDI4MTcyNzIxWjAWAgUCcgAATBcNOTUwNTAyMDIxMjI2WjANBgkqhkiG9w0BAQIF"
+ + "AAN+AHqOEJXSDejYy0UwxxrH/9+N2z5xu/if0J6qQmK92W0hW158wpJg+ovV3+wQ"
+ + "wvIEPRL2rocL0tKfAsVq1IawSJzSNgxG0lrcla3MrJBnZ4GaZDu4FutZh72MR3Gt"
+ + "JaAL3iTJHJD55kK2D/VoyY1djlsPuNh6AEgdVwFAyp0v");
+
+ //
+ // ecdsa cert with extra octet string.
+ //
+ byte[] oldEcdsa = Base64.decode(
+ "MIICljCCAkCgAwIBAgIBATALBgcqhkjOPQQBBQAwgY8xCzAJBgNVBAYTAkFVMSgwJ"
+ + "gYDVQQKEx9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIwEAYDVQQHEw"
+ + "lNZWxib3VybmUxETAPBgNVBAgTCFZpY3RvcmlhMS8wLQYJKoZIhvcNAQkBFiBmZWV"
+ + "kYmFjay1jcnlwdG9AYm91bmN5Y2FzdGxlLm9yZzAeFw0wMTEyMDcwMTAwMDRaFw0w"
+ + "MTEyMDcwMTAxNDRaMIGPMQswCQYDVQQGEwJBVTEoMCYGA1UEChMfVGhlIExlZ2lvb"
+ + "iBvZiB0aGUgQm91bmN5IENhc3RsZTESMBAGA1UEBxMJTWVsYm91cm5lMREwDwYDVQ"
+ + "QIEwhWaWN0b3JpYTEvMC0GCSqGSIb3DQEJARYgZmVlZGJhY2stY3J5cHRvQGJvdW5"
+ + "jeWNhc3RsZS5vcmcwgeQwgb0GByqGSM49AgEwgbECAQEwKQYHKoZIzj0BAQIef///"
+ + "////////////f///////gAAAAAAAf///////MEAEHn///////////////3///////"
+ + "4AAAAAAAH///////AQeawFsO9zxiUHQ1lSSFHXKcanbL7J9HTd5YYXClCwKBB8CD/"
+ + "qWPNyogWzMM7hkK+35BcPTWFc9Pyf7vTs8uaqvAh5///////////////9///+eXpq"
+ + "fXZBx+9FSJoiQnQsDIgAEHwJbbcU7xholSP+w9nFHLebJUhqdLSU05lq/y9X+DHAw"
+ + "CwYHKoZIzj0EAQUAA0MAMEACHnz6t4UNoVROp74ma4XNDjjGcjaqiIWPZLK8Bdw3G"
+ + "QIeLZ4j3a6ividZl344UH+UPUE7xJxlYGuy7ejTsqRR");
+
+ byte[] uncompressedPtEC = Base64.decode(
+ "MIIDKzCCAsGgAwIBAgICA+kwCwYHKoZIzj0EAQUAMGYxCzAJBgNVBAYTAkpQ"
+ + "MRUwEwYDVQQKEwxuaXRlY2guYWMuanAxDjAMBgNVBAsTBWFpbGFiMQ8wDQYD"
+ + "VQQDEwZ0ZXN0Y2ExHzAdBgkqhkiG9w0BCQEWEHRlc3RjYUBsb2NhbGhvc3Qw"
+ + "HhcNMDExMDEzMTE1MzE3WhcNMjAxMjEyMTE1MzE3WjBmMQswCQYDVQQGEwJK"
+ + "UDEVMBMGA1UEChMMbml0ZWNoLmFjLmpwMQ4wDAYDVQQLEwVhaWxhYjEPMA0G"
+ + "A1UEAxMGdGVzdGNhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0Y2FAbG9jYWxob3N0"
+ + "MIIBczCCARsGByqGSM49AgEwggEOAgEBMDMGByqGSM49AQECKEdYWnajFmnZ"
+ + "tzrukK2XWdle2v+GsD9l1ZiR6g7ozQDbhFH/bBiMDQcwVAQoJ5EQKrI54/CT"
+ + "xOQ2pMsd/fsXD+EX8YREd8bKHWiLz8lIVdD5cBNeVwQoMKSc6HfI7vKZp8Q2"
+ + "zWgIFOarx1GQoWJbMcSt188xsl30ncJuJT2OoARRBAqJ4fD+q6hbqgNSjTQ7"
+ + "htle1KO3eiaZgcJ8rrnyN8P+5A8+5K+H9aQ/NbBR4Gs7yto5PXIUZEUgodHA"
+ + "TZMSAcSq5ZYt4KbnSYaLY0TtH9CqAigEwZ+hglbT21B7ZTzYX2xj0x+qooJD"
+ + "hVTLtIPaYJK2HrMPxTw6/zfrAgEPA1IABAnvfFcFDgD/JicwBGn6vR3N8MIn"
+ + "mptZf/mnJ1y649uCF60zOgdwIyI7pVSxBFsJ7ohqXEHW0x7LrGVkdSEiipiH"
+ + "LYslqh3xrqbAgPbl93GUo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB"
+ + "/wQEAwIBxjAdBgNVHQ4EFgQUAEo62Xm9H6DcsE0zUDTza4BRG90wCwYHKoZI"
+ + "zj0EAQUAA1cAMFQCKAQsCHHSNOqfJXLgt3bg5+k49hIBGVr/bfG0B9JU3rNt"
+ + "Ycl9Y2zfRPUCKAK2ccOQXByAWfsasDu8zKHxkZv7LVDTFjAIffz3HaCQeVhD"
+ + "z+fauEg=");
+
+ byte[] keyUsage = Base64.decode(
+ "MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UE"
+ + "BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50"
+ + "cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBs"
+ + "aW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExp"
+ + "bWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0"
+ + "aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBa"
+ + "MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNV"
+ + "BAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3Jw"
+ + "LiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50"
+ + "cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50"
+ + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GL"
+ + "ADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSv"
+ + "x1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHV"
+ + "iTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173"
+ + "iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkw"
+ + "ggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50"
+ + "cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0Ff"
+ + "SW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UE"
+ + "CxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50"
+ + "cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYD"
+ + "VQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9D"
+ + "bGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkx"
+ + "MDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW"
+ + "/O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwG"
+ + "A1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI"
+ + "hvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQ"
+ + "OokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkU"
+ + "ODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapE"
+ + "PHayXOw=");
+
+ byte[] nameCert = Base64.decode(
+ "MIIEFjCCA3+gAwIBAgIEdS8BozANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJE"+
+ "RTERMA8GA1UEChQIREFURVYgZUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRQ0Eg"+
+ "REFURVYgRDAzIDE6UE4wIhgPMjAwMTA1MTAxMDIyNDhaGA8yMDA0MDUwOTEwMjI0"+
+ "OFowgYQxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIFAZCYXllcm4xEjAQBgNVBAcUCU7I"+
+ "dXJuYmVyZzERMA8GA1UEChQIREFURVYgZUcxHTAbBgNVBAUTFDAwMDAwMDAwMDA4"+
+ "OTU3NDM2MDAxMR4wHAYDVQQDFBVEaWV0bWFyIFNlbmdlbmxlaXRuZXIwgaEwDQYJ"+
+ "KoZIhvcNAQEBBQADgY8AMIGLAoGBAJLI/LJLKaHoMk8fBECW/od8u5erZi6jI8Ug"+
+ "C0a/LZyQUO/R20vWJs6GrClQtXB+AtfiBSnyZOSYzOdfDI8yEKPEv8qSuUPpOHps"+
+ "uNCFdLZF1vavVYGEEWs2+y+uuPmg8q1oPRyRmUZ+x9HrDvCXJraaDfTEd9olmB/Z"+
+ "AuC/PqpjAgUAwAAAAaOCAcYwggHCMAwGA1UdEwEB/wQCMAAwDwYDVR0PAQH/BAUD"+
+ "AwdAADAxBgNVHSAEKjAoMCYGBSskCAEBMB0wGwYIKwYBBQUHAgEWD3d3dy56cy5k"+
+ "YXRldi5kZTApBgNVHREEIjAggR5kaWV0bWFyLnNlbmdlbmxlaXRuZXJAZGF0ZXYu"+
+ "ZGUwgYQGA1UdIwR9MHuhc6RxMG8xCzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1"+
+ "bGllcnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0"+
+ "MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjVSLUNBIDE6UE6CBACm8LkwDgYHAoIG"+
+ "AQoMAAQDAQEAMEcGA1UdHwRAMD4wPKAUoBKGEHd3dy5jcmwuZGF0ZXYuZGWiJKQi"+
+ "MCAxCzAJBgNVBAYTAkRFMREwDwYDVQQKFAhEQVRFViBlRzAWBgUrJAgDBAQNMAsT"+
+ "A0VVUgIBBQIBATAdBgNVHQ4EFgQUfv6xFP0xk7027folhy+ziZvBJiwwLAYIKwYB"+
+ "BQUHAQEEIDAeMBwGCCsGAQUFBzABhhB3d3cuZGlyLmRhdGV2LmRlMA0GCSqGSIb3"+
+ "DQEBBQUAA4GBAEOVX6uQxbgtKzdgbTi6YLffMftFr2mmNwch7qzpM5gxcynzgVkg"+
+ "pnQcDNlm5AIbS6pO8jTCLfCd5TZ5biQksBErqmesIl3QD+VqtB+RNghxectZ3VEs"+
+ "nCUtcE7tJ8O14qwCb3TxS9dvIUFiVi4DjbxX46TdcTbTaK8/qr6AIf+l");
+
+ byte[] probSelfSignedCert = Base64.decode(
+ "MIICxTCCAi6gAwIBAgIQAQAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQUFADBF"
+ + "MScwJQYDVQQKEx4gRElSRUNUSU9OIEdFTkVSQUxFIERFUyBJTVBPVFMxGjAYBgNV"
+ + "BAMTESBBQyBNSU5FRkkgQiBURVNUMB4XDTA0MDUwNzEyMDAwMFoXDTE0MDUwNzEy"
+ + "MDAwMFowRTEnMCUGA1UEChMeIERJUkVDVElPTiBHRU5FUkFMRSBERVMgSU1QT1RT"
+ + "MRowGAYDVQQDExEgQUMgTUlORUZJIEIgVEVTVDCBnzANBgkqhkiG9w0BAQEFAAOB"
+ + "jQAwgYkCgYEAveoCUOAukZdcFCs2qJk76vSqEX0ZFzHqQ6faBPZWjwkgUNwZ6m6m"
+ + "qWvvyq1cuxhoDvpfC6NXILETawYc6MNwwxsOtVVIjuXlcF17NMejljJafbPximEt"
+ + "DQ4LcQeSp4K7FyFlIAMLyt3BQ77emGzU5fjFTvHSUNb3jblx0sV28c0CAwEAAaOB"
+ + "tTCBsjAfBgNVHSMEGDAWgBSEJ4bLbvEQY8cYMAFKPFD1/fFXlzAdBgNVHQ4EFgQU"
+ + "hCeGy27xEGPHGDABSjxQ9f3xV5cwDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIB"
+ + "AQQEAwIBBjA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vYWRvbmlzLnBrNy5jZXJ0"
+ + "cGx1cy5uZXQvZGdpLXRlc3QuY3JsMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN"
+ + "AQEFBQADgYEAmToHJWjd3+4zknfsP09H6uMbolHNGG0zTS2lrLKpzcmkQfjhQpT9"
+ + "LUTBvfs1jdjo9fGmQLvOG+Sm51Rbjglb8bcikVI5gLbclOlvqLkm77otjl4U4Z2/"
+ + "Y0vP14Aov3Sn3k+17EfReYUZI4liuB95ncobC4e8ZM++LjQcIM0s+Vs=");
+
+
+ byte[] gost34102001base = Base64.decode(
+ "MIIB1DCCAYECEEjpVKXP6Wn1yVz3VeeDQa8wCgYGKoUDAgIDBQAwbTEfMB0G"
+ + "A1UEAwwWR29zdFIzNDEwLTIwMDEgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRv"
+ + "UHJvMQswCQYDVQQGEwJSVTEpMCcGCSqGSIb3DQEJARYaR29zdFIzNDEwLTIw"
+ + "MDFAZXhhbXBsZS5jb20wHhcNMDUwMjAzMTUxNjQ2WhcNMTUwMjAzMTUxNjQ2"
+ + "WjBtMR8wHQYDVQQDDBZHb3N0UjM0MTAtMjAwMSBleGFtcGxlMRIwEAYDVQQK"
+ + "DAlDcnlwdG9Qcm8xCzAJBgNVBAYTAlJVMSkwJwYJKoZIhvcNAQkBFhpHb3N0"
+ + "UjM0MTAtMjAwMUBleGFtcGxlLmNvbTBjMBwGBiqFAwICEzASBgcqhQMCAiQA"
+ + "BgcqhQMCAh4BA0MABECElWh1YAIaQHUIzROMMYks/eUFA3pDXPRtKw/nTzJ+"
+ + "V4/rzBa5lYgD0Jp8ha4P5I3qprt+VsfLsN8PZrzK6hpgMAoGBiqFAwICAwUA"
+ + "A0EAHw5dw/aw/OiNvHyOE65kvyo4Hp0sfz3csM6UUkp10VO247ofNJK3tsLb"
+ + "HOLjUaqzefrlGb11WpHYrvWFg+FcLA==");
+
+ byte[] gost341094base = Base64.decode(
+ "MIICDzCCAbwCEBcxKsIb0ghYvAQeUjfQdFAwCgYGKoUDAgIEBQAwaTEdMBsG"
+ + "A1UEAwwUR29zdFIzNDEwLTk0IGV4YW1wbGUxEjAQBgNVBAoMCUNyeXB0b1By"
+ + "bzELMAkGA1UEBhMCUlUxJzAlBgkqhkiG9w0BCQEWGEdvc3RSMzQxMC05NEBl"
+ + "eGFtcGxlLmNvbTAeFw0wNTAyMDMxNTE2NTFaFw0xNTAyMDMxNTE2NTFaMGkx"
+ + "HTAbBgNVBAMMFEdvc3RSMzQxMC05NCBleGFtcGxlMRIwEAYDVQQKDAlDcnlw"
+ + "dG9Qcm8xCzAJBgNVBAYTAlJVMScwJQYJKoZIhvcNAQkBFhhHb3N0UjM0MTAt"
+ + "OTRAZXhhbXBsZS5jb20wgaUwHAYGKoUDAgIUMBIGByqFAwICIAIGByqFAwIC"
+ + "HgEDgYQABIGAu4Rm4XmeWzTYLIB/E6gZZnFX/oxUJSFHbzALJ3dGmMb7R1W+"
+ + "t7Lzk2w5tUI3JoTiDRCKJA4fDEJNKzsRK6i/ZjkyXJSLwaj+G2MS9gklh8x1"
+ + "G/TliYoJgmjTXHemD7aQEBON4z58nJHWrA0ILD54wbXCtrcaqCqLRYGTMjJ2"
+ + "+nswCgYGKoUDAgIEBQADQQBxKNhOmjgz/i5CEgLOyKyz9pFGkDcaymsWYQWV"
+ + "v7CZ0pTM8IzMzkUBW3GHsUjCFpanFZDfg2zuN+3kT+694n9B");
+
+ byte[] gost341094A = Base64.decode(
+ "MIICSDCCAfWgAwIBAgIBATAKBgYqhQMCAgQFADCBgTEXMBUGA1UEAxMOZGVmYXVsdDM0MTAtOTQx"
+ + "DTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1vbGExDDAKBgNVBAgT"
+ + "A01FTDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAzMjkx"
+ + "MzExNTdaFw0wNjAzMjkxMzExNTdaMIGBMRcwFQYDVQQDEw5kZWZhdWx0MzQxMC05NDENMAsGA1UE"
+ + "ChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLW9sYTEMMAoGA1UECBMDTUVMMQsw"
+ + "CQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MIGlMBwGBiqFAwICFDASBgcq"
+ + "hQMCAiACBgcqhQMCAh4BA4GEAASBgIQACDLEuxSdRDGgdZxHmy30g/DUYkRxO9Mi/uSHX5NjvZ31"
+ + "b7JMEMFqBtyhql1HC5xZfUwZ0aT3UnEFDfFjLP+Bf54gA+LPkQXw4SNNGOj+klnqgKlPvoqMGlwa"
+ + "+hLPKbS561WpvB2XSTgbV+pqqXR3j6j30STmybelEV3RdS2Now8wDTALBgNVHQ8EBAMCB4AwCgYG"
+ + "KoUDAgIEBQADQQBCFy7xWRXtNVXflKvDs0pBdBuPzjCMeZAXVxK8vUxsxxKu76d9CsvhgIFknFRi"
+ + "wWTPiZenvNoJ4R1uzeX+vREm");
+
+ byte[] gost341094B = Base64.decode(
+ "MIICSDCCAfWgAwIBAgIBATAKBgYqhQMCAgQFADCBgTEXMBUGA1UEAxMOcGFyYW0xLTM0MTAtOTQx"
+ + "DTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1PbGExDDAKBgNVBAgT"
+ + "A01lbDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAzMjkx"
+ + "MzEzNTZaFw0wNjAzMjkxMzEzNTZaMIGBMRcwFQYDVQQDEw5wYXJhbTEtMzQxMC05NDENMAsGA1UE"
+ + "ChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLU9sYTEMMAoGA1UECBMDTWVsMQsw"
+ + "CQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MIGlMBwGBiqFAwICFDASBgcq"
+ + "hQMCAiADBgcqhQMCAh4BA4GEAASBgEa+AAcZmijWs1M9x5Pn9efE8D9ztG1NMoIt0/hNZNqln3+j"
+ + "lMZjyqPt+kTLIjtmvz9BRDmIDk6FZz+4LhG2OTL7yGpWfrMxMRr56nxomTN9aLWRqbyWmn3brz9Y"
+ + "AUD3ifnwjjIuW7UM84JNlDTOdxx0XRUfLQIPMCXe9cO02Xskow8wDTALBgNVHQ8EBAMCB4AwCgYG"
+ + "KoUDAgIEBQADQQBzFcnuYc/639OTW+L5Ecjw9KxGr+dwex7lsS9S1BUgKa3m1d5c+cqI0B2XUFi5"
+ + "4iaHHJG0dCyjtQYLJr0OZjRw");
+
+ byte[] gost34102001A = Base64.decode(
+ "MIICCzCCAbigAwIBAgIBATAKBgYqhQMCAgMFADCBhDEaMBgGA1UEAxMRZGVmYXVsdC0zNDEwLTIw"
+ + "MDExDTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1PbGExDDAKBgNV"
+ + "BAgTA01lbDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAz"
+ + "MjkxMzE4MzFaFw0wNjAzMjkxMzE4MzFaMIGEMRowGAYDVQQDExFkZWZhdWx0LTM0MTAtMjAwMTEN"
+ + "MAsGA1UEChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLU9sYTEMMAoGA1UECBMD"
+ + "TWVsMQswCQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MGMwHAYGKoUDAgIT"
+ + "MBIGByqFAwICIwEGByqFAwICHgEDQwAEQG/4c+ZWb10IpeHfmR+vKcbpmSOClJioYmCVgnojw0Xn"
+ + "ned0KTg7TJreRUc+VX7vca4hLQaZ1o/TxVtfEApK/O6jDzANMAsGA1UdDwQEAwIHgDAKBgYqhQMC"
+ + "AgMFAANBAN8y2b6HuIdkD3aWujpfQbS1VIA/7hro4vLgDhjgVmev/PLzFB8oTh3gKhExpDo82IEs"
+ + "ZftGNsbbyp1NFg7zda0=");
+
+ byte[] gostCA1 = Base64.decode(
+ "MIIDNDCCAuGgAwIBAgIQZLcKDcWcQopF+jp4p9jylDAKBgYqhQMCAgQFADBm"
+ + "MQswCQYDVQQGEwJSVTEPMA0GA1UEBxMGTW9zY293MRcwFQYDVQQKEw5PT08g"
+ + "Q3J5cHRvLVBybzEUMBIGA1UECxMLRGV2ZWxvcG1lbnQxFzAVBgNVBAMTDkNQ"
+ + "IENTUCBUZXN0IENBMB4XDTAyMDYwOTE1NTIyM1oXDTA5MDYwOTE1NTkyOVow"
+ + "ZjELMAkGA1UEBhMCUlUxDzANBgNVBAcTBk1vc2NvdzEXMBUGA1UEChMOT09P"
+ + "IENyeXB0by1Qcm8xFDASBgNVBAsTC0RldmVsb3BtZW50MRcwFQYDVQQDEw5D"
+ + "UCBDU1AgVGVzdCBDQTCBpTAcBgYqhQMCAhQwEgYHKoUDAgIgAgYHKoUDAgIe"
+ + "AQOBhAAEgYAYglywKuz1nMc9UiBYOaulKy53jXnrqxZKbCCBSVaJ+aCKbsQm"
+ + "glhRFrw6Mwu8Cdeabo/ojmea7UDMZd0U2xhZFRti5EQ7OP6YpqD0alllo7za"
+ + "4dZNXdX+/ag6fOORSLFdMpVx5ganU0wHMPk67j+audnCPUj/plbeyccgcdcd"
+ + "WaOCASIwggEeMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud"
+ + "DgQWBBTe840gTo4zt2twHilw3PD9wJaX0TCBygYDVR0fBIHCMIG/MDygOqA4"
+ + "hjYtaHR0cDovL2ZpZXdhbGwvQ2VydEVucm9sbC9DUCUyMENTUCUyMFRlc3Ql"
+ + "MjBDQSgzKS5jcmwwRKBCoECGPmh0dHA6Ly93d3cuY3J5cHRvcHJvLnJ1L0Nl"
+ + "cnRFbnJvbGwvQ1AlMjBDU1AlMjBUZXN0JTIwQ0EoMykuY3JsMDmgN6A1hjMt"
+ + "ZmlsZTovL1xcZmlld2FsbFxDZXJ0RW5yb2xsXENQIENTUCBUZXN0IENBKDMp"
+ + "LmNybC8wEgYJKwYBBAGCNxUBBAUCAwMAAzAKBgYqhQMCAgQFAANBAIJi7ni7"
+ + "9rwMR5rRGTFftt2k70GbqyUEfkZYOzrgdOoKiB4IIsIstyBX0/ne6GsL9Xan"
+ + "G2IN96RB7KrowEHeW+k=");
+
+ byte[] gostCA2 = Base64.decode(
+ "MIIC2DCCAoWgAwIBAgIQe9ZCugm42pRKNcHD8466zTAKBgYqhQMCAgMFADB+"
+ + "MRowGAYJKoZIhvcNAQkBFgtzYmFAZGlndC5ydTELMAkGA1UEBhMCUlUxDDAK"
+ + "BgNVBAgTA01FTDEUMBIGA1UEBxMLWW9zaGthci1PbGExDTALBgNVBAoTBERp"
+ + "Z3QxDzANBgNVBAsTBkNyeXB0bzEPMA0GA1UEAxMGc2JhLUNBMB4XDTA0MDgw"
+ + "MzEzMzE1OVoXDTE0MDgwMzEzNDAxMVowfjEaMBgGCSqGSIb3DQEJARYLc2Jh"
+ + "QGRpZ3QucnUxCzAJBgNVBAYTAlJVMQwwCgYDVQQIEwNNRUwxFDASBgNVBAcT"
+ + "C1lvc2hrYXItT2xhMQ0wCwYDVQQKEwREaWd0MQ8wDQYDVQQLEwZDcnlwdG8x"
+ + "DzANBgNVBAMTBnNiYS1DQTBjMBwGBiqFAwICEzASBgcqhQMCAiMBBgcqhQMC"
+ + "Ah4BA0MABEDMSy10CuOH+i8QKG2UWA4XmCt6+BFrNTZQtS6bOalyDY8Lz+G7"
+ + "HybyipE3PqdTB4OIKAAPsEEeZOCZd2UXGQm5o4HaMIHXMBMGCSsGAQQBgjcU"
+ + "AgQGHgQAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud"
+ + "DgQWBBRJJl3LcNMxkZI818STfoi3ng1xoDBxBgNVHR8EajBoMDGgL6Athito"
+ + "dHRwOi8vc2JhLmRpZ3QubG9jYWwvQ2VydEVucm9sbC9zYmEtQ0EuY3JsMDOg"
+ + "MaAvhi1maWxlOi8vXFxzYmEuZGlndC5sb2NhbFxDZXJ0RW5yb2xsXHNiYS1D"
+ + "QS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwCgYGKoUDAgIDBQADQQA+BRJHbc/p"
+ + "q8EYl6iJqXCuR+ozRmH7hPAP3c4KqYSC38TClCgBloLapx/3/WdatctFJW/L"
+ + "mcTovpq088927shE");
+
+ byte[] inDirectCrl = Base64.decode(
+ "MIIdXjCCHMcCAQEwDQYJKoZIhvcNAQEFBQAwdDELMAkGA1UEBhMCREUxHDAaBgNV"
+ +"BAoUE0RldXRzY2hlIFRlbGVrb20gQUcxFzAVBgNVBAsUDlQtVGVsZVNlYyBUZXN0"
+ +"MS4wDAYHAoIGAQoHFBMBMTAeBgNVBAMUF1QtVGVsZVNlYyBUZXN0IERJUiA4OlBO"
+ +"Fw0wNjA4MDQwODQ1MTRaFw0wNjA4MDQxNDQ1MTRaMIIbfzB+AgQvrj/pFw0wMzA3"
+ +"MjIwNTQxMjhaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+ +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+ +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP+oXDTAzMDcyMjA1NDEyOFowZzBlBgNV"
+ +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+ +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+ +"UE4wfgIEL64/5xcNMDQwNDA1MTMxODE3WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+ +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC"
+ +"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/oFw0wNDA0"
+ +"MDUxMzE4MTdaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+ +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+ +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP+UXDTAzMDExMzExMTgxMVowZzBlBgNV"
+ +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+ +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+ +"UE4wfgIEL64/5hcNMDMwMTEzMTExODExWjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+ +"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");
+
+ byte[] directCRL = Base64.decode(
+ "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"
+ +"MQ==");
+
+ private final byte[] pkcs7CrlProblem = Base64.decode(
+ "MIIwSAYJKoZIhvcNAQcCoIIwOTCCMDUCAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+ + "SIb3DQEHAaCCEsAwggP4MIIC4KADAgECAgF1MA0GCSqGSIb3DQEBBQUAMEUx"
+ + "CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR4wHAYDVQQD"
+ + "ExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUwHhcNMDQxMjAyMjEyNTM5WhcNMDYx"
+ + "MjMwMjEyNTM5WjBMMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMR2VvVHJ1c3Qg"
+ + "SW5jMSYwJAYDVQQDEx1HZW9UcnVzdCBBZG9iZSBPQ1NQIFJlc3BvbmRlcjCB"
+ + "nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4gnNYhtw7U6QeVXZODnGhHMj"
+ + "+OgZ0DB393rEk6a2q9kq129IA2e03yKBTfJfQR9aWKc2Qj90dsSqPjvTDHFG"
+ + "Qsagm2FQuhnA3fb1UWhPzeEIdm6bxDsnQ8nWqKqxnWZzELZbdp3I9bBLizIq"
+ + "obZovzt60LNMghn/unvvuhpeVSsCAwEAAaOCAW4wggFqMA4GA1UdDwEB/wQE"
+ + "AwIE8DCB5QYDVR0gAQH/BIHaMIHXMIHUBgkqhkiG9y8BAgEwgcYwgZAGCCsG"
+ + "AQUFBwICMIGDGoGAVGhpcyBjZXJ0aWZpY2F0ZSBoYXMgYmVlbiBpc3N1ZWQg"
+ + "aW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBBY3JvYmF0IENyZWRlbnRpYWxzIENQ"
+ + "UyBsb2NhdGVkIGF0IGh0dHA6Ly93d3cuZ2VvdHJ1c3QuY29tL3Jlc291cmNl"
+ + "cy9jcHMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2VvdHJ1c3QuY29tL3Jl"
+ + "c291cmNlcy9jcHMwEwYDVR0lBAwwCgYIKwYBBQUHAwkwOgYDVR0fBDMwMTAv"
+ + "oC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9hZG9iZWNhMS5j"
+ + "cmwwHwYDVR0jBBgwFoAUq4BZw2WDbR19E70Zw+wajw1HaqMwDQYJKoZIhvcN"
+ + "AQEFBQADggEBAENJf1BD7PX5ivuaawt90q1OGzXpIQL/ClzEeFVmOIxqPc1E"
+ + "TFRq92YuxG5b6+R+k+tGkmCwPLcY8ipg6ZcbJ/AirQhohzjlFuT6YAXsTfEj"
+ + "CqEZfWM2sS7crK2EYxCMmKE3xDfPclYtrAoz7qZvxfQj0TuxHSstHZv39wu2"
+ + "ZiG1BWiEcyDQyTgqTOXBoZmfJtshuAcXmTpgkrYSrS37zNlPTGh+pMYQ0yWD"
+ + "c8OQRJR4OY5ZXfdna01mjtJTOmj6/6XPoLPYTq2gQrc2BCeNJ4bEhLb7sFVB"
+ + "PbwPrpzTE/HRbQHDrzj0YimDxeOUV/UXctgvYwHNtEkcBLsOm/uytMYwggSh"
+ + "MIIDiaADAgECAgQ+HL0oMA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNVBAYTAlVT"
+ + "MSMwIQYDVQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UE"
+ + "CxMUQWRvYmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3Qg"
+ + "Q0EwHhcNMDMwMTA4MjMzNzIzWhcNMjMwMTA5MDAwNzIzWjBpMQswCQYDVQQG"
+ + "EwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQxHTAb"
+ + "BgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYwFAYDVQQDEw1BZG9iZSBS"
+ + "b290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzE9UhPen"
+ + "ouczU38/nBKIayyZR2d+Dx65rRSI+cMQ2B3w8NWfaQovWTWwzGypTJwVoJ/O"
+ + "IL+gz1Ti4CBmRT85hjh+nMSOByLGJPYBErA131XqaZCw24U3HuJOB7JCoWoT"
+ + "aaBm6oCREVkqmwh5WiBELcm9cziLPC/gQxtdswvwrzUaKf7vppLdgUydPVmO"
+ + "rTE8QH6bkTYG/OJcjdGNJtVcRc+vZT+xqtJilvSoOOq6YEL09BxKNRXO+E4i"
+ + "Vg+VGMX4lp+f+7C3eCXpgGu91grwxnSUnfMPUNuad85LcIMjjaDKeCBEXDxU"
+ + "ZPHqojAZn+pMBk0GeEtekt8i0slns3rSAQIDAQABo4IBTzCCAUswEQYJYIZI"
+ + "AYb4QgEBBAQDAgAHMIGOBgNVHR8EgYYwgYMwgYCgfqB8pHoweDELMAkGA1UE"
+ + "BhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMgSW5jb3Jwb3JhdGVkMR0w"
+ + "GwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEWMBQGA1UEAxMNQWRvYmUg"
+ + "Um9vdCBDQTENMAsGA1UEAxMEQ1JMMTArBgNVHRAEJDAigA8yMDAzMDEwODIz"
+ + "MzcyM1qBDzIwMjMwMTA5MDAwNzIzWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgw"
+ + "FoAUgrc4SpOqmxDvgLvZVOLxD/uAnN4wHQYDVR0OBBYEFIK3OEqTqpsQ74C7"
+ + "2VTi8Q/7gJzeMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjYu"
+ + "MDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQAy2p9DdcH6b8lv26sdNjc+"
+ + "vGEZNrcCPB0jWZhsnu5NhedUyCAfp9S74r8Ad30ka3AvXME6dkm10+AjhCpx"
+ + "aiLzwScpmBX2NZDkBEzDjbyfYRzn/SSM0URDjBa6m02l1DUvvBHOvfdRN42f"
+ + "kOQU8Rg/vulZEjX5M5LznuDVa5pxm5lLyHHD4bFhCcTl+pHwQjo3fTT5cujN"
+ + "qmIcIenV9IIQ43sFti1oVgt+fpIsb01yggztVnSynbmrLSsdEF/bJ3Vwj/0d"
+ + "1+ICoHnlHOX/r2RAUS2em0fbQqV8H8KmSLDXvpJpTaT2KVfFeBEY3IdRyhOy"
+ + "Yp1PKzK9MaXB+lKrBYjIMIIEyzCCA7OgAwIBAgIEPhy9tTANBgkqhkiG9w0B"
+ + "AQUFADBpMQswCQYDVQQGEwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJ"
+ + "bmNvcnBvcmF0ZWQxHTAbBgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYw"
+ + "FAYDVQQDEw1BZG9iZSBSb290IENBMB4XDTA0MDExNzAwMDMzOVoXDTE1MDEx"
+ + "NTA4MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu"
+ + "Yy4xHjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTCCASIwDQYJKoZI"
+ + "hvcNAQEBBQADggEPADCCAQoCggEBAKfld+BkeFrnOYW8r9L1WygTDlTdSfrO"
+ + "YvWS/Z6Ye5/l+HrBbOHqQCXBcSeCpz7kB2WdKMh1FOE4e9JlmICsHerBLdWk"
+ + "emU+/PDb69zh8E0cLoDfxukF6oVPXj6WSThdSG7H9aXFzRr6S3XGCuvgl+Qw"
+ + "DTLiLYW+ONF6DXwt3TQQtKReJjOJZk46ZZ0BvMStKyBaeB6DKZsmiIo89qso"
+ + "13VDZINH2w1KvXg0ygDizoNtbvgAPFymwnsINS1klfQlcvn0x0RJm9bYQXK3"
+ + "5GNZAgL3M7Lqrld0jMfIUaWvuHCLyivytRuzq1dJ7E8rmidjDEk/G+27pf13"
+ + "fNZ7vR7M+IkCAwEAAaOCAZ0wggGZMBIGA1UdEwEB/wQIMAYBAf8CAQEwUAYD"
+ + "VR0gBEkwRzBFBgkqhkiG9y8BAgEwODA2BggrBgEFBQcCARYqaHR0cHM6Ly93"
+ + "d3cuYWRvYmUuY29tL21pc2MvcGtpL2Nkc19jcC5odG1sMBQGA1UdJQQNMAsG"
+ + "CSqGSIb3LwEBBTCBsgYDVR0fBIGqMIGnMCKgIKAehhxodHRwOi8vY3JsLmFk"
+ + "b2JlLmNvbS9jZHMuY3JsMIGAoH6gfKR6MHgxCzAJBgNVBAYTAlVTMSMwIQYD"
+ + "VQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRv"
+ + "YmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0ExDTAL"
+ + "BgNVBAMTBENSTDEwCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFIK3OEqTqpsQ"
+ + "74C72VTi8Q/7gJzeMB0GA1UdDgQWBBSrgFnDZYNtHX0TvRnD7BqPDUdqozAZ"
+ + "BgkqhkiG9n0HQQAEDDAKGwRWNi4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA"
+ + "PzlZLqIAjrFeEWEs0uC29YyJhkXOE9mf3YSaFGsITF+Gl1j0pajTjyH4R35Q"
+ + "r3floW2q3HfNzTeZ90Jnr1DhVERD6zEMgJpCtJqVuk0sixuXJHghS/KicKf4"
+ + "YXJJPx9epuIRF1siBRnznnF90svmOJMXApc0jGnYn3nQfk4kaShSnDaYaeYR"
+ + "DJKcsiWhl6S5zfwS7Gg8hDeyckhMQKKWnlG1CQrwlSFisKCduoodwRtWgft8"
+ + "kx13iyKK3sbalm6vnVc+5nufS4vI+TwMXoV63NqYaSroafBWk0nL53zGXPEy"
+ + "+A69QhzEViJKn2Wgqt5gt++jMMNImbRObIqgfgF1VjCCBUwwggQ0oAMCAQIC"
+ + "AgGDMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1H"
+ + "ZW9UcnVzdCBJbmMuMR4wHAYDVQQDExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUw"
+ + "HhcNMDYwMzI0MTU0MjI5WhcNMDkwNDA2MTQ0MjI5WjBzMQswCQYDVQQGEwJV"
+ + "UzELMAkGA1UECBMCTUExETAPBgNVBAoTCEdlb1RydXN0MR0wGwYDVQQDExRN"
+ + "YXJrZXRpbmcgRGVwYXJ0bWVudDElMCMGCSqGSIb3DQEJARYWbWFya2V0aW5n"
+ + "QGdlb3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB"
+ + "ANmvajTO4XJvAU2nVcLmXeCnAQX7RZt+7+ML3InmqQ3LCGo1weop09zV069/"
+ + "1x/Nmieol7laEzeXxd2ghjGzwfXafqQEqHn6+vBCvqdNPoSi63fSWhnuDVWp"
+ + "KVDOYgxOonrXl+Cc43lu4zRSq+Pi5phhrjDWcH74a3/rdljUt4c4GFezFXfa"
+ + "w2oTzWkxj2cTSn0Szhpr17+p66UNt8uknlhmu4q44Speqql2HwmCEnpLYJrK"
+ + "W3fOq5D4qdsvsLR2EABLhrBezamLI3iGV8cRHOUTsbTMhWhv/lKfHAyf4XjA"
+ + "z9orzvPN5jthhIfICOFq/nStTgakyL4Ln+nFAB/SMPkCAwEAAaOCAhYwggIS"
+ + "MA4GA1UdDwEB/wQEAwIF4DCB5QYDVR0gAQH/BIHaMIHXMIHUBgkqhkiG9y8B"
+ + "AgEwgcYwgZAGCCsGAQUFBwICMIGDGoGAVGhpcyBjZXJ0aWZpY2F0ZSBoYXMg"
+ + "YmVlbiBpc3N1ZWQgaW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBBY3JvYmF0IENy"
+ + "ZWRlbnRpYWxzIENQUyBsb2NhdGVkIGF0IGh0dHA6Ly93d3cuZ2VvdHJ1c3Qu"
+ + "Y29tL3Jlc291cmNlcy9jcHMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2Vv"
+ + "dHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwOgYDVR0fBDMwMTAvoC2gK4YpaHR0"
+ + "cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9hZG9iZWNhMS5jcmwwHwYDVR0j"
+ + "BBgwFoAUq4BZw2WDbR19E70Zw+wajw1HaqMwRAYIKwYBBQUHAQEEODA2MDQG"
+ + "CCsGAQUFBzABhihodHRwOi8vYWRvYmUtb2NzcC5nZW90cnVzdC5jb20vcmVz"
+ + "cG9uZGVyMBQGA1UdJQQNMAsGCSqGSIb3LwEBBTA8BgoqhkiG9y8BAQkBBC4w"
+ + "LAIBAYYnaHR0cDovL2Fkb2JlLXRpbWVzdGFtcC5nZW90cnVzdC5jb20vdHNh"
+ + "MBMGCiqGSIb3LwEBCQIEBTADAgEBMAwGA1UdEwQFMAMCAQAwDQYJKoZIhvcN"
+ + "AQEFBQADggEBAAOhy6QxOo+i3h877fvDvTa0plGD2bIqK7wMdNqbMDoSWied"
+ + "FIcgcBOIm2wLxOjZBAVj/3lDq59q2rnVeNnfXM0/N0MHI9TumHRjU7WNk9e4"
+ + "+JfJ4M+c3anrWOG3NE5cICDVgles+UHjXetHWql/LlP04+K2ZOLb6LE2xGnI"
+ + "YyLW9REzCYNAVF+/WkYdmyceHtaBZdbyVAJq0NAJPsfgY1pWcBo31Mr1fpX9"
+ + "WrXNTYDCqMyxMImJTmN3iI68tkXlNrhweQoArKFqBysiBkXzG/sGKYY6tWKU"
+ + "pzjLc3vIp/LrXC5zilROes8BSvwu1w9qQrJNcGwo7O4uijoNtyYil1Exgh1Q"
+ + "MIIdTAIBATBLMEUxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJ"
+ + "bmMuMR4wHAYDVQQDExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUCAgGDMAkGBSsO"
+ + "AwIaBQCgggxMMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwIwYJKoZIhvcN"
+ + "AQkEMRYEFP4R6qIdpQJzWyzrqO8X1ZfJOgChMIIMCQYJKoZIhvcvAQEIMYIL"
+ + "+jCCC/agggZ5MIIGdTCCA6gwggKQMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV"
+ + "BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR4wHAYDVQQDExVHZW9U"
+ + "cnVzdCBDQSBmb3IgQWRvYmUXDTA2MDQwNDE3NDAxMFoXDTA2MDQwNTE3NDAx"
+ + "MFowggIYMBMCAgC5Fw0wNTEwMTEyMDM2MzJaMBICAVsXDTA0MTEwNDE1MDk0"
+ + "MVowEwICALgXDTA1MTIxMjIyMzgzOFowEgIBWhcNMDQxMTA0MTUwOTMzWjAT"
+ + "AgIA5hcNMDUwODI3MDQwOTM4WjATAgIAtxcNMDYwMTE2MTc1NTEzWjATAgIA"
+ + "hhcNMDUxMjEyMjIzODU1WjATAgIAtRcNMDUwNzA2MTgzODQwWjATAgIA4BcN"
+ + "MDYwMzIwMDc0ODM0WjATAgIAgRcNMDUwODAyMjIzMTE1WjATAgIA3xcNMDUx"
+ + "MjEyMjIzNjUwWjASAgFKFw0wNDExMDQxNTA5MTZaMBICAUQXDTA0MTEwNDE1"
+ + "MDg1M1owEgIBQxcNMDQxMDAzMDEwMDQwWjASAgFsFw0wNDEyMDYxOTQ0MzFa"
+ + "MBMCAgEoFw0wNjAzMDkxMjA3MTJaMBMCAgEkFw0wNjAxMTYxNzU1MzRaMBIC"
+ + "AWcXDTA1MDMxODE3NTYxNFowEwICAVEXDTA2MDEzMTExMjcxMVowEgIBZBcN"
+ + "MDQxMTExMjI0ODQxWjATAgIA8RcNMDUwOTE2MTg0ODAxWjATAgIBThcNMDYw"
+ + "MjIxMjAxMDM2WjATAgIAwRcNMDUxMjEyMjIzODE2WjASAgFiFw0wNTAxMTAx"
+ + "NjE5MzRaMBICAWAXDTA1MDExMDE5MDAwNFowEwICAL4XDTA1MDUxNzE0NTYx"
+ + "MFowDQYJKoZIhvcNAQEFBQADggEBAEKhRMS3wVho1U3EvEQJZC8+JlUngmZQ"
+ + "A78KQbHPWNZWFlNvPuf/b0s7Lu16GfNHXh1QAW6Y5Hi1YtYZ3YOPyMd4Xugt"
+ + "gCdumbB6xtKsDyN5RvTht6ByXj+CYlYqsL7RX0izJZ6mJn4fjMkqzPKNOjb8"
+ + "kSn5T6rn93BjlATtCE8tPVOM8dnqGccRE0OV59+nDBXc90UMt5LdEbwaUOap"
+ + "snVB0oLcNm8d/HnlVH6RY5LnDjrT4vwfe/FApZtTecEWsllVUXDjSpwfcfD/"
+ + "476/lpGySB2otALqzImlA9R8Ok3hJ8dnF6hhQ5Oe6OJMnGYgdhkKbxsKkdib"
+ + "tTVl3qmH5QAwggLFMIIBrQIBATANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQG"
+ + "EwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQxHTAb"
+ + "BgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYwFAYDVQQDEw1BZG9iZSBS"
+ + "b290IENBFw0wNjAxMjcxODMzMzFaFw0wNzAxMjcwMDAwMDBaMIHeMCMCBD4c"
+ + "vUAXDTAzMDEyMTIzNDY1NlowDDAKBgNVHRUEAwoBBDAjAgQ+HL1BFw0wMzAx"
+ + "MjEyMzQ3MjJaMAwwCgYDVR0VBAMKAQQwIwIEPhy9YhcNMDMwMTIxMjM0NzQy"
+ + "WjAMMAoGA1UdFQQDCgEEMCMCBD4cvWEXDTA0MDExNzAxMDg0OFowDDAKBgNV"
+ + "HRUEAwoBBDAjAgQ+HL2qFw0wNDAxMTcwMTA5MDVaMAwwCgYDVR0VBAMKAQQw"
+ + "IwIEPhy9qBcNMDQwMTE3MDEzOTI5WjAMMAoGA1UdFQQDCgEEoC8wLTAKBgNV"
+ + "HRQEAwIBDzAfBgNVHSMEGDAWgBSCtzhKk6qbEO+Au9lU4vEP+4Cc3jANBgkq"
+ + "hkiG9w0BAQUFAAOCAQEAwtXF9042wG39icUlsotn5tpE3oCusLb/hBpEONhx"
+ + "OdfEQOq0w5hf/vqaxkcf71etA+KpbEUeSVaHMHRPhx/CmPrO9odE139dJdbt"
+ + "9iqbrC9iZokFK3h/es5kg73xujLKd7C/u5ngJ4mwBtvhMLjFjF2vJhPKHL4C"
+ + "IgMwdaUAhrcNzy16v+mw/VGJy3Fvc6oCESW1K9tvFW58qZSNXrMlsuidgunM"
+ + "hPKG+z0SXVyCqL7pnqKiaGddcgujYGOSY4S938oVcfZeZQEODtSYGlzldojX"
+ + "C1U1hCK5+tHAH0Ox/WqRBIol5VCZQwJftf44oG8oviYq52aaqSejXwmfT6zb"
+ + "76GCBXUwggVxMIIFbQoBAKCCBWYwggViBgkrBgEFBQcwAQEEggVTMIIFTzCB"
+ + "taIWBBS+8EpykfXdl4h3z7m/NZfdkAQQERgPMjAwNjA0MDQyMDIwMTVaMGUw"
+ + "YzA7MAkGBSsOAwIaBQAEFEb4BuZYkbjBjOjT6VeA/00fBvQaBBT3fTSQniOp"
+ + "BbHBSkz4xridlX0bsAICAYOAABgPMjAwNjA0MDQyMDIwMTVaoBEYDzIwMDYw"
+ + "NDA1MDgyMDE1WqEjMCEwHwYJKwYBBQUHMAECBBIEEFqooq/R2WltD7TposkT"
+ + "BhMwDQYJKoZIhvcNAQEFBQADgYEAMig6lty4b0JDsT/oanfQG5x6jVKPACpp"
+ + "1UA9SJ0apJJa7LeIdDFmu5C2S/CYiKZm4A4P9cAu0YzgLHxE4r6Op+HfVlAG"
+ + "6bzUe1P/hi1KCJ8r8wxOZAktQFPSzs85RAZwkHMfB0lP2e/h666Oye+Zf8VH"
+ + "RaE+/xZ7aswE89HXoumgggQAMIID/DCCA/gwggLgoAMCAQICAXUwDQYJKoZI"
+ + "hvcNAQEFBQAwRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu"
+ + "Yy4xHjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTAeFw0wNDEyMDIy"
+ + "MTI1MzlaFw0wNjEyMzAyMTI1MzlaMEwxCzAJBgNVBAYTAlVTMRUwEwYDVQQK"
+ + "EwxHZW9UcnVzdCBJbmMxJjAkBgNVBAMTHUdlb1RydXN0IEFkb2JlIE9DU1Ag"
+ + "UmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDiCc1iG3Dt"
+ + "TpB5Vdk4OcaEcyP46BnQMHf3esSTprar2SrXb0gDZ7TfIoFN8l9BH1pYpzZC"
+ + "P3R2xKo+O9MMcUZCxqCbYVC6GcDd9vVRaE/N4Qh2bpvEOydDydaoqrGdZnMQ"
+ + "tlt2ncj1sEuLMiqhtmi/O3rQs0yCGf+6e++6Gl5VKwIDAQABo4IBbjCCAWow"
+ + "DgYDVR0PAQH/BAQDAgTwMIHlBgNVHSABAf8EgdowgdcwgdQGCSqGSIb3LwEC"
+ + "ATCBxjCBkAYIKwYBBQUHAgIwgYMagYBUaGlzIGNlcnRpZmljYXRlIGhhcyBi"
+ + "ZWVuIGlzc3VlZCBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIEFjcm9iYXQgQ3Jl"
+ + "ZGVudGlhbHMgQ1BTIGxvY2F0ZWQgYXQgaHR0cDovL3d3dy5nZW90cnVzdC5j"
+ + "b20vcmVzb3VyY2VzL2NwczAxBggrBgEFBQcCARYlaHR0cDovL3d3dy5nZW90"
+ + "cnVzdC5jb20vcmVzb3VyY2VzL2NwczATBgNVHSUEDDAKBggrBgEFBQcDCTA6"
+ + "BgNVHR8EMzAxMC+gLaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxz"
+ + "L2Fkb2JlY2ExLmNybDAfBgNVHSMEGDAWgBSrgFnDZYNtHX0TvRnD7BqPDUdq"
+ + "ozANBgkqhkiG9w0BAQUFAAOCAQEAQ0l/UEPs9fmK+5prC33SrU4bNekhAv8K"
+ + "XMR4VWY4jGo9zURMVGr3Zi7Eblvr5H6T60aSYLA8txjyKmDplxsn8CKtCGiH"
+ + "OOUW5PpgBexN8SMKoRl9YzaxLtysrYRjEIyYoTfEN89yVi2sCjPupm/F9CPR"
+ + "O7EdKy0dm/f3C7ZmIbUFaIRzINDJOCpM5cGhmZ8m2yG4BxeZOmCSthKtLfvM"
+ + "2U9MaH6kxhDTJYNzw5BElHg5jlld92drTWaO0lM6aPr/pc+gs9hOraBCtzYE"
+ + "J40nhsSEtvuwVUE9vA+unNMT8dFtAcOvOPRiKYPF45RX9Rdy2C9jAc20SRwE"
+ + "uw6b+7K0xjANBgkqhkiG9w0BAQEFAASCAQC7a4yICFGCEMPlJbydK5qLG3rV"
+ + "sip7Ojjz9TB4nLhC2DgsIHds8jjdq2zguInluH2nLaBCVS+qxDVlTjgbI2cB"
+ + "TaWS8nglC7nNjzkKAsa8vThA8FZUVXTW0pb74jNJJU2AA27bb4g+4WgunCrj"
+ + "fpYp+QjDyMmdrJVqRmt5eQN+dpVxMS9oq+NrhOSEhyIb4/rejgNg9wnVK1ms"
+ + "l5PxQ4x7kpm7+Ua41//owkJVWykRo4T1jo4eHEz1DolPykAaKie2VKH/sMqR"
+ + "Spjh4E5biKJLOV9fKivZWKAXByXfwUbbMsJvz4v/2yVHFy9xP+tqB5ZbRoDK"
+ + "k8PzUyCprozn+/22oYIPijCCD4YGCyqGSIb3DQEJEAIOMYIPdTCCD3EGCSqG"
+ + "SIb3DQEHAqCCD2Iwgg9eAgEDMQswCQYFKw4DAhoFADCB+gYLKoZIhvcNAQkQ"
+ + "AQSggeoEgecwgeQCAQEGAikCMCEwCQYFKw4DAhoFAAQUoT97qeCv3FXYaEcS"
+ + "gY8patCaCA8CAiMHGA8yMDA2MDQwNDIwMjA1N1owAwIBPAEB/wIIO0yRre3L"
+ + "8/6ggZCkgY0wgYoxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNl"
+ + "dHRzMRAwDgYDVQQHEwdOZWVkaGFtMRUwEwYDVQQKEwxHZW9UcnVzdCBJbmMx"
+ + "EzARBgNVBAsTClByb2R1Y3Rpb24xJTAjBgNVBAMTHGFkb2JlLXRpbWVzdGFt"
+ + "cC5nZW90cnVzdC5jb22gggzJMIIDUTCCAjmgAwIBAgICAI8wDQYJKoZIhvcN"
+ + "AQEFBQAwRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4x"
+ + "HjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTAeFw0wNTAxMTAwMTI5"
+ + "MTBaFw0xNTAxMTUwODAwMDBaMIGKMQswCQYDVQQGEwJVUzEWMBQGA1UECBMN"
+ + "TWFzc2FjaHVzZXR0czEQMA4GA1UEBxMHTmVlZGhhbTEVMBMGA1UEChMMR2Vv"
+ + "VHJ1c3QgSW5jMRMwEQYDVQQLEwpQcm9kdWN0aW9uMSUwIwYDVQQDExxhZG9i"
+ + "ZS10aW1lc3RhbXAuZ2VvdHJ1c3QuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GN"
+ + "ADCBiQKBgQDRbxJotLFPWQuuEDhKtOMaBUJepGxIvWxeahMbq1DVmqnk88+j"
+ + "w/5lfPICPzQZ1oHrcTLSAFM7Mrz3pyyQKQKMqUyiemzuG/77ESUNfBNSUfAF"
+ + "PdtHuDMU8Is8ABVnFk63L+wdlvvDIlKkE08+VTKCRdjmuBVltMpQ6QcLFQzm"
+ + "AQIDAQABo4GIMIGFMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly9jcmwuZ2Vv"
+ + "dHJ1c3QuY29tL2NybHMvYWRvYmVjYTEuY3JsMB8GA1UdIwQYMBaAFKuAWcNl"
+ + "g20dfRO9GcPsGo8NR2qjMA4GA1UdDwEB/wQEAwIGwDAWBgNVHSUBAf8EDDAK"
+ + "BggrBgEFBQcDCDANBgkqhkiG9w0BAQUFAAOCAQEAmnyXjdtX+F79Nf0KggTd"
+ + "6YC2MQD9s09IeXTd8TP3rBmizfM+7f3icggeCGakNfPRmIUMLoa0VM5Kt37T"
+ + "2X0TqzBWusfbKx7HnX4v1t/G8NJJlT4SShSHv+8bjjU4lUoCmW2oEcC5vXwP"
+ + "R5JfjCyois16npgcO05ZBT+LLDXyeBijE6qWmwLDfEpLyILzVRmyU4IE7jvm"
+ + "rgb3GXwDUvd3yQXGRRHbPCh3nj9hBGbuzyt7GnlqnEie3wzIyMG2ET/wvTX5"
+ + "4BFXKNe7lDLvZj/MXvd3V7gMTSVW0kAszKao56LfrVTgp1VX3UBQYwmQqaoA"
+ + "UwFezih+jEvjW6cYJo/ErDCCBKEwggOJoAMCAQICBD4cvSgwDQYJKoZIhvcN"
+ + "AQEFBQAwaTELMAkGA1UEBhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMg"
+ + "SW5jb3Jwb3JhdGVkMR0wGwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEW"
+ + "MBQGA1UEAxMNQWRvYmUgUm9vdCBDQTAeFw0wMzAxMDgyMzM3MjNaFw0yMzAx"
+ + "MDkwMDA3MjNaMGkxCzAJBgNVBAYTAlVTMSMwIQYDVQQKExpBZG9iZSBTeXN0"
+ + "ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRvYmUgVHJ1c3QgU2Vydmlj"
+ + "ZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUA"
+ + "A4IBDwAwggEKAoIBAQDMT1SE96ei5zNTfz+cEohrLJlHZ34PHrmtFIj5wxDY"
+ + "HfDw1Z9pCi9ZNbDMbKlMnBWgn84gv6DPVOLgIGZFPzmGOH6cxI4HIsYk9gES"
+ + "sDXfVeppkLDbhTce4k4HskKhahNpoGbqgJERWSqbCHlaIEQtyb1zOIs8L+BD"
+ + "G12zC/CvNRop/u+mkt2BTJ09WY6tMTxAfpuRNgb84lyN0Y0m1VxFz69lP7Gq"
+ + "0mKW9Kg46rpgQvT0HEo1Fc74TiJWD5UYxfiWn5/7sLd4JemAa73WCvDGdJSd"
+ + "8w9Q25p3zktwgyONoMp4IERcPFRk8eqiMBmf6kwGTQZ4S16S3yLSyWezetIB"
+ + "AgMBAAGjggFPMIIBSzARBglghkgBhvhCAQEEBAMCAAcwgY4GA1UdHwSBhjCB"
+ + "gzCBgKB+oHykejB4MQswCQYDVQQGEwJVUzEjMCEGA1UEChMaQWRvYmUgU3lz"
+ + "dGVtcyBJbmNvcnBvcmF0ZWQxHTAbBgNVBAsTFEFkb2JlIFRydXN0IFNlcnZp"
+ + "Y2VzMRYwFAYDVQQDEw1BZG9iZSBSb290IENBMQ0wCwYDVQQDEwRDUkwxMCsG"
+ + "A1UdEAQkMCKADzIwMDMwMTA4MjMzNzIzWoEPMjAyMzAxMDkwMDA3MjNaMAsG"
+ + "A1UdDwQEAwIBBjAfBgNVHSMEGDAWgBSCtzhKk6qbEO+Au9lU4vEP+4Cc3jAd"
+ + "BgNVHQ4EFgQUgrc4SpOqmxDvgLvZVOLxD/uAnN4wDAYDVR0TBAUwAwEB/zAd"
+ + "BgkqhkiG9n0HQQAEEDAOGwhWNi4wOjQuMAMCBJAwDQYJKoZIhvcNAQEFBQAD"
+ + "ggEBADLan0N1wfpvyW/bqx02Nz68YRk2twI8HSNZmGye7k2F51TIIB+n1Lvi"
+ + "vwB3fSRrcC9cwTp2SbXT4COEKnFqIvPBJymYFfY1kOQETMONvJ9hHOf9JIzR"
+ + "REOMFrqbTaXUNS+8Ec6991E3jZ+Q5BTxGD++6VkSNfkzkvOe4NVrmnGbmUvI"
+ + "ccPhsWEJxOX6kfBCOjd9NPly6M2qYhwh6dX0ghDjewW2LWhWC35+kixvTXKC"
+ + "DO1WdLKduastKx0QX9sndXCP/R3X4gKgeeUc5f+vZEBRLZ6bR9tCpXwfwqZI"
+ + "sNe+kmlNpPYpV8V4ERjch1HKE7JinU8rMr0xpcH6UqsFiMgwggTLMIIDs6AD"
+ + "AgECAgQ+HL21MA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNVBAYTAlVTMSMwIQYD"
+ + "VQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRv"
+ + "YmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0EwHhcN"
+ + "MDQwMTE3MDAwMzM5WhcNMTUwMTE1MDgwMDAwWjBFMQswCQYDVQQGEwJVUzEW"
+ + "MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgQ0Eg"
+ + "Zm9yIEFkb2JlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+V3"
+ + "4GR4Wuc5hbyv0vVbKBMOVN1J+s5i9ZL9nph7n+X4esFs4epAJcFxJ4KnPuQH"
+ + "ZZ0oyHUU4Th70mWYgKwd6sEt1aR6ZT788Nvr3OHwTRwugN/G6QXqhU9ePpZJ"
+ + "OF1Ibsf1pcXNGvpLdcYK6+CX5DANMuIthb440XoNfC3dNBC0pF4mM4lmTjpl"
+ + "nQG8xK0rIFp4HoMpmyaIijz2qyjXdUNkg0fbDUq9eDTKAOLOg21u+AA8XKbC"
+ + "ewg1LWSV9CVy+fTHREmb1thBcrfkY1kCAvczsuquV3SMx8hRpa+4cIvKK/K1"
+ + "G7OrV0nsTyuaJ2MMST8b7bul/Xd81nu9Hsz4iQIDAQABo4IBnTCCAZkwEgYD"
+ + "VR0TAQH/BAgwBgEB/wIBATBQBgNVHSAESTBHMEUGCSqGSIb3LwECATA4MDYG"
+ + "CCsGAQUFBwIBFipodHRwczovL3d3dy5hZG9iZS5jb20vbWlzYy9wa2kvY2Rz"
+ + "X2NwLmh0bWwwFAYDVR0lBA0wCwYJKoZIhvcvAQEFMIGyBgNVHR8Egaowgacw"
+ + "IqAgoB6GHGh0dHA6Ly9jcmwuYWRvYmUuY29tL2Nkcy5jcmwwgYCgfqB8pHow"
+ + "eDELMAkGA1UEBhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMgSW5jb3Jw"
+ + "b3JhdGVkMR0wGwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEWMBQGA1UE"
+ + "AxMNQWRvYmUgUm9vdCBDQTENMAsGA1UEAxMEQ1JMMTALBgNVHQ8EBAMCAQYw"
+ + "HwYDVR0jBBgwFoAUgrc4SpOqmxDvgLvZVOLxD/uAnN4wHQYDVR0OBBYEFKuA"
+ + "WcNlg20dfRO9GcPsGo8NR2qjMBkGCSqGSIb2fQdBAAQMMAobBFY2LjADAgSQ"
+ + "MA0GCSqGSIb3DQEBBQUAA4IBAQA/OVkuogCOsV4RYSzS4Lb1jImGRc4T2Z/d"
+ + "hJoUawhMX4aXWPSlqNOPIfhHflCvd+Whbarcd83NN5n3QmevUOFUREPrMQyA"
+ + "mkK0mpW6TSyLG5ckeCFL8qJwp/hhckk/H16m4hEXWyIFGfOecX3Sy+Y4kxcC"
+ + "lzSMadifedB+TiRpKFKcNphp5hEMkpyyJaGXpLnN/BLsaDyEN7JySExAopae"
+ + "UbUJCvCVIWKwoJ26ih3BG1aB+3yTHXeLIorextqWbq+dVz7me59Li8j5PAxe"
+ + "hXrc2phpKuhp8FaTScvnfMZc8TL4Dr1CHMRWIkqfZaCq3mC376Mww0iZtE5s"
+ + "iqB+AXVWMYIBgDCCAXwCAQEwSzBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN"
+ + "R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgQ0EgZm9yIEFkb2Jl"
+ + "AgIAjzAJBgUrDgMCGgUAoIGMMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRAB"
+ + "BDAcBgkqhkiG9w0BCQUxDxcNMDYwNDA0MjAyMDU3WjAjBgkqhkiG9w0BCQQx"
+ + "FgQUp7AnXBqoNcarvO7fMJut1og2U5AwKwYLKoZIhvcNAQkQAgwxHDAaMBgw"
+ + "FgQU1dH4eZTNhgxdiSABrat6zsPdth0wDQYJKoZIhvcNAQEBBQAEgYCinr/F"
+ + "rMiQz/MRm9ZD5YGcC0Qo2dRTPd0Aop8mZ4g1xAhKFLnp7lLsjCbkSDpVLDBh"
+ + "cnCk7CV+3FT5hlvt8OqZlR0CnkSnCswLFhrppiWle6cpxlwGqyAteC8uKtQu"
+ + "wjE5GtBKLcCOAzQYyyuNZZeB6oCZ+3mPhZ62FxrvvEGJCgAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==");
+
+ private final byte[] emptyDNCert = Base64.decode(
+ "MIICfTCCAeagAwIBAgIBajANBgkqhkiG9w0BAQQFADB8MQswCQYDVQQGEwJVUzEMMAoGA1UEChMD"
+ + "Q0RXMQkwBwYDVQQLEwAxCTAHBgNVBAcTADEJMAcGA1UECBMAMRowGAYDVQQDExFUZW1wbGFyIFRl"
+ + "c3QgMTAyNDEiMCAGCSqGSIb3DQEJARYTdGVtcGxhcnRlc3RAY2R3LmNvbTAeFw0wNjA1MjIwNTAw"
+ + "MDBaFw0xMDA1MjIwNTAwMDBaMHwxCzAJBgNVBAYTAlVTMQwwCgYDVQQKEwNDRFcxCTAHBgNVBAsT"
+ + "ADEJMAcGA1UEBxMAMQkwBwYDVQQIEwAxGjAYBgNVBAMTEVRlbXBsYXIgVGVzdCAxMDI0MSIwIAYJ"
+ + "KoZIhvcNAQkBFhN0ZW1wbGFydGVzdEBjZHcuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB"
+ + "gQDH3aJpJBfM+A3d84j5YcU6zEQaQ76u5xO9NSBmHjZykKS2kCcUqPpvVOPDA5WgV22dtKPh+lYV"
+ + "iUp7wyCVwAKibq8HIbihHceFqMKzjwC639rMoDJ7bi/yzQWz1Zg+075a4FGPlUKn7Yfu89wKkjdW"
+ + "wDpRPXc/agqBnrx5pJTXzQIDAQABow8wDTALBgNVHQ8EBAMCALEwDQYJKoZIhvcNAQEEBQADgYEA"
+ + "RRsRsjse3i2/KClFVd6YLZ+7K1BE0WxFyY2bbytkwQJSxvv3vLSuweFUbhNxutb68wl/yW4GLy4b"
+ + "1QdyswNxrNDXTuu5ILKhRDDuWeocz83aG2KGtr3JlFyr3biWGEyn5WUOE6tbONoQDJ0oPYgI6CAc"
+ + "EHdUp0lioOCt6UOw7Cs=");
+
+ private final byte[] gostRFC4491_94 = Base64.decode(
+ "MIICCzCCAboCECMO42BGlSTOxwvklBgufuswCAYGKoUDAgIEMGkxHTAbBgNVBAMM" +
+ "FEdvc3RSMzQxMC05NCBleGFtcGxlMRIwEAYDVQQKDAlDcnlwdG9Qcm8xCzAJBgNV" +
+ "BAYTAlJVMScwJQYJKoZIhvcNAQkBFhhHb3N0UjM0MTAtOTRAZXhhbXBsZS5jb20w" +
+ "HhcNMDUwODE2MTIzMjUwWhcNMTUwODE2MTIzMjUwWjBpMR0wGwYDVQQDDBRHb3N0" +
+ "UjM0MTAtOTQgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRvUHJvMQswCQYDVQQGEwJS" +
+ "VTEnMCUGCSqGSIb3DQEJARYYR29zdFIzNDEwLTk0QGV4YW1wbGUuY29tMIGlMBwG" +
+ "BiqFAwICFDASBgcqhQMCAiACBgcqhQMCAh4BA4GEAASBgLuEZuF5nls02CyAfxOo" +
+ "GWZxV/6MVCUhR28wCyd3RpjG+0dVvrey85NsObVCNyaE4g0QiiQOHwxCTSs7ESuo" +
+ "v2Y5MlyUi8Go/htjEvYJJYfMdRv05YmKCYJo01x3pg+2kBATjeM+fJyR1qwNCCw+" +
+ "eMG1wra3Gqgqi0WBkzIydvp7MAgGBiqFAwICBANBABHHCH4S3ALxAiMpR3aPRyqB" +
+ "g1DjB8zy5DEjiULIc+HeIveF81W9lOxGkZxnrFjXBSqnjLeFKgF1hffXOAP7zUM=");
+
+ private final byte[] gostRFC4491_2001 = Base64.decode(
+ "MIIB0DCCAX8CECv1xh7CEb0Xx9zUYma0LiEwCAYGKoUDAgIDMG0xHzAdBgNVBAMM" +
+ "Fkdvc3RSMzQxMC0yMDAxIGV4YW1wbGUxEjAQBgNVBAoMCUNyeXB0b1BybzELMAkG" +
+ "A1UEBhMCUlUxKTAnBgkqhkiG9w0BCQEWGkdvc3RSMzQxMC0yMDAxQGV4YW1wbGUu" +
+ "Y29tMB4XDTA1MDgxNjE0MTgyMFoXDTE1MDgxNjE0MTgyMFowbTEfMB0GA1UEAwwW" +
+ "R29zdFIzNDEwLTIwMDEgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRvUHJvMQswCQYD" +
+ "VQQGEwJSVTEpMCcGCSqGSIb3DQEJARYaR29zdFIzNDEwLTIwMDFAZXhhbXBsZS5j" +
+ "b20wYzAcBgYqhQMCAhMwEgYHKoUDAgIkAAYHKoUDAgIeAQNDAARAhJVodWACGkB1" +
+ "CM0TjDGJLP3lBQN6Q1z0bSsP508yfleP68wWuZWIA9CafIWuD+SN6qa7flbHy7Df" +
+ "D2a8yuoaYDAIBgYqhQMCAgMDQQA8L8kJRLcnqeyn1en7U23Sw6pkfEQu3u0xFkVP" +
+ "vFQ/3cHeF26NG+xxtZPz3TaTVXdoiYkXYiD02rEx1bUcM97i");
+
+ private PublicKey dudPublicKey = new PublicKey()
+ {
+ public String getAlgorithm()
+ {
+ return null;
+ }
+
+ public String getFormat()
+ {
+ return null;
+ }
+
+ public byte[] getEncoded()
+ {
+ return null;
+ }
+
+ };
+
+ public String getName()
+ {
+ return "CertTest";
+ }
+
+ public void checkCertificate(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+
+ Certificate cert = fact.generateCertificate(bIn);
+
+ PublicKey k = cert.getPublicKey();
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+ public void checkNameCertificate(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+
+ X509Certificate cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ PublicKey k = cert.getPublicKey();
+ if (!cert.getIssuerDN().toString().equals("C=DE,O=DATEV eG,0.2.262.1.10.7.20=1+CN=CA DATEV D03 1:PN"))
+ {
+ fail(id + " failed - name test.");
+ }
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+ public void checkKeyUsage(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+
+ X509Certificate cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ PublicKey k = cert.getPublicKey();
+
+ if (cert.getKeyUsage()[7])
+ {
+ fail("error generating cert - key usage wrong.");
+ }
+
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+
+ public void checkSelfSignedCertificate(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+
+ Certificate cert = fact.generateCertificate(bIn);
+
+ PublicKey k = cert.getPublicKey();
+
+ cert.verify(k);
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+
+ /**
+ * Test a generated certificate with the sun provider
+ */
+ private void sunProviderCheck(byte[] encoding)
+ throws CertificateException
+ {
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509");
+
+ certFact.generateCertificate(new ByteArrayInputStream(encoding));
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - RSA
+ */
+ public void checkCreation1()
+ throws Exception
+ {
+ //
+ // a sample key pair.
+ //
+ 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));
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory fact = KeyFactory.getInstance("RSA", "SC");
+
+ privKey = fact.generatePrivate(privKeySpec);
+ pubKey = fact.generatePublic(pubKeySpec);
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
+
+ builder.addRDN(BCStyle.C, "AU");
+ builder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ builder.addRDN(BCStyle.L, "Melbourne");
+ builder.addRDN(BCStyle.ST, "Victoria");
+ builder.addRDN(BCStyle.E, "feedback-crypto@bouncycastle.org");
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3 - without extensions
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider(BC).build(privKey);
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000),builder.build(), pubKey);
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ cert.verify(cert.getPublicKey());
+
+ Set dummySet = cert.getNonCriticalExtensionOIDs();
+ if (dummySet != null)
+ {
+ fail("non-critical oid set should be null");
+ }
+ dummySet = cert.getCriticalExtensionOIDs();
+ if (dummySet != null)
+ {
+ fail("critical oid set should be null");
+ }
+
+ //
+ // create the certificate - version 3 - with extensions
+ //
+ sigGen = new JcaContentSignerBuilder("MD5WithRSAEncryption").setProvider(BC).build(privKey);
+ certGen = new JcaX509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1)
+ , new Date(System.currentTimeMillis() - 50000)
+ , new Date(System.currentTimeMillis() + 50000)
+ , builder.build()
+ , pubKey)
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true,
+ new X509KeyUsage(X509KeyUsage.encipherOnly))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.37"), true,
+ new DERSequence(KeyPurposeId.anyExtendedKeyUsage))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true,
+ new GeneralNames(new GeneralName[]
+ {
+ new GeneralName(GeneralName.rfc822Name, "test@test.test"),
+ new GeneralName(GeneralName.dNSName, "dom.test.test")
+ }));
+
+ X509CertificateHolder certHolder = certGen.build(sigGen);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certHolder);
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+ cert.verify(cert.getPublicKey());
+
+ ContentVerifierProvider contentVerifierProvider = new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey);
+ if (!certHolder.isSignatureValid(contentVerifierProvider))
+ {
+ fail("signature test failed");
+ }
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", "SC");
+
+ cert = (X509Certificate)certFact.generateCertificate(bIn);
+
+ if (!cert.getKeyUsage()[7])
+ {
+ fail("error generating cert - key usage wrong.");
+ }
+
+/*
+ List l = cert.getExtendedKeyUsage();
+ if (!l.get(0).equals(KeyPurposeId.anyExtendedKeyUsage.getId()))
+ {
+ fail("failed extended key usage test");
+ }
+
+ Collection c = cert.getSubjectAlternativeNames();
+ Iterator it = c.iterator();
+ while (it.hasNext())
+ {
+ List gn = (List)it.next();
+ if (!gn.get(1).equals("test@test.test") && !gn.get(1).equals("dom.test.test"))
+ {
+ fail("failed subject alternative names test");
+ }
+ }
+*/
+
+ sunProviderCheck(certHolder.getEncoded());
+ sunProviderCheck(cert.getEncoded());
+
+ // System.out.println(cert);
+
+ //
+ // create the certificate - version 1
+ //
+ sigGen = new JcaContentSignerBuilder("MD5WithRSAEncryption").setProvider(BC).build(privKey);
+ X509v1CertificateBuilder certGen1 = new JcaX509v1CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen1.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+ cert.verify(cert.getPublicKey());
+
+ bIn = new ByteArrayInputStream(cert.getEncoded());
+ certFact = CertificateFactory.getInstance("X.509", "SC");
+
+ cert = (X509Certificate)certFact.generateCertificate(bIn);
+
+ // System.out.println(cert);
+ if (!cert.getIssuerDN().equals(cert.getSubjectDN()))
+ {
+ fail("name comparison fails");
+ }
+
+ sunProviderCheck(certHolder.getEncoded());
+ sunProviderCheck(cert.getEncoded());
+//
+ // a lightweight key pair.
+ //
+ RSAKeyParameters lwPubKey = new RSAKeyParameters(
+ false,
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ RSAPrivateCrtKeyParameters lwPrivKey = new RSAPrivateCrtKeyParameters(
+ 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));
+
+ //
+ // distinguished name table.
+ //
+ builder = new X500NameBuilder(BCStyle.INSTANCE);
+
+ builder.addRDN(BCStyle.C, "AU");
+ builder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ builder.addRDN(BCStyle.L, "Melbourne");
+ builder.addRDN(BCStyle.ST, "Victoria");
+ builder.addRDN(BCStyle.E, "feedback-crypto@bouncycastle.org");
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3 - without extensions
+ //
+ AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSAEncryption");
+ AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
+
+ sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(lwPrivKey);
+ SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPublicKey(lwPubKey.getModulus(), lwPubKey.getExponent()));
+ certGen = new X509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000), builder.build(), pubInfo);
+
+ certHolder = certGen.build(sigGen);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certHolder);
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ contentVerifierProvider = new BcRSAContentVerifierProviderBuilder(new DefaultDigestAlgorithmIdentifierFinder()).build(lwPubKey);
+
+ if (!certHolder.isSignatureValid(contentVerifierProvider))
+ {
+ fail("lw sig verification failed");
+ }
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - DSA
+ */
+ public void checkCreation2()
+ throws Exception
+ {
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ try
+ {
+ KeyPairGenerator g = KeyPairGenerator.getInstance("DSA", "SUN");
+
+ g.initialize(512, new SecureRandom());
+
+ KeyPair p = g.generateKeyPair();
+
+ privKey = p.getPrivate();
+ pubKey = p.getPublic();
+ }
+ catch (Exception e)
+ {
+ fail("error setting up keys - " + e.toString());
+ return;
+ }
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3
+ //
+
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA1withDSA").setProvider(BC).build(privKey);
+ JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ // System.out.println(cert);
+
+
+ //
+ // create the certificate - version 1
+ //
+ sigGen = new JcaContentSignerBuilder("SHA1withDSA").setProvider(BC).build(privKey);
+ JcaX509v1CertificateBuilder certGen1 = new JcaX509v1CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen1.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ bIn = new ByteArrayInputStream(cert.getEncoded());
+ fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ //System.out.println(cert);
+
+ //
+ // exception test
+ //
+ try
+ {
+ certGen1 = new JcaX509v1CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),dudPublicKey);
+
+
+ fail("key without encoding not detected in v1");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // expected
+ }
+ }
+
+ private X500NameBuilder createStdBuilder()
+ {
+ X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
+
+ builder.addRDN(BCStyle.C, "AU");
+ builder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ builder.addRDN(BCStyle.L, "Melbourne");
+ builder.addRDN(BCStyle.ST, "Victoria");
+ builder.addRDN(BCStyle.E, "feedback-crypto@bouncycastle.org");
+
+ return builder;
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - ECDSA
+ */
+ public void checkCreation3()
+ {
+ ECCurve curve = new ECCurve.Fp(
+ new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+ new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+ new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+
+ ECParameterSpec spec = new ECParameterSpec(
+ curve,
+ curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+ new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n
+
+
+ ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(
+ new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d
+ spec);
+
+ ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(
+ curve.decodePoint(Hex.decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q
+ spec);
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ try
+ {
+ KeyFactory fact = KeyFactory.getInstance("ECDSA", BC);
+
+ privKey = fact.generatePrivate(privKeySpec);
+ pubKey = fact.generatePublic(pubKeySpec);
+ }
+ catch (Exception e)
+ {
+ fail("error setting up keys - " + e.toString());
+ return;
+ }
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = createStdBuilder();
+
+
+ //
+ // toString test
+ //
+ X500Name p = builder.build();
+ String s = p.toString();
+
+ if (!s.equals("C=AU,O=The Legion of the Bouncy Castle,L=Melbourne,ST=Victoria,E=feedback-crypto@bouncycastle.org"))
+ {
+ fail("ordered X509Principal test failed - s = " + s + ".");
+ }
+
+// p = new X509Principal(attrs);
+// s = p.toString();
+//
+// //
+// // we need two of these as the hash code for strings changed...
+// //
+// if (!s.equals("O=The Legion of the Bouncy Castle,E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU") && !s.equals("ST=Victoria,L=Melbourne,C=AU,E=feedback-crypto@bouncycastle.org,O=The Legion of the Bouncy Castle"))
+// {
+// fail("unordered X509Principal test failed.");
+// }
+
+ //
+ // create the certificate - version 3
+ //
+ try
+ {
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA1withECDSA").setProvider(BC).build(privKey);
+ JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ //
+ // try with point compression turned off
+ //
+ ((ECPointEncoder)pubKey).setPointFormat("UNCOMPRESSED");
+
+ certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ bIn = new ByteArrayInputStream(cert.getEncoded());
+ fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail("error setting generating cert - " + e.toString());
+ }
+
+ X509Principal pr = new X509Principal("O=\"The Bouncy Castle, The Legion of\",E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU");
+
+ if (!pr.toString().equals("O=The Bouncy Castle\\, The Legion of,E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU"))
+ {
+ fail("string based X509Principal test failed.");
+ }
+
+ pr = new X509Principal("O=The Bouncy Castle\\, The Legion of,E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU");
+
+ if (!pr.toString().equals("O=The Bouncy Castle\\, The Legion of,E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU"))
+ {
+ fail("string based X509Principal test failed.");
+ }
+
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - SHA224withECDSA
+ */
+ private void createECCert(String algorithm, DERObjectIdentifier algOid)
+ throws Exception
+ {
+ ECCurve.Fp curve = new ECCurve.Fp(
+ new BigInteger("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"), // q (or p)
+ new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", 16), // a
+ new BigInteger("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", 16)); // b
+
+ ECParameterSpec spec = new ECParameterSpec(
+ curve,
+ curve.decodePoint(Hex.decode("0200C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")), // G
+ new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", 16)); // n
+
+ ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(
+ new BigInteger("5769183828869504557786041598510887460263120754767955773309066354712783118202294874205844512909370791582896372147797293913785865682804434049019366394746072023"), // d
+ spec);
+
+ ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(
+ curve.decodePoint(Hex.decode("02006BFDD2C9278B63C92D6624F151C9D7A822CC75BD983B17D25D74C26740380022D3D8FAF304781E416175EADF4ED6E2B47142D2454A7AC7801DD803CF44A4D1F0AC")), // Q
+ spec);
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory fact = KeyFactory.getInstance("ECDSA", BC);
+
+ privKey = fact.generatePrivate(privKeySpec);
+ pubKey = fact.generatePublic(pubKeySpec);
+
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // create the certificate - version 3
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey);
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)certFact.generateCertificate(bIn);
+
+ //
+ // try with point compression turned off
+ //
+ ((ECPointEncoder)pubKey).setPointFormat("UNCOMPRESSED");
+
+ certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ bIn = new ByteArrayInputStream(cert.getEncoded());
+ certFact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)certFact.generateCertificate(bIn);
+
+ if (!cert.getSigAlgOID().equals(algOid.toString()))
+ {
+ fail("ECDSA oid incorrect.");
+ }
+
+ if (cert.getSigAlgParams() != null)
+ {
+ fail("sig parameters present");
+ }
+
+ Signature sig = Signature.getInstance(algorithm, BC);
+
+ sig.initVerify(pubKey);
+
+ sig.update(cert.getTBSCertificate());
+
+ if (!sig.verify(cert.getSignature()))
+ {
+ fail("EC certificate signature not mapped correctly.");
+ }
+ // System.out.println(cert);
+ }
+
+ private void checkCRL(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
+
+ CRL cert = fact.generateCRL(bIn);
+
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+ public void checkCRLCreation1()
+ throws Exception
+ {
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", BC);
+ Date now = new Date();
+ KeyPair pair = kpGen.generateKeyPair();
+ X509v2CRLBuilder crlGen = new X509v2CRLBuilder(new X500Name("CN=Test CA"), now);
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ crlGen.addCRLEntry(BigInteger.valueOf(1), now, CRLReason.privilegeWithdrawn);
+
+ crlGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.getPublic()));
+
+ X509CRLHolder crl = crlGen.build(new JcaContentSignerBuilder("SHA256withRSAEncryption").setProvider(BC).build(pair.getPrivate()));
+
+ if (!crl.getIssuer().equals(new X500Name("CN=Test CA")))
+ {
+ fail("failed CRL issuer test");
+ }
+
+ Extension authExt = crl.getExtension(Extension.authorityKeyIdentifier);
+
+ if (authExt == null)
+ {
+ fail("failed to find CRL extension");
+ }
+
+ AuthorityKeyIdentifier authId = new AuthorityKeyIdentifierStructure(authExt);
+
+ X509CRLEntryHolder entry = crl.getRevokedCertificate(BigInteger.valueOf(1));
+
+ if (entry == null)
+ {
+ fail("failed to find CRL entry");
+ }
+
+ if (!entry.getSerialNumber().equals(BigInteger.valueOf(1)))
+ {
+ fail("CRL cert serial number does not match");
+ }
+
+ if (!entry.hasExtensions())
+ {
+ fail("CRL entry extension not found");
+ }
+
+ Extension ext = entry.getExtension(X509Extension.reasonCode);
+
+ if (ext != null)
+ {
+ ASN1Enumerated reasonCode = (ASN1Enumerated)ASN1Enumerated.getInstance(ext.getParsedValue());
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found");
+ }
+ }
+
+ public void checkCRLCreation2()
+ throws Exception
+ {
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ Date now = new Date();
+ KeyPair pair = kpGen.generateKeyPair();
+ X509v2CRLBuilder crlGen = new X509v2CRLBuilder(new X500Name("CN=Test CA"), now);
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ Vector extOids = new Vector();
+ Vector extValues = new Vector();
+
+ CRLReason crlReason = CRLReason.lookup(CRLReason.privilegeWithdrawn);
+
+ try
+ {
+ extOids.addElement(X509Extensions.ReasonCode);
+ extValues.addElement(new X509Extension(false, new DEROctetString(crlReason.getEncoded())));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("error encoding reason: " + e);
+ }
+
+ X509Extensions entryExtensions = new X509Extensions(extOids, extValues);
+
+ crlGen.addCRLEntry(BigInteger.valueOf(1), now, entryExtensions);
+
+ crlGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.getPublic()));
+
+ X509CRLHolder crlHolder = crlGen.build(new JcaContentSignerBuilder("SHA256withRSAEncryption").setProvider(BC).build(pair.getPrivate()));
+
+ X509CRL crl = new JcaX509CRLConverter().setProvider(BC).getCRL(crlHolder);
+
+ if (!PrincipalUtil.getIssuerX509Principal(crl).equals(new X509Principal("CN=Test CA")))
+ {
+ fail("failed CRL issuer test");
+ }
+
+ byte[] authExt = crl.getExtensionValue(X509Extensions.AuthorityKeyIdentifier.getId());
+
+ if (authExt == null)
+ {
+ fail("failed to find CRL extension");
+ }
+
+ AuthorityKeyIdentifier authId = new AuthorityKeyIdentifierStructure(authExt);
+
+ X509CRLEntry entry = crl.getRevokedCertificate(BigInteger.valueOf(1));
+
+ if (entry == null)
+ {
+ fail("failed to find CRL entry");
+ }
+
+ if (!entry.getSerialNumber().equals(BigInteger.valueOf(1)))
+ {
+ fail("CRL cert serial number does not match");
+ }
+
+ if (!entry.hasExtensions())
+ {
+ fail("CRL entry extension not found");
+ }
+
+ byte[] ext = entry.getExtensionValue(X509Extensions.ReasonCode.getId());
+
+ if (ext != null)
+ {
+ DEREnumerated reasonCode = (DEREnumerated)X509ExtensionUtil.fromExtensionValue(ext);
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found");
+ }
+ }
+
+ public void checkCRLCreation3()
+ throws Exception
+ {
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", BC);
+ Date now = new Date();
+ KeyPair pair = kpGen.generateKeyPair();
+ X509v2CRLBuilder crlGen = new JcaX509v2CRLBuilder(new X500Name("CN=Test CA"), now);
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ Vector extOids = new Vector();
+ Vector extValues = new Vector();
+
+ CRLReason crlReason = CRLReason.lookup(CRLReason.privilegeWithdrawn);
+
+ try
+ {
+ extOids.addElement(X509Extensions.ReasonCode);
+ extValues.addElement(new X509Extension(false, new DEROctetString(crlReason.getEncoded())));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("error encoding reason: " + e);
+ }
+
+ X509Extensions entryExtensions = new X509Extensions(extOids, extValues);
+
+ crlGen.addCRLEntry(BigInteger.valueOf(1), now, entryExtensions);
+
+ crlGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.getPublic()));
+
+ X509CRLHolder crlHolder = crlGen.build(new JcaContentSignerBuilder("SHA256withRSAEncryption").setProvider(BC).build(pair.getPrivate()));
+
+ X509CRL crl = new JcaX509CRLConverter().setProvider(BC).getCRL(crlHolder);
+
+ if (!PrincipalUtil.getIssuerX509Principal(crl).equals(new X509Principal("CN=Test CA")))
+ {
+ fail("failed CRL issuer test");
+ }
+
+ byte[] authExt = crl.getExtensionValue(X509Extensions.AuthorityKeyIdentifier.getId());
+
+ if (authExt == null)
+ {
+ fail("failed to find CRL extension");
+ }
+
+ AuthorityKeyIdentifier authId = new AuthorityKeyIdentifierStructure(authExt);
+
+ X509CRLEntry entry = crl.getRevokedCertificate(BigInteger.valueOf(1));
+
+ if (entry == null)
+ {
+ fail("failed to find CRL entry");
+ }
+
+ if (!entry.getSerialNumber().equals(BigInteger.valueOf(1)))
+ {
+ fail("CRL cert serial number does not match");
+ }
+
+ if (!entry.hasExtensions())
+ {
+ fail("CRL entry extension not found");
+ }
+
+ byte[] ext = entry.getExtensionValue(X509Extensions.ReasonCode.getId());
+
+ if (ext != null)
+ {
+ DEREnumerated reasonCode = (DEREnumerated)X509ExtensionUtil.fromExtensionValue(ext);
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found");
+ }
+
+ //
+ // check loading of existing CRL
+ //
+ now = new Date();
+ crlGen = new X509v2CRLBuilder(new X500Name("CN=Test CA"), now);
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ crlGen.addCRL(new JcaX509CRLHolder(crl));
+
+ crlGen.addCRLEntry(BigInteger.valueOf(2), now, entryExtensions);
+
+ crlGen.addExtension(X509Extension.authorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.getPublic()));
+
+ crlHolder = crlGen.build(new JcaContentSignerBuilder("SHA256withRSAEncryption").setProvider(BC).build(pair.getPrivate()));
+
+ int count = 0;
+ boolean oneFound = false;
+ boolean twoFound = false;
+
+ Iterator it = crlHolder.getRevokedCertificates().iterator();
+ while (it.hasNext())
+ {
+ X509CRLEntryHolder crlEnt = (X509CRLEntryHolder)it.next();
+
+ if (crlEnt.getSerialNumber().intValue() == 1)
+ {
+ oneFound = true;
+ Extension extn = crlEnt.getExtension(X509Extension.reasonCode);
+
+ if (extn != null)
+ {
+ ASN1Enumerated reasonCode = (ASN1Enumerated)ASN1Enumerated.getInstance(extn.getParsedValue());
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found");
+ }
+ }
+ else if (crlEnt.getSerialNumber().intValue() == 2)
+ {
+ twoFound = true;
+ }
+
+ count++;
+ }
+
+ if (count != 2)
+ {
+ fail("wrong number of CRLs found");
+ }
+
+ if (!oneFound || !twoFound)
+ {
+ fail("wrong CRLs found in copied list");
+ }
+
+ //
+ // check factory read back
+ //
+ CertificateFactory cFact = CertificateFactory.getInstance("X.509", BC);
+
+ X509CRL readCrl = (X509CRL)cFact.generateCRL(new ByteArrayInputStream(crlHolder.getEncoded()));
+
+ if (readCrl == null)
+ {
+ fail("crl not returned!");
+ }
+
+ Collection col = cFact.generateCRLs(new ByteArrayInputStream(crlHolder.getEncoded()));
+
+ if (col.size() != 1)
+ {
+ fail("wrong number of CRLs found in collection");
+ }
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - GOST3410
+ */
+ public void checkCreation4()
+ throws Exception
+ {
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyPairGenerator g = KeyPairGenerator.getInstance("GOST3410", BC);
+ GOST3410ParameterSpec gost3410P = new GOST3410ParameterSpec("GostR3410-94-CryptoPro-A");
+
+ g.initialize(gost3410P, new SecureRandom());
+
+ KeyPair p = g.generateKeyPair();
+
+ privKey = p.getPrivate();
+ pubKey = p.getPublic();
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder("GOST3411withGOST3410").setProvider(BC).build(privKey);
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ //
+ // check verifies in general
+ //
+ cert.verify(pubKey);
+
+ //
+ // check verifies with contained key
+ //
+ cert.verify(cert.getPublicKey());
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ //System.out.println(cert);
+
+ //check getEncoded()
+ byte[] bytes = cert.getEncoded();
+ }
+
+ public void checkCreation5()
+ throws Exception
+ {
+ //
+ // a sample key pair.
+ //
+ 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));
+
+ //
+ // set up the keys
+ //
+ SecureRandom rand = new SecureRandom();
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory fact = KeyFactory.getInstance("RSA", BC);
+
+ privKey = fact.generatePrivate(privKeySpec);
+ pubKey = fact.generatePublic(pubKeySpec);
+
+ //
+ // distinguished name table.
+ //
+ Vector ord = new Vector();
+ Vector values = new Vector();
+
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // create base certificate - version 3
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder("MD5WithRSAEncryption").setProvider(BC).build(privKey);
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey)
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true,
+ new X509KeyUsage(X509KeyUsage.encipherOnly))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.37"), true,
+ new DERSequence(KeyPurposeId.anyExtendedKeyUsage))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true,
+ new GeneralNames(new GeneralName(GeneralName.rfc822Name, "test@test.test")));
+
+ X509Certificate baseCert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ //
+ // copy certificate
+ //
+
+ certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey)
+ .copyAndAddExtension(new ASN1ObjectIdentifier("2.5.29.15"), true, baseCert)
+ .copyAndAddExtension(new ASN1ObjectIdentifier("2.5.29.37"), false, baseCert);
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ if (!areEqual(baseCert.getExtensionValue("2.5.29.15"), cert.getExtensionValue("2.5.29.15")))
+ {
+ fail("2.5.29.15 differs");
+ }
+
+ if (!areEqual(baseCert.getExtensionValue("2.5.29.37"), cert.getExtensionValue("2.5.29.37")))
+ {
+ fail("2.5.29.37 differs");
+ }
+
+ //
+ // exception test
+ //
+
+ try
+ {
+ certGen.copyAndAddExtension(new ASN1ObjectIdentifier("2.5.99.99"), true, new JcaX509CertificateHolder(baseCert));
+
+ fail("exception not thrown on dud extension copy");
+ }
+ catch (NullPointerException e)
+ {
+ // expected
+ }
+
+// try
+// {
+// certGen.setPublicKey(dudPublicKey);
+//
+// certGen.generate(privKey, BC);
+//
+// fail("key without encoding not detected in v3");
+// }
+// catch (IllegalArgumentException e)
+// {
+// // expected
+// }
+
+ }
+
+ private void testForgedSignature()
+ throws Exception
+ {
+ String cert = "MIIBsDCCAVoCAQYwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCQVUxEzARBgNV"
+ + "BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMSMwIQYD"
+ + "VQQDExpTZXJ2ZXIgdGVzdCBjZXJ0ICg1MTIgYml0KTAeFw0wNjA5MTEyMzU4NTVa"
+ + "Fw0wNjEwMTEyMzU4NTVaMGMxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpRdWVlbnNs"
+ + "YW5kMRowGAYDVQQKExFDcnlwdFNvZnQgUHR5IEx0ZDEjMCEGA1UEAxMaU2VydmVy"
+ + "IHRlc3QgY2VydCAoNTEyIGJpdCkwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAn7PD"
+ + "hCeV/xIxUg8V70YRxK2A5jZbD92A12GN4PxyRQk0/lVmRUNMaJdq/qigpd9feP/u"
+ + "12S4PwTLb/8q/v657QIDAQABMA0GCSqGSIb3DQEBBQUAA0EAbynCRIlUQgaqyNgU"
+ + "DF6P14yRKUtX8akOP2TwStaSiVf/akYqfLFm3UGka5XbPj4rifrZ0/sOoZEEBvHQ"
+ + "e20sRA==";
+
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", BC);
+
+ X509Certificate x509 = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(Base64.decode(cert)));
+ try
+ {
+ x509.verify(x509.getPublicKey());
+
+ fail("forged RSA signature passed");
+ }
+ catch (Exception e)
+ {
+ // expected
+ }
+ }
+
+
+ private void pemTest()
+ throws Exception
+ {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509", BC);
+
+ Certificate cert = readPEMCert(cf, PEMData.CERTIFICATE_1);
+ if (cert == null)
+ {
+ fail("PEM cert not read");
+ }
+ cert = readPEMCert(cf, "-----BEGIN CERTIFICATE-----" + PEMData.CERTIFICATE_2);
+ if (cert == null)
+ {
+ fail("PEM cert with extraneous header not read");
+ }
+ CRL crl = cf.generateCRL(new ByteArrayInputStream(PEMData.CRL_1.getBytes("US-ASCII")));
+ if (crl == null)
+ {
+ fail("PEM crl not read");
+ }
+ Collection col = cf.generateCertificates(new ByteArrayInputStream(PEMData.CERTIFICATE_2.getBytes("US-ASCII")));
+ if (col.size() != 1 || !col.contains(cert))
+ {
+ fail("PEM cert collection not right");
+ }
+ col = cf.generateCRLs(new ByteArrayInputStream(PEMData.CRL_2.getBytes("US-ASCII")));
+ if (col.size() != 1 || !col.contains(crl))
+ {
+ fail("PEM crl collection not right");
+ }
+ }
+
+ private static Certificate readPEMCert(CertificateFactory cf, String pemData)
+ throws CertificateException, UnsupportedEncodingException
+ {
+ return cf.generateCertificate(new ByteArrayInputStream(pemData.getBytes("US-ASCII")));
+ }
+
+ private void pkcs7Test()
+ throws Exception
+ {
+ /*
+ ASN1EncodableVector certs = new ASN1EncodableVector();
+
+ certs.add(new ASN1InputStream(CertPathTest.rootCertBin).readObject());
+ certs.add(new DERTaggedObject(false, 2, new ASN1InputStream(AttrCertTest.attrCert).readObject()));
+
+ ASN1EncodableVector crls = new ASN1EncodableVector();
+
+ crls.add(new ASN1InputStream(CertPathTest.rootCrlBin).readObject());
+ SignedData sigData = new SignedData(new DERSet(), new ContentInfo(CMSObjectIdentifiers.data, null), new DERSet(certs), new DERSet(crls), new DERSet());
+
+ ContentInfo info = new ContentInfo(CMSObjectIdentifiers.signedData, sigData);
+
+ CertificateFactory cf = CertificateFactory.getInstance("X.509", BC);
+
+ X509Certificate cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(info.getEncoded()));
+ if (cert == null || !areEqual(cert.getEncoded(), certs.get(0).getDERObject().getEncoded()))
+ {
+ fail("PKCS7 cert not read");
+ }
+ X509CRL crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(info.getEncoded()));
+ if (crl == null || !areEqual(crl.getEncoded(), crls.get(0).getDERObject().getEncoded()))
+ {
+ fail("PKCS7 crl not read");
+ }
+ Collection col = cf.generateCertificates(new ByteArrayInputStream(info.getEncoded()));
+ if (col.size() != 1 || !col.contains(cert))
+ {
+ fail("PKCS7 cert collection not right");
+ }
+ col = cf.generateCRLs(new ByteArrayInputStream(info.getEncoded()));
+ if (col.size() != 1 || !col.contains(crl))
+ {
+ fail("PKCS7 crl collection not right");
+ }
+
+ // data with no certificates or CRLs
+
+ sigData = new SignedData(new DERSet(), new ContentInfo(CMSObjectIdentifiers.data, null), new DERSet(), new DERSet(), new DERSet());
+
+ info = new ContentInfo(CMSObjectIdentifiers.signedData, sigData);
+
+ cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(info.getEncoded()));
+ if (cert != null)
+ {
+ fail("PKCS7 cert present");
+ }
+ crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(info.getEncoded()));
+ if (crl != null)
+ {
+ fail("PKCS7 crl present");
+ }
+
+ // data with absent certificates and CRLS
+
+ sigData = new SignedData(new DERSet(), new ContentInfo(CMSObjectIdentifiers.data, null), null, null, new DERSet());
+
+ info = new ContentInfo(CMSObjectIdentifiers.signedData, sigData);
+
+ cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(info.getEncoded()));
+ if (cert != null)
+ {
+ fail("PKCS7 cert present");
+ }
+ crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(info.getEncoded()));
+ if (crl != null)
+ {
+ fail("PKCS7 crl present");
+ }
+
+ //
+ // sample message
+ //
+ InputStream in = new ByteArrayInputStream(pkcs7CrlProblem);
+ Collection certCol = cf.generateCertificates(in);
+ Collection crlCol = cf.generateCRLs(in);
+
+ if (crlCol.size() != 0)
+ {
+ fail("wrong number of CRLs: " + crlCol.size());
+ }
+
+ if (certCol.size() != 4)
+ {
+ fail("wrong number of Certs: " + certCol.size());
+ }
+ */
+ }
+
+ private void createPSSCert(String algorithm)
+ throws Exception
+ {
+ KeyPair pair = generateLongFixedKeys();
+
+ PrivateKey privKey = pair.getPrivate();
+ PublicKey pubKey = pair.getPublic();
+
+ //
+ // distinguished name table.
+ //
+
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // create base certificate - version 3
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey);
+ JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),
+ new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ certGen.addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true,
+ new X509KeyUsage(X509KeyUsage.encipherOnly));
+ certGen.addExtension(new ASN1ObjectIdentifier("2.5.29.37"), true,
+ new DERSequence(KeyPurposeId.anyExtendedKeyUsage));
+ certGen.addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true,
+ new GeneralNames(new GeneralName(GeneralName.rfc822Name, "test@test.test")));
+
+ X509Certificate baseCert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ baseCert.verify(pubKey);
+ }
+
+ private KeyPair generateLongFixedKeys()
+ throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException
+ {
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+ new BigInteger("010001",16));
+
+ RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec(
+ new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+ new BigInteger("010001",16),
+ new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16),
+ new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16),
+ new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16),
+ new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16),
+ new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16),
+ new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16));
+
+ KeyFactory fact = KeyFactory.getInstance("RSA", BC);
+
+ return new KeyPair(fact.generatePublic(pubKeySpec), fact.generatePrivate(privKeySpec));
+ }
+
+ private void rfc4491Test()
+ throws Exception
+ {
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", BC);
+
+ X509Certificate x509 = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(gostRFC4491_94));
+
+ x509.verify(x509.getPublicKey(), BC);
+
+ x509 = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(gostRFC4491_2001));
+
+ x509.verify(x509.getPublicKey(), BC);
+ }
+
+ private void testNullDerNullCert()
+ throws Exception
+ {
+ KeyPair pair = generateLongFixedKeys();
+ PublicKey pubKey = pair.getPublic();
+ PrivateKey privKey = pair.getPrivate();
+
+ ContentSigner sigGen = new JcaContentSignerBuilder("MD5WithRSAEncryption").setProvider(BC).build(privKey);
+ JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(new X500Name("CN=Test"),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),new X500Name("CN=Test"),pubKey);
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ X509CertificateStructure struct = X509CertificateStructure.getInstance(ASN1Primitive.fromByteArray(cert.getEncoded()));
+
+ ASN1Encodable tbsCertificate = struct.getTBSCertificate();
+ AlgorithmIdentifier sig = struct.getSignatureAlgorithm();
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCertificate);
+ v.add(new AlgorithmIdentifier(sig.getAlgorithm()));
+ v.add(struct.getSignature());
+
+ // verify
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(new DERSequence(v).getEncoded());
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ cert.verify(cert.getPublicKey());
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": testNullDerNull failed - exception " + e.toString(), e);
+ }
+ }
+
+ private void testDirect()
+ throws Exception
+ {
+ KeyStore keyStore = KeyStore.getInstance("PKCS12", "SC");
+
+ ByteArrayInputStream input = new ByteArrayInputStream(testCAp12);
+
+ keyStore.load(input, "test".toCharArray());
+
+ X509Certificate certificate = (X509Certificate) keyStore.getCertificate("ca");
+ PrivateKey privateKey = (PrivateKey) keyStore.getKey("ca", null);
+
+ X500Name issuer = X500Name.getInstance(PrincipalUtil.getIssuerX509Principal(certificate).getEncoded());
+
+ X509v2CRLBuilder builder = new X509v2CRLBuilder(issuer, new Date());
+
+ builder.addCRLEntry(certificate.getSerialNumber(), new Date(), CRLReason.cACompromise);
+
+ JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA256WithRSAEncryption");
+
+ contentSignerBuilder.setProvider("SC");
+
+ X509CRLHolder cRLHolder = builder.build(contentSignerBuilder.build(privateKey));
+
+ JcaX509CRLConverter converter = new JcaX509CRLConverter();
+
+ converter.setProvider("SC");
+
+ X509CRL crl = converter.getCRL(cRLHolder);
+
+ crl.verify(certificate.getPublicKey());
+
+ if (!crl.isRevoked(certificate))
+ {
+ fail("Certificate should be revoked");
+ }
+
+ // now encode the CRL and load the CRL with the JCE provider
+
+ CertificateFactory fac = CertificateFactory.getInstance("X.509");
+
+ X509CRL jceCRL = (X509CRL) fac.generateCRL(new ByteArrayInputStream(crl.getEncoded()));
+
+ jceCRL.verify(certificate.getPublicKey());
+
+ if (!jceCRL.isRevoked(certificate))
+ {
+ fail("This certificate should also be revoked");
+ }
+ }
+
+ private void testIndirect()
+ throws Exception
+ {
+ KeyStore keyStore = KeyStore.getInstance("PKCS12", "SC");
+
+ ByteArrayInputStream input = new ByteArrayInputStream(testCAp12);
+
+ keyStore.load(input, "test".toCharArray());
+
+ X509Certificate certificate = (X509Certificate) keyStore.getCertificate("ca");
+ PrivateKey privateKey = (PrivateKey) keyStore.getKey("ca", null);
+
+ X500Name crlIssuer = X500Name.getInstance(PrincipalUtil.getSubjectX509Principal(certificate).getEncoded());
+ X500Name caName = X500Name.getInstance(PrincipalUtil.getIssuerX509Principal(certificate).getEncoded());
+
+ X509v2CRLBuilder builder = new X509v2CRLBuilder(crlIssuer, new Date());
+
+ builder.addExtension(Extension.issuingDistributionPoint, true, new IssuingDistributionPoint(null, true, false));
+
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+
+ extGen.addExtension(Extension.reasonCode, false, CRLReason.lookup(CRLReason.cACompromise));
+ extGen.addExtension(Extension.certificateIssuer, true, new GeneralNames(new GeneralName(caName)));
+
+ builder.addCRLEntry(certificate.getSerialNumber(), new Date(), extGen.generate());
+
+ JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA256WithRSAEncryption");
+
+ contentSignerBuilder.setProvider("SC");
+
+ X509CRLHolder cRLHolder = builder.build(contentSignerBuilder.build(privateKey));
+
+ JcaX509CRLConverter converter = new JcaX509CRLConverter();
+
+ converter.setProvider("SC");
+
+ X509CRL crl = converter.getCRL(cRLHolder);
+
+ crl.verify(certificate.getPublicKey());
+
+ if (!crl.isRevoked(certificate))
+ {
+ fail("Certificate should be revoked");
+ }
+
+ // now encode the CRL and load the CRL with the JCE provider
+
+ CertificateFactory fac = CertificateFactory.getInstance("X.509");
+
+ X509CRL jceCRL = (X509CRL) fac.generateCRL(new ByteArrayInputStream(crl.getEncoded()));
+
+ jceCRL.verify(certificate.getPublicKey());
+
+ if (!jceCRL.isRevoked(certificate))
+ {
+ fail("This certificate should also be revoked");
+ }
+ }
+
+ // issuing distribution point must be set for an indirect CRL to be recognised
+ private void testMalformedIndirect()
+ throws Exception
+ {
+ KeyStore keyStore = KeyStore.getInstance("PKCS12", "SC");
+
+ ByteArrayInputStream input = new ByteArrayInputStream(testCAp12);
+
+ keyStore.load(input, "test".toCharArray());
+
+ X509Certificate certificate = (X509Certificate) keyStore.getCertificate("ca");
+ PrivateKey privateKey = (PrivateKey) keyStore.getKey("ca", null);
+
+ X500Name crlIssuer = X500Name.getInstance(PrincipalUtil.getSubjectX509Principal(certificate).getEncoded());
+ X500Name caName = X500Name.getInstance(PrincipalUtil.getIssuerX509Principal(certificate).getEncoded());
+
+ X509v2CRLBuilder builder = new X509v2CRLBuilder(crlIssuer, new Date());
+
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+
+ extGen.addExtension(Extension.reasonCode, false, CRLReason.lookup(CRLReason.cACompromise));
+ extGen.addExtension(Extension.certificateIssuer, true, new GeneralNames(new GeneralName(caName)));
+
+ builder.addCRLEntry(certificate.getSerialNumber(), new Date(), extGen.generate());
+
+ JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA256WithRSAEncryption");
+
+ contentSignerBuilder.setProvider("SC");
+
+ X509CRLHolder cRLHolder = builder.build(contentSignerBuilder.build(privateKey));
+
+ JcaX509CRLConverter converter = new JcaX509CRLConverter();
+
+ converter.setProvider("SC");
+
+ X509CRL crl = converter.getCRL(cRLHolder);
+
+ crl.verify(certificate.getPublicKey());
+
+ if (crl.isRevoked(certificate))
+ {
+ throw new Exception("Certificate should not be revoked");
+ }
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ testDirect();
+ testIndirect();
+ testMalformedIndirect();
+
+ checkCertificate(1, cert1);
+ checkCertificate(2, cert2);
+ checkCertificate(3, cert3);
+ checkCertificate(4, cert4);
+ checkCertificate(5, cert5);
+ checkCertificate(6, oldEcdsa);
+ checkCertificate(7, cert7);
+
+ checkKeyUsage(8, keyUsage);
+ checkSelfSignedCertificate(9, uncompressedPtEC);
+ checkNameCertificate(10, nameCert);
+
+ checkSelfSignedCertificate(11, probSelfSignedCert);
+ checkSelfSignedCertificate(12, gostCA1);
+ checkSelfSignedCertificate(13, gostCA2);
+ checkSelfSignedCertificate(14, gost341094base);
+ checkSelfSignedCertificate(15, gost34102001base);
+ checkSelfSignedCertificate(16, gost341094A);
+ checkSelfSignedCertificate(17, gost341094B);
+ checkSelfSignedCertificate(17, gost34102001A);
+
+ checkCRL(1, crl1);
+
+ checkCreation1();
+ checkCreation2();
+ checkCreation3();
+ checkCreation4();
+ checkCreation5();
+
+ createECCert("SHA1withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ createECCert("SHA224withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ createECCert("SHA256withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ createECCert("SHA384withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ createECCert("SHA512withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+
+ createPSSCert("SHA1withRSAandMGF1");
+ createPSSCert("SHA224withRSAandMGF1");
+ createPSSCert("SHA256withRSAandMGF1");
+ createPSSCert("SHA384withRSAandMGF1");
+
+ checkCRLCreation1();
+ checkCRLCreation2();
+ checkCRLCreation3();
+
+ pemTest();
+ pkcs7Test();
+ rfc4491Test();
+
+ testForgedSignature();
+
+ testNullDerNullCert();
+
+ checkCertificate(18, emptyDNCert);
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new CertTest());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/ConverterTest.java b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/ConverterTest.java
new file mode 100644
index 000000000..efc1191c6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/ConverterTest.java
@@ -0,0 +1,66 @@
+package org.spongycastle.cert.test;
+
+import java.math.BigInteger;
+import org.spongycastle.jce.cert.X509CertSelector;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cert.selector.X509CertificateHolderSelector;
+import org.spongycastle.cert.selector.jcajce.JcaSelectorConverter;
+import org.spongycastle.cert.selector.jcajce.JcaX509CertSelectorConverter;
+import org.spongycastle.util.Arrays;
+
+public class ConverterTest
+ extends TestCase
+{
+ public void testCertificateSelectorConversion()
+ throws Exception
+ {
+ JcaX509CertSelectorConverter converter = new JcaX509CertSelectorConverter();
+ JcaSelectorConverter toSelector = new JcaSelectorConverter();
+
+ X509CertificateHolderSelector sid1 = new X509CertificateHolderSelector(new X500Name("CN=Test"), BigInteger.valueOf(1), new byte[20]);
+
+ X509CertSelector conv = converter.getCertSelector(sid1);
+
+ assertTrue(conv.getIssuerAsString().equals("CN=Test"));
+ assertTrue(Arrays.areEqual(conv.getSubjectKeyIdentifier(), new DEROctetString(new byte[20]).getEncoded()));
+ assertEquals(conv.getSerialNumber(), sid1.getSerialNumber());
+
+ X509CertificateHolderSelector sid2 = toSelector.getCertificateHolderSelector(conv);
+
+ assertEquals(sid1, sid2);
+
+ sid1 = new X509CertificateHolderSelector(new X500Name("CN=Test"), BigInteger.valueOf(1));
+
+ conv = converter.getCertSelector(sid1);
+
+ assertTrue(conv.getIssuerAsString().equals("CN=Test"));
+ assertNull(conv.getSubjectKeyIdentifier());
+ assertEquals(conv.getSerialNumber(), sid1.getSerialNumber());
+
+ sid2 = toSelector.getCertificateHolderSelector(conv);
+
+ assertEquals(sid1, sid2);
+
+ sid1 = new X509CertificateHolderSelector(new byte[20]);
+
+ conv = converter.getCertSelector(sid1);
+
+ assertNull(conv.getIssuerAsString());
+ assertTrue(Arrays.areEqual(conv.getSubjectKeyIdentifier(), new DEROctetString(new byte[20]).getEncoded()));
+ assertNull(conv.getSerialNumber());
+
+ sid2 = toSelector.getCertificateHolderSelector(conv);
+
+ assertEquals(sid1, sid2);
+ }
+
+ public static Test suite()
+ {
+ return new TestSuite(ConverterTest.class);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/PKCS10Test.java b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/PKCS10Test.java
new file mode 100644
index 000000000..9e091ec22
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cert/test/PKCS10Test.java
@@ -0,0 +1,578 @@
+package org.spongycastle.cert.test;
+
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Signature;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.Vector;
+
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.Attribute;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.X500NameBuilder;
+import org.spongycastle.asn1.x500.style.BCStyle;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.KeyUsage;
+import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jce.ECGOST3410NamedCurveTable;
+import org.spongycastle.jce.ECNamedCurveTable;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+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.jce.spec.ECPublicKeySpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+import org.spongycastle.pkcs.PKCS10CertificationRequest;
+import org.spongycastle.pkcs.PKCS10CertificationRequestBuilder;
+import org.spongycastle.pkcs.jcajce.JcaPKCS10CertificationRequest;
+import org.spongycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.encoders.Hex;
+import org.spongycastle.util.test.SimpleTest;
+import org.spongycastle.x509.extension.SubjectKeyIdentifierStructure;
+
+/**
+ **/
+public class PKCS10Test
+ extends SimpleTest
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ private byte[] gost3410EC_A = Base64.decode(
+ "MIIBOzCB6wIBADB/MQ0wCwYDVQQDEwR0ZXN0MRUwEwYDVQQKEwxEZW1vcyBDbyBMdGQxHjAcBgNV"
+ +"BAsTFUNyeXB0b2dyYXBoeSBkaXZpc2lvbjEPMA0GA1UEBxMGTW9zY293MQswCQYDVQQGEwJydTEZ"
+ +"MBcGCSqGSIb3DQEJARYKc2RiQGRvbC5ydTBjMBwGBiqFAwICEzASBgcqhQMCAiMBBgcqhQMCAh4B"
+ +"A0MABEBYx0P2D7YuuZo5HgdIAUKAXcLBDZ+4LYFgbKjrfStVfH59lc40BQ2FZ7M703hLpXK8GiBQ"
+ +"GEYpKaAuQZnMIpByoAAwCAYGKoUDAgIDA0EAgXMcTrhdOY2Er2tHOSAgnMezqrYxocZTWhxmW5Rl"
+ +"JY6lbXH5rndCn4swFzXU+YhgAsJv1wQBaoZEWRl5WV4/nA==");
+
+ private byte[] gost3410EC_B = Base64.decode(
+ "MIIBPTCB7QIBADCBgDENMAsGA1UEAxMEdGVzdDEWMBQGA1UEChMNRGVtb3MgQ28gTHRkLjEeMBwG"
+ +"A1UECxMVQ3J5cHRvZ3JhcGh5IGRpdmlzaW9uMQ8wDQYDVQQHEwZNb3Njb3cxCzAJBgNVBAYTAnJ1"
+ +"MRkwFwYJKoZIhvcNAQkBFgpzZGJAZG9sLnJ1MGMwHAYGKoUDAgITMBIGByqFAwICIwIGByqFAwIC"
+ +"HgEDQwAEQI5SLoWT7dZVilbV9j5B/fyIDuDs6x4pjqNC2TtFYbpRHrk/Wc5g/mcHvD80tsm5o1C7"
+ +"7cizNzkvAVUM4VT4Dz6gADAIBgYqhQMCAgMDQQAoT5TwJ8o+bSrxckymyo3diwG7ZbSytX4sRiKy"
+ +"wXPWRS9LlBvPO2NqwpS2HUnxSU8rzfL9fJcybATf7Yt1OEVq");
+
+ private byte[] gost3410EC_C = Base64.decode(
+ "MIIBRDCB9AIBADCBhzEVMBMGA1UEAxMMdGVzdCByZXF1ZXN0MRUwEwYDVQQKEwxEZW1vcyBDbyBM"
+ +"dGQxHjAcBgNVBAsTFUNyeXB0b2dyYXBoeSBkaXZpc2lvbjEPMA0GA1UEBxMGTW9zY293MQswCQYD"
+ +"VQQGEwJydTEZMBcGCSqGSIb3DQEJARYKc2RiQGRvbC5ydTBjMBwGBiqFAwICEzASBgcqhQMCAiMD"
+ +"BgcqhQMCAh4BA0MABEBcmGh7OmR4iqqj+ycYo1S1fS7r5PhisSQU2Ezuz8wmmmR2zeTZkdMYCOBa"
+ +"UTMNms0msW3wuYDho7nTDNscHTB5oAAwCAYGKoUDAgIDA0EAVoOMbfyo1Un4Ss7WQrUjHJoiaYW8"
+ +"Ime5LeGGU2iW3ieAv6es/FdMrwTKkqn5dhd3aL/itFg5oQbhyfXw5yw/QQ==");
+
+ private byte[] gost3410EC_ExA = Base64.decode(
+ "MIIBOzCB6wIBADB/MQ0wCwYDVQQDEwR0ZXN0MRUwEwYDVQQKEwxEZW1vcyBDbyBMdGQxHjAcBgNV"
+ + "BAsTFUNyeXB0b2dyYXBoeSBkaXZpc2lvbjEPMA0GA1UEBxMGTW9zY293MQswCQYDVQQGEwJydTEZ"
+ + "MBcGCSqGSIb3DQEJARYKc2RiQGRvbC5ydTBjMBwGBiqFAwICEzASBgcqhQMCAiQABgcqhQMCAh4B"
+ + "A0MABEDkqNT/3f8NHj6EUiWnK4JbVZBh31bEpkwq9z3jf0u8ZndG56Vt+K1ZB6EpFxLT7hSIos0w"
+ + "weZ2YuTZ4w43OgodoAAwCAYGKoUDAgIDA0EASk/IUXWxoi6NtcUGVF23VRV1L3undB4sRZLp4Vho"
+ + "gQ7m3CMbZFfJ2cPu6QyarseXGYHmazoirH5lGjEo535c1g==");
+
+ private byte[] gost3410EC_ExB = Base64.decode(
+ "MIIBPTCB7QIBADCBgDENMAsGA1UEAxMEdGVzdDEWMBQGA1UEChMNRGVtb3MgQ28gTHRkLjEeMBwG"
+ + "A1UECxMVQ3J5cHRvZ3JhcGh5IGRpdmlzaW9uMQ8wDQYDVQQHEwZNb3Njb3cxCzAJBgNVBAYTAnJ1"
+ + "MRkwFwYJKoZIhvcNAQkBFgpzZGJAZG9sLnJ1MGMwHAYGKoUDAgITMBIGByqFAwICJAEGByqFAwIC"
+ + "HgEDQwAEQMBWYUKPy/1Kxad9ChAmgoSWSYOQxRnXo7KEGLU5RNSXA4qMUvArWzvhav+EYUfTbWLh"
+ + "09nELDyHt2XQcvgQHnSgADAIBgYqhQMCAgMDQQAdaNhgH/ElHp64mbMaEo1tPCg9Q22McxpH8rCz"
+ + "E0QBpF4H5mSSQVGI5OAXHToetnNuh7gHHSynyCupYDEHTbkZ");
+
+ public String getName()
+ {
+ return "PKCS10CertRequest";
+ }
+
+ private void generationTest(int keySize, String keyName, String sigName, String provider)
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyName, "SC");
+
+ kpg.initialize(keySize);
+
+ KeyPair kp = kpg.generateKeyPair();
+
+
+ X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE);
+
+ x500NameBld.addRDN(BCStyle.C, "AU");
+ x500NameBld.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ x500NameBld.addRDN(BCStyle.L, "Melbourne");
+ x500NameBld.addRDN(BCStyle.ST, "Victoria");
+ x500NameBld.addRDN(BCStyle.EmailAddress, "feedback-crypto@bouncycastle.org");
+
+ X500Name subject = x500NameBld.build();
+
+ PKCS10CertificationRequestBuilder requestBuilder = new JcaPKCS10CertificationRequestBuilder(subject, kp.getPublic());
+
+ PKCS10CertificationRequest req1 = requestBuilder.build(new JcaContentSignerBuilder(sigName).setProvider(provider).build(kp.getPrivate()));
+
+ JcaPKCS10CertificationRequest req2 = new JcaPKCS10CertificationRequest(req1.getEncoded()).setProvider(provider);
+
+ if (!req2.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(provider).build(kp.getPublic())))
+ {
+ fail(sigName + ": Failed verify check.");
+ }
+
+ if (!Arrays.areEqual(req2.getPublicKey().getEncoded(), req1.getSubjectPublicKeyInfo().getEncoded()))
+ {
+ fail(keyName + ": Failed public key check.");
+ }
+ }
+
+ /*
+ * we generate a self signed certificate for the sake of testing - SHA224withECDSA
+ */
+ private void createECRequest(String algorithm, DERObjectIdentifier algOid, DERObjectIdentifier curveOid)
+ throws Exception
+ {
+ ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(curveOid.getId());
+ KeyPairGenerator ecGen = KeyPairGenerator.getInstance("ECDSA", "SC");
+
+ ecGen.initialize(spec);
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyPair pair = ecGen.generateKeyPair();
+
+ privKey = pair.getPrivate();
+ pubKey = pair.getPublic();
+
+ ContentSigner signer = new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey);
+
+ PKCS10CertificationRequestBuilder reqBuilder = new JcaPKCS10CertificationRequestBuilder(new X500Name("CN=XXX"), pubKey);
+ PKCS10CertificationRequest req = reqBuilder.build(signer);
+
+ ContentVerifierProvider verifier = new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey);
+
+ if (!req.isSignatureValid(verifier))
+ {
+ fail("Failed verify check EC.");
+ }
+
+ req = new PKCS10CertificationRequest(req.getEncoded());
+ if (!req.isSignatureValid(verifier))
+ {
+ fail("Failed verify check EC encoded.");
+ }
+
+ //
+ // try with point compression turned off
+ //
+ ((ECPointEncoder)pubKey).setPointFormat("UNCOMPRESSED");
+
+ reqBuilder = new JcaPKCS10CertificationRequestBuilder(new X500Name("CN=XXX"), pubKey);
+ req = reqBuilder.build(signer);
+
+ if (!req.isSignatureValid(verifier))
+ {
+ fail("Failed verify check EC uncompressed.");
+ }
+
+ req = new PKCS10CertificationRequest(req.getEncoded());
+ if (!req.isSignatureValid(verifier))
+ {
+ fail("Failed verify check EC uncompressed encoded.");
+ }
+
+ if (!req.toASN1Structure().getSignatureAlgorithm().getAlgorithm().equals(algOid))
+ {
+ fail("ECDSA oid incorrect.");
+ }
+
+ if (req.toASN1Structure().getSignatureAlgorithm().getParameters() != null)
+ {
+ fail("ECDSA parameters incorrect.");
+ }
+
+ Signature sig = Signature.getInstance(algorithm, "SC");
+
+ sig.initVerify(pubKey);
+
+ sig.update(req.toASN1Structure().getCertificationRequestInfo().getEncoded());
+
+ if (!sig.verify(req.toASN1Structure().getSignature().getBytes()))
+ {
+ fail("signature not mapped correctly.");
+ }
+ }
+
+ private void createECRequest(String algorithm, DERObjectIdentifier algOid)
+ throws Exception
+ {
+ ECCurve.Fp curve = new ECCurve.Fp(
+ new BigInteger("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"), // q (or p)
+ new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", 16), // a
+ new BigInteger("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", 16)); // b
+
+ ECParameterSpec spec = new ECParameterSpec(
+ curve,
+ curve.decodePoint(Hex.decode("0200C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")), // G
+ new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", 16)); // n
+
+ ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(
+ new BigInteger("5769183828869504557786041598510887460263120754767955773309066354712783118202294874205844512909370791582896372147797293913785865682804434049019366394746072023"), // d
+ spec);
+
+ ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(
+ curve.decodePoint(Hex.decode("02006BFDD2C9278B63C92D6624F151C9D7A822CC75BD983B17D25D74C26740380022D3D8FAF304781E416175EADF4ED6E2B47142D2454A7AC7801DD803CF44A4D1F0AC")), // Q
+ spec);
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory fact = KeyFactory.getInstance("ECDSA", "SC");
+
+ privKey = fact.generatePrivate(privKeySpec);
+ pubKey = fact.generatePublic(pubKeySpec);
+
+ PKCS10CertificationRequest req = new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("CN=XXX"), pubKey).build(new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey));
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("Failed verify check EC.");
+ }
+
+ req = new PKCS10CertificationRequest(req.getEncoded());
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("Failed verify check EC encoded.");
+ }
+
+ //
+ // try with point compression turned off
+ //
+ ((ECPointEncoder)pubKey).setPointFormat("UNCOMPRESSED");
+
+ req = new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("CN=XXX"), pubKey).build(new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey));
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("Failed verify check EC uncompressed.");
+ }
+
+ JcaPKCS10CertificationRequest jcaReq = new JcaPKCS10CertificationRequest(new PKCS10CertificationRequest(req.getEncoded()));
+ if (!jcaReq.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(jcaReq.getPublicKey())))
+ {
+ fail("Failed verify check EC uncompressed encoded.");
+ }
+
+ if (!jcaReq.getSignatureAlgorithm().getAlgorithm().equals(algOid))
+ {
+ fail("ECDSA oid incorrect.");
+ }
+
+ if (jcaReq.getSignatureAlgorithm().getParameters() != null)
+ {
+ fail("ECDSA parameters incorrect.");
+ }
+
+ Signature sig = Signature.getInstance(algorithm, BC);
+
+ sig.initVerify(pubKey);
+
+ sig.update(req.toASN1Structure().getCertificationRequestInfo().getEncoded());
+
+ if (!sig.verify(req.getSignature()))
+ {
+ fail("signature not mapped correctly.");
+ }
+ }
+
+ private void createECGOSTRequest()
+ throws Exception
+ {
+ String algorithm = "GOST3411withECGOST3410";
+ KeyPairGenerator ecGostKpg = KeyPairGenerator.getInstance("ECGOST3410", "SC");
+
+ ecGostKpg.initialize(ECGOST3410NamedCurveTable.getParameterSpec("GostR3410-2001-CryptoPro-A"), new SecureRandom());
+
+ //
+ // set up the keys
+ //
+ KeyPair pair = ecGostKpg.generateKeyPair();
+ PrivateKey privKey = pair.getPrivate();
+ PublicKey pubKey = pair.getPublic();
+
+ PKCS10CertificationRequest req = new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("CN=XXX"), pubKey).build(new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey));
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("Failed verify check EC.");
+ }
+
+ req = new PKCS10CertificationRequest(req.getEncoded());
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("Failed verify check EC encoded.");
+ }
+
+ if (!req.getSignatureAlgorithm().getAlgorithm().equals(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001))
+ {
+ fail("ECGOST oid incorrect.");
+ }
+
+ if (req.getSignatureAlgorithm().getParameters() != null)
+ {
+ fail("ECGOST parameters incorrect.");
+ }
+
+ Signature sig = Signature.getInstance(algorithm, "SC");
+
+ sig.initVerify(pubKey);
+
+ sig.update(req.toASN1Structure().getCertificationRequestInfo().getEncoded());
+
+ if (!sig.verify(req.getSignature()))
+ {
+ fail("signature not mapped correctly.");
+ }
+ }
+
+ private void createPSSTest(String algorithm)
+ throws Exception
+ {
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+ new BigInteger("010001",16));
+
+ RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec(
+ new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+ new BigInteger("010001",16),
+ new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16),
+ new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16),
+ new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16),
+ new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16),
+ new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16),
+ new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16));
+
+ KeyFactory fact = KeyFactory.getInstance("RSA", "SC");
+
+ PrivateKey privKey = fact.generatePrivate(privKeySpec);
+ PublicKey pubKey = fact.generatePublic(pubKeySpec);
+
+ PKCS10CertificationRequest req = new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("CN=XXX"), pubKey).build(new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey));
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey)))
+ {
+ fail("Failed verify check PSS.");
+ }
+
+ JcaPKCS10CertificationRequest jcaReq = new JcaPKCS10CertificationRequest(req.getEncoded()).setProvider(BC);
+ if (!jcaReq.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(jcaReq.getPublicKey())))
+ {
+ fail("Failed verify check PSS encoded.");
+ }
+
+ if (!jcaReq.getSignatureAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ fail("PSS oid incorrect.");
+ }
+
+ if (jcaReq.getSignatureAlgorithm().getParameters() == null)
+ {
+ fail("PSS parameters incorrect.");
+ }
+
+ Signature sig = Signature.getInstance(algorithm, "SC");
+
+ sig.initVerify(pubKey);
+
+ sig.update(jcaReq.toASN1Structure().getCertificationRequestInfo().getEncoded());
+
+ if (!sig.verify(req.getSignature()))
+ {
+ fail("signature not mapped correctly.");
+ }
+ }
+
+ // previous code found to cause a NullPointerException
+ private void nullPointerTest()
+ throws Exception
+ {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA", "SC");
+ keyGen.initialize(1024, new SecureRandom());
+ KeyPair pair = keyGen.generateKeyPair();
+
+ Vector oids = new Vector();
+ Vector values = new Vector();
+ oids.addElement(X509Extension.basicConstraints);
+ values.addElement(new X509Extension(true, new DEROctetString(new BasicConstraints(true))));
+ oids.addElement(X509Extension.keyUsage);
+ values.addElement(new X509Extension(true, new DEROctetString(
+ new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign))));
+ SubjectKeyIdentifier subjectKeyIdentifier = new SubjectKeyIdentifierStructure(pair.getPublic());
+ X509Extension ski = new X509Extension(false, new DEROctetString(subjectKeyIdentifier));
+ oids.addElement(X509Extension.subjectKeyIdentifier);
+ values.addElement(ski);
+
+ PKCS10CertificationRequest p1 = new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("cn=csr"),
+ pair.getPublic())
+ .addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, new X509Extensions(oids, values))
+ .build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(pair.getPrivate()));
+ PKCS10CertificationRequest p2 = new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("cn=csr"),
+ pair.getPublic())
+ .addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, new X509Extensions(oids, values))
+ .build(new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(pair.getPrivate()));
+
+ if (!p1.equals(p2))
+ {
+ fail("cert request comparison failed");
+ }
+
+ Attribute[] attr1 = p1.getAttributes();
+ Attribute[] attr2 = p1.getAttributes();
+
+ checkAttrs(1, attr1, attr2);
+
+ attr1 = p1.getAttributes(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest);
+ attr2 = p1.getAttributes(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest);
+
+ checkAttrs(1, attr1, attr2);
+ }
+
+ private void checkAttrs(int expectedLength, Attribute[] attr1, Attribute[] attr2)
+ {
+ if (expectedLength != attr1.length)
+ {
+ fail("expected length mismatch");
+ }
+
+ if (attr1.length != attr2.length)
+ {
+ fail("atrribute length mismatch");
+ }
+
+ for (int i = 0; i != attr1.length; i++)
+ {
+ if (!attr1[i].equals(attr2[i]))
+ {
+ fail("atrribute mismatch");
+ }
+ }
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ generationTest(512, "RSA", "SHA1withRSA", "SC");
+ generationTest(512, "GOST3410", "GOST3411withGOST3410", "SC");
+
+ if (Security.getProvider("SunRsaSign") != null)
+ {
+ generationTest(512, "RSA", "SHA1withRSA", "SunRsaSign");
+ }
+
+ // elliptic curve GOST A parameter set
+ JcaPKCS10CertificationRequest req = new JcaPKCS10CertificationRequest(gost3410EC_A).setProvider(BC);
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(req.getPublicKey())))
+ {
+ fail("Failed verify check gost3410EC_A.");
+ }
+
+ // elliptic curve GOST B parameter set
+ req = new JcaPKCS10CertificationRequest(gost3410EC_B).setProvider(BC);
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(req.getPublicKey())))
+ {
+ fail("Failed verify check gost3410EC_B.");
+ }
+
+ // elliptic curve GOST C parameter set
+ req = new JcaPKCS10CertificationRequest(gost3410EC_C).setProvider(BC);
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(req.getPublicKey())))
+ {
+ fail("Failed verify check gost3410EC_C.");
+ }
+
+ // elliptic curve GOST ExA parameter set
+ req = new JcaPKCS10CertificationRequest(gost3410EC_ExA).setProvider(BC);
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(req.getPublicKey())))
+ {
+ fail("Failed verify check gost3410EC_ExA.");
+ }
+
+ // elliptic curve GOST ExB parameter set
+ req = new JcaPKCS10CertificationRequest(gost3410EC_ExB).setProvider(BC);
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(req.getPublicKey())))
+ {
+ fail("Failed verify check gost3410EC_ExA.");
+ }
+
+ // elliptic curve openSSL
+ KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "SC");
+
+ ECCurve curve = new ECCurve.Fp(
+ new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+ new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+ new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+
+ ECParameterSpec ecSpec = new ECParameterSpec(
+ curve,
+ curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+ new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n
+
+ g.initialize(ecSpec, new SecureRandom());
+
+ KeyPair kp = g.generateKeyPair();
+
+ req = new JcaPKCS10CertificationRequest(new JcaPKCS10CertificationRequestBuilder(
+ new X500Name("CN=XXX"), kp.getPublic()).build(new JcaContentSignerBuilder( "ECDSAWITHSHA1").setProvider(BC).build(kp.getPrivate())));
+ if (!req.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(req.getPublicKey())))
+ {
+ fail("Failed verify check EC.");
+ }
+
+ createECRequest("SHA1withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ createECRequest("SHA224withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ createECRequest("SHA256withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ createECRequest("SHA384withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ createECRequest("SHA512withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+
+ createECRequest("SHA1withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1, new DERObjectIdentifier("1.3.132.0.34"));
+
+ createECGOSTRequest();
+
+ createPSSTest("SHA1withRSAandMGF1");
+ createPSSTest("SHA224withRSAandMGF1");
+ createPSSTest("SHA256withRSAandMGF1");
+ createPSSTest("SHA384withRSAandMGF1");
+
+ nullPointerTest();
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new PKCS10Test());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/AllTests.java b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/AllTests.java
new file mode 100644
index 000000000..4c5704445
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/AllTests.java
@@ -0,0 +1,32 @@
+package org.spongycastle.cms.test;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import javax.crypto.Cipher;
+import java.security.Security;
+
+public class AllTests
+{
+ public static void main (String[] args)
+ throws Exception
+ {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ TestSuite suite = new TestSuite("CMS tests");
+
+ suite.addTest(CompressedDataTest.suite());
+ suite.addTest(SignedDataTest.suite());
+ suite.addTest(EnvelopedDataTest.suite());
+
+ suite.addTest(CompressedDataStreamTest.suite());
+ suite.addTest(SignedDataStreamTest.suite());
+ suite.addTest(EnvelopedDataStreamTest.suite());
+
+ return suite;
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/ConverterTest.java b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/ConverterTest.java
new file mode 100644
index 000000000..4fb7b5b08
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/ConverterTest.java
@@ -0,0 +1,111 @@
+package org.spongycastle.cms.test;
+
+import java.math.BigInteger;
+import org.spongycastle.jce.cert.X509CertSelector;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cms.KeyTransRecipientId;
+import org.spongycastle.cms.SignerId;
+import org.spongycastle.cms.jcajce.JcaSelectorConverter;
+import org.spongycastle.cms.jcajce.JcaX509CertSelectorConverter;
+import org.spongycastle.util.Arrays;
+
+public class ConverterTest
+ extends TestCase
+{
+ public void testSignerIdConversion()
+ throws Exception
+ {
+ JcaX509CertSelectorConverter converter = new JcaX509CertSelectorConverter();
+ JcaSelectorConverter toSelector = new JcaSelectorConverter();
+
+ SignerId sid1 = new SignerId(new X500Name("CN=Test"), BigInteger.valueOf(1), new byte[20]);
+
+ X509CertSelector conv = converter.getCertSelector(sid1);
+
+ assertTrue(conv.getIssuerAsString().equals("CN=Test"));
+ assertTrue(Arrays.areEqual(conv.getSubjectKeyIdentifier(), new DEROctetString(new byte[20]).getEncoded()));
+ assertEquals(conv.getSerialNumber(), sid1.getSerialNumber());
+
+ SignerId sid2 = toSelector.getSignerId(conv);
+
+ assertEquals(sid1, sid2);
+
+ sid1 = new SignerId(new X500Name("CN=Test"), BigInteger.valueOf(1));
+
+ conv = converter.getCertSelector(sid1);
+
+ assertTrue(conv.getIssuerAsString().equals("CN=Test"));
+ assertNull(conv.getSubjectKeyIdentifier());
+ assertEquals(conv.getSerialNumber(), sid1.getSerialNumber());
+
+ sid2 = toSelector.getSignerId(conv);
+
+ assertEquals(sid1, sid2);
+
+ sid1 = new SignerId(new byte[20]);
+
+ conv = converter.getCertSelector(sid1);
+
+ assertNull(conv.getIssuerAsString());
+ assertTrue(Arrays.areEqual(conv.getSubjectKeyIdentifier(), new DEROctetString(new byte[20]).getEncoded()));
+ assertNull(conv.getSerialNumber());
+
+ sid2 = toSelector.getSignerId(conv);
+
+ assertEquals(sid1, sid2);
+ }
+
+ public void testRecipientIdConversion()
+ throws Exception
+ {
+ JcaX509CertSelectorConverter converter = new JcaX509CertSelectorConverter();
+ JcaSelectorConverter toSelector = new JcaSelectorConverter();
+
+ KeyTransRecipientId ktid1 = new KeyTransRecipientId(new X500Name("CN=Test"), BigInteger.valueOf(1), new byte[20]);
+
+ X509CertSelector conv = converter.getCertSelector(ktid1);
+
+ assertTrue(conv.getIssuerAsString().equals("CN=Test"));
+ assertTrue(Arrays.areEqual(conv.getSubjectKeyIdentifier(), new DEROctetString(new byte[20]).getEncoded()));
+ assertEquals(conv.getSerialNumber(), ktid1.getSerialNumber());
+
+ KeyTransRecipientId ktid2 = toSelector.getKeyTransRecipientId(conv);
+
+ assertEquals(ktid1, ktid2);
+
+ ktid1 = new KeyTransRecipientId(new X500Name("CN=Test"), BigInteger.valueOf(1));
+
+ conv = converter.getCertSelector(ktid1);
+
+ assertTrue(conv.getIssuerAsString().equals("CN=Test"));
+ assertNull(conv.getSubjectKeyIdentifier());
+ assertEquals(conv.getSerialNumber(), ktid1.getSerialNumber());
+
+ ktid2 = toSelector.getKeyTransRecipientId(conv);
+
+ assertEquals(ktid1, ktid2);
+
+ ktid1 = new KeyTransRecipientId(new byte[20]);
+
+ conv = converter.getCertSelector(ktid1);
+
+ assertNull(conv.getIssuerAsString());
+ assertTrue(Arrays.areEqual(conv.getSubjectKeyIdentifier(), new DEROctetString(new byte[20]).getEncoded()));
+ assertNull(conv.getSerialNumber());
+
+ ktid2 = toSelector.getKeyTransRecipientId(conv);
+
+ assertEquals(ktid1, ktid2);
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ return new TestSuite(ConverterTest.class);
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/Rfc4134Test.java b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/Rfc4134Test.java
new file mode 100644
index 000000000..e9485e822
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/Rfc4134Test.java
@@ -0,0 +1,430 @@
+package org.spongycastle.cms.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.KeyFactory;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Security;
+import org.spongycastle.jce.cert.CertStore;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERUTF8String;
+import org.spongycastle.asn1.cms.Attribute;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSAttributes;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.cms.CMSEnvelopedData;
+import org.spongycastle.cms.CMSEnvelopedDataGenerator;
+import org.spongycastle.cms.CMSEnvelopedDataParser;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.CMSSignedData;
+import org.spongycastle.cms.CMSSignedDataParser;
+import org.spongycastle.cms.CMSTypedStream;
+import org.spongycastle.cms.RecipientInformation;
+import org.spongycastle.cms.RecipientInformationStore;
+import org.spongycastle.cms.SignerInformation;
+import org.spongycastle.cms.SignerInformationStore;
+import org.spongycastle.cms.jcajce.JcaX509CertSelectorConverter;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.encoders.Hex;
+import org.spongycastle.util.io.Streams;
+
+public class Rfc4134Test
+ extends TestCase
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+ private static final String TEST_DATA_HOME = "bc.test.data.home";
+
+ private static byte[] exContent = getRfc4134Data("ExContent.bin");
+ private static byte[] sha1 = Hex.decode("406aec085279ba6e16022d9e0629c0229687dd48");
+
+ private static final JcaX509CertSelectorConverter selectorConverter = new JcaX509CertSelectorConverter();
+
+ public Rfc4134Test(String name)
+ {
+ super(name);
+ }
+
+ public static void main(String args[])
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ junit.textui.TestRunner.run(Rfc4134Test.class);
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ return new CMSTestSetup(new TestSuite(Rfc4134Test.class));
+ }
+
+ public void test4_1()
+ throws Exception
+ {
+ byte[] data = getRfc4134Data("4.1.bin");
+ CMSSignedData signedData = new CMSSignedData(data);
+
+ verifySignatures(signedData);
+
+ CMSSignedDataParser parser = new CMSSignedDataParser(data);
+
+ verifySignatures(parser);
+ }
+
+ public void test4_2()
+ throws Exception
+ {
+ byte[] data = getRfc4134Data("4.2.bin");
+ CMSSignedData signedData = new CMSSignedData(data);
+
+ verifySignatures(signedData);
+
+ CMSSignedDataParser parser = new CMSSignedDataParser(data);
+
+ verifySignatures(parser);
+ }
+
+ public void testRfc4_3()
+ throws Exception
+ {
+ byte[] data = getRfc4134Data("4.3.bin");
+ CMSSignedData signedData = new CMSSignedData(new CMSProcessableByteArray(exContent), data);
+
+ verifySignatures(signedData, sha1);
+
+ CMSSignedDataParser parser = new CMSSignedDataParser(
+ new CMSTypedStream(new ByteArrayInputStream(exContent)),
+ data);
+
+ verifySignatures(parser);
+ }
+
+ public void test4_4()
+ throws Exception
+ {
+ byte[] data = getRfc4134Data("4.4.bin");
+ byte[] counterSigCert = getRfc4134Data("AliceRSASignByCarl.cer");
+ CMSSignedData signedData = new CMSSignedData(data);
+
+ verifySignatures(signedData, sha1);
+
+ verifySignerInfo4_4(getFirstSignerInfo(signedData.getSignerInfos()), counterSigCert);
+
+ CMSSignedDataParser parser = new CMSSignedDataParser(data);
+
+ verifySignatures(parser);
+
+ verifySignerInfo4_4(getFirstSignerInfo(parser.getSignerInfos()), counterSigCert);
+ }
+
+ public void test4_5()
+ throws Exception
+ {
+ byte[] data = getRfc4134Data("4.5.bin");
+ CMSSignedData signedData = new CMSSignedData(data);
+
+ verifySignatures(signedData);
+
+ CMSSignedDataParser parser = new CMSSignedDataParser(data);
+
+ verifySignatures(parser);
+ }
+
+ public void test4_6()
+ throws Exception
+ {
+ byte[] data = getRfc4134Data("4.6.bin");
+ CMSSignedData signedData = new CMSSignedData(data);
+
+ verifySignatures(signedData);
+
+ CMSSignedDataParser parser = new CMSSignedDataParser(data);
+
+ verifySignatures(parser);
+ }
+
+ public void test4_7()
+ throws Exception
+ {
+ byte[] data = getRfc4134Data("4.7.bin");
+ CMSSignedData signedData = new CMSSignedData(data);
+
+ verifySignatures(signedData);
+
+ CMSSignedDataParser parser = new CMSSignedDataParser(data);
+
+ verifySignatures(parser);
+ }
+
+ public void test5_1()
+ throws Exception
+ {
+ byte[] data = getRfc4134Data("5.1.bin");
+ CMSEnvelopedData envelopedData = new CMSEnvelopedData(data);
+
+ verifyEnvelopedData(envelopedData, CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ CMSEnvelopedDataParser envelopedParser = new CMSEnvelopedDataParser(data);
+
+ verifyEnvelopedData(envelopedParser, CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+ }
+
+ public void test5_2()
+ throws Exception
+ {
+ byte[] data = getRfc4134Data("5.2.bin");
+ CMSEnvelopedData envelopedData = new CMSEnvelopedData(data);
+
+ verifyEnvelopedData(envelopedData, CMSEnvelopedDataGenerator.RC2_CBC);
+
+ CMSEnvelopedDataParser envelopedParser = new CMSEnvelopedDataParser(data);
+
+ verifyEnvelopedData(envelopedParser, CMSEnvelopedDataGenerator.RC2_CBC);
+ }
+
+ private void verifyEnvelopedData(CMSEnvelopedData envelopedData, String symAlgorithmOID)
+ throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, CMSException
+ {
+ byte[] privKeyData = getRfc4134Data("BobPrivRSAEncrypt.pri");
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKeyData);
+ KeyFactory keyFact = KeyFactory.getInstance("RSA", BC);
+ PrivateKey privKey = keyFact.generatePrivate(keySpec);
+
+ RecipientInformationStore recipients = envelopedData.getRecipientInfos();
+
+ assertEquals(envelopedData.getEncryptionAlgOID(), symAlgorithmOID);
+
+ Collection c = recipients.getRecipients();
+ assertTrue(c.size() >= 1 && c.size() <= 2);
+
+ Iterator it = c.iterator();
+ verifyRecipient((RecipientInformation)it.next(), privKey);
+
+ if (c.size() == 2)
+ {
+ RecipientInformation recInfo = (RecipientInformation)it.next();
+
+ assertEquals(PKCSObjectIdentifiers.id_alg_CMSRC2wrap.getId(), recInfo.getKeyEncryptionAlgOID());
+ }
+ }
+
+ private void verifyEnvelopedData(CMSEnvelopedDataParser envelopedParser, String symAlgorithmOID)
+ throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, CMSException
+ {
+ byte[] privKeyData = getRfc4134Data("BobPrivRSAEncrypt.pri");
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKeyData);
+ KeyFactory keyFact = KeyFactory.getInstance("RSA", BC);
+ PrivateKey privKey = keyFact.generatePrivate(keySpec);
+
+ RecipientInformationStore recipients = envelopedParser.getRecipientInfos();
+
+ assertEquals(envelopedParser.getEncryptionAlgOID(), symAlgorithmOID);
+
+ Collection c = recipients.getRecipients();
+ assertTrue(c.size() >= 1 && c.size() <= 2);
+
+ Iterator it = c.iterator();
+ verifyRecipient((RecipientInformation)it.next(), privKey);
+
+ if (c.size() == 2)
+ {
+ RecipientInformation recInfo = (RecipientInformation)it.next();
+
+ assertEquals(PKCSObjectIdentifiers.id_alg_CMSRC2wrap.getId(), recInfo.getKeyEncryptionAlgOID());
+ }
+ }
+
+ private void verifyRecipient(RecipientInformation recipient, PrivateKey privKey)
+ throws CMSException, NoSuchProviderException
+ {
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(privKey, BC);
+
+ assertEquals(true, Arrays.equals(exContent, recData));
+ }
+
+ private void verifySignerInfo4_4(SignerInformation signerInfo, byte[] counterSigCert)
+ throws Exception
+ {
+ verifyCounterSignature(signerInfo, counterSigCert);
+
+ verifyContentHint(signerInfo);
+ }
+
+ private SignerInformation getFirstSignerInfo(SignerInformationStore store)
+ {
+ return (SignerInformation)store.getSigners().iterator().next();
+ }
+
+ private void verifyCounterSignature(SignerInformation signInfo, byte[] certificate)
+ throws Exception
+ {
+ SignerInformation csi = (SignerInformation)signInfo.getCounterSignatures().getSigners().iterator().next();
+
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", BC);
+ X509Certificate cert = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(certificate));
+
+ assertTrue(csi.verify(cert, BC));
+ }
+
+ private void verifyContentHint(SignerInformation signInfo)
+ {
+ AttributeTable attrTable = signInfo.getUnsignedAttributes();
+
+ Attribute attr = attrTable.get(CMSAttributes.contentHint);
+
+ assertEquals(1, attr.getAttrValues().size());
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new DERUTF8String("Content Hints Description Buffer"));
+ v.add(CMSObjectIdentifiers.data);
+
+ assertTrue(attr.getAttrValues().getObjectAt(0).equals(new DERSequence(v)));
+ }
+
+ private void verifySignatures(CMSSignedData s, byte[] contentDigest)
+ throws Exception
+ {
+ CertStore certStore = s.getCertificatesAndCRLs("Collection", BC);
+ SignerInformationStore signers = s.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certStore.getCertificates(selectorConverter.getCertSelector(signer.getSID()));
+
+ Iterator certIt = certCollection.iterator();
+ X509Certificate cert = (X509Certificate)certIt.next();
+
+ verifySigner(signer, cert);
+
+ if (contentDigest != null)
+ {
+ assertTrue(MessageDigest.isEqual(contentDigest, signer.getContentDigest()));
+ }
+ }
+
+ Collection certColl = certStore.getCertificates(null);
+ Collection crlColl = certStore.getCRLs(null);
+
+ assertEquals(certColl.size(), s.getCertificates("Collection", BC).getMatches(null).size());
+ assertEquals(crlColl.size(), s.getCRLs("Collection", BC).getMatches(null).size());
+ }
+
+ private void verifySignatures(CMSSignedData s)
+ throws Exception
+ {
+ verifySignatures(s, null);
+ }
+
+ private void verifySignatures(CMSSignedDataParser sp)
+ throws Exception
+ {
+ CMSTypedStream sc = sp.getSignedContent();
+ if (sc != null)
+ {
+ sc.drain();
+ }
+
+ CertStore certs = sp.getCertificatesAndCRLs("Collection", BC);
+ SignerInformationStore signers = sp.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getCertificates(selectorConverter.getCertSelector(signer.getSID()));
+
+ Iterator certIt = certCollection.iterator();
+ X509Certificate cert = (X509Certificate)certIt.next();
+
+ verifySigner(signer, cert);
+ }
+ }
+
+ private void verifySigner(SignerInformation signer, X509Certificate cert)
+ throws Exception
+ {
+ if (cert.getPublicKey() instanceof DSAPublicKey)
+ {
+ DSAPublicKey key = (DSAPublicKey)cert.getPublicKey();
+
+ if (key.getParams() == null)
+ {
+ assertEquals(true, signer.verify(getInheritedKey(key), BC));
+ }
+ else
+ {
+ assertEquals(true, signer.verify(cert, BC));
+ }
+ }
+ else
+ {
+ assertEquals(true, signer.verify(cert, BC));
+ }
+ }
+
+ private PublicKey getInheritedKey(DSAPublicKey key)
+ throws Exception
+ {
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", BC);
+
+ X509Certificate cert = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(getRfc4134Data("CarlDSSSelf.cer")));
+
+ DSAParams dsaParams = ((DSAPublicKey)cert.getPublicKey()).getParams();
+
+ DSAPublicKeySpec dsaPubKeySpec = new DSAPublicKeySpec(
+ key.getY(), dsaParams.getP(), dsaParams.getQ(), dsaParams.getG());
+
+ KeyFactory keyFactory = KeyFactory.getInstance("DSA", BC);
+
+ return keyFactory.generatePublic(dsaPubKeySpec);
+ }
+
+ private static byte[] getRfc4134Data(String name)
+ {
+ String dataHome = System.getProperty(TEST_DATA_HOME);
+
+ if (dataHome == null)
+ {
+ throw new IllegalStateException(TEST_DATA_HOME + " property not set");
+ }
+
+ try
+ {
+ return Streams.readAll(new FileInputStream(dataHome + "/rfc4134/" + name));
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/SignedDataStreamTest.java b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/SignedDataStreamTest.java
new file mode 100644
index 000000000..37deca738
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/SignedDataStreamTest.java
@@ -0,0 +1,1158 @@
+package org.spongycastle.cms.test;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import org.spongycastle.jce.cert.CertStore;
+import org.spongycastle.jce.cert.CollectionCertStoreParameters;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.cms.Attribute;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSAttributes;
+import org.spongycastle.cms.CMSAttributeTableGenerator;
+import org.spongycastle.cms.CMSProcessable;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.CMSSignedData;
+import org.spongycastle.cms.CMSSignedDataGenerator;
+import org.spongycastle.cms.CMSSignedDataParser;
+import org.spongycastle.cms.CMSSignedDataStreamGenerator;
+import org.spongycastle.cms.CMSSignedGenerator;
+import org.spongycastle.cms.CMSTypedStream;
+import org.spongycastle.cms.DefaultSignedAttributeTableGenerator;
+import org.spongycastle.cms.SignerInformation;
+import org.spongycastle.cms.SignerInformationStore;
+import org.spongycastle.cms.jcajce.JcaX509CertSelectorConverter;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.x509.X509AttributeCertificate;
+import org.spongycastle.x509.X509CollectionStoreParameters;
+import org.spongycastle.x509.X509Store;
+
+public class SignedDataStreamTest
+ extends TestCase
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ private static final String TEST_MESSAGE = "Hello World!";
+ private static String _signDN;
+ private static KeyPair _signKP;
+ private static X509Certificate _signCert;
+
+ private static String _origDN;
+ private static KeyPair _origKP;
+ private static X509Certificate _origCert;
+
+ private static String _reciDN;
+ private static KeyPair _reciKP;
+ private static X509Certificate _reciCert;
+
+ private static KeyPair _origDsaKP;
+ private static X509Certificate _origDsaCert;
+
+ private static X509CRL _signCrl;
+ private static X509CRL _origCrl;
+
+ private static boolean _initialised = false;
+
+ private static final JcaX509CertSelectorConverter selectorConverter = new JcaX509CertSelectorConverter();
+
+ public SignedDataStreamTest(String name)
+ {
+ super(name);
+ }
+
+ private static void init()
+ throws Exception
+ {
+ if (!_initialised)
+ {
+ _initialised = true;
+
+ _signDN = "O=Bouncy Castle, C=AU";
+ _signKP = CMSTestUtil.makeKeyPair();
+ _signCert = CMSTestUtil.makeCertificate(_signKP, _signDN, _signKP, _signDN);
+
+ _origDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+ _origKP = CMSTestUtil.makeKeyPair();
+ _origCert = CMSTestUtil.makeCertificate(_origKP, _origDN, _signKP, _signDN);
+
+ _origDsaKP = CMSTestUtil.makeDsaKeyPair();
+ _origDsaCert = CMSTestUtil.makeCertificate(_origDsaKP, _origDN, _signKP, _signDN);
+
+ _reciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+ _reciKP = CMSTestUtil.makeKeyPair();
+ _reciCert = CMSTestUtil.makeCertificate(_reciKP, _reciDN, _signKP, _signDN);
+
+ _signCrl = CMSTestUtil.makeCrl(_signKP);
+ _origCrl = CMSTestUtil.makeCrl(_origKP);
+ }
+ }
+
+ private void verifySignatures(CMSSignedDataParser sp, byte[] contentDigest)
+ throws Exception
+ {
+ CertStore certStore = sp.getCertificatesAndCRLs("Collection", BC);
+ SignerInformationStore signers = sp.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certStore.getCertificates(selectorConverter.getCertSelector(signer.getSID()));
+
+ Iterator certIt = certCollection.iterator();
+ X509Certificate cert = (X509Certificate)certIt.next();
+
+ assertEquals(true, signer.verify(cert, BC));
+
+ if (contentDigest != null)
+ {
+ assertTrue(MessageDigest.isEqual(contentDigest, signer.getContentDigest()));
+ }
+ }
+
+ Collection certColl = certStore.getCertificates(null);
+ Collection crlColl = certStore.getCRLs(null);
+
+ assertEquals(certColl.size(), sp.getCertificates("Collection", BC).getMatches(null).size());
+ assertEquals(crlColl.size(), sp.getCRLs("Collection", BC).getMatches(null).size());
+ }
+
+ private void verifySignatures(CMSSignedDataParser sp)
+ throws Exception
+ {
+ verifySignatures(sp, null);
+ }
+
+ private void verifyEncodedData(ByteArrayOutputStream bOut)
+ throws Exception
+ {
+ CMSSignedDataParser sp;
+ sp = new CMSSignedDataParser(bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+
+ sp.close();
+ }
+
+ private void checkSigParseable(byte[] sig)
+ throws Exception
+ {
+ CMSSignedDataParser sp = new CMSSignedDataParser(sig);
+ sp.getVersion();
+ CMSTypedStream sc = sp.getSignedContent();
+ if (sc != null)
+ {
+ sc.drain();
+ }
+ sp.getCertificatesAndCRLs("Collection", BC);
+ sp.getSignerInfos();
+ sp.close();
+ }
+
+ public void testEarlyInvalidKeyException() throws Exception
+ {
+ try
+ {
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+ gen.addSigner( _origKP.getPrivate(), _origCert,
+ "DSA", // DOESN'T MATCH KEY ALG
+ CMSSignedDataStreamGenerator.DIGEST_SHA1, BC);
+
+ fail("Expected InvalidKeyException in addSigner");
+ }
+ catch (InvalidKeyException e)
+ {
+ // Ignore
+ }
+ }
+
+ public void testEarlyNoSuchAlgorithmException() throws Exception
+ {
+ try
+ {
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+ gen.addSigner( _origKP.getPrivate(), _origCert,
+ CMSSignedDataStreamGenerator.DIGEST_SHA1, // BAD OID!
+ CMSSignedDataStreamGenerator.DIGEST_SHA1, BC);
+
+ fail("Expected NoSuchAlgorithmException in addSigner");
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Ignore
+ }
+ }
+
+ public void testSha1EncapsulatedSignature()
+ throws Exception
+ {
+ byte[] encapSigData = Base64.decode(
+ "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"
+ + "n7MsJMoKN3Kd2Vzh6s10PFgeAAAAAAAA");
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(encapSigData);
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+ }
+
+ public void testSHA1WithRSANoAttributes()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSProcessable msg = new CMSProcessableByteArray(TEST_MESSAGE.getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataGenerator.DIGEST_SHA1);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ CMSSignedData s = gen.generate(CMSSignedDataGenerator.DATA, msg, false, BC, false);
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(
+ new CMSTypedStream(new ByteArrayInputStream(TEST_MESSAGE.getBytes())), s.getEncoded());
+
+ sp.getSignedContent().drain();
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+
+ verifySignatures(sp, md.digest(TEST_MESSAGE.getBytes()));
+ }
+
+ public void testDSANoAttributes()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSProcessable msg = new CMSProcessableByteArray(TEST_MESSAGE.getBytes());
+
+ certList.add(_origDsaCert);
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ gen.addSigner(_origDsaKP.getPrivate(), _origDsaCert, CMSSignedDataGenerator.DIGEST_SHA1);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ CMSSignedData s = gen.generate(CMSSignedDataGenerator.DATA, msg, false, BC, false);
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(
+ new CMSTypedStream(new ByteArrayInputStream(TEST_MESSAGE.getBytes())), s.getEncoded());
+
+ sp.getSignedContent().drain();
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+
+ verifySignatures(sp, md.digest(TEST_MESSAGE.getBytes()));
+ }
+
+ public void testSHA1WithRSA()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ certList.add(_signCrl);
+ certList.add(_origCrl);
+
+ CertStore certsAndCrls = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataStreamGenerator.DIGEST_SHA1, BC);
+
+ gen.addCertificatesAndCRLs(certsAndCrls);
+
+ OutputStream sigOut = gen.open(bOut);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ checkSigParseable(bOut.toByteArray());
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(
+ new CMSTypedStream(new ByteArrayInputStream(TEST_MESSAGE.getBytes())), bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+
+ verifySignatures(sp, md.digest(TEST_MESSAGE.getBytes()));
+
+ //
+ // try using existing signer
+ //
+ gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigners(sp.getSignerInfos());
+
+ gen.addCertificatesAndCRLs(sp.getCertificatesAndCRLs("Collection", BC));
+
+ bOut.reset();
+
+ sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ verifyEncodedData(bOut);
+
+ //
+ // look for the CRLs
+ //
+ Collection col = certsAndCrls.getCRLs(null);
+
+ assertEquals(2, col.size());
+ assertTrue(col.contains(_signCrl));
+ assertTrue(col.contains(_origCrl));
+ }
+
+ public void testSHA1WithRSANonData()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ certList.add(_signCrl);
+ certList.add(_origCrl);
+
+ CertStore certsAndCrls = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataStreamGenerator.DIGEST_SHA1, BC);
+
+ gen.addCertificatesAndCRLs(certsAndCrls);
+
+ OutputStream sigOut = gen.open(bOut, "1.2.3.4", true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(bOut.toByteArray());
+
+ CMSTypedStream stream = sp.getSignedContent();
+
+ assertEquals(new ASN1ObjectIdentifier("1.2.3.4"), stream.getContentType());
+
+ stream.drain();
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+
+ verifySignatures(sp, md.digest(TEST_MESSAGE.getBytes()));
+ }
+
+ public void testSHA1AndMD5WithRSA()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataStreamGenerator.DIGEST_SHA1, BC);
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataStreamGenerator.DIGEST_MD5, BC);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ OutputStream sigOut = gen.open(bOut);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ checkSigParseable(bOut.toByteArray());
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(
+ new CMSTypedStream(new ByteArrayInputStream(TEST_MESSAGE.getBytes())), bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+ }
+
+ public void testSHA1WithRSAEncapsulatedBufferedStream()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ //
+ // find unbuffered length
+ //
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataStreamGenerator.DIGEST_SHA1, BC);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ for (int i = 0; i != 2000; i++)
+ {
+ sigOut.write(i & 0xff);
+ }
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+
+ int unbufferedLength = bOut.toByteArray().length;
+
+ //
+ // find buffered length with buffered stream - should be equal
+ //
+ bOut = new ByteArrayOutputStream();
+
+ gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataStreamGenerator.DIGEST_SHA1, BC);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ sigOut = gen.open(bOut, true);
+
+ BufferedOutputStream bfOut = new BufferedOutputStream(sigOut, 300);
+
+ for (int i = 0; i != 2000; i++)
+ {
+ bfOut.write(i & 0xff);
+ }
+
+ bfOut.close();
+
+ verifyEncodedData(bOut);
+
+ assertTrue(bOut.toByteArray().length == unbufferedLength);
+ }
+
+ public void testSHA1WithRSAEncapsulatedBuffered()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ //
+ // find unbuffered length
+ //
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataStreamGenerator.DIGEST_SHA1, BC);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ for (int i = 0; i != 2000; i++)
+ {
+ sigOut.write(i & 0xff);
+ }
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+
+ int unbufferedLength = bOut.toByteArray().length;
+
+ //
+ // find buffered length - buffer size less than default
+ //
+ bOut = new ByteArrayOutputStream();
+
+ gen = new CMSSignedDataStreamGenerator();
+
+ gen.setBufferSize(300);
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataStreamGenerator.DIGEST_SHA1, BC);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ sigOut = gen.open(bOut, true);
+
+ for (int i = 0; i != 2000; i++)
+ {
+ sigOut.write(i & 0xff);
+ }
+
+ sigOut.close();
+
+ verifyEncodedData(bOut);
+
+ assertTrue(bOut.toByteArray().length > unbufferedLength);
+ }
+
+ public void testSHA1WithRSAEncapsulated()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataStreamGenerator.DIGEST_SHA1, BC);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+
+ byte[] contentDigest = (byte[])gen.getGeneratedDigests().get(CMSSignedGenerator.DIGEST_SHA1);
+
+ AttributeTable table = ((SignerInformation)sp.getSignerInfos().getSigners().iterator().next()).getSignedAttributes();
+ Attribute hash = table.get(CMSAttributes.messageDigest);
+
+ assertTrue(MessageDigest.isEqual(contentDigest, ((ASN1OctetString)hash.getAttrValues().getObjectAt(0)).getOctets()));
+
+ //
+ // try using existing signer
+ //
+ gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigners(sp.getSignerInfos());
+
+ gen.addCertificatesAndCRLs(sp.getCertificatesAndCRLs("Collection", BC));
+
+ bOut.reset();
+
+ sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedData sd = new CMSSignedData(new CMSProcessableByteArray(TEST_MESSAGE.getBytes()), bOut.toByteArray());
+
+ assertEquals(1, sd.getSignerInfos().getSigners().size());
+
+ verifyEncodedData(bOut);
+ }
+
+ public void testSHA1WithRSAEncapsulatedSubjectKeyID()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), CMSTestUtil.createSubjectKeyId(_origCert.getPublicKey()).getKeyIdentifier(), CMSSignedDataStreamGenerator.DIGEST_SHA1, BC);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+
+ byte[] contentDigest = (byte[])gen.getGeneratedDigests().get(CMSSignedGenerator.DIGEST_SHA1);
+
+ AttributeTable table = ((SignerInformation)sp.getSignerInfos().getSigners().iterator().next()).getSignedAttributes();
+ Attribute hash = table.get(CMSAttributes.messageDigest);
+
+ assertTrue(MessageDigest.isEqual(contentDigest, ((ASN1OctetString)hash.getAttrValues().getObjectAt(0)).getOctets()));
+
+ //
+ // try using existing signer
+ //
+ gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigners(sp.getSignerInfos());
+
+ gen.addCertificatesAndCRLs(sp.getCertificatesAndCRLs("Collection", BC));
+
+ bOut.reset();
+
+ sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedData sd = new CMSSignedData(new CMSProcessableByteArray(TEST_MESSAGE.getBytes()), bOut.toByteArray());
+
+ assertEquals(1, sd.getSignerInfos().getSigners().size());
+
+ verifyEncodedData(bOut);
+ }
+
+ public void testAttributeGenerators()
+ throws Exception
+ {
+ final ASN1ObjectIdentifier dummyOid1 = new ASN1ObjectIdentifier("1.2.3");
+ final ASN1ObjectIdentifier dummyOid2 = new ASN1ObjectIdentifier("1.2.3.4");
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ CMSAttributeTableGenerator signedGen = new DefaultSignedAttributeTableGenerator()
+ {
+ public AttributeTable getAttributes(Map parameters)
+ {
+ Hashtable table = createStandardAttributeTable(parameters);
+
+ DEROctetString val = new DEROctetString((byte[])parameters.get(CMSAttributeTableGenerator.DIGEST));
+ Attribute attr = new Attribute(dummyOid1, new DERSet(val));
+
+ table.put(attr.getAttrType(), attr);
+
+ return new AttributeTable(table);
+ }
+ };
+
+ CMSAttributeTableGenerator unsignedGen = new CMSAttributeTableGenerator()
+ {
+ public AttributeTable getAttributes(Map parameters)
+ {
+ DEROctetString val = new DEROctetString((byte[])parameters.get(CMSAttributeTableGenerator.SIGNATURE));
+ Attribute attr = new Attribute(dummyOid2, new DERSet(val));
+
+ return new AttributeTable(new DERSet(attr));
+ }
+ };
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataStreamGenerator.DIGEST_SHA1, signedGen, unsignedGen, BC);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+
+ //
+ // check attributes
+ //
+ SignerInformationStore signers = sp.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ checkAttribute(signer.getContentDigest(), signer.getSignedAttributes().get(dummyOid1));
+ checkAttribute(signer.getSignature(), signer.getUnsignedAttributes().get(dummyOid2));
+ }
+ }
+
+ private void checkAttribute(byte[] expected, Attribute attr)
+ {
+ DEROctetString value = (DEROctetString)attr.getAttrValues().getObjectAt(0);
+
+ assertEquals(new DEROctetString(expected), value);
+ }
+
+ public void testWithAttributeCertificate()
+ throws Exception
+ {
+ List certList = new ArrayList();
+
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataGenerator.DIGEST_SHA1, BC);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ X509AttributeCertificate attrCert = CMSTestUtil.getAttributeCertificate();
+
+ X509Store store = X509Store.getInstance("AttributeCertificate/Collection",
+ new X509CollectionStoreParameters(Collections.singleton(attrCert)), BC);
+
+ gen.addAttributeCertificates(store);
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ assertEquals(4, sp.getVersion());
+
+ store = sp.getAttributeCertificates("Collection", BC);
+
+ Collection coll = store.getMatches(null);
+
+ assertEquals(1, coll.size());
+
+ assertTrue(coll.contains(attrCert));
+ }
+
+ public void testSignerStoreReplacement()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ byte[] data = TEST_MESSAGE.getBytes();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataStreamGenerator.DIGEST_SHA1, BC);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ OutputStream sigOut = gen.open(bOut, false);
+
+ sigOut.write(data);
+
+ sigOut.close();
+
+ checkSigParseable(bOut.toByteArray());
+
+ //
+ // create new Signer
+ //
+ ByteArrayInputStream original = new ByteArrayInputStream(bOut.toByteArray());
+
+ bOut.reset();
+
+ gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataStreamGenerator.DIGEST_SHA224, BC);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ sigOut = gen.open(bOut);
+
+ sigOut.write(data);
+
+ sigOut.close();
+
+ checkSigParseable(bOut.toByteArray());
+
+ CMSSignedData sd = new CMSSignedData(bOut.toByteArray());
+
+ //
+ // replace signer
+ //
+ ByteArrayOutputStream newOut = new ByteArrayOutputStream();
+
+ CMSSignedDataParser.replaceSigners(original, sd.getSignerInfos(), newOut);
+
+ sd = new CMSSignedData(new CMSProcessableByteArray(data), newOut.toByteArray());
+ SignerInformation signer = (SignerInformation)sd.getSignerInfos().getSigners().iterator().next();
+
+ assertEquals(signer.getDigestAlgOID(), CMSSignedDataStreamGenerator.DIGEST_SHA224);
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new CMSTypedStream(new ByteArrayInputStream(data)), newOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+ }
+
+ public void testEncapsulatedSignerStoreReplacement()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataStreamGenerator.DIGEST_SHA1, BC);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ //
+ // create new Signer
+ //
+ ByteArrayInputStream original = new ByteArrayInputStream(bOut.toByteArray());
+
+ bOut.reset();
+
+ gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataStreamGenerator.DIGEST_SHA224, BC);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedData sd = new CMSSignedData(bOut.toByteArray());
+
+ //
+ // replace signer
+ //
+ ByteArrayOutputStream newOut = new ByteArrayOutputStream();
+
+ CMSSignedDataParser.replaceSigners(original, sd.getSignerInfos(), newOut);
+
+ sd = new CMSSignedData(newOut.toByteArray());
+ SignerInformation signer = (SignerInformation)sd.getSignerInfos().getSigners().iterator().next();
+
+ assertEquals(signer.getDigestAlgOID(), CMSSignedDataStreamGenerator.DIGEST_SHA224);
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(newOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+ }
+
+ public void testCertStoreReplacement()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ byte[] data = TEST_MESSAGE.getBytes();
+
+ certList.add(_origDsaCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataStreamGenerator.DIGEST_SHA1, BC);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ OutputStream sigOut = gen.open(bOut);
+
+ sigOut.write(data);
+
+ sigOut.close();
+
+ checkSigParseable(bOut.toByteArray());
+
+ //
+ // create new certstore with the right certificates
+ //
+ certList = new ArrayList();
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ //
+ // replace certs
+ //
+ ByteArrayInputStream original = new ByteArrayInputStream(bOut.toByteArray());
+ ByteArrayOutputStream newOut = new ByteArrayOutputStream();
+
+ CMSSignedDataParser.replaceCertificatesAndCRLs(original, certs, newOut);
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(new CMSTypedStream(new ByteArrayInputStream(data)), newOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+ }
+
+ public void testEncapsulatedCertStoreReplacement()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origDsaCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataStreamGenerator.DIGEST_SHA1, BC);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ //
+ // create new certstore with the right certificates
+ //
+ certList = new ArrayList();
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ //
+ // replace certs
+ //
+ ByteArrayInputStream original = new ByteArrayInputStream(bOut.toByteArray());
+ ByteArrayOutputStream newOut = new ByteArrayOutputStream();
+
+ CMSSignedDataParser.replaceCertificatesAndCRLs(original, certs, newOut);
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(newOut.toByteArray());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+ }
+
+ public void testCertOrdering1()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataStreamGenerator.DIGEST_SHA1, BC);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+ certs = sp.getCertificatesAndCRLs("Collection", BC);
+ Iterator it = certs.getCertificates(null).iterator();
+
+ assertEquals(_origCert, it.next());
+ assertEquals(_signCert, it.next());
+ }
+
+ public void testCertOrdering2()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ certList.add(_signCert);
+ certList.add(_origCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataStreamGenerator.DIGEST_SHA1, BC);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ OutputStream sigOut = gen.open(bOut, true);
+
+ sigOut.write(TEST_MESSAGE.getBytes());
+
+ sigOut.close();
+
+ CMSSignedDataParser sp = new CMSSignedDataParser(bOut.toByteArray());
+
+ sp.getSignedContent().drain();
+ certs = sp.getCertificatesAndCRLs("Collection", BC);
+ Iterator it = certs.getCertificates(null).iterator();
+
+ assertEquals(_signCert, it.next());
+ assertEquals(_origCert, it.next());
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ init();
+
+ return new CMSTestSetup(new TestSuite(SignedDataStreamTest.class));
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/SignedDataTest.java b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/SignedDataTest.java
new file mode 100644
index 000000000..b8775ef78
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/cms/test/SignedDataTest.java
@@ -0,0 +1,1573 @@
+package org.spongycastle.cms.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import org.spongycastle.jce.cert.CertStore;
+import org.spongycastle.jce.cert.CollectionCertStoreParameters;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.cms.Attribute;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.cms.CMSAttributes;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.cms.CMSConfig;
+import org.spongycastle.cms.CMSProcessable;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.CMSSignedData;
+import org.spongycastle.cms.CMSSignedDataGenerator;
+import org.spongycastle.cms.CMSSignedDataParser;
+import org.spongycastle.cms.SignerId;
+import org.spongycastle.cms.SignerInformation;
+import org.spongycastle.cms.SignerInformationStore;
+import org.spongycastle.cms.jcajce.JcaX509CertSelectorConverter;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.io.Streams;
+import org.spongycastle.x509.X509AttributeCertificate;
+import org.spongycastle.x509.X509CollectionStoreParameters;
+import org.spongycastle.x509.X509Store;
+
+public class SignedDataTest
+ extends TestCase
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ boolean DEBUG = true;
+
+ private static String _origDN;
+ private static KeyPair _origKP;
+ private static X509Certificate _origCert;
+
+ private static String _signDN;
+ private static KeyPair _signKP;
+ private static X509Certificate _signCert;
+
+ private static KeyPair _signGostKP;
+ private static X509Certificate _signGostCert;
+
+ private static KeyPair _signEcDsaKP;
+ private static X509Certificate _signEcDsaCert;
+
+ private static KeyPair _signEcGostKP;
+ private static X509Certificate _signEcGostCert;
+
+ private static KeyPair _signDsaKP;
+ private static X509Certificate _signDsaCert;
+
+ private static String _reciDN;
+ private static KeyPair _reciKP;
+ private static X509Certificate _reciCert;
+
+ private static X509CRL _signCrl;
+
+ private static boolean _initialised = false;
+
+ private byte[] disorderedMessage = Base64.decode(
+ "SU9fc3RkaW5fdXNlZABfX2xpYmNfc3RhcnRfbWFpbgBnZXRob3N0aWQAX19n"
+ + "bW9uX3M=");
+
+ private byte[] disorderedSet = Base64.decode(
+ "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"
+ + "gQBpSRdnDb6AcNVaXSmGo6+kVPIBhot1LzJOGaPyDNpGXxd7LV4tMBF1U7gr"
+ + "4k1g9BO6YiMWvw9uiTZmn0CfV8+k4fWEuG/nmafRoGIuay2f+ILuT+C0rnp1"
+ + "4FgMsEhuVNJJAmb12QV0PZII+UneyhAneZuQQzVUkTcVgYxogxdSOzCCAlUw"
+ + "ggHBoAMCAQICBACdekowCgYGKyQDAwECBQAwbzELMAkGA1UEBhMCREUxPTA7"
+ + "BgNVBAoUNFJlZ3VsaWVydW5nc2JlaMhvcmRlIGbIdXIgVGVsZWtvbW11bmlr"
+ + "YXRpb24gdW5kIFBvc3QxITAMBgcCggYBCgcUEwExMBEGA1UEAxQKNlItQ2Eg"
+ + "MTpQTjAiGA8yMDAxMDIwMTEzNDcwN1oYDzIwMDUwMzIyMDg1NTUxWjBvMQsw"
+ + "CQYDVQQGEwJERTE9MDsGA1UEChQ0UmVndWxpZXJ1bmdzYmVoyG9yZGUgZsh1"
+ + "ciBUZWxla29tbXVuaWthdGlvbiB1bmQgUG9zdDEhMAwGBwKCBgEKBxQTATEw"
+ + "EQYDVQQDFAo1Ui1DQSAxOlBOMIGhMA0GCSqGSIb3DQEBAQUAA4GPADCBiwKB"
+ + "gQCKHkFTJx8GmoqFTxEOxpK9XkC3NZ5dBEKiUv0Ife3QMqeGMoCUnyJxwW0k"
+ + "2/53duHxtv2yHSZpFKjrjvE/uGwdOMqBMTjMzkFg19e9JPv061wyADOucOIa"
+ + "NAgha/zFt9XUyrHF21knKCvDNExv2MYIAagkTKajLMAw0bu1J0FadQIFAMAA"
+ + "AAEwCgYGKyQDAwECBQADgYEAV1yTi+2gyB7sUhn4PXmi/tmBxAfe5oBjDW8m"
+ + "gxtfudxKGZ6l/FUPNcrSc5oqBYxKWtLmf3XX87LcblYsch617jtNTkMzhx9e"
+ + "qxiD02ufcrxz2EVt0Akdqiz8mdVeqp3oLcNU/IttpSrcA91CAnoUXtDZYwb/"
+ + "gdQ4FI9l3+qo/0UwggJVMIIBwaADAgECAgQAxIymMAoGBiskAwMBAgUAMG8x"
+ + "CzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1bGllcnVuZ3NiZWjIb3JkZSBm"
+ + "yHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0MSEwDAYHAoIGAQoHFBMB"
+ + "MTARBgNVBAMUCjZSLUNhIDE6UE4wIhgPMjAwMTEwMTUxMzMxNThaGA8yMDA1"
+ + "MDYwMTA5NTIxN1owbzELMAkGA1UEBhMCREUxPTA7BgNVBAoUNFJlZ3VsaWVy"
+ + "dW5nc2JlaMhvcmRlIGbIdXIgVGVsZWtvbW11bmlrYXRpb24gdW5kIFBvc3Qx"
+ + "ITAMBgcCggYBCgcUEwExMBEGA1UEAxQKN1ItQ0EgMTpQTjCBoTANBgkqhkiG"
+ + "9w0BAQEFAAOBjwAwgYsCgYEAiokD/j6lEP4FexF356OpU5teUpGGfUKjIrFX"
+ + "BHc79G0TUzgVxqMoN1PWnWktQvKo8ETaugxLkP9/zfX3aAQzDW4Zki6x6GDq"
+ + "fy09Agk+RJvhfbbIzRkV4sBBco0n73x7TfG/9NTgVr/96U+I+z/1j30aboM6"
+ + "9OkLEhjxAr0/GbsCBQDAAAABMAoGBiskAwMBAgUAA4GBAHWRqRixt+EuqHhR"
+ + "K1kIxKGZL2vZuakYV0R24Gv/0ZR52FE4ECr+I49o8FP1qiGSwnXB0SwjuH2S"
+ + "iGiSJi+iH/MeY85IHwW1P5e+bOMvEOFhZhQXQixOD7totIoFtdyaj1XGYRef"
+ + "0f2cPOjNJorXHGV8wuBk+/j++sxbd/Net3FtMIICVTCCAcGgAwIBAgIEAMSM"
+ + "pzAKBgYrJAMDAQIFADBvMQswCQYDVQQGEwJERTE9MDsGA1UEChQ0UmVndWxp"
+ + "ZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxla29tbXVuaWthdGlvbiB1bmQgUG9z"
+ + "dDEhMAwGBwKCBgEKBxQTATEwEQYDVQQDFAo3Ui1DQSAxOlBOMCIYDzIwMDEx"
+ + "MDE1MTMzNDE0WhgPMjAwNTA2MDEwOTUyMTdaMG8xCzAJBgNVBAYTAkRFMT0w"
+ + "OwYDVQQKFDRSZWd1bGllcnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5p"
+ + "a2F0aW9uIHVuZCBQb3N0MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjZSLUNh"
+ + "IDE6UE4wgaEwDQYJKoZIhvcNAQEBBQADgY8AMIGLAoGBAIOiqxUkzVyqnvth"
+ + "ihnltsE5m1Xn5TZKeR/2MQPStc5hJ+V4yptEtIx+Fn5rOoqT5VEVWhcE35wd"
+ + "bPvgJyQFn5msmhPQT/6XSGOlrWRoFummXN9lQzAjCj1sgTcmoLCVQ5s5WpCA"
+ + "OXFwVWu16qndz3sPItn3jJ0F3Kh3w79NglvPAgUAwAAAATAKBgYrJAMDAQIF"
+ + "AAOBgQBi5W96UVDoNIRkCncqr1LLG9vF9SGBIkvFpLDIIbcvp+CXhlvsdCJl"
+ + "0pt2QEPSDl4cmpOet+CxJTdTuMeBNXxhb7Dvualog69w/+K2JbPhZYxuVFZs"
+ + "Zh5BkPn2FnbNu3YbJhE60aIkikr72J4XZsI5DxpZCGh6xyV/YPRdKSljFjCC"
+ + "AlQwggHAoAMCAQICAwyDqzAKBgYrJAMDAQIFADBvMQswCQYDVQQGEwJERTE9"
+ + "MDsGA1UEChQ0UmVndWxpZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxla29tbXVu"
+ + "aWthdGlvbiB1bmQgUG9zdDEhMAwGBwKCBgEKBxQTATEwEQYDVQQDFAo1Ui1D"
+ + "QSAxOlBOMCIYDzIwMDAwMzIyMDk0MTI3WhgPMjAwNDAxMjExNjA0NTNaMG8x"
+ + "CzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1bGllcnVuZ3NiZWjIb3JkZSBm"
+ + "yHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0MSEwDAYHAoIGAQoHFBMB"
+ + "MTARBgNVBAMUCjRSLUNBIDE6UE4wgaEwDQYJKoZIhvcNAQEBBQADgY8AMIGL"
+ + "AoGBAI8x26tmrFJanlm100B7KGlRemCD1R93PwdnG7svRyf5ZxOsdGrDszNg"
+ + "xg6ouO8ZHQMT3NC2dH8TvO65Js+8bIyTm51azF6clEg0qeWNMKiiXbBXa+ph"
+ + "hTkGbXiLYvACZ6/MTJMJ1lcrjpRF7BXtYeYMcEF6znD4pxOqrtbf9z5hAgUA"
+ + "wAAAATAKBgYrJAMDAQIFAAOBgQB99BjSKlGPbMLQAgXlvA9jUsDNhpnVm3a1"
+ + "YkfxSqS/dbQlYkbOKvCxkPGA9NBxisBM8l1zFynVjJoy++aysRmcnLY/sHaz"
+ + "23BF2iU7WERy18H3lMBfYB6sXkfYiZtvQZcWaO48m73ZBySuiV3iXpb2wgs/"
+ + "Cs20iqroAWxwq/W/9jCCAlMwggG/oAMCAQICBDsFZ9UwCgYGKyQDAwECBQAw"
+ + "bzELMAkGA1UEBhMCREUxITAMBgcCggYBCgcUEwExMBEGA1UEAxQKNFItQ0Eg"
+ + "MTpQTjE9MDsGA1UEChQ0UmVndWxpZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxl"
+ + "a29tbXVuaWthdGlvbiB1bmQgUG9zdDAiGA8xOTk5MDEyMTE3MzUzNFoYDzIw"
+ + "MDQwMTIxMTYwMDAyWjBvMQswCQYDVQQGEwJERTE9MDsGA1UEChQ0UmVndWxp"
+ + "ZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxla29tbXVuaWthdGlvbiB1bmQgUG9z"
+ + "dDEhMAwGBwKCBgEKBxQTATEwEQYDVQQDFAozUi1DQSAxOlBOMIGfMA0GCSqG"
+ + "SIb3DQEBAQUAA4GNADCBiQKBgI4B557mbKQg/AqWBXNJhaT/6lwV93HUl4U8"
+ + "u35udLq2+u9phns1WZkdM3gDfEpL002PeLfHr1ID/96dDYf04lAXQfombils"
+ + "of1C1k32xOvxjlcrDOuPEMxz9/HDAQZA5MjmmYHAIulGI8Qg4Tc7ERRtg/hd"
+ + "0QX0/zoOeXoDSEOBAgTAAAABMAoGBiskAwMBAgUAA4GBAIyzwfT3keHI/n2P"
+ + "LrarRJv96mCohmDZNpUQdZTVjGu5VQjVJwk3hpagU0o/t/FkdzAjOdfEw8Ql"
+ + "3WXhfIbNLv1YafMm2eWSdeYbLcbB5yJ1od+SYyf9+tm7cwfDAcr22jNRBqx8"
+ + "wkWKtKDjWKkevaSdy99sAI8jebHtWz7jzydKMIID9TCCA16gAwIBAgICbMcw"
+ + "DQYJKoZIhvcNAQEFBQAwSzELMAkGA1UEBhMCREUxEjAQBgNVBAoUCVNpZ250"
+ + "cnVzdDEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFDQSBTSUdOVFJVU1QgMTpQ"
+ + "TjAeFw0wNDA3MzAxMzAyNDZaFw0wNzA3MzAxMzAyNDZaMDwxETAPBgNVBAMM"
+ + "CFlhY29tOlBOMQ4wDAYDVQRBDAVZYWNvbTELMAkGA1UEBhMCREUxCjAIBgNV"
+ + "BAUTATEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAIWzLlYLQApocXIp"
+ + "pgCCpkkOUVLgcLYKeOd6/bXAnI2dTHQqT2bv7qzfUnYvOqiNgYdF13pOYtKg"
+ + "XwXMTNFL4ZOI6GoBdNs9TQiZ7KEWnqnr2945HYx7UpgTBclbOK/wGHuCdcwO"
+ + "x7juZs1ZQPFG0Lv8RoiV9s6HP7POqh1sO0P/AgMBAAGjggH1MIIB8TCBnAYD"
+ + "VR0jBIGUMIGRgBQcZzNghfnXoXRm8h1+VITC5caNRqFzpHEwbzELMAkGA1UE"
+ + "BhMCREUxPTA7BgNVBAoUNFJlZ3VsaWVydW5nc2JlaMhvcmRlIGbIdXIgVGVs"
+ + "ZWtvbW11bmlrYXRpb24gdW5kIFBvc3QxITAMBgcCggYBCgcUEwExMBEGA1UE"
+ + "AxQKNVItQ0EgMTpQToIEALs8rjAdBgNVHQ4EFgQU2e5KAzkVuKaM9I5heXkz"
+ + "bcAIuR8wDgYDVR0PAQH/BAQDAgZAMBIGA1UdIAQLMAkwBwYFKyQIAQEwfwYD"
+ + "VR0fBHgwdjB0oCygKoYobGRhcDovL2Rpci5zaWdudHJ1c3QuZGUvbz1TaWdu"
+ + "dHJ1c3QsYz1kZaJEpEIwQDEdMBsGA1UEAxMUQ1JMU2lnblNpZ250cnVzdDE6"
+ + "UE4xEjAQBgNVBAoTCVNpZ250cnVzdDELMAkGA1UEBhMCREUwYgYIKwYBBQUH"
+ + "AQEEVjBUMFIGCCsGAQUFBzABhkZodHRwOi8vZGlyLnNpZ250cnVzdC5kZS9T"
+ + "aWdudHJ1c3QvT0NTUC9zZXJ2bGV0L2h0dHBHYXRld2F5LlBvc3RIYW5kbGVy"
+ + "MBgGCCsGAQUFBwEDBAwwCjAIBgYEAI5GAQEwDgYHAoIGAQoMAAQDAQH/MA0G"
+ + "CSqGSIb3DQEBBQUAA4GBAHn1m3GcoyD5GBkKUY/OdtD6Sj38LYqYCF+qDbJR"
+ + "6pqUBjY2wsvXepUppEler+stH8mwpDDSJXrJyuzf7xroDs4dkLl+Rs2x+2tg"
+ + "BjU+ABkBDMsym2WpwgA8LCdymmXmjdv9tULxY+ec2pjSEzql6nEZNEfrU8nt"
+ + "ZCSCavgqW4TtMYIBejCCAXYCAQEwUTBLMQswCQYDVQQGEwJERTESMBAGA1UE"
+ + "ChQJU2lnbnRydXN0MSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEUNBIFNJR05U"
+ + "UlVTVCAxOlBOAgJsxzAJBgUrDgMCGgUAoIGAMBgGCSqGSIb3DQEJAzELBgkq"
+ + "hkiG9w0BBwEwIwYJKoZIhvcNAQkEMRYEFIYfhPoyfGzkLWWSSLjaHb4HQmaK"
+ + "MBwGCSqGSIb3DQEJBTEPFw0wNTAzMjQwNzM4MzVaMCEGBSskCAYFMRgWFi92"
+ + "YXIvZmlsZXMvdG1wXzEvdGVzdDEwDQYJKoZIhvcNAQEFBQAEgYA2IvA8lhVz"
+ + "VD5e/itUxbFboKxeKnqJ5n/KuO/uBCl1N14+7Z2vtw1sfkIG+bJdp3OY2Cmn"
+ + "mrQcwsN99Vjal4cXVj8t+DJzFG9tK9dSLvD3q9zT/GQ0kJXfimLVwCa4NaSf"
+ + "Qsu4xtG0Rav6bCcnzabAkKuNNvKtH8amSRzk870DBg==");
+
+ public static byte[] xtraCounterSig = Base64.decode(
+ "MIIR/AYJKoZIhvcNAQcCoIIR7TCCEekCAQExCzAJBgUrDgMCGgUAMBoGCSqG"
+ + "SIb3DQEHAaANBAtIZWxsbyB3b3JsZKCCDnkwggTPMIIDt6ADAgECAgRDnYD3"
+ + "MA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNVBAYTAklUMRowGAYDVQQKExFJbi5U"
+ + "ZS5TLkEuIFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5BLiAtIENlcnRpZmlj"
+ + "YXRpb24gQXV0aG9yaXR5MB4XDTA4MDkxMjExNDMxMloXDTEwMDkxMjExNDMx"
+ + "MlowgdgxCzAJBgNVBAYTAklUMSIwIAYDVQQKDBlJbnRlc2EgUy5wLkEuLzA1"
+ + "MjYyODkwMDE0MSowKAYDVQQLDCFCdXNpbmVzcyBDb2xsYWJvcmF0aW9uICYg"
+ + "U2VjdXJpdHkxHjAcBgNVBAMMFU1BU1NJTUlMSUFOTyBaSUNDQVJESTERMA8G"
+ + "A1UEBAwIWklDQ0FSREkxFTATBgNVBCoMDE1BU1NJTUlMSUFOTzEcMBoGA1UE"
+ + "BRMTSVQ6WkNDTVNNNzZIMTRMMjE5WTERMA8GA1UELhMIMDAwMDI1ODUwgaAw"
+ + "DQYJKoZIhvcNAQEBBQADgY4AMIGKAoGBALeJTjmyFgx1SIP6c2AuB/kuyHo5"
+ + "j/prKELTALsFDimre/Hxr3wOSet1TdQfFzU8Lu+EJqgfV9cV+cI1yeH1rZs7"
+ + "lei7L3tX/VR565IywnguX5xwvteASgWZr537Fkws50bvTEMyYOj1Tf3FZvZU"
+ + "z4n4OD39KI4mfR9i1eEVIxR3AgQAizpNo4IBoTCCAZ0wHQYDVR0RBBYwFIES"
+ + "emljY2FyZGlAaW50ZXNhLml0MC8GCCsGAQUFBwEDBCMwITAIBgYEAI5GAQEw"
+ + "CwYGBACORgEDAgEUMAgGBgQAjkYBBDBZBgNVHSAEUjBQME4GBgQAizABATBE"
+ + "MEIGCCsGAQUFBwIBFjZodHRwOi8vZS10cnVzdGNvbS5pbnRlc2EuaXQvY2Ff"
+ + "cHViYmxpY2EvQ1BTX0lOVEVTQS5odG0wDgYDVR0PAQH/BAQDAgZAMIGDBgNV"
+ + "HSMEfDB6gBQZCQOW0bjFWBt+EORuxPagEgkQqKFcpFowWDELMAkGA1UEBhMC"
+ + "SVQxGjAYBgNVBAoTEUluLlRlLlMuQS4gUy5wLkEuMS0wKwYDVQQDEyRJbi5U"
+ + "ZS5TLkEuIC0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHmCBDzRARMwOwYDVR0f"
+ + "BDQwMjAwoC6gLIYqaHR0cDovL2UtdHJ1c3Rjb20uaW50ZXNhLml0L0NSTC9J"
+ + "TlRFU0EuY3JsMB0GA1UdDgQWBBTf5ItL8KmQh541Dxt7YxcWI1254TANBgkq"
+ + "hkiG9w0BAQUFAAOCAQEAgW+uL1CVWQepbC/wfCmR6PN37Sueb4xiKQj2mTD5"
+ + "UZ5KQjpivy/Hbuf0NrfKNiDEhAvoHSPC31ebGiKuTMFNyZPHfPEUnyYGSxea"
+ + "2w837aXJFr6utPNQGBRi89kH90sZDlXtOSrZI+AzJJn5QK3F9gjcayU2NZXQ"
+ + "MJgRwYmFyn2w4jtox+CwXPQ9E5XgxiMZ4WDL03cWVXDLX00EOJwnDDMUNTRI"
+ + "m9Zv+4SKTNlfFbi9UTBqWBySkDzAelsfB2U61oqc2h1xKmCtkGMmN9iZT+Qz"
+ + "ZC/vaaT+hLEBFGAH2gwFrYc4/jTBKyBYeU1vsAxsibIoTs1Apgl6MH75qPDL"
+ + "BzCCBM8wggO3oAMCAQICBEOdgPcwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UE"
+ + "BhMCSVQxGjAYBgNVBAoTEUluLlRlLlMuQS4gUy5wLkEuMS0wKwYDVQQDEyRJ"
+ + "bi5UZS5TLkEuIC0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwOTEy"
+ + "MTE0MzEyWhcNMTAwOTEyMTE0MzEyWjCB2DELMAkGA1UEBhMCSVQxIjAgBgNV"
+ + "BAoMGUludGVzYSBTLnAuQS4vMDUyNjI4OTAwMTQxKjAoBgNVBAsMIUJ1c2lu"
+ + "ZXNzIENvbGxhYm9yYXRpb24gJiBTZWN1cml0eTEeMBwGA1UEAwwVTUFTU0lN"
+ + "SUxJQU5PIFpJQ0NBUkRJMREwDwYDVQQEDAhaSUNDQVJESTEVMBMGA1UEKgwM"
+ + "TUFTU0lNSUxJQU5PMRwwGgYDVQQFExNJVDpaQ0NNU003NkgxNEwyMTlZMREw"
+ + "DwYDVQQuEwgwMDAwMjU4NTCBoDANBgkqhkiG9w0BAQEFAAOBjgAwgYoCgYEA"
+ + "t4lOObIWDHVIg/pzYC4H+S7IejmP+msoQtMAuwUOKat78fGvfA5J63VN1B8X"
+ + "NTwu74QmqB9X1xX5wjXJ4fWtmzuV6Lsve1f9VHnrkjLCeC5fnHC+14BKBZmv"
+ + "nfsWTCznRu9MQzJg6PVN/cVm9lTPifg4Pf0ojiZ9H2LV4RUjFHcCBACLOk2j"
+ + "ggGhMIIBnTAdBgNVHREEFjAUgRJ6aWNjYXJkaUBpbnRlc2EuaXQwLwYIKwYB"
+ + "BQUHAQMEIzAhMAgGBgQAjkYBATALBgYEAI5GAQMCARQwCAYGBACORgEEMFkG"
+ + "A1UdIARSMFAwTgYGBACLMAEBMEQwQgYIKwYBBQUHAgEWNmh0dHA6Ly9lLXRy"
+ + "dXN0Y29tLmludGVzYS5pdC9jYV9wdWJibGljYS9DUFNfSU5URVNBLmh0bTAO"
+ + "BgNVHQ8BAf8EBAMCBkAwgYMGA1UdIwR8MHqAFBkJA5bRuMVYG34Q5G7E9qAS"
+ + "CRCooVykWjBYMQswCQYDVQQGEwJJVDEaMBgGA1UEChMRSW4uVGUuUy5BLiBT"
+ + "LnAuQS4xLTArBgNVBAMTJEluLlRlLlMuQS4gLSBDZXJ0aWZpY2F0aW9uIEF1"
+ + "dGhvcml0eYIEPNEBEzA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vZS10cnVz"
+ + "dGNvbS5pbnRlc2EuaXQvQ1JML0lOVEVTQS5jcmwwHQYDVR0OBBYEFN/ki0vw"
+ + "qZCHnjUPG3tjFxYjXbnhMA0GCSqGSIb3DQEBBQUAA4IBAQCBb64vUJVZB6ls"
+ + "L/B8KZHo83ftK55vjGIpCPaZMPlRnkpCOmK/L8du5/Q2t8o2IMSEC+gdI8Lf"
+ + "V5saIq5MwU3Jk8d88RSfJgZLF5rbDzftpckWvq6081AYFGLz2Qf3SxkOVe05"
+ + "Ktkj4DMkmflArcX2CNxrJTY1ldAwmBHBiYXKfbDiO2jH4LBc9D0TleDGIxnh"
+ + "YMvTdxZVcMtfTQQ4nCcMMxQ1NEib1m/7hIpM2V8VuL1RMGpYHJKQPMB6Wx8H"
+ + "ZTrWipzaHXEqYK2QYyY32JlP5DNkL+9ppP6EsQEUYAfaDAWthzj+NMErIFh5"
+ + "TW+wDGyJsihOzUCmCXowfvmo8MsHMIIEzzCCA7egAwIBAgIEQ52A9zANBgkq"
+ + "hkiG9w0BAQUFADBYMQswCQYDVQQGEwJJVDEaMBgGA1UEChMRSW4uVGUuUy5B"
+ + "LiBTLnAuQS4xLTArBgNVBAMTJEluLlRlLlMuQS4gLSBDZXJ0aWZpY2F0aW9u"
+ + "IEF1dGhvcml0eTAeFw0wODA5MTIxMTQzMTJaFw0xMDA5MTIxMTQzMTJaMIHY"
+ + "MQswCQYDVQQGEwJJVDEiMCAGA1UECgwZSW50ZXNhIFMucC5BLi8wNTI2Mjg5"
+ + "MDAxNDEqMCgGA1UECwwhQnVzaW5lc3MgQ29sbGFib3JhdGlvbiAmIFNlY3Vy"
+ + "aXR5MR4wHAYDVQQDDBVNQVNTSU1JTElBTk8gWklDQ0FSREkxETAPBgNVBAQM"
+ + "CFpJQ0NBUkRJMRUwEwYDVQQqDAxNQVNTSU1JTElBTk8xHDAaBgNVBAUTE0lU"
+ + "OlpDQ01TTTc2SDE0TDIxOVkxETAPBgNVBC4TCDAwMDAyNTg1MIGgMA0GCSqG"
+ + "SIb3DQEBAQUAA4GOADCBigKBgQC3iU45shYMdUiD+nNgLgf5Lsh6OY/6ayhC"
+ + "0wC7BQ4pq3vx8a98DknrdU3UHxc1PC7vhCaoH1fXFfnCNcnh9a2bO5Xouy97"
+ + "V/1UeeuSMsJ4Ll+ccL7XgEoFma+d+xZMLOdG70xDMmDo9U39xWb2VM+J+Dg9"
+ + "/SiOJn0fYtXhFSMUdwIEAIs6TaOCAaEwggGdMB0GA1UdEQQWMBSBEnppY2Nh"
+ + "cmRpQGludGVzYS5pdDAvBggrBgEFBQcBAwQjMCEwCAYGBACORgEBMAsGBgQA"
+ + "jkYBAwIBFDAIBgYEAI5GAQQwWQYDVR0gBFIwUDBOBgYEAIswAQEwRDBCBggr"
+ + "BgEFBQcCARY2aHR0cDovL2UtdHJ1c3Rjb20uaW50ZXNhLml0L2NhX3B1YmJs"
+ + "aWNhL0NQU19JTlRFU0EuaHRtMA4GA1UdDwEB/wQEAwIGQDCBgwYDVR0jBHww"
+ + "eoAUGQkDltG4xVgbfhDkbsT2oBIJEKihXKRaMFgxCzAJBgNVBAYTAklUMRow"
+ + "GAYDVQQKExFJbi5UZS5TLkEuIFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5B"
+ + "LiAtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ80QETMDsGA1UdHwQ0MDIw"
+ + "MKAuoCyGKmh0dHA6Ly9lLXRydXN0Y29tLmludGVzYS5pdC9DUkwvSU5URVNB"
+ + "LmNybDAdBgNVHQ4EFgQU3+SLS/CpkIeeNQ8be2MXFiNdueEwDQYJKoZIhvcN"
+ + "AQEFBQADggEBAIFvri9QlVkHqWwv8Hwpkejzd+0rnm+MYikI9pkw+VGeSkI6"
+ + "Yr8vx27n9Da3yjYgxIQL6B0jwt9XmxoirkzBTcmTx3zxFJ8mBksXmtsPN+2l"
+ + "yRa+rrTzUBgUYvPZB/dLGQ5V7Tkq2SPgMySZ+UCtxfYI3GslNjWV0DCYEcGJ"
+ + "hcp9sOI7aMfgsFz0PROV4MYjGeFgy9N3FlVwy19NBDicJwwzFDU0SJvWb/uE"
+ + "ikzZXxW4vVEwalgckpA8wHpbHwdlOtaKnNodcSpgrZBjJjfYmU/kM2Qv72mk"
+ + "/oSxARRgB9oMBa2HOP40wSsgWHlNb7AMbImyKE7NQKYJejB++ajwywcxggM8"
+ + "MIIDOAIBATBgMFgxCzAJBgNVBAYTAklUMRowGAYDVQQKExFJbi5UZS5TLkEu"
+ + "IFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5BLiAtIENlcnRpZmljYXRpb24g"
+ + "QXV0aG9yaXR5AgRDnYD3MAkGBSsOAwIaBQAwDQYJKoZIhvcNAQEBBQAEgYB+"
+ + "lH2cwLqc91mP8prvgSV+RRzk13dJdZvdoVjgQoFrPhBiZCNIEoHvIhMMA/sM"
+ + "X6euSRZk7EjD24FasCEGYyd0mJVLEy6TSPmuW+wWz/28w3a6IWXBGrbb/ild"
+ + "/CJMkPgLPGgOVD1WDwiNKwfasiQSFtySf5DPn3jFevdLeMmEY6GCAjIwggEV"
+ + "BgkqhkiG9w0BCQYxggEGMIIBAgIBATBgMFgxCzAJBgNVBAYTAklUMRowGAYD"
+ + "VQQKExFJbi5UZS5TLkEuIFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5BLiAt"
+ + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5AgRDnYD3MAkGBSsOAwIaBQAwDQYJ"
+ + "KoZIhvcNAQEBBQAEgYBHlOULfT5GDigIvxP0qZOy8VbpntmzaPF55VV4buKV"
+ + "35J+uHp98gXKp0LrHM69V5IRKuyuQzHHFBqsXxsRI9o6KoOfgliD9Xc+BeMg"
+ + "dKzQhBhBYoFREq8hQM0nSbqDNHYAQyNHMzUA/ZQUO5dlFuH8Dw3iDYAhNtfd"
+ + "PrlchKJthDCCARUGCSqGSIb3DQEJBjGCAQYwggECAgEBMGAwWDELMAkGA1UE"
+ + "BhMCSVQxGjAYBgNVBAoTEUluLlRlLlMuQS4gUy5wLkEuMS0wKwYDVQQDEyRJ"
+ + "bi5UZS5TLkEuIC0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkCBEOdgPcwCQYF"
+ + "Kw4DAhoFADANBgkqhkiG9w0BAQEFAASBgEeU5Qt9PkYOKAi/E/Spk7LxVume"
+ + "2bNo8XnlVXhu4pXfkn64en3yBcqnQusczr1XkhEq7K5DMccUGqxfGxEj2joq"
+ + "g5+CWIP1dz4F4yB0rNCEGEFigVESryFAzSdJuoM0dgBDI0czNQD9lBQ7l2UW"
+ + "4fwPDeINgCE2190+uVyEom2E");
+
+ byte[] noSignedAttrSample2 = Base64.decode(
+ "MIIIlAYJKoZIhvcNAQcCoIIIhTCCCIECAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+ + "SIb3DQEHAaCCB3UwggOtMIIDa6ADAgECAgEzMAsGByqGSM44BAMFADCBkDEL"
+ + "MAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlQYWxvIEFsdG8x"
+ + "HTAbBgNVBAoTFFN1biBNaWNyb3N5c3RlbXMgSW5jMSMwIQYDVQQLExpKYXZh"
+ + "IFNvZnR3YXJlIENvZGUgU2lnbmluZzEcMBoGA1UEAxMTSkNFIENvZGUgU2ln"
+ + "bmluZyBDQTAeFw0wMTA1MjkxNjQ3MTFaFw0wNjA1MjgxNjQ3MTFaMG4xHTAb"
+ + "BgNVBAoTFFN1biBNaWNyb3N5c3RlbXMgSW5jMSMwIQYDVQQLExpKYXZhIFNv"
+ + "ZnR3YXJlIENvZGUgU2lnbmluZzEoMCYGA1UEAxMfVGhlIExlZ2lvbiBvZiB0"
+ + "aGUgQm91bmN5IENhc3RsZTCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OB"
+ + "HXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2"
+ + "y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58aophUP"
+ + "BPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvM"
+ + "spK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9"
+ + "B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCj"
+ + "rh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtV"
+ + "JWQBTDv+z0kqA4GEAAKBgBWry/FCAZ6miyy39+ftsa+h9lxoL+JtV0MJcUyQ"
+ + "E4VAhpAwWb8vyjba9AwOylYQTktHX5sAkFvjBiU0LOYDbFSTVZSHMRJgfjxB"
+ + "SHtICjOEvr1BJrrOrdzqdxcOUge5n7El124BCrv91x5Ol8UTwtiO9LrRXF/d"
+ + "SyK+RT5n1klRo3YwdDARBglghkgBhvhCAQEEBAMCAIcwDgYDVR0PAQH/BAQD"
+ + "AgHGMB0GA1UdDgQWBBQwMY4NRcco1AO3w1YsokfDLVseEjAPBgNVHRMBAf8E"
+ + "BTADAQH/MB8GA1UdIwQYMBaAFGXi9IbJ007wkU5Yomr12HhamsGmMAsGByqG"
+ + "SM44BAMFAAMvADAsAhRmigTu6QV0sTfEkVljgij/hhdVfAIUQZvMxAnIHc30"
+ + "y/u0C1T5UEG9glUwggPAMIIDfqADAgECAgEQMAsGByqGSM44BAMFADCBkDEL"
+ + "MAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlQYWxvIEFsdG8x"
+ + "HTAbBgNVBAoTFFN1biBNaWNyb3N5c3RlbXMgSW5jMSMwIQYDVQQLExpKYXZh"
+ + "IFNvZnR3YXJlIENvZGUgU2lnbmluZzEcMBoGA1UEAxMTSkNFIENvZGUgU2ln"
+ + "bmluZyBDQTAeFw0wMTA0MjUwNzAwMDBaFw0yMDA0MjUwNzAwMDBaMIGQMQsw"
+ + "CQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVBhbG8gQWx0bzEd"
+ + "MBsGA1UEChMUU3VuIE1pY3Jvc3lzdGVtcyBJbmMxIzAhBgNVBAsTGkphdmEg"
+ + "U29mdHdhcmUgQ29kZSBTaWduaW5nMRwwGgYDVQQDExNKQ0UgQ29kZSBTaWdu"
+ + "aW5nIENBMIIBtzCCASwGByqGSM44BAEwggEfAoGBAOuvNwQeylEeaV2w8o/2"
+ + "tUkfxqSZBdcpv3S3avUZ2B7kG/gKAZqY/3Cr4kpWhmxTs/zhyIGMMfDE87CL"
+ + "5nAG7PdpaNuDTHIpiSk2F1w7SgegIAIqRpdRHXDICBgLzgxum3b3BePn+9Nh"
+ + "eeFgmiSNBpWDPFEg4TDPOFeCphpyDc7TAhUAhCVF4bq5qWKreehbMLiJaxv/"
+ + "e3UCgYEAq8l0e3Tv7kK1alNNO92QBnJokQ8LpCl2LlU71a5NZVx+KjoEpmem"
+ + "0HGqpde34sFyDaTRqh6SVEwgAAmisAlBGTMAssNcrkL4sYvKfJbYEH83RFuq"
+ + "zHjI13J2N2tAmahVZvqoAx6LShECactMuCUGHKB30sms0j3pChD6dnC3+9wD"
+ + "gYQAAoGALQmYXKy4nMeZfu4gGSo0kPnXq6uu3WtylQ1m+O8nj0Sy7ShEx/6v"
+ + "sKYnbwBnRYJbB6hWVjvSKVFhXmk51y50dxLPGUr1LcjLcmHETm/6R0M/FLv6"
+ + "vBhmKMLZZot6LS/CYJJLFP5YPiF/aGK+bEhJ+aBLXoWdGRD5FUVRG3HU9wuj"
+ + "ZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1Ud"
+ + "IwQYMBaAFGXi9IbJ007wkU5Yomr12HhamsGmMB0GA1UdDgQWBBRl4vSGydNO"
+ + "8JFOWKJq9dh4WprBpjALBgcqhkjOOAQDBQADLwAwLAIUKvfPPJdd+Xi2CNdB"
+ + "tNkNRUzktJwCFEXNdWkOIfod1rMpsun3Mx0z/fxJMYHoMIHlAgEBMIGWMIGQ"
+ + "MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVBhbG8gQWx0"
+ + "bzEdMBsGA1UEChMUU3VuIE1pY3Jvc3lzdGVtcyBJbmMxIzAhBgNVBAsTGkph"
+ + "dmEgU29mdHdhcmUgQ29kZSBTaWduaW5nMRwwGgYDVQQDExNKQ0UgQ29kZSBT"
+ + "aWduaW5nIENBAgEzMAkGBSsOAwIaBQAwCwYHKoZIzjgEAQUABC8wLQIVAIGV"
+ + "khm+kbV4a/+EP45PHcq0hIViAhR4M9os6IrJnoEDS3Y3l7O6zrSosA==");
+
+ private JcaX509CertSelectorConverter selectorConverter = new JcaX509CertSelectorConverter();
+
+ /*
+ *
+ * INFRASTRUCTURE
+ *
+ */
+
+ public SignedDataTest(String name)
+ {
+ super(name);
+ }
+
+ public static void main(String args[])
+ {
+
+ junit.textui.TestRunner.run(SignedDataTest.class);
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ init();
+
+ return new CMSTestSetup(new TestSuite(SignedDataTest.class));
+ }
+
+ private static void init()
+ throws Exception
+ {
+ if (!_initialised)
+ {
+ _initialised = true;
+
+ _origDN = "O=Bouncy Castle, C=AU";
+ _origKP = CMSTestUtil.makeKeyPair();
+ _origCert = CMSTestUtil.makeCertificate(_origKP, _origDN, _origKP, _origDN);
+
+ _signDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+ _signKP = CMSTestUtil.makeKeyPair();
+ _signCert = CMSTestUtil.makeCertificate(_signKP, _signDN, _origKP, _origDN);
+
+ _signGostKP = CMSTestUtil.makeGostKeyPair();
+ _signGostCert = CMSTestUtil.makeCertificate(_signGostKP, _signDN, _origKP, _origDN);
+
+ _signDsaKP = CMSTestUtil.makeDsaKeyPair();
+ _signDsaCert = CMSTestUtil.makeCertificate(_signDsaKP, _signDN, _origKP, _origDN);
+
+ _signEcDsaKP = CMSTestUtil.makeEcDsaKeyPair();
+ _signEcDsaCert = CMSTestUtil.makeCertificate(_signEcDsaKP, _signDN, _origKP, _origDN);
+
+ _signEcGostKP = CMSTestUtil.makeEcGostKeyPair();
+ _signEcGostCert = CMSTestUtil.makeCertificate(_signEcGostKP, _signDN, _origKP, _origDN);
+
+ _reciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+ _reciKP = CMSTestUtil.makeKeyPair();
+ _reciCert = CMSTestUtil.makeCertificate(_reciKP, _reciDN, _signKP, _signDN);
+
+ _signCrl = CMSTestUtil.makeCrl(_signKP);
+ }
+ }
+
+ private void verifySignatures(CMSSignedData s, byte[] contentDigest)
+ throws Exception
+ {
+ CertStore certStore = s.getCertificatesAndCRLs("Collection", BC);
+ SignerInformationStore signers = s.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certStore.getCertificates(selectorConverter.getCertSelector(signer.getSID()));
+
+ Iterator certIt = certCollection.iterator();
+ X509Certificate cert = (X509Certificate)certIt.next();
+
+ assertEquals(true, signer.verify(cert, BC));
+
+ if (contentDigest != null)
+ {
+ assertTrue(MessageDigest.isEqual(contentDigest, signer.getContentDigest()));
+ }
+ }
+
+ Collection certColl = certStore.getCertificates(null);
+ Collection crlColl = certStore.getCRLs(null);
+
+ assertEquals(certColl.size(), s.getCertificates("Collection", BC).getMatches(null).size());
+ assertEquals(crlColl.size(), s.getCRLs("Collection", BC).getMatches(null).size());
+ }
+
+ private void verifySignatures(CMSSignedData s)
+ throws Exception
+ {
+ verifySignatures(s, null);
+ }
+
+ public void testDetachedVerification()
+ throws Exception
+ {
+ byte[] data = "Hello World!".getBytes();
+ List certList = new ArrayList();
+ CMSProcessable msg = new CMSProcessableByteArray(data);
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataGenerator.DIGEST_SHA1);
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataGenerator.DIGEST_MD5);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ CMSSignedData s = gen.generate(msg, BC);
+
+ MessageDigest sha1 = MessageDigest.getInstance("SHA1", BC);
+ MessageDigest md5 = MessageDigest.getInstance("MD5", BC);
+ Map hashes = new HashMap();
+ byte[] sha1Hash = sha1.digest(data);
+ byte[] md5Hash = md5.digest(data);
+
+ hashes.put(CMSSignedDataGenerator.DIGEST_SHA1, sha1Hash);
+ hashes.put(CMSSignedDataGenerator.DIGEST_MD5, md5Hash);
+
+ s = new CMSSignedData(hashes, s.getEncoded());
+
+ verifySignatures(s, null);
+ }
+
+ public void testSHA1AndMD5WithRSAEncapsulatedRepeated()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSProcessable msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataGenerator.DIGEST_SHA1);
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataGenerator.DIGEST_MD5);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ CMSSignedData s = gen.generate(msg, true, BC);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded());
+ ASN1InputStream aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ certs = s.getCertificatesAndCRLs("Collection", BC);
+
+ SignerInformationStore signers = s.getSignerInfos();
+
+ assertEquals(2, signers.size());
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+ SignerId sid = null;
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getCertificates(selectorConverter.getCertSelector(signer.getSID()));
+
+ Iterator certIt = certCollection.iterator();
+ X509Certificate cert = (X509Certificate)certIt.next();
+
+ sid = signer.getSID();
+
+ assertEquals(true, signer.verify(cert, BC));
+
+ //
+ // check content digest
+ //
+
+ byte[] contentDigest = (byte[])gen.getGeneratedDigests().get(signer.getDigestAlgOID());
+
+ AttributeTable table = signer.getSignedAttributes();
+ Attribute hash = table.get(CMSAttributes.messageDigest);
+
+ assertTrue(MessageDigest.isEqual(contentDigest, ((ASN1OctetString)hash.getAttrValues().getObjectAt(0)).getOctets()));
+ }
+
+ c = signers.getSigners(sid);
+
+ assertEquals(2, c.size());
+
+
+ //
+ // try using existing signer
+ //
+
+ gen = new CMSSignedDataGenerator();
+
+ gen.addSigners(s.getSignerInfos());
+
+ gen.addCertificatesAndCRLs(s.getCertificatesAndCRLs("Collection", BC));
+
+ s = gen.generate(msg, true, BC);
+
+ bIn = new ByteArrayInputStream(s.getEncoded());
+ aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ certs = s.getCertificatesAndCRLs("Collection", BC);
+
+ signers = s.getSignerInfos();
+ c = signers.getSigners();
+ it = c.iterator();
+
+ assertEquals(2, c.size());
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getCertificates(selectorConverter.getCertSelector(signer.getSID()));
+
+ Iterator certIt = certCollection.iterator();
+ X509Certificate cert = (X509Certificate)certIt.next();
+
+ assertEquals(true, signer.verify(cert, BC));
+ }
+
+ checkSignerStoreReplacement(s, signers);
+ }
+
+ public void testSHA1WithRSANoAttributes()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSProcessable msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataGenerator.DIGEST_SHA1);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ CMSSignedData s = gen.generate(CMSSignedDataGenerator.DATA, msg, false, BC, false);
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+
+ verifySignatures(s, md.digest("Hello world!".getBytes()));
+ }
+
+ public void testSHA1WithRSAViaConfig()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSProcessable msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ // set some bogus mappings.
+ CMSConfig.setSigningEncryptionAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption.getId(), "XXXX");
+ CMSConfig.setSigningDigestAlgorithmMapping(OIWObjectIdentifiers.idSHA1.getId(), "YYYY");
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataGenerator.DIGEST_SHA1);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ CMSSignedData s;
+
+ try
+ {
+ // try the bogus mappings
+ s = gen.generate(CMSSignedDataGenerator.DATA, msg, false, BC, false);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ if (!e.getMessage().startsWith("Unknown signature type requested: YYYYWITHXXXX"))
+ {
+ throw e;
+ }
+ }
+ finally
+ {
+ // reset to the real ones
+ CMSConfig.setSigningEncryptionAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption.getId(), "RSA");
+ CMSConfig.setSigningDigestAlgorithmMapping(OIWObjectIdentifiers.idSHA1.getId(), "SHA1");
+ }
+
+ s = gen.generate(CMSSignedDataGenerator.DATA, msg, false, BC, false);
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+
+ verifySignatures(s, md.digest("Hello world!".getBytes()));
+ }
+
+ public void testSHA1WithRSAAndAttributeTable()
+ throws Exception
+ {
+ MessageDigest md = MessageDigest.getInstance("SHA1", BC);
+ List certList = new ArrayList();
+ CMSProcessable msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ Attribute attr = new Attribute(CMSAttributes.messageDigest,
+ new DERSet(
+ new DEROctetString(
+ md.digest("Hello world!".getBytes()))));
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(attr);
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataGenerator.DIGEST_SHA1, new AttributeTable(v), null);
+
+ gen.addCertificatesAndCRLs(certs);
+
+
+ CMSSignedData s = gen.generate(CMSSignedDataGenerator.DATA, null, false, BC);
+
+ //
+ // the signature is detached, so need to add msg before passing on
+ //
+ s = new CMSSignedData(msg, s.getEncoded());
+ //
+ // compute expected content digest
+ //
+
+ verifySignatures(s, md.digest("Hello world!".getBytes()));
+ }
+
+ public void testSHA1WithRSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signKP, _signCert, CMSSignedDataGenerator.DIGEST_SHA1);
+ }
+
+ public void testSHA1WithRSAEncapsulatedSubjectKeyID()
+ throws Exception
+ {
+ subjectKeyIDTest(_signKP, _signCert, CMSSignedDataGenerator.DIGEST_SHA1);
+ }
+
+ public void testSHA1WithRSAPSS()
+ throws Exception
+ {
+ rsaPSSTest("SHA1", CMSSignedDataGenerator.DIGEST_SHA1);
+ }
+
+ public void testSHA224WithRSAPSS()
+ throws Exception
+ {
+ rsaPSSTest("SHA224", CMSSignedDataGenerator.DIGEST_SHA224);
+ }
+
+ public void testSHA256WithRSAPSS()
+ throws Exception
+ {
+ rsaPSSTest("SHA256", CMSSignedDataGenerator.DIGEST_SHA256);
+ }
+
+ public void testSHA384WithRSAPSS()
+ throws Exception
+ {
+ rsaPSSTest("SHA384", CMSSignedDataGenerator.DIGEST_SHA384);
+ }
+
+ public void testSHA224WithRSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signKP, _signCert, CMSSignedDataGenerator.DIGEST_SHA224);
+ }
+
+ public void testSHA256WithRSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signKP, _signCert, CMSSignedDataGenerator.DIGEST_SHA256);
+ }
+
+ public void testRIPEMD128WithRSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signKP, _signCert, CMSSignedDataGenerator.DIGEST_RIPEMD128);
+ }
+
+ public void testRIPEMD160WithRSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signKP, _signCert, CMSSignedDataGenerator.DIGEST_RIPEMD160);
+ }
+
+ public void testRIPEMD256WithRSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signKP, _signCert, CMSSignedDataGenerator.DIGEST_RIPEMD256);
+ }
+
+ public void testECDSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signEcDsaKP, _signEcDsaCert, CMSSignedDataGenerator.DIGEST_SHA1);
+ }
+
+ public void testECDSAEncapsulatedSubjectKeyID()
+ throws Exception
+ {
+ subjectKeyIDTest(_signEcDsaKP, _signEcDsaCert, CMSSignedDataGenerator.DIGEST_SHA1);
+ }
+
+ public void testECDSASHA224Encapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signEcDsaKP, _signEcDsaCert, CMSSignedDataGenerator.DIGEST_SHA224);
+ }
+
+ public void testECDSASHA256Encapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signEcDsaKP, _signEcDsaCert, CMSSignedDataGenerator.DIGEST_SHA256);
+ }
+
+ public void testECDSASHA384Encapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signEcDsaKP, _signEcDsaCert, CMSSignedDataGenerator.DIGEST_SHA384);
+ }
+
+ public void testECDSASHA512Encapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signEcDsaKP, _signEcDsaCert, CMSSignedDataGenerator.DIGEST_SHA512);
+ }
+
+ public void testECDSASHA512EncapsulatedWithKeyFactoryAsEC()
+ throws Exception
+ {
+ X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(_signEcDsaKP.getPublic().getEncoded());
+ PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(_signEcDsaKP.getPrivate().getEncoded());
+ KeyFactory keyFact = KeyFactory.getInstance("EC", BC);
+ KeyPair kp = new KeyPair(keyFact.generatePublic(pubSpec), keyFact.generatePrivate(privSpec));
+
+ encapsulatedTest(kp, _signEcDsaCert, CMSSignedDataGenerator.DIGEST_SHA512);
+ }
+
+ public void testDSAEncapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signDsaKP, _signDsaCert, CMSSignedDataGenerator.DIGEST_SHA1);
+ }
+
+ public void testDSAEncapsulatedSubjectKeyID()
+ throws Exception
+ {
+ subjectKeyIDTest(_signDsaKP, _signDsaCert, CMSSignedDataGenerator.DIGEST_SHA1);
+ }
+
+ public void testGOST3411WithGOST3410Encapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signGostKP, _signGostCert, CMSSignedDataGenerator.DIGEST_GOST3411);
+ }
+
+ public void testGOST3411WithECGOST3410Encapsulated()
+ throws Exception
+ {
+ encapsulatedTest(_signEcGostKP, _signEcGostCert, CMSSignedDataGenerator.DIGEST_GOST3411);
+ }
+
+ public void testSHA1WithRSACounterSignature()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSProcessable msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(_signCert);
+ certList.add(_origCert);
+
+ certList.add(_signCrl);
+
+ CertStore certsAndCrls = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ gen.addSigner(_signKP.getPrivate(), _signCert, CMSSignedDataGenerator.DIGEST_SHA1);
+
+ gen.addCertificatesAndCRLs(certsAndCrls);
+
+ CMSSignedData s = gen.generate(msg, true, BC);
+ SignerInformation origSigner = (SignerInformation)s.getSignerInfos().getSigners().toArray()[0];
+ SignerInformationStore counterSigners1 = gen.generateCounterSigners(origSigner, BC);
+ SignerInformationStore counterSigners2 = gen.generateCounterSigners(origSigner, BC);
+
+ SignerInformation signer1 = SignerInformation.addCounterSigners(origSigner, counterSigners1);
+ SignerInformation signer2 = SignerInformation.addCounterSigners(signer1, counterSigners2);
+
+ SignerInformationStore cs = signer2.getCounterSignatures();
+ Collection csSigners = cs.getSigners();
+ assertEquals(2, csSigners.size());
+
+ Iterator it = csSigners.iterator();
+ while (it.hasNext())
+ {
+ SignerInformation cSigner = (SignerInformation)it.next();
+ Collection certCollection = certsAndCrls.getCertificates(selectorConverter.getCertSelector(cSigner.getSID()));
+
+ Iterator certIt = certCollection.iterator();
+ X509Certificate cert = (X509Certificate)certIt.next();
+
+ assertNull(cSigner.getSignedAttributes().get(PKCSObjectIdentifiers.pkcs_9_at_contentType));
+ assertEquals(true, cSigner.verify(cert, BC));
+ }
+ }
+
+ private void rsaPSSTest(String digestName, String digestOID)
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSProcessable msg = new CMSProcessableByteArray("Hello world!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataGenerator.ENCRYPTION_RSA_PSS, digestOID);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ CMSSignedData s = gen.generate(CMSSignedDataGenerator.DATA, msg, false, BC, false);
+
+ //
+ // compute expected content digest
+ //
+ MessageDigest md = MessageDigest.getInstance(digestName, BC);
+
+ verifySignatures(s, md.digest("Hello world!".getBytes()));
+ }
+
+ private void subjectKeyIDTest(
+ KeyPair signaturePair,
+ X509Certificate signatureCert,
+ String digestAlgorithm)
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSProcessable msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(signatureCert);
+ certList.add(_origCert);
+
+ certList.add(_signCrl);
+
+ CertStore certsAndCrls = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ gen.addSigner(signaturePair.getPrivate(), CMSTestUtil.createSubjectKeyId(signatureCert.getPublicKey()).getKeyIdentifier(), digestAlgorithm);
+
+ gen.addCertificatesAndCRLs(certsAndCrls);
+
+ CMSSignedData s = gen.generate(msg, true, BC);
+
+ assertEquals(3, s.getVersion());
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded());
+ ASN1InputStream aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ certsAndCrls = s.getCertificatesAndCRLs("Collection", BC);
+
+ SignerInformationStore signers = s.getSignerInfos();
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certsAndCrls.getCertificates(selectorConverter.getCertSelector(signer.getSID()));
+
+ Iterator certIt = certCollection.iterator();
+ X509Certificate cert = (X509Certificate)certIt.next();
+
+ assertEquals(true, signer.verify(cert, BC));
+ }
+
+ //
+ // check for CRLs
+ //
+ Collection crls = certsAndCrls.getCRLs(null);
+
+ assertEquals(1, crls.size());
+
+ assertTrue(crls.contains(_signCrl));
+
+ //
+ // try using existing signer
+ //
+
+ gen = new CMSSignedDataGenerator();
+
+ gen.addSigners(s.getSignerInfos());
+
+ gen.addCertificatesAndCRLs(s.getCertificatesAndCRLs("Collection", BC));
+
+ s = gen.generate(msg, true, BC);
+
+ bIn = new ByteArrayInputStream(s.getEncoded());
+ aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ certsAndCrls = s.getCertificatesAndCRLs("Collection", BC);
+
+ signers = s.getSignerInfos();
+ c = signers.getSigners();
+ it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certsAndCrls.getCertificates(selectorConverter.getCertSelector(signer.getSID()));
+
+ Iterator certIt = certCollection.iterator();
+ X509Certificate cert = (X509Certificate)certIt.next();
+
+ assertEquals(true, signer.verify(cert, BC));
+ }
+
+ checkSignerStoreReplacement(s, signers);
+ }
+
+ private void encapsulatedTest(
+ KeyPair signaturePair,
+ X509Certificate signatureCert,
+ String digestAlgorithm)
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSProcessable msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(signatureCert);
+ certList.add(_origCert);
+
+ certList.add(_signCrl);
+
+ CertStore certsAndCrls = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ gen.addSigner(signaturePair.getPrivate(), signatureCert, digestAlgorithm);
+
+ gen.addCertificatesAndCRLs(certsAndCrls);
+
+ CMSSignedData s = gen.generate(msg, true, BC);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded());
+ ASN1InputStream aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ certsAndCrls = s.getCertificatesAndCRLs("Collection", BC);
+
+ SignerInformationStore signers = s.getSignerInfos();
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certsAndCrls.getCertificates(selectorConverter.getCertSelector(signer.getSID()));
+
+ Iterator certIt = certCollection.iterator();
+ X509Certificate cert = (X509Certificate)certIt.next();
+
+ assertEquals(true, signer.verify(cert, BC));
+ }
+
+ //
+ // check for CRLs
+ //
+ Collection crls = certsAndCrls.getCRLs(null);
+
+ assertEquals(1, crls.size());
+
+ assertTrue(crls.contains(_signCrl));
+
+ //
+ // try using existing signer
+ //
+
+ gen = new CMSSignedDataGenerator();
+
+ gen.addSigners(s.getSignerInfos());
+
+ gen.addCertificatesAndCRLs(s.getCertificatesAndCRLs("Collection", BC));
+
+ s = gen.generate(msg, true, BC);
+
+ bIn = new ByteArrayInputStream(s.getEncoded());
+ aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ certsAndCrls = s.getCertificatesAndCRLs("Collection", BC);
+
+ signers = s.getSignerInfos();
+ c = signers.getSigners();
+ it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certsAndCrls.getCertificates(selectorConverter.getCertSelector(signer.getSID()));
+
+ Iterator certIt = certCollection.iterator();
+ X509Certificate cert = (X509Certificate)certIt.next();
+
+ assertEquals(true, signer.verify(cert, BC));
+ }
+
+ checkSignerStoreReplacement(s, signers);
+ }
+
+ //
+ // signerInformation store replacement test.
+ //
+ private void checkSignerStoreReplacement(
+ CMSSignedData orig,
+ SignerInformationStore signers)
+ throws Exception
+ {
+ CMSSignedData s = CMSSignedData.replaceSigners(orig, signers);
+
+ CertStore certs = s.getCertificatesAndCRLs("Collection", BC);
+
+ signers = s.getSignerInfos();
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getCertificates(selectorConverter.getCertSelector(signer.getSID()));
+
+ Iterator certIt = certCollection.iterator();
+ X509Certificate cert = (X509Certificate)certIt.next();
+
+ assertEquals(true, signer.verify(cert, BC));
+ }
+ }
+
+ public void testUnsortedAttributes()
+ throws Exception
+ {
+ CMSSignedData s = new CMSSignedData(new CMSProcessableByteArray(disorderedMessage), disorderedSet);
+
+ CertStore certs = s.getCertificatesAndCRLs("Collection", BC);
+
+ SignerInformationStore signers = s.getSignerInfos();
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getCertificates(selectorConverter.getCertSelector(signer.getSID()));
+
+ Iterator certIt = certCollection.iterator();
+ X509Certificate cert = (X509Certificate)certIt.next();
+
+ assertEquals(true, signer.verify(cert, BC));
+ }
+ }
+
+ public void testNullContentWithSigner()
+ throws Exception
+ {
+ List certList = new ArrayList();
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataGenerator.DIGEST_SHA1);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ CMSSignedData s = gen.generate(null, false, BC);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded());
+ ASN1InputStream aIn = new ASN1InputStream(bIn);
+
+ s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
+
+ verifySignatures(s);
+ }
+
+ public void testWithAttributeCertificate()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSProcessable msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+
+ certList.add(_signDsaCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataGenerator.DIGEST_SHA1);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ X509AttributeCertificate attrCert = CMSTestUtil.getAttributeCertificate();
+
+ X509Store store = X509Store.getInstance("AttributeCertificate/Collection",
+ new X509CollectionStoreParameters(Collections.singleton(attrCert)), BC);
+
+ gen.addAttributeCertificates(store);
+
+ CMSSignedData sd = gen.generate(msg, BC);
+
+ assertEquals(4, sd.getVersion());
+
+ store = sd.getAttributeCertificates("Collection", BC);
+
+ Collection coll = store.getMatches(null);
+
+ assertEquals(1, coll.size());
+
+ assertTrue(coll.contains(attrCert));
+
+ //
+ // create new certstore
+ //
+ certList = new ArrayList();
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+
+ //
+ // replace certs
+ //
+ sd = CMSSignedData.replaceCertificatesAndCRLs(sd, certs);
+
+ verifySignatures(sd);
+ }
+
+ public void testCertStoreReplacement()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSProcessable msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+
+ certList.add(_signDsaCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataGenerator.DIGEST_SHA1);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ CMSSignedData sd = gen.generate(msg, BC);
+
+ //
+ // create new certstore
+ //
+ certList = new ArrayList();
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ //
+ // replace certs
+ //
+ sd = CMSSignedData.replaceCertificatesAndCRLs(sd, certs);
+
+ verifySignatures(sd);
+ }
+
+ public void testEncapsulatedCertStoreReplacement()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSProcessable msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+
+ certList.add(_signDsaCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataGenerator.DIGEST_SHA1);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ CMSSignedData sd = gen.generate(msg, true, BC);
+
+ //
+ // create new certstore
+ //
+ certList = new ArrayList();
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ //
+ // replace certs
+ //
+ sd = CMSSignedData.replaceCertificatesAndCRLs(sd, certs);
+
+ verifySignatures(sd);
+ }
+
+ public void testCertOrdering1()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSProcessable msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+ certList.add(_signDsaCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataGenerator.DIGEST_SHA1);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ CMSSignedData sd = gen.generate(msg, true, BC);
+
+ certs = sd.getCertificatesAndCRLs("Collection", BC);
+ Iterator it = certs.getCertificates(null).iterator();
+
+ assertEquals(_origCert, it.next());
+ assertEquals(_signCert, it.next());
+ assertEquals(_signDsaCert, it.next());
+ }
+
+ public void testCertOrdering2()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSProcessable msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(_signCert);
+ certList.add(_signDsaCert);
+ certList.add(_origCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataGenerator.DIGEST_SHA1);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ CMSSignedData sd = gen.generate(msg, true, BC);
+
+ certs = sd.getCertificatesAndCRLs("Collection", BC);
+ Iterator it = certs.getCertificates(null).iterator();
+
+ assertEquals(_signCert, it.next());
+ assertEquals(_signDsaCert, it.next());
+ assertEquals(_origCert, it.next());
+ }
+
+ public void testSignerStoreReplacement()
+ throws Exception
+ {
+ List certList = new ArrayList();
+ CMSProcessable msg = new CMSProcessableByteArray("Hello World!".getBytes());
+
+ certList.add(_origCert);
+ certList.add(_signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), BC);
+
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataGenerator.DIGEST_SHA1);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ CMSSignedData original = gen.generate(msg, true, BC);
+
+ //
+ // create new Signer
+ //
+ gen = new CMSSignedDataGenerator();
+
+ gen.addSigner(_origKP.getPrivate(), _origCert, CMSSignedDataGenerator.DIGEST_SHA224);
+
+ gen.addCertificatesAndCRLs(certs);
+
+ CMSSignedData newSD = gen.generate(msg, true, BC);
+
+ //
+ // replace signer
+ //
+ CMSSignedData sd = CMSSignedData.replaceSigners(original, newSD.getSignerInfos());
+
+ SignerInformation signer = (SignerInformation)sd.getSignerInfos().getSigners().iterator().next();
+
+ assertEquals(CMSSignedDataGenerator.DIGEST_SHA224, signer.getDigestAlgOID());
+
+ // we use a parser here as it requires the digests to be correct in the digest set, if it
+ // isn't we'll get a NullPointerException
+ CMSSignedDataParser sp = new CMSSignedDataParser(sd.getEncoded());
+
+ sp.getSignedContent().drain();
+
+ verifySignatures(sp);
+ }
+
+ public void testEncapsulatedSamples()
+ throws Exception
+ {
+ testSample("PSSSignDataSHA1Enc.sig");
+ testSample("PSSSignDataSHA256Enc.sig");
+ testSample("PSSSignDataSHA512Enc.sig");
+ }
+
+ public void testSamples()
+ throws Exception
+ {
+ testSample("PSSSignData.data", "PSSSignDataSHA1.sig");
+ testSample("PSSSignData.data", "PSSSignDataSHA256.sig");
+ testSample("PSSSignData.data", "PSSSignDataSHA512.sig");
+ }
+
+ public void testCounterSig()
+ throws Exception
+ {
+ CMSSignedData sig = new CMSSignedData(getInput("counterSig.p7m"));
+
+ SignerInformationStore ss = sig.getSignerInfos();
+ Collection signers = ss.getSigners();
+
+ SignerInformationStore cs = ((SignerInformation)signers.iterator().next()).getCounterSignatures();
+ Collection csSigners = cs.getSigners();
+ assertEquals(1, csSigners.size());
+
+ Iterator it = csSigners.iterator();
+ while (it.hasNext())
+ {
+ SignerInformation cSigner = (SignerInformation)it.next();
+ Collection certCollection = sig.getCertificatesAndCRLs("Collection", BC).getCertificates(selectorConverter.getCertSelector(cSigner.getSID()));
+
+ Iterator certIt = certCollection.iterator();
+ X509Certificate cert = (X509Certificate)certIt.next();
+
+ assertNull(cSigner.getSignedAttributes().get(PKCSObjectIdentifiers.pkcs_9_at_contentType));
+ assertEquals(true, cSigner.verify(cert, BC));
+ }
+
+ verifySignatures(sig);
+ }
+
+ private void testSample(String sigName)
+ throws Exception
+ {
+ CMSSignedData sig = new CMSSignedData(getInput(sigName));
+
+ verifySignatures(sig);
+ }
+
+ private void testSample(String messageName, String sigName)
+ throws Exception
+ {
+ CMSSignedData sig = new CMSSignedData(new CMSProcessableByteArray(getInput(messageName)), getInput(sigName));
+
+ verifySignatures(sig);
+ }
+
+ private byte[] getInput(String name)
+ throws IOException
+ {
+ return Streams.readAll(getClass().getResourceAsStream(name));
+ }
+
+ public void testForMultipleCounterSignatures()
+ throws Exception
+ {
+ CMSSignedData sd = new CMSSignedData(xtraCounterSig);
+
+ for (Iterator sI = sd.getSignerInfos().getSigners().iterator(); sI.hasNext();)
+ {
+ SignerInformation sigI = (SignerInformation)sI.next();
+
+ SignerInformationStore counter = sigI.getCounterSignatures();
+ List sigs = new ArrayList(counter.getSigners());
+
+ assertEquals(2, sigs.size());
+ }
+ }
+
+ private void verifySignatures(CMSSignedDataParser sp)
+ throws Exception
+ {
+ CertStore certs = sp.getCertificatesAndCRLs("Collection", BC);
+ SignerInformationStore signers = sp.getSignerInfos();
+
+ Collection c = signers.getSigners();
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ SignerInformation signer = (SignerInformation)it.next();
+ Collection certCollection = certs.getCertificates(selectorConverter.getCertSelector(signer.getSID()));
+
+ Iterator certIt = certCollection.iterator();
+ X509Certificate cert = (X509Certificate)certIt.next();
+
+ assertEquals(true, signer.verify(cert, BC));
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/openssl/test/ParserTest.java b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/openssl/test/ParserTest.java
new file mode 100644
index 000000000..b4f932c4d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/openssl/test/ParserTest.java
@@ -0,0 +1,492 @@
+package org.spongycastle.openssl.test;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Signature;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.ECNamedCurveTable;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.openssl.PEMDecryptorProvider;
+import org.spongycastle.openssl.PEMEncryptedKeyPair;
+import org.spongycastle.openssl.PEMKeyPair;
+import org.spongycastle.openssl.PEMParser;
+import org.spongycastle.openssl.PEMWriter;
+import org.spongycastle.openssl.PasswordFinder;
+import org.spongycastle.openssl.jcajce.JcaPEMKeyConverter;
+import org.spongycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
+import org.spongycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
+import org.spongycastle.operator.InputDecryptorProvider;
+import org.spongycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
+import org.spongycastle.util.test.SimpleTest;
+
+/**
+ * basic class for reading test.pem - the password is "secret"
+ */
+public class ParserTest
+ extends SimpleTest
+{
+ private static class Password
+ implements PasswordFinder
+ {
+ char[] password;
+
+ Password(
+ char[] word)
+ {
+ this.password = word;
+ }
+
+ public char[] getPassword()
+ {
+ return password;
+ }
+ }
+
+ public String getName()
+ {
+ return "PEMParserTest";
+ }
+
+ private PEMParser openPEMResource(
+ String fileName)
+ {
+ InputStream res = this.getClass().getResourceAsStream(fileName);
+ Reader fRd = new BufferedReader(new InputStreamReader(res));
+ return new PEMParser(fRd);
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ PEMParser pemRd = openPEMResource("test.pem");
+ Object o;
+ PEMKeyPair pemPair;
+ KeyPair pair;
+
+ while ((o = pemRd.readObject()) != null)
+ {
+ if (o instanceof KeyPair)
+ {
+ //pair = (KeyPair)o;
+
+ //System.out.println(pair.getPublic());
+ //System.out.println(pair.getPrivate());
+ }
+ else
+ {
+ //System.out.println(o.toString());
+ }
+ }
+
+ // test bogus lines before begin are ignored.
+ pemRd = openPEMResource("extratest.pem");
+
+ while ((o = pemRd.readObject()) != null)
+ {
+ if (!(o instanceof X509CertificateHolder))
+ {
+ fail("wrong object found");
+ }
+ }
+
+ //
+ // pkcs 7 data
+ //
+ pemRd = openPEMResource("pkcs7.pem");
+ ContentInfo d = (ContentInfo)pemRd.readObject();
+
+ if (!d.getContentType().equals(CMSObjectIdentifiers.envelopedData))
+ {
+ fail("failed envelopedData check");
+ }
+
+ //
+ // ECKey
+ //
+ pemRd = openPEMResource("eckey.pem");
+ ASN1ObjectIdentifier ecOID = (ASN1ObjectIdentifier)pemRd.readObject();
+ X9ECParameters ecSpec = ECNamedCurveTable.getByOID(ecOID);
+
+ if (ecSpec == null)
+ {
+ fail("ecSpec not found for named curve");
+ }
+
+ pemPair = (PEMKeyPair)pemRd.readObject();
+
+ pair = new JcaPEMKeyConverter().setProvider("SC").getKeyPair(pemPair);
+
+ Signature sgr = Signature.getInstance("ECDSA", "SC");
+
+ sgr.initSign(pair.getPrivate());
+
+ byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
+
+ sgr.update(message);
+
+ byte[] sigBytes = sgr.sign();
+
+ sgr.initVerify(pair.getPublic());
+
+ sgr.update(message);
+
+ if (!sgr.verify(sigBytes))
+ {
+ fail("EC verification failed");
+ }
+
+ if (!pair.getPublic().getAlgorithm().equals("ECDSA"))
+ {
+ fail("wrong algorithm name on public got: " + pair.getPublic().getAlgorithm());
+ }
+
+ if (!pair.getPrivate().getAlgorithm().equals("ECDSA"))
+ {
+ fail("wrong algorithm name on private");
+ }
+
+ //
+ // ECKey -- explicit parameters
+ //
+ pemRd = openPEMResource("ecexpparam.pem");
+ ecSpec = (X9ECParameters)pemRd.readObject();
+
+ pemPair = (PEMKeyPair)pemRd.readObject();
+
+ pair = new JcaPEMKeyConverter().setProvider("SC").getKeyPair(pemPair);
+
+ sgr = Signature.getInstance("ECDSA", "SC");
+
+ sgr.initSign(pair.getPrivate());
+
+ message = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
+
+ sgr.update(message);
+
+ sigBytes = sgr.sign();
+
+ sgr.initVerify(pair.getPublic());
+
+ sgr.update(message);
+
+ if (!sgr.verify(sigBytes))
+ {
+ fail("EC verification failed");
+ }
+
+ if (!pair.getPublic().getAlgorithm().equals("ECDSA"))
+ {
+ fail("wrong algorithm name on public got: " + pair.getPublic().getAlgorithm());
+ }
+
+ if (!pair.getPrivate().getAlgorithm().equals("ECDSA"))
+ {
+ fail("wrong algorithm name on private");
+ }
+
+ //
+ // writer/parser test
+ //
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "SC");
+
+ pair = kpGen.generateKeyPair();
+
+ keyPairTest("RSA", pair);
+
+ kpGen = KeyPairGenerator.getInstance("DSA", "SC");
+ kpGen.initialize(512, new SecureRandom());
+ pair = kpGen.generateKeyPair();
+
+ keyPairTest("DSA", pair);
+
+ //
+ // PKCS7
+ //
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ PEMWriter pWrt = new PEMWriter(new OutputStreamWriter(bOut));
+
+ pWrt.writeObject(d);
+
+ pWrt.close();
+
+ pemRd = new PEMParser(new InputStreamReader(new ByteArrayInputStream(bOut.toByteArray())));
+ d = (ContentInfo)pemRd.readObject();
+
+ if (!d.getContentType().equals(CMSObjectIdentifiers.envelopedData))
+ {
+ fail("failed envelopedData recode check");
+ }
+
+
+ // OpenSSL test cases (as embedded resources)
+ doOpenSslDsaTest("unencrypted");
+ doOpenSslRsaTest("unencrypted");
+
+ doOpenSslTests("aes128");
+ doOpenSslTests("aes192");
+ doOpenSslTests("aes256");
+ doOpenSslTests("blowfish");
+ doOpenSslTests("des1");
+ doOpenSslTests("des2");
+ doOpenSslTests("des3");
+ doOpenSslTests("rc2_128");
+
+ doOpenSslDsaTest("rc2_40_cbc");
+ doOpenSslRsaTest("rc2_40_cbc");
+ doOpenSslDsaTest("rc2_64_cbc");
+ doOpenSslRsaTest("rc2_64_cbc");
+
+ doDudPasswordTest("7fd98", 0, "corrupted stream - out of bounds length found");
+ doDudPasswordTest("ef677", 1, "corrupted stream - out of bounds length found");
+ doDudPasswordTest("800ce", 2, "unknown tag 26 encountered");
+ doDudPasswordTest("b6cd8", 3, "DEF length 81 object truncated by 56");
+ doDudPasswordTest("28ce09", 4, "DEF length 110 object truncated by 28");
+ doDudPasswordTest("2ac3b9", 5, "DER length more than 4 bytes: 11");
+ doDudPasswordTest("2cba96", 6, "DEF length 100 object truncated by 35");
+ doDudPasswordTest("2e3354", 7, "DEF length 42 object truncated by 9");
+ doDudPasswordTest("2f4142", 8, "DER length more than 4 bytes: 14");
+ doDudPasswordTest("2fe9bb", 9, "DER length more than 4 bytes: 65");
+ doDudPasswordTest("3ee7a8", 10, "DER length more than 4 bytes: 57");
+ doDudPasswordTest("41af75", 11, "unknown tag 16 encountered");
+ doDudPasswordTest("1704a5", 12, "corrupted stream detected");
+ doDudPasswordTest("1c5822", 13, "unknown object in getInstance: org.spongycastle.asn1.DERUTF8String");
+ doDudPasswordTest("5a3d16", 14, "corrupted stream detected");
+ doDudPasswordTest("8d0c97", 15, "corrupted stream detected");
+ doDudPasswordTest("bc0daf", 16, "corrupted stream detected");
+ doDudPasswordTest("aaf9c4d",17, "corrupted stream - out of bounds length found");
+
+ doNoPasswordTest();
+
+ // encrypted private key test
+ InputDecryptorProvider pkcs8Prov = new JceOpenSSLPKCS8DecryptorProviderBuilder().build("password".toCharArray());
+ pemRd = openPEMResource("enckey.pem");
+
+ PKCS8EncryptedPrivateKeyInfo encPrivKeyInfo = (PKCS8EncryptedPrivateKeyInfo)pemRd.readObject();
+ JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("SC");
+
+ RSAPrivateCrtKey privKey = (RSAPrivateCrtKey)converter.getPrivateKey(encPrivKeyInfo.decryptPrivateKeyInfo(pkcs8Prov));
+
+ if (!privKey.getPublicExponent().equals(new BigInteger("10001", 16)))
+ {
+ fail("decryption of private key data check failed");
+ }
+
+ // general PKCS8 test
+
+ pemRd = openPEMResource("pkcs8test.pem");
+
+ Object privInfo;
+
+ while ((privInfo = pemRd.readObject()) != null)
+ {
+ if (privInfo instanceof PrivateKeyInfo)
+ {
+ privKey = (RSAPrivateCrtKey)converter.getPrivateKey(PrivateKeyInfo.getInstance(privInfo));
+ }
+ else
+ {
+ privKey = (RSAPrivateCrtKey)converter.getPrivateKey(((PKCS8EncryptedPrivateKeyInfo)privInfo).decryptPrivateKeyInfo(pkcs8Prov));
+ }
+ if (!privKey.getPublicExponent().equals(new BigInteger("10001", 16)))
+ {
+ fail("decryption of private key data check failed");
+ }
+ }
+ }
+
+ private void keyPairTest(
+ String name,
+ KeyPair pair)
+ throws IOException
+ {
+ PEMParser pemRd;
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ PEMWriter pWrt = new PEMWriter(new OutputStreamWriter(bOut));
+
+ pWrt.writeObject(pair.getPublic());
+
+ pWrt.close();
+
+ pemRd = new PEMParser(new InputStreamReader(new ByteArrayInputStream(bOut.toByteArray())));
+
+ SubjectPublicKeyInfo pub = SubjectPublicKeyInfo.getInstance(pemRd.readObject());
+ JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("SC");
+
+ PublicKey k = converter.getPublicKey(pub);
+
+ if (!k.equals(pair.getPublic()))
+ {
+ fail("Failed public key read: " + name);
+ }
+
+ bOut = new ByteArrayOutputStream();
+ pWrt = new PEMWriter(new OutputStreamWriter(bOut));
+
+ pWrt.writeObject(pair.getPrivate());
+
+ pWrt.close();
+
+ pemRd = new PEMParser(new InputStreamReader(new ByteArrayInputStream(bOut.toByteArray())));
+
+ KeyPair kPair = converter.getKeyPair((PEMKeyPair)pemRd.readObject());
+ if (!kPair.getPrivate().equals(pair.getPrivate()))
+ {
+ fail("Failed private key read: " + name);
+ }
+
+ if (!kPair.getPublic().equals(pair.getPublic()))
+ {
+ fail("Failed private key public read: " + name);
+ }
+ }
+
+ private void doOpenSslTests(
+ String baseName)
+ throws IOException
+ {
+ doOpenSslDsaModesTest(baseName);
+ doOpenSslRsaModesTest(baseName);
+ }
+
+ private void doOpenSslDsaModesTest(
+ String baseName)
+ throws IOException
+ {
+ doOpenSslDsaTest(baseName + "_cbc");
+ doOpenSslDsaTest(baseName + "_cfb");
+ doOpenSslDsaTest(baseName + "_ecb");
+ doOpenSslDsaTest(baseName + "_ofb");
+ }
+
+ private void doOpenSslRsaModesTest(
+ String baseName)
+ throws IOException
+ {
+ doOpenSslRsaTest(baseName + "_cbc");
+ doOpenSslRsaTest(baseName + "_cfb");
+ doOpenSslRsaTest(baseName + "_ecb");
+ doOpenSslRsaTest(baseName + "_ofb");
+ }
+
+ private void doOpenSslDsaTest(
+ String name)
+ throws IOException
+ {
+ String fileName = "dsa/openssl_dsa_" + name + ".pem";
+
+ doOpenSslTestFile(fileName, DSAPrivateKey.class);
+ }
+
+ private void doOpenSslRsaTest(
+ String name)
+ throws IOException
+ {
+ String fileName = "rsa/openssl_rsa_" + name + ".pem";
+
+ doOpenSslTestFile(fileName, RSAPrivateKey.class);
+ }
+
+ private void doOpenSslTestFile(
+ String fileName,
+ Class expectedPrivKeyClass)
+ throws IOException
+ {
+ JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("SC");
+ PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().setProvider("SC").build("changeit".toCharArray());
+ PEMParser pr = openPEMResource("data/" + fileName);
+ Object o = pr.readObject();
+
+ if (o == null || !((o instanceof PEMKeyPair) || (o instanceof PEMEncryptedKeyPair)))
+ {
+ fail("Didn't find OpenSSL key");
+ }
+
+ KeyPair kp = (o instanceof PEMEncryptedKeyPair) ?
+ converter.getKeyPair(((PEMEncryptedKeyPair)o).decryptKeyPair(decProv)) : converter.getKeyPair((PEMKeyPair)o);
+
+ PrivateKey privKey = kp.getPrivate();
+
+ if (!expectedPrivKeyClass.isInstance(privKey))
+ {
+ fail("Returned key not of correct type");
+ }
+ }
+
+ private void doDudPasswordTest(String password, int index, String message)
+ {
+ // illegal state exception check - in this case the wrong password will
+ // cause an underlying class cast exception.
+ try
+ {
+ PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().setProvider("SC").build(password.toCharArray());
+
+ PEMParser pemRd = openPEMResource("test.pem");
+ Object o;
+
+ while ((o = pemRd.readObject()) != null)
+ {
+ if (o instanceof PEMEncryptedKeyPair)
+ {
+ ((PEMEncryptedKeyPair)o).decryptKeyPair(decProv);
+ }
+ }
+
+ fail("issue not detected: " + index);
+ }
+ catch (IOException e)
+ {
+ // ignore
+ }
+ }
+
+ private void doNoPasswordTest()
+ throws IOException
+ {
+ PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().setProvider("SC").build("".toCharArray());
+
+ PEMParser pemRd = openPEMResource("smimenopw.pem");
+ Object o;
+ PrivateKeyInfo key = null;
+
+ while ((o = pemRd.readObject()) != null)
+ {
+ key = (PrivateKeyInfo)o;
+ }
+
+ if (key == null)
+ {
+ fail("private key not detected");
+ }
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new ParserTest());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/openssl/test/ReaderTest.java b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/openssl/test/ReaderTest.java
new file mode 100644
index 000000000..8305bb284
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/openssl/test/ReaderTest.java
@@ -0,0 +1,323 @@
+package org.spongycastle.openssl.test;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Signature;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.RSAPrivateKey;
+
+import org.spongycastle.asn1.cms.CMSObjectIdentifiers;
+import org.spongycastle.asn1.cms.ContentInfo;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.openssl.PEMWriter;
+import org.spongycastle.openssl.PasswordFinder;
+import org.spongycastle.util.test.SimpleTest;
+
+/**
+ * basic class for reading test.pem - the password is "secret"
+ */
+public class ReaderTest
+ extends SimpleTest
+{
+ private static class Password
+ implements PasswordFinder
+ {
+ char[] password;
+
+ Password(
+ char[] word)
+ {
+ this.password = word;
+ }
+
+ public char[] getPassword()
+ {
+ return password;
+ }
+ }
+
+ public String getName()
+ {
+ return "PEMReaderTest";
+ }
+
+ private PEMReader openPEMResource(
+ String fileName,
+ PasswordFinder pGet)
+ {
+ InputStream res = this.getClass().getResourceAsStream(fileName);
+ Reader fRd = new BufferedReader(new InputStreamReader(res));
+ return new PEMReader(fRd, pGet);
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ PasswordFinder pGet = new Password("secret".toCharArray());
+ PEMReader pemRd = openPEMResource("test.pem", pGet);
+ Object o;
+ KeyPair pair;
+
+ while ((o = pemRd.readObject()) != null)
+ {
+ if (o instanceof KeyPair)
+ {
+ //pair = (KeyPair)o;
+
+ //System.out.println(pair.getPublic());
+ //System.out.println(pair.getPrivate());
+ }
+ else
+ {
+ //System.out.println(o.toString());
+ }
+ }
+
+ //
+ // pkcs 7 data
+ //
+ pemRd = openPEMResource("pkcs7.pem", null);
+ ContentInfo d = (ContentInfo)pemRd.readObject();
+
+ if (!d.getContentType().equals(CMSObjectIdentifiers.envelopedData))
+ {
+ fail("failed envelopedData check");
+ }
+
+ //
+ // ECKey
+ //
+ pemRd = openPEMResource("eckey.pem", null);
+ ECNamedCurveParameterSpec spec = (ECNamedCurveParameterSpec)pemRd.readObject();
+
+ pair = (KeyPair)pemRd.readObject();
+ Signature sgr = Signature.getInstance("ECDSA", "SC");
+
+ sgr.initSign(pair.getPrivate());
+
+ byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
+
+ sgr.update(message);
+
+ byte[] sigBytes = sgr.sign();
+
+ sgr.initVerify(pair.getPublic());
+
+ sgr.update(message);
+
+ if (!sgr.verify(sigBytes))
+ {
+ fail("EC verification failed");
+ }
+
+ if (!pair.getPublic().getAlgorithm().equals("ECDSA"))
+ {
+ fail("wrong algorithm name on public got: " + pair.getPublic().getAlgorithm());
+ }
+
+ if (!pair.getPrivate().getAlgorithm().equals("ECDSA"))
+ {
+ fail("wrong algorithm name on private");
+ }
+
+ //
+ // writer/parser test
+ //
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "SC");
+
+ pair = kpGen.generateKeyPair();
+
+ keyPairTest("RSA", pair);
+
+ kpGen = KeyPairGenerator.getInstance("DSA", "SC");
+ kpGen.initialize(512, new SecureRandom());
+ pair = kpGen.generateKeyPair();
+
+ keyPairTest("DSA", pair);
+
+ //
+ // PKCS7
+ //
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ PEMWriter pWrt = new PEMWriter(new OutputStreamWriter(bOut));
+
+ pWrt.writeObject(d);
+
+ pWrt.close();
+
+ pemRd = new PEMReader(new InputStreamReader(new ByteArrayInputStream(bOut.toByteArray())));
+ d = (ContentInfo)pemRd.readObject();
+
+ if (!d.getContentType().equals(CMSObjectIdentifiers.envelopedData))
+ {
+ fail("failed envelopedData recode check");
+ }
+
+
+ // OpenSSL test cases (as embedded resources)
+ doOpenSslDsaTest("unencrypted");
+ doOpenSslRsaTest("unencrypted");
+
+ doOpenSslTests("aes128");
+ doOpenSslTests("aes192");
+ doOpenSslTests("aes256");
+ doOpenSslTests("blowfish");
+ doOpenSslTests("des1");
+ doOpenSslTests("des2");
+ doOpenSslTests("des3");
+ doOpenSslTests("rc2_128");
+
+ doOpenSslDsaTest("rc2_40_cbc");
+ doOpenSslRsaTest("rc2_40_cbc");
+ doOpenSslDsaTest("rc2_64_cbc");
+ doOpenSslRsaTest("rc2_64_cbc");
+
+ // heap space check - a failure by the ASN.1 library to detect an
+ // out of band stream will cause this to run out of memory.
+ try
+ {
+ pGet = new Password("7fd98".toCharArray());
+
+ pemRd = openPEMResource("test.pem", pGet);
+
+ while ((o = pemRd.readObject()) != null)
+ {
+ }
+ fail("bounds issue not detected");
+ }
+ catch (IOException e)
+ {
+ }
+ }
+
+ private void keyPairTest(
+ String name,
+ KeyPair pair)
+ throws IOException
+ {
+ PEMReader pemRd;
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ PEMWriter pWrt = new PEMWriter(new OutputStreamWriter(bOut));
+
+ pWrt.writeObject(pair.getPublic());
+
+ pWrt.close();
+
+ pemRd = new PEMReader(new InputStreamReader(new ByteArrayInputStream(bOut.toByteArray())));
+
+ PublicKey k = (PublicKey)pemRd.readObject();
+ if (!k.equals(pair.getPublic()))
+ {
+ fail("Failed public key read: " + name);
+ }
+
+ bOut = new ByteArrayOutputStream();
+ pWrt = new PEMWriter(new OutputStreamWriter(bOut));
+
+ pWrt.writeObject(pair.getPrivate());
+
+ pWrt.close();
+
+ pemRd = new PEMReader(new InputStreamReader(new ByteArrayInputStream(bOut.toByteArray())));
+
+ KeyPair kPair = (KeyPair)pemRd.readObject();
+ if (!kPair.getPrivate().equals(pair.getPrivate()))
+ {
+ fail("Failed private key read: " + name);
+ }
+
+ if (!kPair.getPublic().equals(pair.getPublic()))
+ {
+ fail("Failed private key public read: " + name);
+ }
+ }
+
+ private void doOpenSslTests(
+ String baseName)
+ throws IOException
+ {
+ doOpenSslDsaModesTest(baseName);
+ doOpenSslRsaModesTest(baseName);
+ }
+
+ private void doOpenSslDsaModesTest(
+ String baseName)
+ throws IOException
+ {
+ doOpenSslDsaTest(baseName + "_cbc");
+ doOpenSslDsaTest(baseName + "_cfb");
+ doOpenSslDsaTest(baseName + "_ecb");
+ doOpenSslDsaTest(baseName + "_ofb");
+ }
+
+ private void doOpenSslRsaModesTest(
+ String baseName)
+ throws IOException
+ {
+ doOpenSslRsaTest(baseName + "_cbc");
+ doOpenSslRsaTest(baseName + "_cfb");
+ doOpenSslRsaTest(baseName + "_ecb");
+ doOpenSslRsaTest(baseName + "_ofb");
+ }
+
+ private void doOpenSslDsaTest(
+ String name)
+ throws IOException
+ {
+ String fileName = "dsa/openssl_dsa_" + name + ".pem";
+
+ doOpenSslTestFile(fileName, DSAPrivateKey.class);
+ }
+
+ private void doOpenSslRsaTest(
+ String name)
+ throws IOException
+ {
+ String fileName = "rsa/openssl_rsa_" + name + ".pem";
+
+ doOpenSslTestFile(fileName, RSAPrivateKey.class);
+ }
+
+ private void doOpenSslTestFile(
+ String fileName,
+ Class expectedPrivKeyClass)
+ throws IOException
+ {
+ PEMReader pr = openPEMResource("data/" + fileName, new Password("changeit".toCharArray()));
+ Object o = pr.readObject();
+
+ if (o == null || !(o instanceof KeyPair))
+ {
+ fail("Didn't find OpenSSL key");
+ }
+
+ KeyPair kp = (KeyPair) o;
+ PrivateKey privKey = kp.getPrivate();
+
+ if (!expectedPrivKeyClass.isInstance(privKey))
+ {
+ fail("Returned key not of correct type");
+ }
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new ReaderTest());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/tsp/test/TSPTest.java b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/tsp/test/TSPTest.java
new file mode 100644
index 000000000..adf5ddf94
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/jdk1.3/org/spongycastle/tsp/test/TSPTest.java
@@ -0,0 +1,603 @@
+package org.spongycastle.tsp.test;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import org.spongycastle.jce.cert.CertStore;
+import org.spongycastle.jce.cert.CollectionCertStoreParameters;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+
+import junit.framework.TestCase;
+import org.spongycastle.asn1.cmp.PKIFailureInfo;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.tsp.GenTimeAccuracy;
+import org.spongycastle.tsp.TSPAlgorithms;
+import org.spongycastle.tsp.TSPValidationException;
+import org.spongycastle.tsp.TimeStampRequest;
+import org.spongycastle.tsp.TimeStampRequestGenerator;
+import org.spongycastle.tsp.TimeStampResponse;
+import org.spongycastle.tsp.TimeStampResponseGenerator;
+import org.spongycastle.tsp.TimeStampToken;
+import org.spongycastle.tsp.TimeStampTokenGenerator;
+import org.spongycastle.tsp.TimeStampTokenInfo;
+import org.spongycastle.util.Arrays;
+
+public class TSPTest
+ extends TestCase
+{
+ public void testGeneral()
+ throws Exception
+ {
+ String signDN = "O=Bouncy Castle, C=AU";
+ KeyPair signKP = TSPTestUtil.makeKeyPair();
+ X509Certificate signCert = TSPTestUtil.makeCACertificate(signKP,
+ signDN, signKP, signDN);
+
+ String origDN = "CN=Eric H. Echidna, E=eric@bouncycastle.org, O=Bouncy Castle, C=AU";
+ KeyPair origKP = TSPTestUtil.makeKeyPair();
+ X509Certificate origCert = TSPTestUtil.makeCertificate(origKP,
+ origDN, signKP, signDN);
+
+
+
+ List certList = new ArrayList();
+ certList.add(origCert);
+ certList.add(signCert);
+
+ CertStore certs = CertStore.getInstance("Collection",
+ new CollectionCertStoreParameters(certList), "SC");
+
+ basicTest(origKP.getPrivate(), origCert, certs);
+ responseValidationTest(origKP.getPrivate(), origCert, certs);
+ incorrectHashTest(origKP.getPrivate(), origCert, certs);
+ badAlgorithmTest(origKP.getPrivate(), origCert, certs);
+ timeNotAvailableTest(origKP.getPrivate(), origCert, certs);
+ badPolicyTest(origKP.getPrivate(), origCert, certs);
+ tokenEncodingTest(origKP.getPrivate(), origCert, certs);
+ certReqTest(origKP.getPrivate(), origCert, certs);
+ testAccuracyZeroCerts(origKP.getPrivate(), origCert, certs);
+ testAccuracyWithCertsAndOrdering(origKP.getPrivate(), origCert, certs);
+ testNoNonse(origKP.getPrivate(), origCert, certs);
+ }
+
+ private void basicTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ CertStore certs)
+ throws Exception
+ {
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+ privateKey, cert, TSPAlgorithms.SHA1, "1.2");
+
+ tsTokenGen.setCertificatesAndCRLs(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date(), "SC");
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ tsToken.validate(cert, "SC");
+
+ AttributeTable table = tsToken.getSignedAttributes();
+
+ assertNotNull("no signingCertificate attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificate));
+ }
+
+ private void responseValidationTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ CertStore certs)
+ throws Exception
+ {
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+ privateKey, cert, TSPAlgorithms.MD5, "1.2");
+
+ tsTokenGen.setCertificatesAndCRLs(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date(), "SC");
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ tsToken.validate(cert, "SC");
+
+ //
+ // check validation
+ //
+ tsResp.validate(request);
+
+ try
+ {
+ request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(101));
+
+ tsResp.validate(request);
+
+ fail("response validation failed on invalid nonce.");
+ }
+ catch (TSPValidationException e)
+ {
+ // ignore
+ }
+
+ try
+ {
+ request = reqGen.generate(TSPAlgorithms.SHA1, new byte[22], BigInteger.valueOf(100));
+
+ tsResp.validate(request);
+
+ fail("response validation failed on wrong digest.");
+ }
+ catch (TSPValidationException e)
+ {
+ // ignore
+ }
+
+ try
+ {
+ request = reqGen.generate(TSPAlgorithms.MD5, new byte[20], BigInteger.valueOf(100));
+
+ tsResp.validate(request);
+
+ fail("response validation failed on wrong digest.");
+ }
+ catch (TSPValidationException e)
+ {
+ // ignore
+ }
+ }
+
+ private void incorrectHashTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ CertStore certs)
+ throws Exception
+ {
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+ privateKey, cert, TSPAlgorithms.SHA1, "1.2");
+
+ tsTokenGen.setCertificatesAndCRLs(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[16]);
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date(), "SC");
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ if (tsToken != null)
+ {
+ fail("incorrectHash - token not null.");
+ }
+
+ PKIFailureInfo failInfo = tsResp.getFailInfo();
+
+ if (failInfo == null)
+ {
+ fail("incorrectHash - failInfo set to null.");
+ }
+
+ if (failInfo.intValue() != PKIFailureInfo.badDataFormat)
+ {
+ fail("incorrectHash - wrong failure info returned.");
+ }
+ }
+
+ private void badAlgorithmTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ CertStore certs)
+ throws Exception
+ {
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+ privateKey, cert, TSPAlgorithms.SHA1, "1.2");
+
+ tsTokenGen.setCertificatesAndCRLs(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate("1.2.3.4.5", new byte[20]);
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date(), "SC");
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ if (tsToken != null)
+ {
+ fail("badAlgorithm - token not null.");
+ }
+
+ PKIFailureInfo failInfo = tsResp.getFailInfo();
+
+ if (failInfo == null)
+ {
+ fail("badAlgorithm - failInfo set to null.");
+ }
+
+ if (failInfo.intValue() != PKIFailureInfo.badAlg)
+ {
+ fail("badAlgorithm - wrong failure info returned.");
+ }
+ }
+
+ private void timeNotAvailableTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ CertStore certs)
+ throws Exception
+ {
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+ privateKey, cert, TSPAlgorithms.SHA1, "1.2");
+
+ tsTokenGen.setCertificatesAndCRLs(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate("1.2.3.4.5", new byte[20]);
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), null, "SC");
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ if (tsToken != null)
+ {
+ fail("timeNotAvailable - token not null.");
+ }
+
+ PKIFailureInfo failInfo = tsResp.getFailInfo();
+
+ if (failInfo == null)
+ {
+ fail("timeNotAvailable - failInfo set to null.");
+ }
+
+ if (failInfo.intValue() != PKIFailureInfo.timeNotAvailable)
+ {
+ fail("timeNotAvailable - wrong failure info returned.");
+ }
+ }
+
+ private void badPolicyTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ CertStore certs)
+ throws Exception
+ {
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+ privateKey, cert, TSPAlgorithms.SHA1, "1.2");
+
+ tsTokenGen.setCertificatesAndCRLs(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+
+ reqGen.setReqPolicy("1.1");
+
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20]);
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED, new HashSet());
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date(), "SC");
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ if (tsToken != null)
+ {
+ fail("badPolicy - token not null.");
+ }
+
+ PKIFailureInfo failInfo = tsResp.getFailInfo();
+
+ if (failInfo == null)
+ {
+ fail("badPolicy - failInfo set to null.");
+ }
+
+ if (failInfo.intValue() != PKIFailureInfo.unacceptedPolicy)
+ {
+ fail("badPolicy - wrong failure info returned.");
+ }
+ }
+
+ private void certReqTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ CertStore certs)
+ throws Exception
+ {
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+ privateKey, cert, TSPAlgorithms.MD5, "1.2");
+
+ tsTokenGen.setCertificatesAndCRLs(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+
+ //
+ // request with certReq false
+ //
+ reqGen.setCertReq(false);
+
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date(), "SC");
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ assertNull(tsToken.getTimeStampInfo().getGenTimeAccuracy()); // check for abscence of accuracy
+
+ assertEquals("1.2", tsToken.getTimeStampInfo().getPolicy().getId());
+
+ try
+ {
+ tsToken.validate(cert, "SC");
+ }
+ catch (TSPValidationException e)
+ {
+ fail("certReq(false) verification of token failed.");
+ }
+
+ CertStore respCerts = tsToken.getCertificatesAndCRLs("Collection", "SC");
+
+ Collection certsColl = respCerts.getCertificates(null);
+
+ if (!certsColl.isEmpty())
+ {
+ fail("certReq(false) found certificates in response.");
+ }
+ }
+
+
+ private void tokenEncodingTest(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ CertStore certs)
+ throws Exception
+ {
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+ privateKey, cert, TSPAlgorithms.SHA1, "1.2.3.4.5.6");
+
+ tsTokenGen.setCertificatesAndCRLs(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date(), "SC");
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampResponse tsResponse = new TimeStampResponse(tsResp.getEncoded());
+
+ if (!Arrays.areEqual(tsResponse.getEncoded(), tsResp.getEncoded())
+ || !Arrays.areEqual(tsResponse.getTimeStampToken().getEncoded(),
+ tsResp.getTimeStampToken().getEncoded()))
+ {
+ fail();
+ }
+ }
+
+ private void testAccuracyZeroCerts(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ CertStore certs)
+ throws Exception
+ {
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+ privateKey, cert, TSPAlgorithms.MD5, "1.2");
+
+ tsTokenGen.setCertificatesAndCRLs(certs);
+
+ tsTokenGen.setAccuracySeconds(1);
+ tsTokenGen.setAccuracyMillis(2);
+ tsTokenGen.setAccuracyMicros(3);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date(), "SC");
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ tsToken.validate(cert, "SC");
+
+ //
+ // check validation
+ //
+ tsResp.validate(request);
+
+ //
+ // check tstInfo
+ //
+ TimeStampTokenInfo tstInfo = tsToken.getTimeStampInfo();
+
+ //
+ // check accuracy
+ //
+ GenTimeAccuracy accuracy = tstInfo.getGenTimeAccuracy();
+
+ assertEquals(1, accuracy.getSeconds());
+ assertEquals(2, accuracy.getMillis());
+ assertEquals(3, accuracy.getMicros());
+
+ assertEquals(new BigInteger("23"), tstInfo.getSerialNumber());
+
+ assertEquals("1.2", tstInfo.getPolicy().getId());
+
+ //
+ // test certReq
+ //
+ CertStore store = tsToken.getCertificatesAndCRLs("Collection", "SC");
+
+ Collection certificates = store.getCertificates(null);
+
+ assertEquals(0, certificates.size());
+ }
+
+ private void testAccuracyWithCertsAndOrdering(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ CertStore certs)
+ throws Exception
+ {
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+ privateKey, cert, TSPAlgorithms.MD5, "1.2.3");
+
+ tsTokenGen.setCertificatesAndCRLs(certs);
+
+ tsTokenGen.setAccuracySeconds(3);
+ tsTokenGen.setAccuracyMillis(1);
+ tsTokenGen.setAccuracyMicros(2);
+
+ tsTokenGen.setOrdering(true);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+
+ reqGen.setCertReq(true);
+
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
+
+ assertTrue(request.getCertReq());
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("23"), new Date(), "SC");
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ tsToken.validate(cert, "SC");
+
+ //
+ // check validation
+ //
+ tsResp.validate(request);
+
+ //
+ // check tstInfo
+ //
+ TimeStampTokenInfo tstInfo = tsToken.getTimeStampInfo();
+
+ //
+ // check accuracy
+ //
+ GenTimeAccuracy accuracy = tstInfo.getGenTimeAccuracy();
+
+ assertEquals(3, accuracy.getSeconds());
+ assertEquals(1, accuracy.getMillis());
+ assertEquals(2, accuracy.getMicros());
+
+ assertEquals(new BigInteger("23"), tstInfo.getSerialNumber());
+
+ assertEquals("1.2.3", tstInfo.getPolicy().getId());
+
+ assertEquals(true, tstInfo.isOrdered());
+
+ assertEquals(tstInfo.getNonce(), BigInteger.valueOf(100));
+
+ //
+ // test certReq
+ //
+ CertStore store = tsToken.getCertificatesAndCRLs("Collection", "SC");
+
+ Collection certificates = store.getCertificates(null);
+
+ assertEquals(2, certificates.size());
+ }
+
+ private void testNoNonse(
+ PrivateKey privateKey,
+ X509Certificate cert,
+ CertStore certs)
+ throws Exception
+ {
+ TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+ privateKey, cert, TSPAlgorithms.MD5, "1.2.3");
+
+ tsTokenGen.setCertificatesAndCRLs(certs);
+
+ TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+ TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA1, new byte[20]);
+
+ assertFalse(request.getCertReq());
+
+ TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TSPAlgorithms.ALLOWED);
+
+ TimeStampResponse tsResp = tsRespGen.generate(request, new BigInteger("24"), new Date(), "SC");
+
+ tsResp = new TimeStampResponse(tsResp.getEncoded());
+
+ TimeStampToken tsToken = tsResp.getTimeStampToken();
+
+ tsToken.validate(cert, "SC");
+
+ //
+ // check validation
+ //
+ tsResp.validate(request);
+
+ //
+ // check tstInfo
+ //
+ TimeStampTokenInfo tstInfo = tsToken.getTimeStampInfo();
+
+ //
+ // check accuracy
+ //
+ GenTimeAccuracy accuracy = tstInfo.getGenTimeAccuracy();
+
+ assertNull(accuracy);
+
+ assertEquals(new BigInteger("24"), tstInfo.getSerialNumber());
+
+ assertEquals("1.2.3", tstInfo.getPolicy().getId());
+
+ assertEquals(false, tstInfo.isOrdered());
+
+ assertNull(tstInfo.getNonce());
+
+ //
+ // test certReq
+ //
+ CertStore store = tsToken.getCertificatesAndCRLs("Collection", "SC");
+
+ Collection certificates = store.getCertificates(null);
+
+ assertEquals(0, certificates.size());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/jdk1.4/org/spongycastle/cert/test/CertTest.java b/libraries/spongycastle/pkix/src/test/jdk1.4/org/spongycastle/cert/test/CertTest.java
new file mode 100644
index 000000000..8cf26dca2
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/jdk1.4/org/spongycastle/cert/test/CertTest.java
@@ -0,0 +1,2984 @@
+package org.spongycastle.cert.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Signature;
+import java.security.cert.CRL;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Enumerated;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DEREnumerated;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSAPublicKey;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.X500NameBuilder;
+import org.spongycastle.asn1.x500.style.BCStyle;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.ExtensionsGenerator;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.IssuingDistributionPoint;
+import org.spongycastle.asn1.x509.KeyPurposeId;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509CertificateStructure;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.cert.X509CRLEntryHolder;
+import org.spongycastle.cert.X509CRLHolder;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.X509v1CertificateBuilder;
+import org.spongycastle.cert.X509v2CRLBuilder;
+import org.spongycastle.cert.X509v3CertificateBuilder;
+import org.spongycastle.cert.jcajce.JcaX509CRLConverter;
+import org.spongycastle.cert.jcajce.JcaX509CRLHolder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.cert.jcajce.JcaX509v1CertificateBuilder;
+import org.spongycastle.cert.jcajce.JcaX509v2CRLBuilder;
+import org.spongycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.spongycastle.jce.X509KeyUsage;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPrivateKeySpec;
+import org.spongycastle.jce.spec.ECPublicKeySpec;
+import org.spongycastle.jce.spec.GOST3410ParameterSpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.ContentVerifierProvider;
+import org.spongycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
+import org.spongycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
+import org.spongycastle.operator.bc.BcRSAContentSignerBuilder;
+import org.spongycastle.operator.bc.BcRSAContentVerifierProviderBuilder;
+import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.encoders.Hex;
+import org.spongycastle.util.test.SimpleTest;
+import org.spongycastle.x509.extension.AuthorityKeyIdentifierStructure;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+
+public class CertTest
+ extends SimpleTest
+{
+ private static final String BC = org.spongycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
+
+ // test CA
+ byte[] testCAp12 = Base64.decode(
+ "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"
+ + "HLhcYQcQ1R+RucctAgIEAAAA");
+
+ //
+ // server.crt
+ //
+ byte[] cert1 = Base64.decode(
+ "MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx"
+ + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY"
+ + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB"
+ + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ"
+ + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2"
+ + "MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW"
+ + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM"
+ + "dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l"
+ + "Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv"
+ + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re"
+ + "Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO"
+ + "Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE"
+ + "7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy"
+ + "QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0"
+ + "ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw"
+ + "DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL"
+ + "iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4"
+ + "yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF"
+ + "5/8=");
+
+ //
+ // ca.crt
+ //
+ byte[] cert2 = Base64.decode(
+ "MIIDbDCCAtWgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx"
+ + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY"
+ + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB"
+ + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ"
+ + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU1MzNaFw0wMTA2"
+ + "MDIwNzU1MzNaMIG3MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW"
+ + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM"
+ + "dGQxHjAcBgNVBAsTFUNlcnRpZmljYXRlIEF1dGhvcml0eTEVMBMGA1UEAxMMQ29u"
+ + "bmVjdCA0IENBMSgwJgYJKoZIhvcNAQkBFhl3ZWJtYXN0ZXJAY29ubmVjdDQuY29t"
+ + "LmF1MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgs5ptNG6Qv1ZpCDuUNGmv"
+ + "rhjqMDPd3ri8JzZNRiiFlBA4e6/ReaO1U8ASewDeQMH6i9R6degFdQRLngbuJP0s"
+ + "xcEE+SksEWNvygfzLwV9J/q+TQDyJYK52utb++lS0b48A1KPLwEsyL6kOAgelbur"
+ + "ukwxowprKUIV7Knf1ajetQIDAQABo4GFMIGCMCQGA1UdEQQdMBuBGXdlYm1hc3Rl"
+ + "ckBjb25uZWN0NC5jb20uYXUwDwYDVR0TBAgwBgEB/wIBADA2BglghkgBhvhCAQ0E"
+ + "KRYnbW9kX3NzbCBnZW5lcmF0ZWQgY3VzdG9tIENBIGNlcnRpZmljYXRlMBEGCWCG"
+ + "SAGG+EIBAQQEAwICBDANBgkqhkiG9w0BAQQFAAOBgQCsGvfdghH8pPhlwm1r3pQk"
+ + "msnLAVIBb01EhbXm2861iXZfWqGQjrGAaA0ZpXNk9oo110yxoqEoSJSzniZa7Xtz"
+ + "soTwNUpE0SLHvWf/SlKdFWlzXA+vOZbzEv4UmjeelekTm7lc01EEa5QRVzOxHFtQ"
+ + "DhkaJ8VqOMajkQFma2r9iA==");
+
+ //
+ // testx509.pem
+ //
+ byte[] cert3 = Base64.decode(
+ "MIIBWzCCAQYCARgwDQYJKoZIhvcNAQEEBQAwODELMAkGA1UEBhMCQVUxDDAKBgNV"
+ + "BAgTA1FMRDEbMBkGA1UEAxMSU1NMZWF5L3JzYSB0ZXN0IENBMB4XDTk1MDYxOTIz"
+ + "MzMxMloXDTk1MDcxNzIzMzMxMlowOjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA1FM"
+ + "RDEdMBsGA1UEAxMUU1NMZWF5L3JzYSB0ZXN0IGNlcnQwXDANBgkqhkiG9w0BAQEF"
+ + "AANLADBIAkEAqtt6qS5GTxVxGZYWa0/4u+IwHf7p2LNZbcPBp9/OfIcYAXBQn8hO"
+ + "/Re1uwLKXdCjIoaGs4DLdG88rkzfyK5dPQIDAQABMAwGCCqGSIb3DQIFBQADQQAE"
+ + "Wc7EcF8po2/ZO6kNCwK/ICH6DobgLekA5lSLr5EvuioZniZp5lFzAw4+YzPQ7XKJ"
+ + "zl9HYIMxATFyqSiD9jsx");
+
+ //
+ // v3-cert1.pem
+ //
+ byte[] cert4 = Base64.decode(
+ "MIICjTCCAfigAwIBAgIEMaYgRzALBgkqhkiG9w0BAQQwRTELMAkGA1UEBhMCVVMx"
+ + "NjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFuZCBTcGFjZSBBZG1pbmlz"
+ + "dHJhdGlvbjAmFxE5NjA1MjgxMzQ5MDUrMDgwMBcROTgwNTI4MTM0OTA1KzA4MDAw"
+ + "ZzELMAkGA1UEBhMCVVMxNjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFu"
+ + "ZCBTcGFjZSBBZG1pbmlzdHJhdGlvbjEgMAkGA1UEBRMCMTYwEwYDVQQDEwxTdGV2"
+ + "ZSBTY2hvY2gwWDALBgkqhkiG9w0BAQEDSQAwRgJBALrAwyYdgxmzNP/ts0Uyf6Bp"
+ + "miJYktU/w4NG67ULaN4B5CnEz7k57s9o3YY3LecETgQ5iQHmkwlYDTL2fTgVfw0C"
+ + "AQOjgaswgagwZAYDVR0ZAQH/BFowWDBWMFQxCzAJBgNVBAYTAlVTMTYwNAYDVQQK"
+ + "Ey1OYXRpb25hbCBBZXJvbmF1dGljcyBhbmQgU3BhY2UgQWRtaW5pc3RyYXRpb24x"
+ + "DTALBgNVBAMTBENSTDEwFwYDVR0BAQH/BA0wC4AJODMyOTcwODEwMBgGA1UdAgQR"
+ + "MA8ECTgzMjk3MDgyM4ACBSAwDQYDVR0KBAYwBAMCBkAwCwYJKoZIhvcNAQEEA4GB"
+ + "AH2y1VCEw/A4zaXzSYZJTTUi3uawbbFiS2yxHvgf28+8Js0OHXk1H1w2d6qOHH21"
+ + "X82tZXd/0JtG0g1T9usFFBDvYK8O0ebgz/P5ELJnBL2+atObEuJy1ZZ0pBDWINR3"
+ + "WkDNLCGiTkCKp0F5EWIrVDwh54NNevkCQRZita+z4IBO");
+
+ //
+ // v3-cert2.pem
+ //
+ byte[] cert5 = Base64.decode(
+ "MIICiTCCAfKgAwIBAgIEMeZfHzANBgkqhkiG9w0BAQQFADB9MQswCQYDVQQGEwJD"
+ + "YTEPMA0GA1UEBxMGTmVwZWFuMR4wHAYDVQQLExVObyBMaWFiaWxpdHkgQWNjZXB0"
+ + "ZWQxHzAdBgNVBAoTFkZvciBEZW1vIFB1cnBvc2VzIE9ubHkxHDAaBgNVBAMTE0Vu"
+ + "dHJ1c3QgRGVtbyBXZWIgQ0EwHhcNOTYwNzEyMTQyMDE1WhcNOTYxMDEyMTQyMDE1"
+ + "WjB0MSQwIgYJKoZIhvcNAQkBExVjb29rZUBpc3NsLmF0bC5ocC5jb20xCzAJBgNV"
+ + "BAYTAlVTMScwJQYDVQQLEx5IZXdsZXR0IFBhY2thcmQgQ29tcGFueSAoSVNTTCkx"
+ + "FjAUBgNVBAMTDVBhdWwgQS4gQ29va2UwXDANBgkqhkiG9w0BAQEFAANLADBIAkEA"
+ + "6ceSq9a9AU6g+zBwaL/yVmW1/9EE8s5you1mgjHnj0wAILuoB3L6rm6jmFRy7QZT"
+ + "G43IhVZdDua4e+5/n1ZslwIDAQABo2MwYTARBglghkgBhvhCAQEEBAMCB4AwTAYJ"
+ + "YIZIAYb4QgENBD8WPVRoaXMgY2VydGlmaWNhdGUgaXMgb25seSBpbnRlbmRlZCBm"
+ + "b3IgZGVtb25zdHJhdGlvbiBwdXJwb3Nlcy4wDQYJKoZIhvcNAQEEBQADgYEAi8qc"
+ + "F3zfFqy1sV8NhjwLVwOKuSfhR/Z8mbIEUeSTlnH3QbYt3HWZQ+vXI8mvtZoBc2Fz"
+ + "lexKeIkAZXCesqGbs6z6nCt16P6tmdfbZF3I3AWzLquPcOXjPf4HgstkyvVBn0Ap"
+ + "jAFN418KF/Cx4qyHB4cjdvLrRjjQLnb2+ibo7QU=");
+
+ //
+ // pem encoded pkcs7
+ //
+ byte[] cert6 = Base64.decode(
+ "MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIJbzCCAj0w"
+ + "ggGmAhEAzbp/VvDf5LxU/iKss3KqVTANBgkqhkiG9w0BAQIFADBfMQswCQYDVQQGEwJVUzEXMBUG"
+ + "A1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGljIFByaW1hcnkgQ2Vy"
+ + "dGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNOTYwMTI5MDAwMDAwWhcNMjgwODAxMjM1OTU5WjBfMQsw"
+ + "CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVi"
+ + "bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwgZ8wDQYJKoZIhvcNAQEBBQADgY0A"
+ + "MIGJAoGBAOUZv22jVmEtmUhx9mfeuY3rt56GgAqRDvo4Ja9GiILlc6igmyRdDR/MZW4MsNBWhBiH"
+ + "mgabEKFz37RYOWtuwfYV1aioP6oSBo0xrH+wNNePNGeICc0UEeJORVZpH3gCgNrcR5EpuzbJY1zF"
+ + "4Ncth3uhtzKwezC6Ki8xqu6jZ9rbAgMBAAEwDQYJKoZIhvcNAQECBQADgYEATD+4i8Zo3+5DMw5d"
+ + "6abLB4RNejP/khv0Nq3YlSI2aBFsfELM85wuxAc/FLAPT/+Qknb54rxK6Y/NoIAK98Up8YIiXbix"
+ + "3YEjo3slFUYweRb46gVLlH8dwhzI47f0EEA8E8NfH1PoSOSGtHuhNbB7Jbq4046rPzidADQAmPPR"
+ + "cZQwggMuMIICl6ADAgECAhEA0nYujRQMPX2yqCVdr+4NdTANBgkqhkiG9w0BAQIFADBfMQswCQYD"
+ + "VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGlj"
+ + "IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNOTgwNTEyMDAwMDAwWhcNMDgwNTEy"
+ + "MjM1OTU5WjCBzDEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy"
+ + "dXN0IE5ldHdvcmsxRjBEBgNVBAsTPXd3dy52ZXJpc2lnbi5jb20vcmVwb3NpdG9yeS9SUEEgSW5j"
+ + "b3JwLiBCeSBSZWYuLExJQUIuTFREKGMpOTgxSDBGBgNVBAMTP1ZlcmlTaWduIENsYXNzIDEgQ0Eg"
+ + "SW5kaXZpZHVhbCBTdWJzY3JpYmVyLVBlcnNvbmEgTm90IFZhbGlkYXRlZDCBnzANBgkqhkiG9w0B"
+ + "AQEFAAOBjQAwgYkCgYEAu1pEigQWu1X9A3qKLZRPFXg2uA1Ksm+cVL+86HcqnbnwaLuV2TFBcHqB"
+ + "S7lIE1YtxwjhhEKrwKKSq0RcqkLwgg4C6S/7wju7vsknCl22sDZCM7VuVIhPh0q/Gdr5FegPh7Yc"
+ + "48zGmo5/aiSS4/zgZbqnsX7vyds3ashKyAkG5JkCAwEAAaN8MHowEQYJYIZIAYb4QgEBBAQDAgEG"
+ + "MEcGA1UdIARAMD4wPAYLYIZIAYb4RQEHAQEwLTArBggrBgEFBQcCARYfd3d3LnZlcmlzaWduLmNv"
+ + "bS9yZXBvc2l0b3J5L1JQQTAPBgNVHRMECDAGAQH/AgEAMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0B"
+ + "AQIFAAOBgQCIuDc73dqUNwCtqp/hgQFxHpJqbS/28Z3TymQ43BuYDAeGW4UVag+5SYWklfEXfWe0"
+ + "fy0s3ZpCnsM+tI6q5QsG3vJWKvozx74Z11NMw73I4xe1pElCY+zCphcPXVgaSTyQXFWjZSAA/Rgg"
+ + "5V+CprGoksVYasGNAzzrw80FopCubjCCA/gwggNhoAMCAQICEBbbn/1G1zppD6KsP01bwywwDQYJ"
+ + "KoZIhvcNAQEEBQAwgcwxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln"
+ + "biBUcnVzdCBOZXR3b3JrMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvUlBB"
+ + "IEluY29ycC4gQnkgUmVmLixMSUFCLkxURChjKTk4MUgwRgYDVQQDEz9WZXJpU2lnbiBDbGFzcyAx"
+ + "IENBIEluZGl2aWR1YWwgU3Vic2NyaWJlci1QZXJzb25hIE5vdCBWYWxpZGF0ZWQwHhcNMDAxMDAy"
+ + "MDAwMDAwWhcNMDAxMjAxMjM1OTU5WjCCAQcxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYD"
+ + "VQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3Jl"
+ + "cG9zaXRvcnkvUlBBIEluY29ycC4gYnkgUmVmLixMSUFCLkxURChjKTk4MR4wHAYDVQQLExVQZXJz"
+ + "b25hIE5vdCBWYWxpZGF0ZWQxJzAlBgNVBAsTHkRpZ2l0YWwgSUQgQ2xhc3MgMSAtIE1pY3Jvc29m"
+ + "dDETMBEGA1UEAxQKRGF2aWQgUnlhbjElMCMGCSqGSIb3DQEJARYWZGF2aWRAbGl2ZW1lZGlhLmNv"
+ + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqxBsdeNmSvFqhMNwhQgNzM8mdjX9eSXb"
+ + "DawpHtQHjmh0AKJSa3IwUY0VIsyZHuXWktO/CgaMBVPt6OVf/n0R2sQigMP6Y+PhEiS0vCJBL9aK"
+ + "0+pOo2qXrjVBmq+XuCyPTnc+BOSrU26tJsX0P9BYorwySiEGxGanBNATdVL4NdUCAwEAAaOBnDCB"
+ + "mTAJBgNVHRMEAjAAMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQgwKjAoBggrBgEFBQcCARYcaHR0"
+ + "cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYTARBglghkgBhvhCAQEEBAMCB4AwMwYDVR0fBCwwKjAo"
+ + "oCagJIYiaHR0cDovL2NybC52ZXJpc2lnbi5jb20vY2xhc3MxLmNybDANBgkqhkiG9w0BAQQFAAOB"
+ + "gQBC8yIIdVGpFTf8/YiL14cMzcmL0nIRm4kGR3U59z7UtcXlfNXXJ8MyaeI/BnXwG/gD5OKYqW6R"
+ + "yca9vZOxf1uoTBl82gInk865ED3Tej6msCqFzZffnSUQvOIeqLxxDlqYRQ6PmW2nAnZeyjcnbI5Y"
+ + "syQSM2fmo7n6qJFP+GbFezGCAkUwggJBAgEBMIHhMIHMMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5j"
+ + "LjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazFGMEQGA1UECxM9d3d3LnZlcmlzaWdu"
+ + "LmNvbS9yZXBvc2l0b3J5L1JQQSBJbmNvcnAuIEJ5IFJlZi4sTElBQi5MVEQoYyk5ODFIMEYGA1UE"
+ + "AxM/VmVyaVNpZ24gQ2xhc3MgMSBDQSBJbmRpdmlkdWFsIFN1YnNjcmliZXItUGVyc29uYSBOb3Qg"
+ + "VmFsaWRhdGVkAhAW25/9Rtc6aQ+irD9NW8MsMAkGBSsOAwIaBQCggbowGAYJKoZIhvcNAQkDMQsG"
+ + "CSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMDAxMDAyMTczNTE4WjAjBgkqhkiG9w0BCQQxFgQU"
+ + "gZjSaBEY2oxGvlQUIMnxSXhivK8wWwYJKoZIhvcNAQkPMU4wTDAKBggqhkiG9w0DBzAOBggqhkiG"
+ + "9w0DAgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwBwYFKw4DAh0w"
+ + "DQYJKoZIhvcNAQEBBQAEgYAzk+PU91/ZFfoiuKOECjxEh9fDYE2jfDCheBIgh5gdcCo+sS1WQs8O"
+ + "HreQ9Nop/JdJv1DQMBK6weNBBDoP0EEkRm1XCC144XhXZC82jBZohYmi2WvDbbC//YN58kRMYMyy"
+ + "srrfn4Z9I+6kTriGXkrpGk9Q0LSGjmG2BIsqiF0dvwAAAAAAAA==");
+
+ //
+ // dsaWithSHA1 cert
+ //
+ byte[] cert7 = Base64.decode(
+ "MIIEXAYJKoZIhvcNAQcCoIIETTCCBEkCAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+ + "SIb3DQEHAaCCAsMwggK/MIIB4AIBADCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7"
+ + "d8miwTMN55CUSmo3TO8WGCxgY61TX5k+7NU4XPf1TULjw3GobwaJX13kquPh"
+ + "fVXk+gVy46n4Iw3hAhUBSe/QF4BUj+pJOF9ROBM4u+FEWA8CQQD4mSJbrABj"
+ + "TUWrlnAte8pS22Tq4/FPO7jHSqjijUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/z"
+ + "m8Q12PFp/PjOhh+nMA4xDDAKBgNVBAMTA0lEMzAeFw05NzEwMDEwMDAwMDBa"
+ + "Fw0zODAxMDEwMDAwMDBaMA4xDDAKBgNVBAMTA0lEMzCB8DCBpwYFKw4DAhsw"
+ + "gZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxgY61TX5k+7NU4XPf1TULj"
+ + "w3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/QF4BUj+pJOF9ROBM4u+FE"
+ + "WA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jHSqjijUHfXKTrHL1OEqV3"
+ + "SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nA0QAAkEAkYkXLYMtGVGWj9OnzjPn"
+ + "sB9sefSRPrVegZJCZbpW+Iv0/1RP1u04pHG9vtRpIQLjzUiWvLMU9EKQTThc"
+ + "eNMmWDCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxg"
+ + "Y61TX5k+7NU4XPf1TULjw3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/Q"
+ + "F4BUj+pJOF9ROBM4u+FEWA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jH"
+ + "SqjijUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nAy8AMCwC"
+ + "FBY3dBSdeprGcqpr6wr3xbG+6WW+AhRMm/facKJNxkT3iKgJbp7R8Xd3QTGC"
+ + "AWEwggFdAgEBMBMwDjEMMAoGA1UEAxMDSUQzAgEAMAkGBSsOAwIaBQCgXTAY"
+ + "BgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0wMjA1"
+ + "MjQyMzEzMDdaMCMGCSqGSIb3DQEJBDEWBBS4WMsoJhf7CVbZYCFcjoTRzPkJ"
+ + "xjCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxgY61T"
+ + "X5k+7NU4XPf1TULjw3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/QF4BU"
+ + "j+pJOF9ROBM4u+FEWA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jHSqji"
+ + "jUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nBC8wLQIVALID"
+ + "dt+MHwawrDrwsO1Z6sXBaaJsAhRaKssrpevmLkbygKPV07XiAKBG02Zvb2Jh"
+ + "cg==");
+
+ //
+ // testcrl.pem
+ //
+ byte[] crl1 = Base64.decode(
+ "MIICjTCCAfowDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoT"
+ + "F1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVy"
+ + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5Fw05NTA1MDIwMjEyMjZaFw05NTA2MDEw"
+ + "MDAxNDlaMIIBaDAWAgUCQQAABBcNOTUwMjAxMTcyNDI2WjAWAgUCQQAACRcNOTUw"
+ + "MjEwMDIxNjM5WjAWAgUCQQAADxcNOTUwMjI0MDAxMjQ5WjAWAgUCQQAADBcNOTUw"
+ + "MjI1MDA0NjQ0WjAWAgUCQQAAGxcNOTUwMzEzMTg0MDQ5WjAWAgUCQQAAFhcNOTUw"
+ + "MzE1MTkxNjU0WjAWAgUCQQAAGhcNOTUwMzE1MTk0MDQxWjAWAgUCQQAAHxcNOTUw"
+ + "MzI0MTk0NDMzWjAWAgUCcgAABRcNOTUwMzI5MjAwNzExWjAWAgUCcgAAERcNOTUw"
+ + "MzMwMDIzNDI2WjAWAgUCQQAAIBcNOTUwNDA3MDExMzIxWjAWAgUCcgAAHhcNOTUw"
+ + "NDA4MDAwMjU5WjAWAgUCcgAAQRcNOTUwNDI4MTcxNzI0WjAWAgUCcgAAOBcNOTUw"
+ + "NDI4MTcyNzIxWjAWAgUCcgAATBcNOTUwNTAyMDIxMjI2WjANBgkqhkiG9w0BAQIF"
+ + "AAN+AHqOEJXSDejYy0UwxxrH/9+N2z5xu/if0J6qQmK92W0hW158wpJg+ovV3+wQ"
+ + "wvIEPRL2rocL0tKfAsVq1IawSJzSNgxG0lrcla3MrJBnZ4GaZDu4FutZh72MR3Gt"
+ + "JaAL3iTJHJD55kK2D/VoyY1djlsPuNh6AEgdVwFAyp0v");
+
+ //
+ // ecdsa cert with extra octet string.
+ //
+ byte[] oldEcdsa = Base64.decode(
+ "MIICljCCAkCgAwIBAgIBATALBgcqhkjOPQQBBQAwgY8xCzAJBgNVBAYTAkFVMSgwJ"
+ + "gYDVQQKEx9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIwEAYDVQQHEw"
+ + "lNZWxib3VybmUxETAPBgNVBAgTCFZpY3RvcmlhMS8wLQYJKoZIhvcNAQkBFiBmZWV"
+ + "kYmFjay1jcnlwdG9AYm91bmN5Y2FzdGxlLm9yZzAeFw0wMTEyMDcwMTAwMDRaFw0w"
+ + "MTEyMDcwMTAxNDRaMIGPMQswCQYDVQQGEwJBVTEoMCYGA1UEChMfVGhlIExlZ2lvb"
+ + "iBvZiB0aGUgQm91bmN5IENhc3RsZTESMBAGA1UEBxMJTWVsYm91cm5lMREwDwYDVQ"
+ + "QIEwhWaWN0b3JpYTEvMC0GCSqGSIb3DQEJARYgZmVlZGJhY2stY3J5cHRvQGJvdW5"
+ + "jeWNhc3RsZS5vcmcwgeQwgb0GByqGSM49AgEwgbECAQEwKQYHKoZIzj0BAQIef///"
+ + "////////////f///////gAAAAAAAf///////MEAEHn///////////////3///////"
+ + "4AAAAAAAH///////AQeawFsO9zxiUHQ1lSSFHXKcanbL7J9HTd5YYXClCwKBB8CD/"
+ + "qWPNyogWzMM7hkK+35BcPTWFc9Pyf7vTs8uaqvAh5///////////////9///+eXpq"
+ + "fXZBx+9FSJoiQnQsDIgAEHwJbbcU7xholSP+w9nFHLebJUhqdLSU05lq/y9X+DHAw"
+ + "CwYHKoZIzj0EAQUAA0MAMEACHnz6t4UNoVROp74ma4XNDjjGcjaqiIWPZLK8Bdw3G"
+ + "QIeLZ4j3a6ividZl344UH+UPUE7xJxlYGuy7ejTsqRR");
+
+ byte[] uncompressedPtEC = Base64.decode(
+ "MIIDKzCCAsGgAwIBAgICA+kwCwYHKoZIzj0EAQUAMGYxCzAJBgNVBAYTAkpQ"
+ + "MRUwEwYDVQQKEwxuaXRlY2guYWMuanAxDjAMBgNVBAsTBWFpbGFiMQ8wDQYD"
+ + "VQQDEwZ0ZXN0Y2ExHzAdBgkqhkiG9w0BCQEWEHRlc3RjYUBsb2NhbGhvc3Qw"
+ + "HhcNMDExMDEzMTE1MzE3WhcNMjAxMjEyMTE1MzE3WjBmMQswCQYDVQQGEwJK"
+ + "UDEVMBMGA1UEChMMbml0ZWNoLmFjLmpwMQ4wDAYDVQQLEwVhaWxhYjEPMA0G"
+ + "A1UEAxMGdGVzdGNhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0Y2FAbG9jYWxob3N0"
+ + "MIIBczCCARsGByqGSM49AgEwggEOAgEBMDMGByqGSM49AQECKEdYWnajFmnZ"
+ + "tzrukK2XWdle2v+GsD9l1ZiR6g7ozQDbhFH/bBiMDQcwVAQoJ5EQKrI54/CT"
+ + "xOQ2pMsd/fsXD+EX8YREd8bKHWiLz8lIVdD5cBNeVwQoMKSc6HfI7vKZp8Q2"
+ + "zWgIFOarx1GQoWJbMcSt188xsl30ncJuJT2OoARRBAqJ4fD+q6hbqgNSjTQ7"
+ + "htle1KO3eiaZgcJ8rrnyN8P+5A8+5K+H9aQ/NbBR4Gs7yto5PXIUZEUgodHA"
+ + "TZMSAcSq5ZYt4KbnSYaLY0TtH9CqAigEwZ+hglbT21B7ZTzYX2xj0x+qooJD"
+ + "hVTLtIPaYJK2HrMPxTw6/zfrAgEPA1IABAnvfFcFDgD/JicwBGn6vR3N8MIn"
+ + "mptZf/mnJ1y649uCF60zOgdwIyI7pVSxBFsJ7ohqXEHW0x7LrGVkdSEiipiH"
+ + "LYslqh3xrqbAgPbl93GUo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB"
+ + "/wQEAwIBxjAdBgNVHQ4EFgQUAEo62Xm9H6DcsE0zUDTza4BRG90wCwYHKoZI"
+ + "zj0EAQUAA1cAMFQCKAQsCHHSNOqfJXLgt3bg5+k49hIBGVr/bfG0B9JU3rNt"
+ + "Ycl9Y2zfRPUCKAK2ccOQXByAWfsasDu8zKHxkZv7LVDTFjAIffz3HaCQeVhD"
+ + "z+fauEg=");
+
+ byte[] keyUsage = Base64.decode(
+ "MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UE"
+ + "BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50"
+ + "cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBs"
+ + "aW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExp"
+ + "bWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0"
+ + "aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBa"
+ + "MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNV"
+ + "BAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3Jw"
+ + "LiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50"
+ + "cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50"
+ + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GL"
+ + "ADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSv"
+ + "x1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHV"
+ + "iTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173"
+ + "iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkw"
+ + "ggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50"
+ + "cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0Ff"
+ + "SW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UE"
+ + "CxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50"
+ + "cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYD"
+ + "VQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9D"
+ + "bGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkx"
+ + "MDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW"
+ + "/O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwG"
+ + "A1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI"
+ + "hvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQ"
+ + "OokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkU"
+ + "ODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapE"
+ + "PHayXOw=");
+
+ byte[] nameCert = Base64.decode(
+ "MIIEFjCCA3+gAwIBAgIEdS8BozANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJE"+
+ "RTERMA8GA1UEChQIREFURVYgZUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRQ0Eg"+
+ "REFURVYgRDAzIDE6UE4wIhgPMjAwMTA1MTAxMDIyNDhaGA8yMDA0MDUwOTEwMjI0"+
+ "OFowgYQxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIFAZCYXllcm4xEjAQBgNVBAcUCU7I"+
+ "dXJuYmVyZzERMA8GA1UEChQIREFURVYgZUcxHTAbBgNVBAUTFDAwMDAwMDAwMDA4"+
+ "OTU3NDM2MDAxMR4wHAYDVQQDFBVEaWV0bWFyIFNlbmdlbmxlaXRuZXIwgaEwDQYJ"+
+ "KoZIhvcNAQEBBQADgY8AMIGLAoGBAJLI/LJLKaHoMk8fBECW/od8u5erZi6jI8Ug"+
+ "C0a/LZyQUO/R20vWJs6GrClQtXB+AtfiBSnyZOSYzOdfDI8yEKPEv8qSuUPpOHps"+
+ "uNCFdLZF1vavVYGEEWs2+y+uuPmg8q1oPRyRmUZ+x9HrDvCXJraaDfTEd9olmB/Z"+
+ "AuC/PqpjAgUAwAAAAaOCAcYwggHCMAwGA1UdEwEB/wQCMAAwDwYDVR0PAQH/BAUD"+
+ "AwdAADAxBgNVHSAEKjAoMCYGBSskCAEBMB0wGwYIKwYBBQUHAgEWD3d3dy56cy5k"+
+ "YXRldi5kZTApBgNVHREEIjAggR5kaWV0bWFyLnNlbmdlbmxlaXRuZXJAZGF0ZXYu"+
+ "ZGUwgYQGA1UdIwR9MHuhc6RxMG8xCzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1"+
+ "bGllcnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0"+
+ "MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjVSLUNBIDE6UE6CBACm8LkwDgYHAoIG"+
+ "AQoMAAQDAQEAMEcGA1UdHwRAMD4wPKAUoBKGEHd3dy5jcmwuZGF0ZXYuZGWiJKQi"+
+ "MCAxCzAJBgNVBAYTAkRFMREwDwYDVQQKFAhEQVRFViBlRzAWBgUrJAgDBAQNMAsT"+
+ "A0VVUgIBBQIBATAdBgNVHQ4EFgQUfv6xFP0xk7027folhy+ziZvBJiwwLAYIKwYB"+
+ "BQUHAQEEIDAeMBwGCCsGAQUFBzABhhB3d3cuZGlyLmRhdGV2LmRlMA0GCSqGSIb3"+
+ "DQEBBQUAA4GBAEOVX6uQxbgtKzdgbTi6YLffMftFr2mmNwch7qzpM5gxcynzgVkg"+
+ "pnQcDNlm5AIbS6pO8jTCLfCd5TZ5biQksBErqmesIl3QD+VqtB+RNghxectZ3VEs"+
+ "nCUtcE7tJ8O14qwCb3TxS9dvIUFiVi4DjbxX46TdcTbTaK8/qr6AIf+l");
+
+ byte[] probSelfSignedCert = Base64.decode(
+ "MIICxTCCAi6gAwIBAgIQAQAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQUFADBF"
+ + "MScwJQYDVQQKEx4gRElSRUNUSU9OIEdFTkVSQUxFIERFUyBJTVBPVFMxGjAYBgNV"
+ + "BAMTESBBQyBNSU5FRkkgQiBURVNUMB4XDTA0MDUwNzEyMDAwMFoXDTE0MDUwNzEy"
+ + "MDAwMFowRTEnMCUGA1UEChMeIERJUkVDVElPTiBHRU5FUkFMRSBERVMgSU1QT1RT"
+ + "MRowGAYDVQQDExEgQUMgTUlORUZJIEIgVEVTVDCBnzANBgkqhkiG9w0BAQEFAAOB"
+ + "jQAwgYkCgYEAveoCUOAukZdcFCs2qJk76vSqEX0ZFzHqQ6faBPZWjwkgUNwZ6m6m"
+ + "qWvvyq1cuxhoDvpfC6NXILETawYc6MNwwxsOtVVIjuXlcF17NMejljJafbPximEt"
+ + "DQ4LcQeSp4K7FyFlIAMLyt3BQ77emGzU5fjFTvHSUNb3jblx0sV28c0CAwEAAaOB"
+ + "tTCBsjAfBgNVHSMEGDAWgBSEJ4bLbvEQY8cYMAFKPFD1/fFXlzAdBgNVHQ4EFgQU"
+ + "hCeGy27xEGPHGDABSjxQ9f3xV5cwDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIB"
+ + "AQQEAwIBBjA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vYWRvbmlzLnBrNy5jZXJ0"
+ + "cGx1cy5uZXQvZGdpLXRlc3QuY3JsMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN"
+ + "AQEFBQADgYEAmToHJWjd3+4zknfsP09H6uMbolHNGG0zTS2lrLKpzcmkQfjhQpT9"
+ + "LUTBvfs1jdjo9fGmQLvOG+Sm51Rbjglb8bcikVI5gLbclOlvqLkm77otjl4U4Z2/"
+ + "Y0vP14Aov3Sn3k+17EfReYUZI4liuB95ncobC4e8ZM++LjQcIM0s+Vs=");
+
+
+ byte[] gost34102001base = Base64.decode(
+ "MIIB1DCCAYECEEjpVKXP6Wn1yVz3VeeDQa8wCgYGKoUDAgIDBQAwbTEfMB0G"
+ + "A1UEAwwWR29zdFIzNDEwLTIwMDEgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRv"
+ + "UHJvMQswCQYDVQQGEwJSVTEpMCcGCSqGSIb3DQEJARYaR29zdFIzNDEwLTIw"
+ + "MDFAZXhhbXBsZS5jb20wHhcNMDUwMjAzMTUxNjQ2WhcNMTUwMjAzMTUxNjQ2"
+ + "WjBtMR8wHQYDVQQDDBZHb3N0UjM0MTAtMjAwMSBleGFtcGxlMRIwEAYDVQQK"
+ + "DAlDcnlwdG9Qcm8xCzAJBgNVBAYTAlJVMSkwJwYJKoZIhvcNAQkBFhpHb3N0"
+ + "UjM0MTAtMjAwMUBleGFtcGxlLmNvbTBjMBwGBiqFAwICEzASBgcqhQMCAiQA"
+ + "BgcqhQMCAh4BA0MABECElWh1YAIaQHUIzROMMYks/eUFA3pDXPRtKw/nTzJ+"
+ + "V4/rzBa5lYgD0Jp8ha4P5I3qprt+VsfLsN8PZrzK6hpgMAoGBiqFAwICAwUA"
+ + "A0EAHw5dw/aw/OiNvHyOE65kvyo4Hp0sfz3csM6UUkp10VO247ofNJK3tsLb"
+ + "HOLjUaqzefrlGb11WpHYrvWFg+FcLA==");
+
+ byte[] gost341094base = Base64.decode(
+ "MIICDzCCAbwCEBcxKsIb0ghYvAQeUjfQdFAwCgYGKoUDAgIEBQAwaTEdMBsG"
+ + "A1UEAwwUR29zdFIzNDEwLTk0IGV4YW1wbGUxEjAQBgNVBAoMCUNyeXB0b1By"
+ + "bzELMAkGA1UEBhMCUlUxJzAlBgkqhkiG9w0BCQEWGEdvc3RSMzQxMC05NEBl"
+ + "eGFtcGxlLmNvbTAeFw0wNTAyMDMxNTE2NTFaFw0xNTAyMDMxNTE2NTFaMGkx"
+ + "HTAbBgNVBAMMFEdvc3RSMzQxMC05NCBleGFtcGxlMRIwEAYDVQQKDAlDcnlw"
+ + "dG9Qcm8xCzAJBgNVBAYTAlJVMScwJQYJKoZIhvcNAQkBFhhHb3N0UjM0MTAt"
+ + "OTRAZXhhbXBsZS5jb20wgaUwHAYGKoUDAgIUMBIGByqFAwICIAIGByqFAwIC"
+ + "HgEDgYQABIGAu4Rm4XmeWzTYLIB/E6gZZnFX/oxUJSFHbzALJ3dGmMb7R1W+"
+ + "t7Lzk2w5tUI3JoTiDRCKJA4fDEJNKzsRK6i/ZjkyXJSLwaj+G2MS9gklh8x1"
+ + "G/TliYoJgmjTXHemD7aQEBON4z58nJHWrA0ILD54wbXCtrcaqCqLRYGTMjJ2"
+ + "+nswCgYGKoUDAgIEBQADQQBxKNhOmjgz/i5CEgLOyKyz9pFGkDcaymsWYQWV"
+ + "v7CZ0pTM8IzMzkUBW3GHsUjCFpanFZDfg2zuN+3kT+694n9B");
+
+ byte[] gost341094A = Base64.decode(
+ "MIICSDCCAfWgAwIBAgIBATAKBgYqhQMCAgQFADCBgTEXMBUGA1UEAxMOZGVmYXVsdDM0MTAtOTQx"
+ + "DTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1vbGExDDAKBgNVBAgT"
+ + "A01FTDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAzMjkx"
+ + "MzExNTdaFw0wNjAzMjkxMzExNTdaMIGBMRcwFQYDVQQDEw5kZWZhdWx0MzQxMC05NDENMAsGA1UE"
+ + "ChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLW9sYTEMMAoGA1UECBMDTUVMMQsw"
+ + "CQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MIGlMBwGBiqFAwICFDASBgcq"
+ + "hQMCAiACBgcqhQMCAh4BA4GEAASBgIQACDLEuxSdRDGgdZxHmy30g/DUYkRxO9Mi/uSHX5NjvZ31"
+ + "b7JMEMFqBtyhql1HC5xZfUwZ0aT3UnEFDfFjLP+Bf54gA+LPkQXw4SNNGOj+klnqgKlPvoqMGlwa"
+ + "+hLPKbS561WpvB2XSTgbV+pqqXR3j6j30STmybelEV3RdS2Now8wDTALBgNVHQ8EBAMCB4AwCgYG"
+ + "KoUDAgIEBQADQQBCFy7xWRXtNVXflKvDs0pBdBuPzjCMeZAXVxK8vUxsxxKu76d9CsvhgIFknFRi"
+ + "wWTPiZenvNoJ4R1uzeX+vREm");
+
+ byte[] gost341094B = Base64.decode(
+ "MIICSDCCAfWgAwIBAgIBATAKBgYqhQMCAgQFADCBgTEXMBUGA1UEAxMOcGFyYW0xLTM0MTAtOTQx"
+ + "DTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1PbGExDDAKBgNVBAgT"
+ + "A01lbDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAzMjkx"
+ + "MzEzNTZaFw0wNjAzMjkxMzEzNTZaMIGBMRcwFQYDVQQDEw5wYXJhbTEtMzQxMC05NDENMAsGA1UE"
+ + "ChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLU9sYTEMMAoGA1UECBMDTWVsMQsw"
+ + "CQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MIGlMBwGBiqFAwICFDASBgcq"
+ + "hQMCAiADBgcqhQMCAh4BA4GEAASBgEa+AAcZmijWs1M9x5Pn9efE8D9ztG1NMoIt0/hNZNqln3+j"
+ + "lMZjyqPt+kTLIjtmvz9BRDmIDk6FZz+4LhG2OTL7yGpWfrMxMRr56nxomTN9aLWRqbyWmn3brz9Y"
+ + "AUD3ifnwjjIuW7UM84JNlDTOdxx0XRUfLQIPMCXe9cO02Xskow8wDTALBgNVHQ8EBAMCB4AwCgYG"
+ + "KoUDAgIEBQADQQBzFcnuYc/639OTW+L5Ecjw9KxGr+dwex7lsS9S1BUgKa3m1d5c+cqI0B2XUFi5"
+ + "4iaHHJG0dCyjtQYLJr0OZjRw");
+
+ byte[] gost34102001A = Base64.decode(
+ "MIICCzCCAbigAwIBAgIBATAKBgYqhQMCAgMFADCBhDEaMBgGA1UEAxMRZGVmYXVsdC0zNDEwLTIw"
+ + "MDExDTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1PbGExDDAKBgNV"
+ + "BAgTA01lbDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAz"
+ + "MjkxMzE4MzFaFw0wNjAzMjkxMzE4MzFaMIGEMRowGAYDVQQDExFkZWZhdWx0LTM0MTAtMjAwMTEN"
+ + "MAsGA1UEChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLU9sYTEMMAoGA1UECBMD"
+ + "TWVsMQswCQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MGMwHAYGKoUDAgIT"
+ + "MBIGByqFAwICIwEGByqFAwICHgEDQwAEQG/4c+ZWb10IpeHfmR+vKcbpmSOClJioYmCVgnojw0Xn"
+ + "ned0KTg7TJreRUc+VX7vca4hLQaZ1o/TxVtfEApK/O6jDzANMAsGA1UdDwQEAwIHgDAKBgYqhQMC"
+ + "AgMFAANBAN8y2b6HuIdkD3aWujpfQbS1VIA/7hro4vLgDhjgVmev/PLzFB8oTh3gKhExpDo82IEs"
+ + "ZftGNsbbyp1NFg7zda0=");
+
+ byte[] gostCA1 = Base64.decode(
+ "MIIDNDCCAuGgAwIBAgIQZLcKDcWcQopF+jp4p9jylDAKBgYqhQMCAgQFADBm"
+ + "MQswCQYDVQQGEwJSVTEPMA0GA1UEBxMGTW9zY293MRcwFQYDVQQKEw5PT08g"
+ + "Q3J5cHRvLVBybzEUMBIGA1UECxMLRGV2ZWxvcG1lbnQxFzAVBgNVBAMTDkNQ"
+ + "IENTUCBUZXN0IENBMB4XDTAyMDYwOTE1NTIyM1oXDTA5MDYwOTE1NTkyOVow"
+ + "ZjELMAkGA1UEBhMCUlUxDzANBgNVBAcTBk1vc2NvdzEXMBUGA1UEChMOT09P"
+ + "IENyeXB0by1Qcm8xFDASBgNVBAsTC0RldmVsb3BtZW50MRcwFQYDVQQDEw5D"
+ + "UCBDU1AgVGVzdCBDQTCBpTAcBgYqhQMCAhQwEgYHKoUDAgIgAgYHKoUDAgIe"
+ + "AQOBhAAEgYAYglywKuz1nMc9UiBYOaulKy53jXnrqxZKbCCBSVaJ+aCKbsQm"
+ + "glhRFrw6Mwu8Cdeabo/ojmea7UDMZd0U2xhZFRti5EQ7OP6YpqD0alllo7za"
+ + "4dZNXdX+/ag6fOORSLFdMpVx5ganU0wHMPk67j+audnCPUj/plbeyccgcdcd"
+ + "WaOCASIwggEeMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud"
+ + "DgQWBBTe840gTo4zt2twHilw3PD9wJaX0TCBygYDVR0fBIHCMIG/MDygOqA4"
+ + "hjYtaHR0cDovL2ZpZXdhbGwvQ2VydEVucm9sbC9DUCUyMENTUCUyMFRlc3Ql"
+ + "MjBDQSgzKS5jcmwwRKBCoECGPmh0dHA6Ly93d3cuY3J5cHRvcHJvLnJ1L0Nl"
+ + "cnRFbnJvbGwvQ1AlMjBDU1AlMjBUZXN0JTIwQ0EoMykuY3JsMDmgN6A1hjMt"
+ + "ZmlsZTovL1xcZmlld2FsbFxDZXJ0RW5yb2xsXENQIENTUCBUZXN0IENBKDMp"
+ + "LmNybC8wEgYJKwYBBAGCNxUBBAUCAwMAAzAKBgYqhQMCAgQFAANBAIJi7ni7"
+ + "9rwMR5rRGTFftt2k70GbqyUEfkZYOzrgdOoKiB4IIsIstyBX0/ne6GsL9Xan"
+ + "G2IN96RB7KrowEHeW+k=");
+
+ byte[] gostCA2 = Base64.decode(
+ "MIIC2DCCAoWgAwIBAgIQe9ZCugm42pRKNcHD8466zTAKBgYqhQMCAgMFADB+"
+ + "MRowGAYJKoZIhvcNAQkBFgtzYmFAZGlndC5ydTELMAkGA1UEBhMCUlUxDDAK"
+ + "BgNVBAgTA01FTDEUMBIGA1UEBxMLWW9zaGthci1PbGExDTALBgNVBAoTBERp"
+ + "Z3QxDzANBgNVBAsTBkNyeXB0bzEPMA0GA1UEAxMGc2JhLUNBMB4XDTA0MDgw"
+ + "MzEzMzE1OVoXDTE0MDgwMzEzNDAxMVowfjEaMBgGCSqGSIb3DQEJARYLc2Jh"
+ + "QGRpZ3QucnUxCzAJBgNVBAYTAlJVMQwwCgYDVQQIEwNNRUwxFDASBgNVBAcT"
+ + "C1lvc2hrYXItT2xhMQ0wCwYDVQQKEwREaWd0MQ8wDQYDVQQLEwZDcnlwdG8x"
+ + "DzANBgNVBAMTBnNiYS1DQTBjMBwGBiqFAwICEzASBgcqhQMCAiMBBgcqhQMC"
+ + "Ah4BA0MABEDMSy10CuOH+i8QKG2UWA4XmCt6+BFrNTZQtS6bOalyDY8Lz+G7"
+ + "HybyipE3PqdTB4OIKAAPsEEeZOCZd2UXGQm5o4HaMIHXMBMGCSsGAQQBgjcU"
+ + "AgQGHgQAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud"
+ + "DgQWBBRJJl3LcNMxkZI818STfoi3ng1xoDBxBgNVHR8EajBoMDGgL6Athito"
+ + "dHRwOi8vc2JhLmRpZ3QubG9jYWwvQ2VydEVucm9sbC9zYmEtQ0EuY3JsMDOg"
+ + "MaAvhi1maWxlOi8vXFxzYmEuZGlndC5sb2NhbFxDZXJ0RW5yb2xsXHNiYS1D"
+ + "QS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwCgYGKoUDAgIDBQADQQA+BRJHbc/p"
+ + "q8EYl6iJqXCuR+ozRmH7hPAP3c4KqYSC38TClCgBloLapx/3/WdatctFJW/L"
+ + "mcTovpq088927shE");
+
+ byte[] inDirectCrl = Base64.decode(
+ "MIIdXjCCHMcCAQEwDQYJKoZIhvcNAQEFBQAwdDELMAkGA1UEBhMCREUxHDAaBgNV"
+ +"BAoUE0RldXRzY2hlIFRlbGVrb20gQUcxFzAVBgNVBAsUDlQtVGVsZVNlYyBUZXN0"
+ +"MS4wDAYHAoIGAQoHFBMBMTAeBgNVBAMUF1QtVGVsZVNlYyBUZXN0IERJUiA4OlBO"
+ +"Fw0wNjA4MDQwODQ1MTRaFw0wNjA4MDQxNDQ1MTRaMIIbfzB+AgQvrj/pFw0wMzA3"
+ +"MjIwNTQxMjhaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+ +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+ +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP+oXDTAzMDcyMjA1NDEyOFowZzBlBgNV"
+ +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+ +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+ +"UE4wfgIEL64/5xcNMDQwNDA1MTMxODE3WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+ +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC"
+ +"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/oFw0wNDA0"
+ +"MDUxMzE4MTdaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+ +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+ +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP+UXDTAzMDExMzExMTgxMVowZzBlBgNV"
+ +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+ +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+ +"UE4wfgIEL64/5hcNMDMwMTEzMTExODExWjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+ +"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");
+
+ byte[] directCRL = Base64.decode(
+ "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"
+ +"MQ==");
+
+ private final byte[] pkcs7CrlProblem = Base64.decode(
+ "MIIwSAYJKoZIhvcNAQcCoIIwOTCCMDUCAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+ + "SIb3DQEHAaCCEsAwggP4MIIC4KADAgECAgF1MA0GCSqGSIb3DQEBBQUAMEUx"
+ + "CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR4wHAYDVQQD"
+ + "ExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUwHhcNMDQxMjAyMjEyNTM5WhcNMDYx"
+ + "MjMwMjEyNTM5WjBMMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMR2VvVHJ1c3Qg"
+ + "SW5jMSYwJAYDVQQDEx1HZW9UcnVzdCBBZG9iZSBPQ1NQIFJlc3BvbmRlcjCB"
+ + "nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4gnNYhtw7U6QeVXZODnGhHMj"
+ + "+OgZ0DB393rEk6a2q9kq129IA2e03yKBTfJfQR9aWKc2Qj90dsSqPjvTDHFG"
+ + "Qsagm2FQuhnA3fb1UWhPzeEIdm6bxDsnQ8nWqKqxnWZzELZbdp3I9bBLizIq"
+ + "obZovzt60LNMghn/unvvuhpeVSsCAwEAAaOCAW4wggFqMA4GA1UdDwEB/wQE"
+ + "AwIE8DCB5QYDVR0gAQH/BIHaMIHXMIHUBgkqhkiG9y8BAgEwgcYwgZAGCCsG"
+ + "AQUFBwICMIGDGoGAVGhpcyBjZXJ0aWZpY2F0ZSBoYXMgYmVlbiBpc3N1ZWQg"
+ + "aW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBBY3JvYmF0IENyZWRlbnRpYWxzIENQ"
+ + "UyBsb2NhdGVkIGF0IGh0dHA6Ly93d3cuZ2VvdHJ1c3QuY29tL3Jlc291cmNl"
+ + "cy9jcHMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2VvdHJ1c3QuY29tL3Jl"
+ + "c291cmNlcy9jcHMwEwYDVR0lBAwwCgYIKwYBBQUHAwkwOgYDVR0fBDMwMTAv"
+ + "oC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9hZG9iZWNhMS5j"
+ + "cmwwHwYDVR0jBBgwFoAUq4BZw2WDbR19E70Zw+wajw1HaqMwDQYJKoZIhvcN"
+ + "AQEFBQADggEBAENJf1BD7PX5ivuaawt90q1OGzXpIQL/ClzEeFVmOIxqPc1E"
+ + "TFRq92YuxG5b6+R+k+tGkmCwPLcY8ipg6ZcbJ/AirQhohzjlFuT6YAXsTfEj"
+ + "CqEZfWM2sS7crK2EYxCMmKE3xDfPclYtrAoz7qZvxfQj0TuxHSstHZv39wu2"
+ + "ZiG1BWiEcyDQyTgqTOXBoZmfJtshuAcXmTpgkrYSrS37zNlPTGh+pMYQ0yWD"
+ + "c8OQRJR4OY5ZXfdna01mjtJTOmj6/6XPoLPYTq2gQrc2BCeNJ4bEhLb7sFVB"
+ + "PbwPrpzTE/HRbQHDrzj0YimDxeOUV/UXctgvYwHNtEkcBLsOm/uytMYwggSh"
+ + "MIIDiaADAgECAgQ+HL0oMA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNVBAYTAlVT"
+ + "MSMwIQYDVQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UE"
+ + "CxMUQWRvYmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3Qg"
+ + "Q0EwHhcNMDMwMTA4MjMzNzIzWhcNMjMwMTA5MDAwNzIzWjBpMQswCQYDVQQG"
+ + "EwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQxHTAb"
+ + "BgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYwFAYDVQQDEw1BZG9iZSBS"
+ + "b290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzE9UhPen"
+ + "ouczU38/nBKIayyZR2d+Dx65rRSI+cMQ2B3w8NWfaQovWTWwzGypTJwVoJ/O"
+ + "IL+gz1Ti4CBmRT85hjh+nMSOByLGJPYBErA131XqaZCw24U3HuJOB7JCoWoT"
+ + "aaBm6oCREVkqmwh5WiBELcm9cziLPC/gQxtdswvwrzUaKf7vppLdgUydPVmO"
+ + "rTE8QH6bkTYG/OJcjdGNJtVcRc+vZT+xqtJilvSoOOq6YEL09BxKNRXO+E4i"
+ + "Vg+VGMX4lp+f+7C3eCXpgGu91grwxnSUnfMPUNuad85LcIMjjaDKeCBEXDxU"
+ + "ZPHqojAZn+pMBk0GeEtekt8i0slns3rSAQIDAQABo4IBTzCCAUswEQYJYIZI"
+ + "AYb4QgEBBAQDAgAHMIGOBgNVHR8EgYYwgYMwgYCgfqB8pHoweDELMAkGA1UE"
+ + "BhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMgSW5jb3Jwb3JhdGVkMR0w"
+ + "GwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEWMBQGA1UEAxMNQWRvYmUg"
+ + "Um9vdCBDQTENMAsGA1UEAxMEQ1JMMTArBgNVHRAEJDAigA8yMDAzMDEwODIz"
+ + "MzcyM1qBDzIwMjMwMTA5MDAwNzIzWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgw"
+ + "FoAUgrc4SpOqmxDvgLvZVOLxD/uAnN4wHQYDVR0OBBYEFIK3OEqTqpsQ74C7"
+ + "2VTi8Q/7gJzeMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjYu"
+ + "MDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQAy2p9DdcH6b8lv26sdNjc+"
+ + "vGEZNrcCPB0jWZhsnu5NhedUyCAfp9S74r8Ad30ka3AvXME6dkm10+AjhCpx"
+ + "aiLzwScpmBX2NZDkBEzDjbyfYRzn/SSM0URDjBa6m02l1DUvvBHOvfdRN42f"
+ + "kOQU8Rg/vulZEjX5M5LznuDVa5pxm5lLyHHD4bFhCcTl+pHwQjo3fTT5cujN"
+ + "qmIcIenV9IIQ43sFti1oVgt+fpIsb01yggztVnSynbmrLSsdEF/bJ3Vwj/0d"
+ + "1+ICoHnlHOX/r2RAUS2em0fbQqV8H8KmSLDXvpJpTaT2KVfFeBEY3IdRyhOy"
+ + "Yp1PKzK9MaXB+lKrBYjIMIIEyzCCA7OgAwIBAgIEPhy9tTANBgkqhkiG9w0B"
+ + "AQUFADBpMQswCQYDVQQGEwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJ"
+ + "bmNvcnBvcmF0ZWQxHTAbBgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYw"
+ + "FAYDVQQDEw1BZG9iZSBSb290IENBMB4XDTA0MDExNzAwMDMzOVoXDTE1MDEx"
+ + "NTA4MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu"
+ + "Yy4xHjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTCCASIwDQYJKoZI"
+ + "hvcNAQEBBQADggEPADCCAQoCggEBAKfld+BkeFrnOYW8r9L1WygTDlTdSfrO"
+ + "YvWS/Z6Ye5/l+HrBbOHqQCXBcSeCpz7kB2WdKMh1FOE4e9JlmICsHerBLdWk"
+ + "emU+/PDb69zh8E0cLoDfxukF6oVPXj6WSThdSG7H9aXFzRr6S3XGCuvgl+Qw"
+ + "DTLiLYW+ONF6DXwt3TQQtKReJjOJZk46ZZ0BvMStKyBaeB6DKZsmiIo89qso"
+ + "13VDZINH2w1KvXg0ygDizoNtbvgAPFymwnsINS1klfQlcvn0x0RJm9bYQXK3"
+ + "5GNZAgL3M7Lqrld0jMfIUaWvuHCLyivytRuzq1dJ7E8rmidjDEk/G+27pf13"
+ + "fNZ7vR7M+IkCAwEAAaOCAZ0wggGZMBIGA1UdEwEB/wQIMAYBAf8CAQEwUAYD"
+ + "VR0gBEkwRzBFBgkqhkiG9y8BAgEwODA2BggrBgEFBQcCARYqaHR0cHM6Ly93"
+ + "d3cuYWRvYmUuY29tL21pc2MvcGtpL2Nkc19jcC5odG1sMBQGA1UdJQQNMAsG"
+ + "CSqGSIb3LwEBBTCBsgYDVR0fBIGqMIGnMCKgIKAehhxodHRwOi8vY3JsLmFk"
+ + "b2JlLmNvbS9jZHMuY3JsMIGAoH6gfKR6MHgxCzAJBgNVBAYTAlVTMSMwIQYD"
+ + "VQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRv"
+ + "YmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0ExDTAL"
+ + "BgNVBAMTBENSTDEwCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFIK3OEqTqpsQ"
+ + "74C72VTi8Q/7gJzeMB0GA1UdDgQWBBSrgFnDZYNtHX0TvRnD7BqPDUdqozAZ"
+ + "BgkqhkiG9n0HQQAEDDAKGwRWNi4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA"
+ + "PzlZLqIAjrFeEWEs0uC29YyJhkXOE9mf3YSaFGsITF+Gl1j0pajTjyH4R35Q"
+ + "r3floW2q3HfNzTeZ90Jnr1DhVERD6zEMgJpCtJqVuk0sixuXJHghS/KicKf4"
+ + "YXJJPx9epuIRF1siBRnznnF90svmOJMXApc0jGnYn3nQfk4kaShSnDaYaeYR"
+ + "DJKcsiWhl6S5zfwS7Gg8hDeyckhMQKKWnlG1CQrwlSFisKCduoodwRtWgft8"
+ + "kx13iyKK3sbalm6vnVc+5nufS4vI+TwMXoV63NqYaSroafBWk0nL53zGXPEy"
+ + "+A69QhzEViJKn2Wgqt5gt++jMMNImbRObIqgfgF1VjCCBUwwggQ0oAMCAQIC"
+ + "AgGDMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1H"
+ + "ZW9UcnVzdCBJbmMuMR4wHAYDVQQDExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUw"
+ + "HhcNMDYwMzI0MTU0MjI5WhcNMDkwNDA2MTQ0MjI5WjBzMQswCQYDVQQGEwJV"
+ + "UzELMAkGA1UECBMCTUExETAPBgNVBAoTCEdlb1RydXN0MR0wGwYDVQQDExRN"
+ + "YXJrZXRpbmcgRGVwYXJ0bWVudDElMCMGCSqGSIb3DQEJARYWbWFya2V0aW5n"
+ + "QGdlb3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB"
+ + "ANmvajTO4XJvAU2nVcLmXeCnAQX7RZt+7+ML3InmqQ3LCGo1weop09zV069/"
+ + "1x/Nmieol7laEzeXxd2ghjGzwfXafqQEqHn6+vBCvqdNPoSi63fSWhnuDVWp"
+ + "KVDOYgxOonrXl+Cc43lu4zRSq+Pi5phhrjDWcH74a3/rdljUt4c4GFezFXfa"
+ + "w2oTzWkxj2cTSn0Szhpr17+p66UNt8uknlhmu4q44Speqql2HwmCEnpLYJrK"
+ + "W3fOq5D4qdsvsLR2EABLhrBezamLI3iGV8cRHOUTsbTMhWhv/lKfHAyf4XjA"
+ + "z9orzvPN5jthhIfICOFq/nStTgakyL4Ln+nFAB/SMPkCAwEAAaOCAhYwggIS"
+ + "MA4GA1UdDwEB/wQEAwIF4DCB5QYDVR0gAQH/BIHaMIHXMIHUBgkqhkiG9y8B"
+ + "AgEwgcYwgZAGCCsGAQUFBwICMIGDGoGAVGhpcyBjZXJ0aWZpY2F0ZSBoYXMg"
+ + "YmVlbiBpc3N1ZWQgaW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBBY3JvYmF0IENy"
+ + "ZWRlbnRpYWxzIENQUyBsb2NhdGVkIGF0IGh0dHA6Ly93d3cuZ2VvdHJ1c3Qu"
+ + "Y29tL3Jlc291cmNlcy9jcHMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2Vv"
+ + "dHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwOgYDVR0fBDMwMTAvoC2gK4YpaHR0"
+ + "cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9hZG9iZWNhMS5jcmwwHwYDVR0j"
+ + "BBgwFoAUq4BZw2WDbR19E70Zw+wajw1HaqMwRAYIKwYBBQUHAQEEODA2MDQG"
+ + "CCsGAQUFBzABhihodHRwOi8vYWRvYmUtb2NzcC5nZW90cnVzdC5jb20vcmVz"
+ + "cG9uZGVyMBQGA1UdJQQNMAsGCSqGSIb3LwEBBTA8BgoqhkiG9y8BAQkBBC4w"
+ + "LAIBAYYnaHR0cDovL2Fkb2JlLXRpbWVzdGFtcC5nZW90cnVzdC5jb20vdHNh"
+ + "MBMGCiqGSIb3LwEBCQIEBTADAgEBMAwGA1UdEwQFMAMCAQAwDQYJKoZIhvcN"
+ + "AQEFBQADggEBAAOhy6QxOo+i3h877fvDvTa0plGD2bIqK7wMdNqbMDoSWied"
+ + "FIcgcBOIm2wLxOjZBAVj/3lDq59q2rnVeNnfXM0/N0MHI9TumHRjU7WNk9e4"
+ + "+JfJ4M+c3anrWOG3NE5cICDVgles+UHjXetHWql/LlP04+K2ZOLb6LE2xGnI"
+ + "YyLW9REzCYNAVF+/WkYdmyceHtaBZdbyVAJq0NAJPsfgY1pWcBo31Mr1fpX9"
+ + "WrXNTYDCqMyxMImJTmN3iI68tkXlNrhweQoArKFqBysiBkXzG/sGKYY6tWKU"
+ + "pzjLc3vIp/LrXC5zilROes8BSvwu1w9qQrJNcGwo7O4uijoNtyYil1Exgh1Q"
+ + "MIIdTAIBATBLMEUxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJ"
+ + "bmMuMR4wHAYDVQQDExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUCAgGDMAkGBSsO"
+ + "AwIaBQCgggxMMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwIwYJKoZIhvcN"
+ + "AQkEMRYEFP4R6qIdpQJzWyzrqO8X1ZfJOgChMIIMCQYJKoZIhvcvAQEIMYIL"
+ + "+jCCC/agggZ5MIIGdTCCA6gwggKQMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV"
+ + "BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR4wHAYDVQQDExVHZW9U"
+ + "cnVzdCBDQSBmb3IgQWRvYmUXDTA2MDQwNDE3NDAxMFoXDTA2MDQwNTE3NDAx"
+ + "MFowggIYMBMCAgC5Fw0wNTEwMTEyMDM2MzJaMBICAVsXDTA0MTEwNDE1MDk0"
+ + "MVowEwICALgXDTA1MTIxMjIyMzgzOFowEgIBWhcNMDQxMTA0MTUwOTMzWjAT"
+ + "AgIA5hcNMDUwODI3MDQwOTM4WjATAgIAtxcNMDYwMTE2MTc1NTEzWjATAgIA"
+ + "hhcNMDUxMjEyMjIzODU1WjATAgIAtRcNMDUwNzA2MTgzODQwWjATAgIA4BcN"
+ + "MDYwMzIwMDc0ODM0WjATAgIAgRcNMDUwODAyMjIzMTE1WjATAgIA3xcNMDUx"
+ + "MjEyMjIzNjUwWjASAgFKFw0wNDExMDQxNTA5MTZaMBICAUQXDTA0MTEwNDE1"
+ + "MDg1M1owEgIBQxcNMDQxMDAzMDEwMDQwWjASAgFsFw0wNDEyMDYxOTQ0MzFa"
+ + "MBMCAgEoFw0wNjAzMDkxMjA3MTJaMBMCAgEkFw0wNjAxMTYxNzU1MzRaMBIC"
+ + "AWcXDTA1MDMxODE3NTYxNFowEwICAVEXDTA2MDEzMTExMjcxMVowEgIBZBcN"
+ + "MDQxMTExMjI0ODQxWjATAgIA8RcNMDUwOTE2MTg0ODAxWjATAgIBThcNMDYw"
+ + "MjIxMjAxMDM2WjATAgIAwRcNMDUxMjEyMjIzODE2WjASAgFiFw0wNTAxMTAx"
+ + "NjE5MzRaMBICAWAXDTA1MDExMDE5MDAwNFowEwICAL4XDTA1MDUxNzE0NTYx"
+ + "MFowDQYJKoZIhvcNAQEFBQADggEBAEKhRMS3wVho1U3EvEQJZC8+JlUngmZQ"
+ + "A78KQbHPWNZWFlNvPuf/b0s7Lu16GfNHXh1QAW6Y5Hi1YtYZ3YOPyMd4Xugt"
+ + "gCdumbB6xtKsDyN5RvTht6ByXj+CYlYqsL7RX0izJZ6mJn4fjMkqzPKNOjb8"
+ + "kSn5T6rn93BjlATtCE8tPVOM8dnqGccRE0OV59+nDBXc90UMt5LdEbwaUOap"
+ + "snVB0oLcNm8d/HnlVH6RY5LnDjrT4vwfe/FApZtTecEWsllVUXDjSpwfcfD/"
+ + "476/lpGySB2otALqzImlA9R8Ok3hJ8dnF6hhQ5Oe6OJMnGYgdhkKbxsKkdib"
+ + "tTVl3qmH5QAwggLFMIIBrQIBATANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQG"
+ + "EwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQxHTAb"
+ + "BgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYwFAYDVQQDEw1BZG9iZSBS"
+ + "b290IENBFw0wNjAxMjcxODMzMzFaFw0wNzAxMjcwMDAwMDBaMIHeMCMCBD4c"
+ + "vUAXDTAzMDEyMTIzNDY1NlowDDAKBgNVHRUEAwoBBDAjAgQ+HL1BFw0wMzAx"
+ + "MjEyMzQ3MjJaMAwwCgYDVR0VBAMKAQQwIwIEPhy9YhcNMDMwMTIxMjM0NzQy"
+ + "WjAMMAoGA1UdFQQDCgEEMCMCBD4cvWEXDTA0MDExNzAxMDg0OFowDDAKBgNV"
+ + "HRUEAwoBBDAjAgQ+HL2qFw0wNDAxMTcwMTA5MDVaMAwwCgYDVR0VBAMKAQQw"
+ + "IwIEPhy9qBcNMDQwMTE3MDEzOTI5WjAMMAoGA1UdFQQDCgEEoC8wLTAKBgNV"
+ + "HRQEAwIBDzAfBgNVHSMEGDAWgBSCtzhKk6qbEO+Au9lU4vEP+4Cc3jANBgkq"
+ + "hkiG9w0BAQUFAAOCAQEAwtXF9042wG39icUlsotn5tpE3oCusLb/hBpEONhx"
+ + "OdfEQOq0w5hf/vqaxkcf71etA+KpbEUeSVaHMHRPhx/CmPrO9odE139dJdbt"
+ + "9iqbrC9iZokFK3h/es5kg73xujLKd7C/u5ngJ4mwBtvhMLjFjF2vJhPKHL4C"
+ + "IgMwdaUAhrcNzy16v+mw/VGJy3Fvc6oCESW1K9tvFW58qZSNXrMlsuidgunM"
+ + "hPKG+z0SXVyCqL7pnqKiaGddcgujYGOSY4S938oVcfZeZQEODtSYGlzldojX"
+ + "C1U1hCK5+tHAH0Ox/WqRBIol5VCZQwJftf44oG8oviYq52aaqSejXwmfT6zb"
+ + "76GCBXUwggVxMIIFbQoBAKCCBWYwggViBgkrBgEFBQcwAQEEggVTMIIFTzCB"
+ + "taIWBBS+8EpykfXdl4h3z7m/NZfdkAQQERgPMjAwNjA0MDQyMDIwMTVaMGUw"
+ + "YzA7MAkGBSsOAwIaBQAEFEb4BuZYkbjBjOjT6VeA/00fBvQaBBT3fTSQniOp"
+ + "BbHBSkz4xridlX0bsAICAYOAABgPMjAwNjA0MDQyMDIwMTVaoBEYDzIwMDYw"
+ + "NDA1MDgyMDE1WqEjMCEwHwYJKwYBBQUHMAECBBIEEFqooq/R2WltD7TposkT"
+ + "BhMwDQYJKoZIhvcNAQEFBQADgYEAMig6lty4b0JDsT/oanfQG5x6jVKPACpp"
+ + "1UA9SJ0apJJa7LeIdDFmu5C2S/CYiKZm4A4P9cAu0YzgLHxE4r6Op+HfVlAG"
+ + "6bzUe1P/hi1KCJ8r8wxOZAktQFPSzs85RAZwkHMfB0lP2e/h666Oye+Zf8VH"
+ + "RaE+/xZ7aswE89HXoumgggQAMIID/DCCA/gwggLgoAMCAQICAXUwDQYJKoZI"
+ + "hvcNAQEFBQAwRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu"
+ + "Yy4xHjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTAeFw0wNDEyMDIy"
+ + "MTI1MzlaFw0wNjEyMzAyMTI1MzlaMEwxCzAJBgNVBAYTAlVTMRUwEwYDVQQK"
+ + "EwxHZW9UcnVzdCBJbmMxJjAkBgNVBAMTHUdlb1RydXN0IEFkb2JlIE9DU1Ag"
+ + "UmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDiCc1iG3Dt"
+ + "TpB5Vdk4OcaEcyP46BnQMHf3esSTprar2SrXb0gDZ7TfIoFN8l9BH1pYpzZC"
+ + "P3R2xKo+O9MMcUZCxqCbYVC6GcDd9vVRaE/N4Qh2bpvEOydDydaoqrGdZnMQ"
+ + "tlt2ncj1sEuLMiqhtmi/O3rQs0yCGf+6e++6Gl5VKwIDAQABo4IBbjCCAWow"
+ + "DgYDVR0PAQH/BAQDAgTwMIHlBgNVHSABAf8EgdowgdcwgdQGCSqGSIb3LwEC"
+ + "ATCBxjCBkAYIKwYBBQUHAgIwgYMagYBUaGlzIGNlcnRpZmljYXRlIGhhcyBi"
+ + "ZWVuIGlzc3VlZCBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIEFjcm9iYXQgQ3Jl"
+ + "ZGVudGlhbHMgQ1BTIGxvY2F0ZWQgYXQgaHR0cDovL3d3dy5nZW90cnVzdC5j"
+ + "b20vcmVzb3VyY2VzL2NwczAxBggrBgEFBQcCARYlaHR0cDovL3d3dy5nZW90"
+ + "cnVzdC5jb20vcmVzb3VyY2VzL2NwczATBgNVHSUEDDAKBggrBgEFBQcDCTA6"
+ + "BgNVHR8EMzAxMC+gLaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxz"
+ + "L2Fkb2JlY2ExLmNybDAfBgNVHSMEGDAWgBSrgFnDZYNtHX0TvRnD7BqPDUdq"
+ + "ozANBgkqhkiG9w0BAQUFAAOCAQEAQ0l/UEPs9fmK+5prC33SrU4bNekhAv8K"
+ + "XMR4VWY4jGo9zURMVGr3Zi7Eblvr5H6T60aSYLA8txjyKmDplxsn8CKtCGiH"
+ + "OOUW5PpgBexN8SMKoRl9YzaxLtysrYRjEIyYoTfEN89yVi2sCjPupm/F9CPR"
+ + "O7EdKy0dm/f3C7ZmIbUFaIRzINDJOCpM5cGhmZ8m2yG4BxeZOmCSthKtLfvM"
+ + "2U9MaH6kxhDTJYNzw5BElHg5jlld92drTWaO0lM6aPr/pc+gs9hOraBCtzYE"
+ + "J40nhsSEtvuwVUE9vA+unNMT8dFtAcOvOPRiKYPF45RX9Rdy2C9jAc20SRwE"
+ + "uw6b+7K0xjANBgkqhkiG9w0BAQEFAASCAQC7a4yICFGCEMPlJbydK5qLG3rV"
+ + "sip7Ojjz9TB4nLhC2DgsIHds8jjdq2zguInluH2nLaBCVS+qxDVlTjgbI2cB"
+ + "TaWS8nglC7nNjzkKAsa8vThA8FZUVXTW0pb74jNJJU2AA27bb4g+4WgunCrj"
+ + "fpYp+QjDyMmdrJVqRmt5eQN+dpVxMS9oq+NrhOSEhyIb4/rejgNg9wnVK1ms"
+ + "l5PxQ4x7kpm7+Ua41//owkJVWykRo4T1jo4eHEz1DolPykAaKie2VKH/sMqR"
+ + "Spjh4E5biKJLOV9fKivZWKAXByXfwUbbMsJvz4v/2yVHFy9xP+tqB5ZbRoDK"
+ + "k8PzUyCprozn+/22oYIPijCCD4YGCyqGSIb3DQEJEAIOMYIPdTCCD3EGCSqG"
+ + "SIb3DQEHAqCCD2Iwgg9eAgEDMQswCQYFKw4DAhoFADCB+gYLKoZIhvcNAQkQ"
+ + "AQSggeoEgecwgeQCAQEGAikCMCEwCQYFKw4DAhoFAAQUoT97qeCv3FXYaEcS"
+ + "gY8patCaCA8CAiMHGA8yMDA2MDQwNDIwMjA1N1owAwIBPAEB/wIIO0yRre3L"
+ + "8/6ggZCkgY0wgYoxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNl"
+ + "dHRzMRAwDgYDVQQHEwdOZWVkaGFtMRUwEwYDVQQKEwxHZW9UcnVzdCBJbmMx"
+ + "EzARBgNVBAsTClByb2R1Y3Rpb24xJTAjBgNVBAMTHGFkb2JlLXRpbWVzdGFt"
+ + "cC5nZW90cnVzdC5jb22gggzJMIIDUTCCAjmgAwIBAgICAI8wDQYJKoZIhvcN"
+ + "AQEFBQAwRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4x"
+ + "HjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTAeFw0wNTAxMTAwMTI5"
+ + "MTBaFw0xNTAxMTUwODAwMDBaMIGKMQswCQYDVQQGEwJVUzEWMBQGA1UECBMN"
+ + "TWFzc2FjaHVzZXR0czEQMA4GA1UEBxMHTmVlZGhhbTEVMBMGA1UEChMMR2Vv"
+ + "VHJ1c3QgSW5jMRMwEQYDVQQLEwpQcm9kdWN0aW9uMSUwIwYDVQQDExxhZG9i"
+ + "ZS10aW1lc3RhbXAuZ2VvdHJ1c3QuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GN"
+ + "ADCBiQKBgQDRbxJotLFPWQuuEDhKtOMaBUJepGxIvWxeahMbq1DVmqnk88+j"
+ + "w/5lfPICPzQZ1oHrcTLSAFM7Mrz3pyyQKQKMqUyiemzuG/77ESUNfBNSUfAF"
+ + "PdtHuDMU8Is8ABVnFk63L+wdlvvDIlKkE08+VTKCRdjmuBVltMpQ6QcLFQzm"
+ + "AQIDAQABo4GIMIGFMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly9jcmwuZ2Vv"
+ + "dHJ1c3QuY29tL2NybHMvYWRvYmVjYTEuY3JsMB8GA1UdIwQYMBaAFKuAWcNl"
+ + "g20dfRO9GcPsGo8NR2qjMA4GA1UdDwEB/wQEAwIGwDAWBgNVHSUBAf8EDDAK"
+ + "BggrBgEFBQcDCDANBgkqhkiG9w0BAQUFAAOCAQEAmnyXjdtX+F79Nf0KggTd"
+ + "6YC2MQD9s09IeXTd8TP3rBmizfM+7f3icggeCGakNfPRmIUMLoa0VM5Kt37T"
+ + "2X0TqzBWusfbKx7HnX4v1t/G8NJJlT4SShSHv+8bjjU4lUoCmW2oEcC5vXwP"
+ + "R5JfjCyois16npgcO05ZBT+LLDXyeBijE6qWmwLDfEpLyILzVRmyU4IE7jvm"
+ + "rgb3GXwDUvd3yQXGRRHbPCh3nj9hBGbuzyt7GnlqnEie3wzIyMG2ET/wvTX5"
+ + "4BFXKNe7lDLvZj/MXvd3V7gMTSVW0kAszKao56LfrVTgp1VX3UBQYwmQqaoA"
+ + "UwFezih+jEvjW6cYJo/ErDCCBKEwggOJoAMCAQICBD4cvSgwDQYJKoZIhvcN"
+ + "AQEFBQAwaTELMAkGA1UEBhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMg"
+ + "SW5jb3Jwb3JhdGVkMR0wGwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEW"
+ + "MBQGA1UEAxMNQWRvYmUgUm9vdCBDQTAeFw0wMzAxMDgyMzM3MjNaFw0yMzAx"
+ + "MDkwMDA3MjNaMGkxCzAJBgNVBAYTAlVTMSMwIQYDVQQKExpBZG9iZSBTeXN0"
+ + "ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRvYmUgVHJ1c3QgU2Vydmlj"
+ + "ZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUA"
+ + "A4IBDwAwggEKAoIBAQDMT1SE96ei5zNTfz+cEohrLJlHZ34PHrmtFIj5wxDY"
+ + "HfDw1Z9pCi9ZNbDMbKlMnBWgn84gv6DPVOLgIGZFPzmGOH6cxI4HIsYk9gES"
+ + "sDXfVeppkLDbhTce4k4HskKhahNpoGbqgJERWSqbCHlaIEQtyb1zOIs8L+BD"
+ + "G12zC/CvNRop/u+mkt2BTJ09WY6tMTxAfpuRNgb84lyN0Y0m1VxFz69lP7Gq"
+ + "0mKW9Kg46rpgQvT0HEo1Fc74TiJWD5UYxfiWn5/7sLd4JemAa73WCvDGdJSd"
+ + "8w9Q25p3zktwgyONoMp4IERcPFRk8eqiMBmf6kwGTQZ4S16S3yLSyWezetIB"
+ + "AgMBAAGjggFPMIIBSzARBglghkgBhvhCAQEEBAMCAAcwgY4GA1UdHwSBhjCB"
+ + "gzCBgKB+oHykejB4MQswCQYDVQQGEwJVUzEjMCEGA1UEChMaQWRvYmUgU3lz"
+ + "dGVtcyBJbmNvcnBvcmF0ZWQxHTAbBgNVBAsTFEFkb2JlIFRydXN0IFNlcnZp"
+ + "Y2VzMRYwFAYDVQQDEw1BZG9iZSBSb290IENBMQ0wCwYDVQQDEwRDUkwxMCsG"
+ + "A1UdEAQkMCKADzIwMDMwMTA4MjMzNzIzWoEPMjAyMzAxMDkwMDA3MjNaMAsG"
+ + "A1UdDwQEAwIBBjAfBgNVHSMEGDAWgBSCtzhKk6qbEO+Au9lU4vEP+4Cc3jAd"
+ + "BgNVHQ4EFgQUgrc4SpOqmxDvgLvZVOLxD/uAnN4wDAYDVR0TBAUwAwEB/zAd"
+ + "BgkqhkiG9n0HQQAEEDAOGwhWNi4wOjQuMAMCBJAwDQYJKoZIhvcNAQEFBQAD"
+ + "ggEBADLan0N1wfpvyW/bqx02Nz68YRk2twI8HSNZmGye7k2F51TIIB+n1Lvi"
+ + "vwB3fSRrcC9cwTp2SbXT4COEKnFqIvPBJymYFfY1kOQETMONvJ9hHOf9JIzR"
+ + "REOMFrqbTaXUNS+8Ec6991E3jZ+Q5BTxGD++6VkSNfkzkvOe4NVrmnGbmUvI"
+ + "ccPhsWEJxOX6kfBCOjd9NPly6M2qYhwh6dX0ghDjewW2LWhWC35+kixvTXKC"
+ + "DO1WdLKduastKx0QX9sndXCP/R3X4gKgeeUc5f+vZEBRLZ6bR9tCpXwfwqZI"
+ + "sNe+kmlNpPYpV8V4ERjch1HKE7JinU8rMr0xpcH6UqsFiMgwggTLMIIDs6AD"
+ + "AgECAgQ+HL21MA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNVBAYTAlVTMSMwIQYD"
+ + "VQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRv"
+ + "YmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0EwHhcN"
+ + "MDQwMTE3MDAwMzM5WhcNMTUwMTE1MDgwMDAwWjBFMQswCQYDVQQGEwJVUzEW"
+ + "MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgQ0Eg"
+ + "Zm9yIEFkb2JlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+V3"
+ + "4GR4Wuc5hbyv0vVbKBMOVN1J+s5i9ZL9nph7n+X4esFs4epAJcFxJ4KnPuQH"
+ + "ZZ0oyHUU4Th70mWYgKwd6sEt1aR6ZT788Nvr3OHwTRwugN/G6QXqhU9ePpZJ"
+ + "OF1Ibsf1pcXNGvpLdcYK6+CX5DANMuIthb440XoNfC3dNBC0pF4mM4lmTjpl"
+ + "nQG8xK0rIFp4HoMpmyaIijz2qyjXdUNkg0fbDUq9eDTKAOLOg21u+AA8XKbC"
+ + "ewg1LWSV9CVy+fTHREmb1thBcrfkY1kCAvczsuquV3SMx8hRpa+4cIvKK/K1"
+ + "G7OrV0nsTyuaJ2MMST8b7bul/Xd81nu9Hsz4iQIDAQABo4IBnTCCAZkwEgYD"
+ + "VR0TAQH/BAgwBgEB/wIBATBQBgNVHSAESTBHMEUGCSqGSIb3LwECATA4MDYG"
+ + "CCsGAQUFBwIBFipodHRwczovL3d3dy5hZG9iZS5jb20vbWlzYy9wa2kvY2Rz"
+ + "X2NwLmh0bWwwFAYDVR0lBA0wCwYJKoZIhvcvAQEFMIGyBgNVHR8Egaowgacw"
+ + "IqAgoB6GHGh0dHA6Ly9jcmwuYWRvYmUuY29tL2Nkcy5jcmwwgYCgfqB8pHow"
+ + "eDELMAkGA1UEBhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMgSW5jb3Jw"
+ + "b3JhdGVkMR0wGwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEWMBQGA1UE"
+ + "AxMNQWRvYmUgUm9vdCBDQTENMAsGA1UEAxMEQ1JMMTALBgNVHQ8EBAMCAQYw"
+ + "HwYDVR0jBBgwFoAUgrc4SpOqmxDvgLvZVOLxD/uAnN4wHQYDVR0OBBYEFKuA"
+ + "WcNlg20dfRO9GcPsGo8NR2qjMBkGCSqGSIb2fQdBAAQMMAobBFY2LjADAgSQ"
+ + "MA0GCSqGSIb3DQEBBQUAA4IBAQA/OVkuogCOsV4RYSzS4Lb1jImGRc4T2Z/d"
+ + "hJoUawhMX4aXWPSlqNOPIfhHflCvd+Whbarcd83NN5n3QmevUOFUREPrMQyA"
+ + "mkK0mpW6TSyLG5ckeCFL8qJwp/hhckk/H16m4hEXWyIFGfOecX3Sy+Y4kxcC"
+ + "lzSMadifedB+TiRpKFKcNphp5hEMkpyyJaGXpLnN/BLsaDyEN7JySExAopae"
+ + "UbUJCvCVIWKwoJ26ih3BG1aB+3yTHXeLIorextqWbq+dVz7me59Li8j5PAxe"
+ + "hXrc2phpKuhp8FaTScvnfMZc8TL4Dr1CHMRWIkqfZaCq3mC376Mww0iZtE5s"
+ + "iqB+AXVWMYIBgDCCAXwCAQEwSzBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN"
+ + "R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgQ0EgZm9yIEFkb2Jl"
+ + "AgIAjzAJBgUrDgMCGgUAoIGMMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRAB"
+ + "BDAcBgkqhkiG9w0BCQUxDxcNMDYwNDA0MjAyMDU3WjAjBgkqhkiG9w0BCQQx"
+ + "FgQUp7AnXBqoNcarvO7fMJut1og2U5AwKwYLKoZIhvcNAQkQAgwxHDAaMBgw"
+ + "FgQU1dH4eZTNhgxdiSABrat6zsPdth0wDQYJKoZIhvcNAQEBBQAEgYCinr/F"
+ + "rMiQz/MRm9ZD5YGcC0Qo2dRTPd0Aop8mZ4g1xAhKFLnp7lLsjCbkSDpVLDBh"
+ + "cnCk7CV+3FT5hlvt8OqZlR0CnkSnCswLFhrppiWle6cpxlwGqyAteC8uKtQu"
+ + "wjE5GtBKLcCOAzQYyyuNZZeB6oCZ+3mPhZ62FxrvvEGJCgAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==");
+
+ private final byte[] emptyDNCert = Base64.decode(
+ "MIICfTCCAeagAwIBAgIBajANBgkqhkiG9w0BAQQFADB8MQswCQYDVQQGEwJVUzEMMAoGA1UEChMD"
+ + "Q0RXMQkwBwYDVQQLEwAxCTAHBgNVBAcTADEJMAcGA1UECBMAMRowGAYDVQQDExFUZW1wbGFyIFRl"
+ + "c3QgMTAyNDEiMCAGCSqGSIb3DQEJARYTdGVtcGxhcnRlc3RAY2R3LmNvbTAeFw0wNjA1MjIwNTAw"
+ + "MDBaFw0xMDA1MjIwNTAwMDBaMHwxCzAJBgNVBAYTAlVTMQwwCgYDVQQKEwNDRFcxCTAHBgNVBAsT"
+ + "ADEJMAcGA1UEBxMAMQkwBwYDVQQIEwAxGjAYBgNVBAMTEVRlbXBsYXIgVGVzdCAxMDI0MSIwIAYJ"
+ + "KoZIhvcNAQkBFhN0ZW1wbGFydGVzdEBjZHcuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB"
+ + "gQDH3aJpJBfM+A3d84j5YcU6zEQaQ76u5xO9NSBmHjZykKS2kCcUqPpvVOPDA5WgV22dtKPh+lYV"
+ + "iUp7wyCVwAKibq8HIbihHceFqMKzjwC639rMoDJ7bi/yzQWz1Zg+075a4FGPlUKn7Yfu89wKkjdW"
+ + "wDpRPXc/agqBnrx5pJTXzQIDAQABow8wDTALBgNVHQ8EBAMCALEwDQYJKoZIhvcNAQEEBQADgYEA"
+ + "RRsRsjse3i2/KClFVd6YLZ+7K1BE0WxFyY2bbytkwQJSxvv3vLSuweFUbhNxutb68wl/yW4GLy4b"
+ + "1QdyswNxrNDXTuu5ILKhRDDuWeocz83aG2KGtr3JlFyr3biWGEyn5WUOE6tbONoQDJ0oPYgI6CAc"
+ + "EHdUp0lioOCt6UOw7Cs=");
+
+ private final byte[] gostRFC4491_94 = Base64.decode(
+ "MIICCzCCAboCECMO42BGlSTOxwvklBgufuswCAYGKoUDAgIEMGkxHTAbBgNVBAMM" +
+ "FEdvc3RSMzQxMC05NCBleGFtcGxlMRIwEAYDVQQKDAlDcnlwdG9Qcm8xCzAJBgNV" +
+ "BAYTAlJVMScwJQYJKoZIhvcNAQkBFhhHb3N0UjM0MTAtOTRAZXhhbXBsZS5jb20w" +
+ "HhcNMDUwODE2MTIzMjUwWhcNMTUwODE2MTIzMjUwWjBpMR0wGwYDVQQDDBRHb3N0" +
+ "UjM0MTAtOTQgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRvUHJvMQswCQYDVQQGEwJS" +
+ "VTEnMCUGCSqGSIb3DQEJARYYR29zdFIzNDEwLTk0QGV4YW1wbGUuY29tMIGlMBwG" +
+ "BiqFAwICFDASBgcqhQMCAiACBgcqhQMCAh4BA4GEAASBgLuEZuF5nls02CyAfxOo" +
+ "GWZxV/6MVCUhR28wCyd3RpjG+0dVvrey85NsObVCNyaE4g0QiiQOHwxCTSs7ESuo" +
+ "v2Y5MlyUi8Go/htjEvYJJYfMdRv05YmKCYJo01x3pg+2kBATjeM+fJyR1qwNCCw+" +
+ "eMG1wra3Gqgqi0WBkzIydvp7MAgGBiqFAwICBANBABHHCH4S3ALxAiMpR3aPRyqB" +
+ "g1DjB8zy5DEjiULIc+HeIveF81W9lOxGkZxnrFjXBSqnjLeFKgF1hffXOAP7zUM=");
+
+ private final byte[] gostRFC4491_2001 = Base64.decode(
+ "MIIB0DCCAX8CECv1xh7CEb0Xx9zUYma0LiEwCAYGKoUDAgIDMG0xHzAdBgNVBAMM" +
+ "Fkdvc3RSMzQxMC0yMDAxIGV4YW1wbGUxEjAQBgNVBAoMCUNyeXB0b1BybzELMAkG" +
+ "A1UEBhMCUlUxKTAnBgkqhkiG9w0BCQEWGkdvc3RSMzQxMC0yMDAxQGV4YW1wbGUu" +
+ "Y29tMB4XDTA1MDgxNjE0MTgyMFoXDTE1MDgxNjE0MTgyMFowbTEfMB0GA1UEAwwW" +
+ "R29zdFIzNDEwLTIwMDEgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRvUHJvMQswCQYD" +
+ "VQQGEwJSVTEpMCcGCSqGSIb3DQEJARYaR29zdFIzNDEwLTIwMDFAZXhhbXBsZS5j" +
+ "b20wYzAcBgYqhQMCAhMwEgYHKoUDAgIkAAYHKoUDAgIeAQNDAARAhJVodWACGkB1" +
+ "CM0TjDGJLP3lBQN6Q1z0bSsP508yfleP68wWuZWIA9CafIWuD+SN6qa7flbHy7Df" +
+ "D2a8yuoaYDAIBgYqhQMCAgMDQQA8L8kJRLcnqeyn1en7U23Sw6pkfEQu3u0xFkVP" +
+ "vFQ/3cHeF26NG+xxtZPz3TaTVXdoiYkXYiD02rEx1bUcM97i");
+
+ private PublicKey dudPublicKey = new PublicKey()
+ {
+ public String getAlgorithm()
+ {
+ return null;
+ }
+
+ public String getFormat()
+ {
+ return null;
+ }
+
+ public byte[] getEncoded()
+ {
+ return null;
+ }
+
+ };
+
+ public String getName()
+ {
+ return "CertTest";
+ }
+
+ public void checkCertificate(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+
+ Certificate cert = fact.generateCertificate(bIn);
+
+ PublicKey k = cert.getPublicKey();
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+ public void checkNameCertificate(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+
+ X509Certificate cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ PublicKey k = cert.getPublicKey();
+ if (!cert.getIssuerDN().toString().equals("C=DE,O=DATEV eG,0.2.262.1.10.7.20=1+CN=CA DATEV D03 1:PN"))
+ {
+ fail(id + " failed - name test.");
+ }
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+ public void checkKeyUsage(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+
+ X509Certificate cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ PublicKey k = cert.getPublicKey();
+
+ if (cert.getKeyUsage()[7])
+ {
+ fail("error generating cert - key usage wrong.");
+ }
+
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+
+ public void checkSelfSignedCertificate(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", "SC");
+
+ Certificate cert = fact.generateCertificate(bIn);
+
+ PublicKey k = cert.getPublicKey();
+
+ cert.verify(k);
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+
+ /**
+ * Test a generated certificate with the sun provider
+ */
+ private void sunProviderCheck(byte[] encoding)
+ throws CertificateException
+ {
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509");
+
+ certFact.generateCertificate(new ByteArrayInputStream(encoding));
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - RSA
+ */
+ public void checkCreation1()
+ throws Exception
+ {
+ //
+ // a sample key pair.
+ //
+ 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));
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory fact = KeyFactory.getInstance("RSA", "SC");
+
+ privKey = fact.generatePrivate(privKeySpec);
+ pubKey = fact.generatePublic(pubKeySpec);
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
+
+ builder.addRDN(BCStyle.C, "AU");
+ builder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ builder.addRDN(BCStyle.L, "Melbourne");
+ builder.addRDN(BCStyle.ST, "Victoria");
+ builder.addRDN(BCStyle.E, "feedback-crypto@bouncycastle.org");
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3 - without extensions
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider(BC).build(privKey);
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000),builder.build(), pubKey);
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ cert.verify(cert.getPublicKey());
+
+ Set dummySet = cert.getNonCriticalExtensionOIDs();
+ if (dummySet != null)
+ {
+ fail("non-critical oid set should be null");
+ }
+ dummySet = cert.getCriticalExtensionOIDs();
+ if (dummySet != null)
+ {
+ fail("critical oid set should be null");
+ }
+
+ //
+ // create the certificate - version 3 - with extensions
+ //
+ sigGen = new JcaContentSignerBuilder("MD5WithRSAEncryption").setProvider(BC).build(privKey);
+ certGen = new JcaX509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1)
+ , new Date(System.currentTimeMillis() - 50000)
+ , new Date(System.currentTimeMillis() + 50000)
+ , builder.build()
+ , pubKey)
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true,
+ new X509KeyUsage(X509KeyUsage.encipherOnly))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.37"), true,
+ new DERSequence(KeyPurposeId.anyExtendedKeyUsage))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true,
+ new GeneralNames(new GeneralName[]
+ {
+ new GeneralName(GeneralName.rfc822Name, "test@test.test"),
+ new GeneralName(GeneralName.dNSName, "dom.test.test")
+ }));
+
+ X509CertificateHolder certHolder = certGen.build(sigGen);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certHolder);
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+ cert.verify(cert.getPublicKey());
+
+ ContentVerifierProvider contentVerifierProvider = new JcaContentVerifierProviderBuilder().setProvider(BC).build(pubKey);
+ if (!certHolder.isSignatureValid(contentVerifierProvider))
+ {
+ fail("signature test failed");
+ }
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", "SC");
+
+ cert = (X509Certificate)certFact.generateCertificate(bIn);
+
+ if (!cert.getKeyUsage()[7])
+ {
+ fail("error generating cert - key usage wrong.");
+ }
+
+ List l = cert.getExtendedKeyUsage();
+ if (!l.get(0).equals(KeyPurposeId.anyExtendedKeyUsage.getId()))
+ {
+ fail("failed extended key usage test");
+ }
+
+ Collection c = cert.getSubjectAlternativeNames();
+ Iterator it = c.iterator();
+ while (it.hasNext())
+ {
+ List gn = (List)it.next();
+ if (!gn.get(1).equals("test@test.test") && !gn.get(1).equals("dom.test.test"))
+ {
+ fail("failed subject alternative names test");
+ }
+ }
+
+ sunProviderCheck(certHolder.getEncoded());
+ sunProviderCheck(cert.getEncoded());
+
+ // System.out.println(cert);
+
+ //
+ // create the certificate - version 1
+ //
+ sigGen = new JcaContentSignerBuilder("MD5WithRSAEncryption").setProvider(BC).build(privKey);
+ X509v1CertificateBuilder certGen1 = new JcaX509v1CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen1.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+ cert.verify(cert.getPublicKey());
+
+ bIn = new ByteArrayInputStream(cert.getEncoded());
+ certFact = CertificateFactory.getInstance("X.509", "SC");
+
+ cert = (X509Certificate)certFact.generateCertificate(bIn);
+
+ // System.out.println(cert);
+ if (!cert.getIssuerDN().equals(cert.getSubjectDN()))
+ {
+ fail("name comparison fails");
+ }
+
+ sunProviderCheck(certHolder.getEncoded());
+ sunProviderCheck(cert.getEncoded());
+//
+ // a lightweight key pair.
+ //
+ RSAKeyParameters lwPubKey = new RSAKeyParameters(
+ false,
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ RSAPrivateCrtKeyParameters lwPrivKey = new RSAPrivateCrtKeyParameters(
+ 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));
+
+ //
+ // distinguished name table.
+ //
+ builder = new X500NameBuilder(BCStyle.INSTANCE);
+
+ builder.addRDN(BCStyle.C, "AU");
+ builder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ builder.addRDN(BCStyle.L, "Melbourne");
+ builder.addRDN(BCStyle.ST, "Victoria");
+ builder.addRDN(BCStyle.E, "feedback-crypto@bouncycastle.org");
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3 - without extensions
+ //
+ AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSAEncryption");
+ AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
+
+ sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(lwPrivKey);
+ SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPublicKey(lwPubKey.getModulus(), lwPubKey.getExponent()));
+ certGen = new X509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000), builder.build(), pubInfo);
+
+ certHolder = certGen.build(sigGen);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certHolder);
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ contentVerifierProvider = new BcRSAContentVerifierProviderBuilder(new DefaultDigestAlgorithmIdentifierFinder()).build(lwPubKey);
+
+ if (!certHolder.isSignatureValid(contentVerifierProvider))
+ {
+ fail("lw sig verification failed");
+ }
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - DSA
+ */
+ public void checkCreation2()
+ throws Exception
+ {
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ try
+ {
+ KeyPairGenerator g = KeyPairGenerator.getInstance("DSA", "SUN");
+
+ g.initialize(512, new SecureRandom());
+
+ KeyPair p = g.generateKeyPair();
+
+ privKey = p.getPrivate();
+ pubKey = p.getPublic();
+ }
+ catch (Exception e)
+ {
+ fail("error setting up keys - " + e.toString());
+ return;
+ }
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3
+ //
+
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA1withDSA").setProvider(BC).build(privKey);
+ JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ // System.out.println(cert);
+
+
+ //
+ // create the certificate - version 1
+ //
+ sigGen = new JcaContentSignerBuilder("SHA1withDSA").setProvider(BC).build(privKey);
+ JcaX509v1CertificateBuilder certGen1 = new JcaX509v1CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen1.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ bIn = new ByteArrayInputStream(cert.getEncoded());
+ fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ //System.out.println(cert);
+
+ //
+ // exception test
+ //
+ try
+ {
+ certGen1 = new JcaX509v1CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),dudPublicKey);
+
+
+ fail("key without encoding not detected in v1");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // expected
+ }
+ }
+
+ private X500NameBuilder createStdBuilder()
+ {
+ X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
+
+ builder.addRDN(BCStyle.C, "AU");
+ builder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle");
+ builder.addRDN(BCStyle.L, "Melbourne");
+ builder.addRDN(BCStyle.ST, "Victoria");
+ builder.addRDN(BCStyle.E, "feedback-crypto@bouncycastle.org");
+
+ return builder;
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - ECDSA
+ */
+ public void checkCreation3()
+ {
+ ECCurve curve = new ECCurve.Fp(
+ new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+ new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+ new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+
+ ECParameterSpec spec = new ECParameterSpec(
+ curve,
+ curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+ new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n
+
+
+ ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(
+ new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d
+ spec);
+
+ ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(
+ curve.decodePoint(Hex.decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q
+ spec);
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ try
+ {
+ KeyFactory fact = KeyFactory.getInstance("ECDSA", BC);
+
+ privKey = fact.generatePrivate(privKeySpec);
+ pubKey = fact.generatePublic(pubKeySpec);
+ }
+ catch (Exception e)
+ {
+ fail("error setting up keys - " + e.toString());
+ return;
+ }
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = createStdBuilder();
+
+
+ //
+ // toString test
+ //
+ X500Name p = builder.build();
+ String s = p.toString();
+
+ if (!s.equals("C=AU,O=The Legion of the Bouncy Castle,L=Melbourne,ST=Victoria,E=feedback-crypto@bouncycastle.org"))
+ {
+ fail("ordered X509Principal test failed - s = " + s + ".");
+ }
+
+// p = new X509Principal(attrs);
+// s = p.toString();
+//
+// //
+// // we need two of these as the hash code for strings changed...
+// //
+// if (!s.equals("O=The Legion of the Bouncy Castle,E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU") && !s.equals("ST=Victoria,L=Melbourne,C=AU,E=feedback-crypto@bouncycastle.org,O=The Legion of the Bouncy Castle"))
+// {
+// fail("unordered X509Principal test failed.");
+// }
+
+ //
+ // create the certificate - version 3
+ //
+ try
+ {
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA1withECDSA").setProvider(BC).build(privKey);
+ JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ //
+ // try with point compression turned off
+ //
+ ((ECPointEncoder)pubKey).setPointFormat("UNCOMPRESSED");
+
+ certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ bIn = new ByteArrayInputStream(cert.getEncoded());
+ fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail("error setting generating cert - " + e.toString());
+ }
+
+ X509Principal pr = new X509Principal("O=\"The Bouncy Castle, The Legion of\",E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU");
+
+ if (!pr.toString().equals("O=The Bouncy Castle\\, The Legion of,E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU"))
+ {
+ fail("string based X509Principal test failed.");
+ }
+
+ pr = new X509Principal("O=The Bouncy Castle\\, The Legion of,E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU");
+
+ if (!pr.toString().equals("O=The Bouncy Castle\\, The Legion of,E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU"))
+ {
+ fail("string based X509Principal test failed.");
+ }
+
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - SHA224withECDSA
+ */
+ private void createECCert(String algorithm, DERObjectIdentifier algOid)
+ throws Exception
+ {
+ ECCurve.Fp curve = new ECCurve.Fp(
+ new BigInteger("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"), // q (or p)
+ new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", 16), // a
+ new BigInteger("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", 16)); // b
+
+ ECParameterSpec spec = new ECParameterSpec(
+ curve,
+ curve.decodePoint(Hex.decode("0200C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")), // G
+ new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", 16)); // n
+
+ ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(
+ new BigInteger("5769183828869504557786041598510887460263120754767955773309066354712783118202294874205844512909370791582896372147797293913785865682804434049019366394746072023"), // d
+ spec);
+
+ ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(
+ curve.decodePoint(Hex.decode("02006BFDD2C9278B63C92D6624F151C9D7A822CC75BD983B17D25D74C26740380022D3D8FAF304781E416175EADF4ED6E2B47142D2454A7AC7801DD803CF44A4D1F0AC")), // Q
+ spec);
+
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory fact = KeyFactory.getInstance("ECDSA", BC);
+
+ privKey = fact.generatePrivate(privKeySpec);
+ pubKey = fact.generatePublic(pubKeySpec);
+
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // create the certificate - version 3
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey);
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)certFact.generateCertificate(bIn);
+
+ //
+ // try with point compression turned off
+ //
+ ((ECPointEncoder)pubKey).setPointFormat("UNCOMPRESSED");
+
+ certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ bIn = new ByteArrayInputStream(cert.getEncoded());
+ certFact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)certFact.generateCertificate(bIn);
+
+ if (!cert.getSigAlgOID().equals(algOid.toString()))
+ {
+ fail("ECDSA oid incorrect.");
+ }
+
+ if (cert.getSigAlgParams() != null)
+ {
+ fail("sig parameters present");
+ }
+
+ Signature sig = Signature.getInstance(algorithm, BC);
+
+ sig.initVerify(pubKey);
+
+ sig.update(cert.getTBSCertificate());
+
+ if (!sig.verify(cert.getSignature()))
+ {
+ fail("EC certificate signature not mapped correctly.");
+ }
+ // System.out.println(cert);
+ }
+
+ private void checkCRL(
+ int id,
+ byte[] bytes)
+ {
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(bytes);
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
+
+ CRL cert = fact.generateCRL(bIn);
+
+ // System.out.println(cert);
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": "+ id + " failed - exception " + e.toString(), e);
+ }
+
+ }
+
+ public void checkCRLCreation1()
+ throws Exception
+ {
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", BC);
+ Date now = new Date();
+ KeyPair pair = kpGen.generateKeyPair();
+ X509v2CRLBuilder crlGen = new X509v2CRLBuilder(new X500Name("CN=Test CA"), now);
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ crlGen.addCRLEntry(BigInteger.ONE, now, CRLReason.privilegeWithdrawn);
+
+ crlGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.getPublic()));
+
+ X509CRLHolder crl = crlGen.build(new JcaContentSignerBuilder("SHA256withRSAEncryption").setProvider(BC).build(pair.getPrivate()));
+
+ if (!crl.getIssuer().equals(new X500Name("CN=Test CA")))
+ {
+ fail("failed CRL issuer test");
+ }
+
+ Extension authExt = crl.getExtension(Extension.authorityKeyIdentifier);
+
+ if (authExt == null)
+ {
+ fail("failed to find CRL extension");
+ }
+
+ AuthorityKeyIdentifier authId = new AuthorityKeyIdentifierStructure(authExt);
+
+ X509CRLEntryHolder entry = crl.getRevokedCertificate(BigInteger.ONE);
+
+ if (entry == null)
+ {
+ fail("failed to find CRL entry");
+ }
+
+ if (!entry.getSerialNumber().equals(BigInteger.ONE))
+ {
+ fail("CRL cert serial number does not match");
+ }
+
+ if (!entry.hasExtensions())
+ {
+ fail("CRL entry extension not found");
+ }
+
+ Extension ext = entry.getExtension(X509Extension.reasonCode);
+
+ if (ext != null)
+ {
+ ASN1Enumerated reasonCode = (ASN1Enumerated)ASN1Enumerated.getInstance(ext.getParsedValue());
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found");
+ }
+ }
+
+ public void checkCRLCreation2()
+ throws Exception
+ {
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", BC);
+
+ Date now = new Date();
+ KeyPair pair = kpGen.generateKeyPair();
+ X509v2CRLBuilder crlGen = new JcaX509v2CRLBuilder(new X500Principal("CN=Test CA"), now);
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ Vector extOids = new Vector();
+ Vector extValues = new Vector();
+
+ CRLReason crlReason = CRLReason.lookup(CRLReason.privilegeWithdrawn);
+
+ try
+ {
+ extOids.addElement(X509Extensions.ReasonCode);
+ extValues.addElement(new X509Extension(false, new DEROctetString(crlReason.getEncoded())));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("error encoding reason: " + e);
+ }
+
+ X509Extensions entryExtensions = new X509Extensions(extOids, extValues);
+
+ crlGen.addCRLEntry(BigInteger.ONE, now, entryExtensions);
+
+ crlGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.getPublic()));
+
+ X509CRLHolder crlHolder = crlGen.build(new JcaContentSignerBuilder("SHA256withRSAEncryption").setProvider(BC).build(pair.getPrivate()));
+
+ X509CRL crl = new JcaX509CRLConverter().setProvider(BC).getCRL(crlHolder);
+
+ if (!crl.getIssuerX500Principal().equals(new X500Principal("CN=Test CA")))
+ {
+ fail("failed CRL issuer test");
+ }
+
+ byte[] authExt = crl.getExtensionValue(X509Extensions.AuthorityKeyIdentifier.getId());
+
+ if (authExt == null)
+ {
+ fail("failed to find CRL extension");
+ }
+
+ AuthorityKeyIdentifier authId = new AuthorityKeyIdentifierStructure(authExt);
+
+ X509CRLEntry entry = crl.getRevokedCertificate(BigInteger.ONE);
+
+ if (entry == null)
+ {
+ fail("failed to find CRL entry");
+ }
+
+ if (!entry.getSerialNumber().equals(BigInteger.ONE))
+ {
+ fail("CRL cert serial number does not match");
+ }
+
+ if (!entry.hasExtensions())
+ {
+ fail("CRL entry extension not found");
+ }
+
+ byte[] ext = entry.getExtensionValue(X509Extensions.ReasonCode.getId());
+
+ if (ext != null)
+ {
+ DEREnumerated reasonCode = (DEREnumerated)X509ExtensionUtil.fromExtensionValue(ext);
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found");
+ }
+ }
+
+ public void checkCRLCreation3()
+ throws Exception
+ {
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", BC);
+ Date now = new Date();
+ KeyPair pair = kpGen.generateKeyPair();
+ X509v2CRLBuilder crlGen = new JcaX509v2CRLBuilder(new X500Principal("CN=Test CA"), now);
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ Vector extOids = new Vector();
+ Vector extValues = new Vector();
+
+ CRLReason crlReason = CRLReason.lookup(CRLReason.privilegeWithdrawn);
+
+ try
+ {
+ extOids.addElement(X509Extensions.ReasonCode);
+ extValues.addElement(new X509Extension(false, new DEROctetString(crlReason.getEncoded())));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("error encoding reason: " + e);
+ }
+
+ X509Extensions entryExtensions = new X509Extensions(extOids, extValues);
+
+ crlGen.addCRLEntry(BigInteger.ONE, now, entryExtensions);
+
+ crlGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.getPublic()));
+
+ X509CRLHolder crlHolder = crlGen.build(new JcaContentSignerBuilder("SHA256withRSAEncryption").setProvider(BC).build(pair.getPrivate()));
+
+ X509CRL crl = new JcaX509CRLConverter().setProvider(BC).getCRL(crlHolder);
+
+ if (!crl.getIssuerX500Principal().equals(new X500Principal("CN=Test CA")))
+ {
+ fail("failed CRL issuer test");
+ }
+
+ byte[] authExt = crl.getExtensionValue(X509Extensions.AuthorityKeyIdentifier.getId());
+
+ if (authExt == null)
+ {
+ fail("failed to find CRL extension");
+ }
+
+ AuthorityKeyIdentifier authId = new AuthorityKeyIdentifierStructure(authExt);
+
+ X509CRLEntry entry = crl.getRevokedCertificate(BigInteger.ONE);
+
+ if (entry == null)
+ {
+ fail("failed to find CRL entry");
+ }
+
+ if (!entry.getSerialNumber().equals(BigInteger.ONE))
+ {
+ fail("CRL cert serial number does not match");
+ }
+
+ if (!entry.hasExtensions())
+ {
+ fail("CRL entry extension not found");
+ }
+
+ byte[] ext = entry.getExtensionValue(X509Extensions.ReasonCode.getId());
+
+ if (ext != null)
+ {
+ DEREnumerated reasonCode = (DEREnumerated)X509ExtensionUtil.fromExtensionValue(ext);
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found");
+ }
+
+ //
+ // check loading of existing CRL
+ //
+ now = new Date();
+ crlGen = new X509v2CRLBuilder(new X500Name("CN=Test CA"), now);
+
+ crlGen.setNextUpdate(new Date(now.getTime() + 100000));
+
+ crlGen.addCRL(new JcaX509CRLHolder(crl));
+
+ crlGen.addCRLEntry(BigInteger.valueOf(2), now, entryExtensions);
+
+ crlGen.addExtension(X509Extension.authorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.getPublic()));
+
+ crlHolder = crlGen.build(new JcaContentSignerBuilder("SHA256withRSAEncryption").setProvider(BC).build(pair.getPrivate()));
+
+ int count = 0;
+ boolean oneFound = false;
+ boolean twoFound = false;
+
+ Iterator it = crlHolder.getRevokedCertificates().iterator();
+ while (it.hasNext())
+ {
+ X509CRLEntryHolder crlEnt = (X509CRLEntryHolder)it.next();
+
+ if (crlEnt.getSerialNumber().intValue() == 1)
+ {
+ oneFound = true;
+ Extension extn = crlEnt.getExtension(X509Extension.reasonCode);
+
+ if (extn != null)
+ {
+ ASN1Enumerated reasonCode = (ASN1Enumerated)ASN1Enumerated.getInstance(extn.getParsedValue());
+
+ if (reasonCode.getValue().intValue() != CRLReason.privilegeWithdrawn)
+ {
+ fail("CRL entry reasonCode wrong");
+ }
+ }
+ else
+ {
+ fail("CRL entry reasonCode not found");
+ }
+ }
+ else if (crlEnt.getSerialNumber().intValue() == 2)
+ {
+ twoFound = true;
+ }
+
+ count++;
+ }
+
+ if (count != 2)
+ {
+ fail("wrong number of CRLs found");
+ }
+
+ if (!oneFound || !twoFound)
+ {
+ fail("wrong CRLs found in copied list");
+ }
+
+ //
+ // check factory read back
+ //
+ CertificateFactory cFact = CertificateFactory.getInstance("X.509", BC);
+
+ X509CRL readCrl = (X509CRL)cFact.generateCRL(new ByteArrayInputStream(crlHolder.getEncoded()));
+
+ if (readCrl == null)
+ {
+ fail("crl not returned!");
+ }
+
+ Collection col = cFact.generateCRLs(new ByteArrayInputStream(crlHolder.getEncoded()));
+
+ if (col.size() != 1)
+ {
+ fail("wrong number of CRLs found in collection");
+ }
+ }
+
+ /**
+ * we generate a self signed certificate for the sake of testing - GOST3410
+ */
+ public void checkCreation4()
+ throws Exception
+ {
+ //
+ // set up the keys
+ //
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyPairGenerator g = KeyPairGenerator.getInstance("GOST3410", BC);
+ GOST3410ParameterSpec gost3410P = new GOST3410ParameterSpec("GostR3410-94-CryptoPro-A");
+
+ g.initialize(gost3410P, new SecureRandom());
+
+ KeyPair p = g.generateKeyPair();
+
+ privKey = p.getPrivate();
+ pubKey = p.getPublic();
+
+ //
+ // distinguished name table.
+ //
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // extensions
+ //
+
+ //
+ // create the certificate - version 3
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder("GOST3411withGOST3410").setProvider(BC).build(privKey);
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ //
+ // check verifies in general
+ //
+ cert.verify(pubKey);
+
+ //
+ // check verifies with contained key
+ //
+ cert.verify(cert.getPublicKey());
+
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ //System.out.println(cert);
+
+ //check getEncoded()
+ byte[] bytes = cert.getEncoded();
+ }
+
+ public void checkCreation5()
+ throws Exception
+ {
+ //
+ // a sample key pair.
+ //
+ 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));
+
+ //
+ // set up the keys
+ //
+ SecureRandom rand = new SecureRandom();
+ PrivateKey privKey;
+ PublicKey pubKey;
+
+ KeyFactory fact = KeyFactory.getInstance("RSA", BC);
+
+ privKey = fact.generatePrivate(privKeySpec);
+ pubKey = fact.generatePublic(pubKeySpec);
+
+ //
+ // distinguished name table.
+ //
+ Vector ord = new Vector();
+ Vector values = new Vector();
+
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // create base certificate - version 3
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder("MD5WithRSAEncryption").setProvider(BC).build(privKey);
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey)
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true,
+ new X509KeyUsage(X509KeyUsage.encipherOnly))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.37"), true,
+ new DERSequence(KeyPurposeId.anyExtendedKeyUsage))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true,
+ new GeneralNames(new GeneralName(GeneralName.rfc822Name, "test@test.test")));
+
+ X509Certificate baseCert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ //
+ // copy certificate
+ //
+
+ certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey)
+ .copyAndAddExtension(new ASN1ObjectIdentifier("2.5.29.15"), true, baseCert)
+ .copyAndAddExtension(new ASN1ObjectIdentifier("2.5.29.37"), false, baseCert);
+
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ if (!areEqual(baseCert.getExtensionValue("2.5.29.15"), cert.getExtensionValue("2.5.29.15")))
+ {
+ fail("2.5.29.15 differs");
+ }
+
+ if (!areEqual(baseCert.getExtensionValue("2.5.29.37"), cert.getExtensionValue("2.5.29.37")))
+ {
+ fail("2.5.29.37 differs");
+ }
+
+ //
+ // exception test
+ //
+
+ try
+ {
+ certGen.copyAndAddExtension(new ASN1ObjectIdentifier("2.5.99.99"), true, new JcaX509CertificateHolder(baseCert));
+
+ fail("exception not thrown on dud extension copy");
+ }
+ catch (NullPointerException e)
+ {
+ // expected
+ }
+
+// try
+// {
+// certGen.setPublicKey(dudPublicKey);
+//
+// certGen.generate(privKey, BC);
+//
+// fail("key without encoding not detected in v3");
+// }
+// catch (IllegalArgumentException e)
+// {
+// // expected
+// }
+
+ }
+
+ private void testForgedSignature()
+ throws Exception
+ {
+ String cert = "MIIBsDCCAVoCAQYwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCQVUxEzARBgNV"
+ + "BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMSMwIQYD"
+ + "VQQDExpTZXJ2ZXIgdGVzdCBjZXJ0ICg1MTIgYml0KTAeFw0wNjA5MTEyMzU4NTVa"
+ + "Fw0wNjEwMTEyMzU4NTVaMGMxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpRdWVlbnNs"
+ + "YW5kMRowGAYDVQQKExFDcnlwdFNvZnQgUHR5IEx0ZDEjMCEGA1UEAxMaU2VydmVy"
+ + "IHRlc3QgY2VydCAoNTEyIGJpdCkwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAn7PD"
+ + "hCeV/xIxUg8V70YRxK2A5jZbD92A12GN4PxyRQk0/lVmRUNMaJdq/qigpd9feP/u"
+ + "12S4PwTLb/8q/v657QIDAQABMA0GCSqGSIb3DQEBBQUAA0EAbynCRIlUQgaqyNgU"
+ + "DF6P14yRKUtX8akOP2TwStaSiVf/akYqfLFm3UGka5XbPj4rifrZ0/sOoZEEBvHQ"
+ + "e20sRA==";
+
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", BC);
+
+ X509Certificate x509 = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(Base64.decode(cert)));
+ try
+ {
+ x509.verify(x509.getPublicKey());
+
+ fail("forged RSA signature passed");
+ }
+ catch (Exception e)
+ {
+ // expected
+ }
+ }
+
+
+ private void pemTest()
+ throws Exception
+ {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509", BC);
+
+ Certificate cert = readPEMCert(cf, PEMData.CERTIFICATE_1);
+ if (cert == null)
+ {
+ fail("PEM cert not read");
+ }
+ cert = readPEMCert(cf, "-----BEGIN CERTIFICATE-----" + PEMData.CERTIFICATE_2);
+ if (cert == null)
+ {
+ fail("PEM cert with extraneous header not read");
+ }
+ CRL crl = cf.generateCRL(new ByteArrayInputStream(PEMData.CRL_1.getBytes("US-ASCII")));
+ if (crl == null)
+ {
+ fail("PEM crl not read");
+ }
+ Collection col = cf.generateCertificates(new ByteArrayInputStream(PEMData.CERTIFICATE_2.getBytes("US-ASCII")));
+ if (col.size() != 1 || !col.contains(cert))
+ {
+ fail("PEM cert collection not right");
+ }
+ col = cf.generateCRLs(new ByteArrayInputStream(PEMData.CRL_2.getBytes("US-ASCII")));
+ if (col.size() != 1 || !col.contains(crl))
+ {
+ fail("PEM crl collection not right");
+ }
+ }
+
+ private static Certificate readPEMCert(CertificateFactory cf, String pemData)
+ throws CertificateException, UnsupportedEncodingException
+ {
+ return cf.generateCertificate(new ByteArrayInputStream(pemData.getBytes("US-ASCII")));
+ }
+
+ private void pkcs7Test()
+ throws Exception
+ {
+ /*
+ ASN1EncodableVector certs = new ASN1EncodableVector();
+
+ certs.add(new ASN1InputStream(CertPathTest.rootCertBin).readObject());
+ certs.add(new DERTaggedObject(false, 2, new ASN1InputStream(AttrCertTest.attrCert).readObject()));
+
+ ASN1EncodableVector crls = new ASN1EncodableVector();
+
+ crls.add(new ASN1InputStream(CertPathTest.rootCrlBin).readObject());
+ SignedData sigData = new SignedData(new DERSet(), new ContentInfo(CMSObjectIdentifiers.data, null), new DERSet(certs), new DERSet(crls), new DERSet());
+
+ ContentInfo info = new ContentInfo(CMSObjectIdentifiers.signedData, sigData);
+
+ CertificateFactory cf = CertificateFactory.getInstance("X.509", BC);
+
+ X509Certificate cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(info.getEncoded()));
+ if (cert == null || !areEqual(cert.getEncoded(), certs.get(0).getDERObject().getEncoded()))
+ {
+ fail("PKCS7 cert not read");
+ }
+ X509CRL crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(info.getEncoded()));
+ if (crl == null || !areEqual(crl.getEncoded(), crls.get(0).getDERObject().getEncoded()))
+ {
+ fail("PKCS7 crl not read");
+ }
+ Collection col = cf.generateCertificates(new ByteArrayInputStream(info.getEncoded()));
+ if (col.size() != 1 || !col.contains(cert))
+ {
+ fail("PKCS7 cert collection not right");
+ }
+ col = cf.generateCRLs(new ByteArrayInputStream(info.getEncoded()));
+ if (col.size() != 1 || !col.contains(crl))
+ {
+ fail("PKCS7 crl collection not right");
+ }
+
+ // data with no certificates or CRLs
+
+ sigData = new SignedData(new DERSet(), new ContentInfo(CMSObjectIdentifiers.data, null), new DERSet(), new DERSet(), new DERSet());
+
+ info = new ContentInfo(CMSObjectIdentifiers.signedData, sigData);
+
+ cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(info.getEncoded()));
+ if (cert != null)
+ {
+ fail("PKCS7 cert present");
+ }
+ crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(info.getEncoded()));
+ if (crl != null)
+ {
+ fail("PKCS7 crl present");
+ }
+
+ // data with absent certificates and CRLS
+
+ sigData = new SignedData(new DERSet(), new ContentInfo(CMSObjectIdentifiers.data, null), null, null, new DERSet());
+
+ info = new ContentInfo(CMSObjectIdentifiers.signedData, sigData);
+
+ cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(info.getEncoded()));
+ if (cert != null)
+ {
+ fail("PKCS7 cert present");
+ }
+ crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(info.getEncoded()));
+ if (crl != null)
+ {
+ fail("PKCS7 crl present");
+ }
+
+ //
+ // sample message
+ //
+ InputStream in = new ByteArrayInputStream(pkcs7CrlProblem);
+ Collection certCol = cf.generateCertificates(in);
+ Collection crlCol = cf.generateCRLs(in);
+
+ if (crlCol.size() != 0)
+ {
+ fail("wrong number of CRLs: " + crlCol.size());
+ }
+
+ if (certCol.size() != 4)
+ {
+ fail("wrong number of Certs: " + certCol.size());
+ }
+ */
+ }
+
+ private void createPSSCert(String algorithm)
+ throws Exception
+ {
+ KeyPair pair = generateLongFixedKeys();
+
+ PrivateKey privKey = pair.getPrivate();
+ PublicKey pubKey = pair.getPublic();
+
+ //
+ // distinguished name table.
+ //
+
+ X500NameBuilder builder = createStdBuilder();
+
+ //
+ // create base certificate - version 3
+ //
+ ContentSigner sigGen = new JcaContentSignerBuilder(algorithm).setProvider(BC).build(privKey);
+ JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),BigInteger.valueOf(1),
+ new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),builder.build(),pubKey);
+
+ certGen.addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true,
+ new X509KeyUsage(X509KeyUsage.encipherOnly));
+ certGen.addExtension(new ASN1ObjectIdentifier("2.5.29.37"), true,
+ new DERSequence(KeyPurposeId.anyExtendedKeyUsage));
+ certGen.addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true,
+ new GeneralNames(new GeneralName(GeneralName.rfc822Name, "test@test.test")));
+
+ X509Certificate baseCert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ baseCert.verify(pubKey);
+ }
+
+ private KeyPair generateLongFixedKeys()
+ throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException
+ {
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+ new BigInteger("010001",16));
+
+ RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec(
+ new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+ new BigInteger("010001",16),
+ new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16),
+ new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16),
+ new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16),
+ new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16),
+ new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16),
+ new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16));
+
+ KeyFactory fact = KeyFactory.getInstance("RSA", BC);
+
+ return new KeyPair(fact.generatePublic(pubKeySpec), fact.generatePrivate(privKeySpec));
+ }
+
+ private void rfc4491Test()
+ throws Exception
+ {
+ CertificateFactory certFact = CertificateFactory.getInstance("X.509", BC);
+
+ X509Certificate x509 = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(gostRFC4491_94));
+
+ x509.verify(x509.getPublicKey(), BC);
+
+ x509 = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(gostRFC4491_2001));
+
+ x509.verify(x509.getPublicKey(), BC);
+ }
+
+ private void testNullDerNullCert()
+ throws Exception
+ {
+ KeyPair pair = generateLongFixedKeys();
+ PublicKey pubKey = pair.getPublic();
+ PrivateKey privKey = pair.getPrivate();
+
+ ContentSigner sigGen = new JcaContentSignerBuilder("MD5WithRSAEncryption").setProvider(BC).build(privKey);
+ JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(new X500Name("CN=Test"),BigInteger.valueOf(1),new Date(System.currentTimeMillis() - 50000),new Date(System.currentTimeMillis() + 50000),new X500Name("CN=Test"),pubKey);
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
+
+ X509CertificateStructure struct = X509CertificateStructure.getInstance(ASN1Primitive.fromByteArray(cert.getEncoded()));
+
+ ASN1Encodable tbsCertificate = struct.getTBSCertificate();
+ AlgorithmIdentifier sig = struct.getSignatureAlgorithm();
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCertificate);
+ v.add(new AlgorithmIdentifier(sig.getAlgorithm()));
+ v.add(struct.getSignature());
+
+ // verify
+ ByteArrayInputStream bIn;
+ String dump = "";
+
+ try
+ {
+ bIn = new ByteArrayInputStream(new DERSequence(v).getEncoded());
+
+ CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
+
+ cert = (X509Certificate)fact.generateCertificate(bIn);
+
+ cert.verify(cert.getPublicKey());
+ }
+ catch (Exception e)
+ {
+ fail(dump + System.getProperty("line.separator") + getName() + ": testNullDerNull failed - exception " + e.toString(), e);
+ }
+ }
+
+ private void testDirect()
+ throws Exception
+ {
+ KeyStore keyStore = KeyStore.getInstance("PKCS12", "SC");
+
+ ByteArrayInputStream input = new ByteArrayInputStream(testCAp12);
+
+ keyStore.load(input, "test".toCharArray());
+
+ X509Certificate certificate = (X509Certificate) keyStore.getCertificate("ca");
+ PrivateKey privateKey = (PrivateKey) keyStore.getKey("ca", null);
+
+ X500Name issuer = X500Name.getInstance(certificate.getIssuerX500Principal().getEncoded());
+
+ X509v2CRLBuilder builder = new X509v2CRLBuilder(issuer, new Date());
+
+ builder.addCRLEntry(certificate.getSerialNumber(), new Date(), CRLReason.cACompromise);
+
+ JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA256WithRSAEncryption");
+
+ contentSignerBuilder.setProvider("SC");
+
+ X509CRLHolder cRLHolder = builder.build(contentSignerBuilder.build(privateKey));
+
+ if (!cRLHolder.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider("SC").build(certificate)))
+ {
+ fail("CRL signature not valid");
+ }
+
+ X509CRLEntryHolder cRLEntryHolder = cRLHolder.getRevokedCertificate(certificate.getSerialNumber());
+
+ if (!cRLEntryHolder.getCertificateIssuer().equals(new GeneralNames(new GeneralName(cRLHolder.getIssuer()))))
+ {
+ fail("certificate issuer incorrect");
+ }
+
+ JcaX509CRLConverter converter = new JcaX509CRLConverter();
+
+ converter.setProvider("SC");
+
+ X509CRL crl = converter.getCRL(cRLHolder);
+
+ crl.verify(certificate.getPublicKey());
+
+ if (!crl.isRevoked(certificate))
+ {
+ fail("Certificate should be revoked");
+ }
+
+ // now encode the CRL and load the CRL with the JCE provider
+
+ CertificateFactory fac = CertificateFactory.getInstance("X.509");
+
+ X509CRL jceCRL = (X509CRL) fac.generateCRL(new ByteArrayInputStream(crl.getEncoded()));
+
+ jceCRL.verify(certificate.getPublicKey());
+
+ if (!jceCRL.isRevoked(certificate))
+ {
+ fail("This certificate should also be revoked");
+ }
+ }
+
+ private void testIndirect()
+ throws Exception
+ {
+ KeyStore keyStore = KeyStore.getInstance("PKCS12", "SC");
+
+ ByteArrayInputStream input = new ByteArrayInputStream(testCAp12);
+
+ keyStore.load(input, "test".toCharArray());
+
+ X509Certificate certificate = (X509Certificate) keyStore.getCertificate("ca");
+ PrivateKey privateKey = (PrivateKey) keyStore.getKey("ca", null);
+
+ X500Name crlIssuer = X500Name.getInstance(certificate.getSubjectX500Principal().getEncoded());
+ X500Name caName = X500Name.getInstance(certificate.getIssuerX500Principal().getEncoded());
+
+ X509v2CRLBuilder builder = new X509v2CRLBuilder(crlIssuer, new Date());
+
+ builder.addExtension(Extension.issuingDistributionPoint, true, new IssuingDistributionPoint(null, true, false));
+
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+
+ extGen.addExtension(Extension.reasonCode, false, CRLReason.lookup(CRLReason.cACompromise));
+ extGen.addExtension(Extension.certificateIssuer, true, new GeneralNames(new GeneralName(caName)));
+
+ builder.addCRLEntry(certificate.getSerialNumber(), new Date(), extGen.generate());
+
+ JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA256WithRSAEncryption");
+
+ contentSignerBuilder.setProvider("SC");
+
+ X509CRLHolder cRLHolder = builder.build(contentSignerBuilder.build(privateKey));
+
+ if (!cRLHolder.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider("SC").build(certificate)))
+ {
+ fail("CRL signature not valid");
+ }
+
+ X509CRLEntryHolder cRLEntryHolder = cRLHolder.getRevokedCertificate(certificate.getSerialNumber());
+
+ if (!cRLEntryHolder.getCertificateIssuer().equals(new GeneralNames(new GeneralName(X500Name.getInstance(certificate.getIssuerX500Principal().getEncoded())))))
+ {
+ fail("certificate issuer incorrect");
+ }
+
+ JcaX509CRLConverter converter = new JcaX509CRLConverter();
+
+ converter.setProvider("SC");
+
+ X509CRL crl = converter.getCRL(cRLHolder);
+
+ crl.verify(certificate.getPublicKey());
+
+ if (!crl.isRevoked(certificate))
+ {
+ fail("Certificate should be revoked");
+ }
+
+ // now encode the CRL and load the CRL with the JCE provider
+
+ CertificateFactory fac = CertificateFactory.getInstance("X.509");
+
+ X509CRL jceCRL = (X509CRL) fac.generateCRL(new ByteArrayInputStream(crl.getEncoded()));
+
+ jceCRL.verify(certificate.getPublicKey());
+
+ if (!jceCRL.isRevoked(certificate))
+ {
+ fail("This certificate should also be revoked");
+ }
+ }
+
+ private void testIndirect2()
+ throws Exception
+ {
+ KeyStore keyStore = KeyStore.getInstance("PKCS12", "SC");
+
+ ByteArrayInputStream input = new ByteArrayInputStream(testCAp12);
+
+ keyStore.load(input, "test".toCharArray());
+
+ X509Certificate certificate = (X509Certificate) keyStore.getCertificate("ca");
+ PrivateKey privateKey = (PrivateKey) keyStore.getKey("ca", null);
+
+ X500Name crlIssuer = X500Name.getInstance(certificate.getSubjectX500Principal().getEncoded());
+ X500Name caName = X500Name.getInstance(certificate.getIssuerX500Principal().getEncoded());
+
+ X509v2CRLBuilder builder = new X509v2CRLBuilder(crlIssuer, new Date());
+
+ builder.addExtension(Extension.issuingDistributionPoint, true, new IssuingDistributionPoint(null, true, false));
+
+ builder.addCRLEntry(BigInteger.valueOf(100), new Date(), CRLReason.cACompromise);
+ builder.addCRLEntry(BigInteger.valueOf(120), new Date(), CRLReason.cACompromise);
+
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+
+ extGen.addExtension(Extension.reasonCode, false, CRLReason.lookup(CRLReason.cACompromise));
+ extGen.addExtension(Extension.certificateIssuer, true, new GeneralNames(new GeneralName(caName)));
+
+ builder.addCRLEntry(certificate.getSerialNumber(), new Date(), extGen.generate());
+
+ builder.addCRLEntry(BigInteger.valueOf(130), new Date(), CRLReason.cACompromise);
+
+ JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA256WithRSAEncryption");
+
+ contentSignerBuilder.setProvider("SC");
+
+ X509CRLHolder cRLHolder = builder.build(contentSignerBuilder.build(privateKey));
+
+ if (!cRLHolder.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider("SC").build(certificate)))
+ {
+ fail("CRL signature not valid");
+ }
+
+ X509CRLEntryHolder cRLEntryHolder = cRLHolder.getRevokedCertificate(certificate.getSerialNumber());
+
+ if (!cRLEntryHolder.getCertificateIssuer().equals(new GeneralNames(new GeneralName(caName))))
+ {
+ fail("certificate issuer incorrect");
+ }
+
+ cRLEntryHolder = cRLHolder.getRevokedCertificate(BigInteger.valueOf(130));
+
+ if (!cRLEntryHolder.getCertificateIssuer().equals(new GeneralNames(new GeneralName(caName))))
+ {
+ fail("certificate issuer incorrect");
+ }
+
+ cRLEntryHolder = cRLHolder.getRevokedCertificate(BigInteger.valueOf(100));
+
+ if (!cRLEntryHolder.getCertificateIssuer().equals(new GeneralNames(new GeneralName(cRLHolder.getIssuer()))))
+ {
+ fail("certificate issuer incorrect");
+ }
+
+ JcaX509CRLConverter converter = new JcaX509CRLConverter();
+
+ converter.setProvider("SC");
+
+ X509CRL crl = converter.getCRL(cRLHolder);
+
+ crl.verify(certificate.getPublicKey());
+ }
+
+ // issuing distribution point must be set for an indirect CRL to be recognised
+ private void testMalformedIndirect()
+ throws Exception
+ {
+ KeyStore keyStore = KeyStore.getInstance("PKCS12", "SC");
+
+ ByteArrayInputStream input = new ByteArrayInputStream(testCAp12);
+
+ keyStore.load(input, "test".toCharArray());
+
+ X509Certificate certificate = (X509Certificate) keyStore.getCertificate("ca");
+ PrivateKey privateKey = (PrivateKey) keyStore.getKey("ca", null);
+
+ X500Name crlIssuer = X500Name.getInstance(certificate.getSubjectX500Principal().getEncoded());
+ X500Name caName = X500Name.getInstance(certificate.getIssuerX500Principal().getEncoded());
+
+ X509v2CRLBuilder builder = new X509v2CRLBuilder(crlIssuer, new Date());
+
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+
+ extGen.addExtension(Extension.reasonCode, false, CRLReason.lookup(CRLReason.cACompromise));
+ extGen.addExtension(Extension.certificateIssuer, true, new GeneralNames(new GeneralName(caName)));
+
+ builder.addCRLEntry(certificate.getSerialNumber(), new Date(), extGen.generate());
+
+ JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA256WithRSAEncryption");
+
+ contentSignerBuilder.setProvider("SC");
+
+ X509CRLHolder cRLHolder = builder.build(contentSignerBuilder.build(privateKey));
+
+ if (!cRLHolder.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider("SC").build(certificate)))
+ {
+ fail("CRL signature not valid");
+ }
+
+ X509CRLEntryHolder cRLEntryHolder = cRLHolder.getRevokedCertificate(certificate.getSerialNumber());
+
+ if (!cRLEntryHolder.getCertificateIssuer().equals(new GeneralNames(new GeneralName(cRLHolder.getIssuer()))))
+ {
+ fail("certificate issuer incorrect");
+ }
+
+ JcaX509CRLConverter converter = new JcaX509CRLConverter();
+
+ converter.setProvider("SC");
+
+ X509CRL crl = converter.getCRL(cRLHolder);
+
+ crl.verify(certificate.getPublicKey());
+
+ if (crl.isRevoked(certificate))
+ {
+ throw new Exception("Certificate should not be revoked");
+ }
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ testDirect();
+ testIndirect();
+ testIndirect2();
+ testMalformedIndirect();
+
+ checkCertificate(1, cert1);
+ checkCertificate(2, cert2);
+ checkCertificate(3, cert3);
+ checkCertificate(4, cert4);
+ checkCertificate(5, cert5);
+ checkCertificate(6, oldEcdsa);
+ checkCertificate(7, cert7);
+
+ checkKeyUsage(8, keyUsage);
+ checkSelfSignedCertificate(9, uncompressedPtEC);
+ checkNameCertificate(10, nameCert);
+
+ checkSelfSignedCertificate(11, probSelfSignedCert);
+ checkSelfSignedCertificate(12, gostCA1);
+ checkSelfSignedCertificate(13, gostCA2);
+ checkSelfSignedCertificate(14, gost341094base);
+ checkSelfSignedCertificate(15, gost34102001base);
+ checkSelfSignedCertificate(16, gost341094A);
+ checkSelfSignedCertificate(17, gost341094B);
+ checkSelfSignedCertificate(17, gost34102001A);
+
+ checkCRL(1, crl1);
+
+ checkCreation1();
+ checkCreation2();
+ checkCreation3();
+ checkCreation4();
+ checkCreation5();
+
+ createECCert("SHA1withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ createECCert("SHA224withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ createECCert("SHA256withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ createECCert("SHA384withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ createECCert("SHA512withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+
+ createPSSCert("SHA1withRSAandMGF1");
+ createPSSCert("SHA224withRSAandMGF1");
+ createPSSCert("SHA256withRSAandMGF1");
+ createPSSCert("SHA384withRSAandMGF1");
+
+ checkCRLCreation1();
+ checkCRLCreation2();
+ checkCRLCreation3();
+
+ pemTest();
+ pkcs7Test();
+ rfc4491Test();
+
+ testForgedSignature();
+
+ testNullDerNullCert();
+
+ checkCertificate(18, emptyDNCert);
+ }
+
+ public static void main(
+ String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new CertTest());
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/jdk1.4/org/spongycastle/cms/test/NewEnvelopedDataTest.java b/libraries/spongycastle/pkix/src/test/jdk1.4/org/spongycastle/cms/test/NewEnvelopedDataTest.java
new file mode 100644
index 000000000..57205f2a0
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/jdk1.4/org/spongycastle/cms/test/NewEnvelopedDataTest.java
@@ -0,0 +1,1317 @@
+package org.spongycastle.cms.test;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.DERUTF8String;
+import org.spongycastle.asn1.cms.Attribute;
+import org.spongycastle.asn1.cms.AttributeTable;
+import org.spongycastle.asn1.kisa.KISAObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.ntt.NTTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RC2CBCParameter;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.cert.jcajce.JcaX509CertificateHolder;
+import org.spongycastle.cms.CMSAlgorithm;
+import org.spongycastle.cms.CMSEnvelopedData;
+import org.spongycastle.cms.CMSEnvelopedDataGenerator;
+import org.spongycastle.cms.CMSException;
+import org.spongycastle.cms.CMSProcessableByteArray;
+import org.spongycastle.cms.KeyTransRecipientInformation;
+import org.spongycastle.cms.OriginatorInfoGenerator;
+import org.spongycastle.cms.OriginatorInformation;
+import org.spongycastle.cms.PasswordRecipient;
+import org.spongycastle.cms.PasswordRecipientInformation;
+import org.spongycastle.cms.RecipientId;
+import org.spongycastle.cms.RecipientInformation;
+import org.spongycastle.cms.RecipientInformationStore;
+import org.spongycastle.cms.SimpleAttributeTableGenerator;
+import org.spongycastle.cms.bc.BcCMSContentEncryptorBuilder;
+import org.spongycastle.cms.bc.BcRSAKeyTransRecipientInfoGenerator;
+import org.spongycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
+import org.spongycastle.cms.jcajce.JceKEKEnvelopedRecipient;
+import org.spongycastle.cms.jcajce.JceKEKRecipientInfoGenerator;
+import org.spongycastle.cms.jcajce.JceKeyAgreeEnvelopedRecipient;
+import org.spongycastle.cms.jcajce.JceKeyAgreeRecipientId;
+import org.spongycastle.cms.jcajce.JceKeyAgreeRecipientInfoGenerator;
+import org.spongycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
+import org.spongycastle.cms.jcajce.JceKeyTransRecipientId;
+import org.spongycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
+import org.spongycastle.cms.jcajce.JcePasswordEnvelopedRecipient;
+import org.spongycastle.cms.jcajce.JcePasswordRecipientInfoGenerator;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.operator.OutputEncryptor;
+import org.spongycastle.operator.jcajce.JcaAlgorithmParametersConverter;
+import org.spongycastle.util.encoders.Base64;
+import org.spongycastle.util.encoders.Hex;
+
+public class NewEnvelopedDataTest
+ extends TestCase
+{
+ private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ private static String _signDN;
+ private static KeyPair _signKP;
+ private static X509Certificate _signCert;
+
+ private static String _origDN;
+ private static KeyPair _origKP;
+ private static X509Certificate _origCert;
+
+ private static String _reciDN;
+ private static String _reciDN2;
+ private static KeyPair _reciKP;
+ private static KeyPair _reciOaepKP;
+ private static X509Certificate _reciCert;
+ private static X509Certificate _reciCertOaep;
+
+ private static KeyPair _origEcKP;
+ private static KeyPair _reciEcKP;
+ private static X509Certificate _reciEcCert;
+ private static KeyPair _reciEcKP2;
+ private static X509Certificate _reciEcCert2;
+
+ private static boolean _initialised = false;
+
+ private byte[] oldKEK = Base64.decode(
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxQaI/MD0CAQQwBwQFAQIDBAUwDQYJYIZIAWUDBAEFBQAEI"
+ + "Fi2eHTPM4bQSjP4DUeDzJZLpfemW2gF1SPq7ZPHJi1mMIAGCSqGSIb3DQEHATAUBggqhkiG9w"
+ + "0DBwQImtdGyUdGGt6ggAQYk9X9z01YFBkU7IlS3wmsKpm/zpZClTceAAAAAAAAAAAAAA==");
+
+ private byte[] ecKeyAgreeMsgAES256 = Base64.decode(
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxgcShgcECAQOgQ6FBMAsGByqGSM49AgEF"
+ + "AAMyAAPdXlSTpub+qqno9hUGkUDl+S3/ABhPziIB5yGU4678tgOgU5CiKG9Z"
+ + "kfnabIJ3nZYwGgYJK4EFEIZIPwACMA0GCWCGSAFlAwQBLQUAMFswWTAtMCgx"
+ + "EzARBgNVBAMTCkFkbWluLU1EU0UxETAPBgNVBAoTCDRCQ1QtMklEAgEBBCi/"
+ + "rJRLbFwEVW6PcLLmojjW9lI/xGD7CfZzXrqXFw8iHaf3hTRau1gYMIAGCSqG"
+ + "SIb3DQEHATAdBglghkgBZQMEASoEEMtCnKKPwccmyrbgeSIlA3qggAQQDLw8"
+ + "pNJR97bPpj6baG99bQQQwhEDsoj5Xg1oOxojHVcYzAAAAAAAAAAAAAA=");
+
+ private byte[] ecKeyAgreeMsgAES128 = Base64.decode(
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxgbShgbECAQOgQ6FBMAsGByqGSM49AgEF"
+ + "AAMyAAL01JLEgKvKh5rbxI/hOxs/9WEezMIsAbUaZM4l5tn3CzXAN505nr5d"
+ + "LhrcurMK+tAwGgYJK4EFEIZIPwACMA0GCWCGSAFlAwQBBQUAMEswSTAtMCgx"
+ + "EzARBgNVBAMTCkFkbWluLU1EU0UxETAPBgNVBAoTCDRCQ1QtMklEAgEBBBhi"
+ + "FLjc5g6aqDT3f8LomljOwl1WTrplUT8wgAYJKoZIhvcNAQcBMB0GCWCGSAFl"
+ + "AwQBAgQQzXjms16Y69S/rB0EbHqRMaCABBAFmc/QdVW6LTKdEy97kaZzBBBa"
+ + "fQuviUS03NycpojELx0bAAAAAAAAAAAAAA==");
+
+ private byte[] ecKeyAgreeMsgDESEDE = Base64.decode(
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxgcahgcMCAQOgQ6FBMAsGByqGSM49AgEF"
+ + "AAMyAALIici6Nx1WN5f0ThH2A8ht9ovm0thpC5JK54t73E1RDzCifePaoQo0"
+ + "xd6sUqoyGaYwHAYJK4EFEIZIPwACMA8GCyqGSIb3DQEJEAMGBQAwWzBZMC0w"
+ + "KDETMBEGA1UEAxMKQWRtaW4tTURTRTERMA8GA1UEChMINEJDVC0ySUQCAQEE"
+ + "KJuqZQ1NB1vXrKPOnb4TCpYOsdm6GscWdwAAZlm2EHMp444j0s55J9wwgAYJ"
+ + "KoZIhvcNAQcBMBQGCCqGSIb3DQMHBAjwnsDMsafCrKCABBjyPvqFOVMKxxut"
+ + "VfTx4fQlNGJN8S2ATRgECMcTQ/dsmeViAAAAAAAAAAAAAA==");
+
+ private byte[] ecMQVKeyAgreeMsgAES128 = Base64.decode(
+ "MIAGCSqGSIb3DQEHA6CAMIACAQIxgf2hgfoCAQOgQ6FBMAsGByqGSM49AgEF"
+ + "AAMyAAPDKU+0H58tsjpoYmYCInMr/FayvCCkupebgsnpaGEB7qS9vzcNVUj6"
+ + "mrnmiC2grpmhRwRFMEMwQTALBgcqhkjOPQIBBQADMgACZpD13z9c7DzRWx6S"
+ + "0xdbq3S+EJ7vWO+YcHVjTD8NcQDcZcWASW899l1PkL936zsuMBoGCSuBBRCG"
+ + "SD8AEDANBglghkgBZQMEAQUFADBLMEkwLTAoMRMwEQYDVQQDEwpBZG1pbi1N"
+ + "RFNFMREwDwYDVQQKEwg0QkNULTJJRAIBAQQYFq58L71nyMK/70w3nc6zkkRy"
+ + "RL7DHmpZMIAGCSqGSIb3DQEHATAdBglghkgBZQMEAQIEEDzRUpreBsZXWHBe"
+ + "onxOtSmggAQQ7csAZXwT1lHUqoazoy8bhAQQq+9Zjj8iGdOWgyebbfj67QAA"
+ + "AAAAAAAAAAA=");
+
+
+ private byte[] ecKeyAgreeKey = Base64.decode(
+ "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDC8vp7xVTbKSgYVU5Wc"
+ + "hGkWbzaj+yUFETIWP1Dt7+WSpq3ikSPdl7PpHPqnPVZfoIWhZANiAgSYHTgxf+Dd"
+ + "Tt84dUvuSKkFy3RhjxJmjwIscK6zbEUzKhcPQG2GHzXhWK5x1kov0I74XpGhVkya"
+ + "ElH5K6SaOXiXAzcyNGggTOk4+ZFnz5Xl0pBje3zKxPhYu0SnCw7Pcqw=");
+
+ private byte[] bobPrivRsaEncrypt = Base64.decode(
+ "MIIChQIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKnhZ5g/OdVf"
+ + "8qCTQV6meYmFyDVdmpFb+x0B2hlwJhcPvaUi0DWFbXqYZhRBXM+3twg7CcmR"
+ + "uBlpN235ZR572akzJKN/O7uvRgGGNjQyywcDWVL8hYsxBLjMGAgUSOZPHPtd"
+ + "YMTgXB9T039T2GkB8QX4enDRvoPGXzjPHCyqaqfrAgMBAAECgYBnzUhMmg2P"
+ + "mMIbZf8ig5xt8KYGHbztpwOIlPIcaw+LNd4Ogngwy+e6alatd8brUXlweQqg"
+ + "9P5F4Kmy9Bnah5jWMIR05PxZbMHGd9ypkdB8MKCixQheIXFD/A0HPfD6bRSe"
+ + "TmPwF1h5HEuYHD09sBvf+iU7o8AsmAX2EAnYh9sDGQJBANDDIsbeopkYdo+N"
+ + "vKZ11mY/1I1FUox29XLE6/BGmvE+XKpVC5va3Wtt+Pw7PAhDk7Vb/s7q/WiE"
+ + "I2Kv8zHCueUCQQDQUfweIrdb7bWOAcjXq/JY1PeClPNTqBlFy2bKKBlf4hAr"
+ + "84/sajB0+E0R9KfEILVHIdxJAfkKICnwJAiEYH2PAkA0umTJSChXdNdVUN5q"
+ + "SO8bKlocSHseIVnDYDubl6nA7xhmqU5iUjiEzuUJiEiUacUgFJlaV/4jbOSn"
+ + "I3vQgLeFAkEAni+zN5r7CwZdV+EJBqRd2ZCWBgVfJAZAcpw6iIWchw+dYhKI"
+ + "FmioNRobQ+g4wJhprwMKSDIETukPj3d9NDAlBwJAVxhn1grStavCunrnVNqc"
+ + "BU+B1O8BiR4yPWnLMcRSyFRVJQA7HCp8JlDV6abXd8vPFfXuC9WN7rOvTKF8"
+ + "Y0ZB9qANMAsGA1UdDzEEAwIAEA==");
+
+ private byte[] rfc4134ex5_1 = Base64.decode(
+ "MIIBHgYJKoZIhvcNAQcDoIIBDzCCAQsCAQAxgcAwgb0CAQAwJjASMRAwDgYD"
+ + "VQQDEwdDYXJsUlNBAhBGNGvHgABWvBHTbi7NXXHQMA0GCSqGSIb3DQEBAQUA"
+ + "BIGAC3EN5nGIiJi2lsGPcP2iJ97a4e8kbKQz36zg6Z2i0yx6zYC4mZ7mX7FB"
+ + "s3IWg+f6KgCLx3M1eCbWx8+MDFbbpXadCDgO8/nUkUNYeNxJtuzubGgzoyEd"
+ + "8Ch4H/dd9gdzTd+taTEgS0ipdSJuNnkVY4/M652jKKHRLFf02hosdR8wQwYJ"
+ + "KoZIhvcNAQcBMBQGCCqGSIb3DQMHBAgtaMXpRwZRNYAgDsiSf8Z9P43LrY4O"
+ + "xUk660cu1lXeCSFOSOpOJ7FuVyU=");
+
+ private byte[] rfc4134ex5_2 = Base64.decode(
+ "MIIBZQYJKoZIhvcNAQcDoIIBVjCCAVICAQIxggEAMIG9AgEAMCYwEjEQMA4G"
+ + "A1UEAxMHQ2FybFJTQQIQRjRrx4AAVrwR024uzV1x0DANBgkqhkiG9w0BAQEF"
+ + "AASBgJQmQojGi7Z4IP+CVypBmNFoCDoEp87khtgyff2N4SmqD3RxPx+8hbLQ"
+ + "t9i3YcMwcap+aiOkyqjMalT03VUC0XBOGv+HYI3HBZm/aFzxoq+YOXAWs5xl"
+ + "GerZwTOc9j6AYlK4qXvnztR5SQ8TBjlzytm4V7zg+TGrnGVNQBNw47Ewoj4C"
+ + "AQQwDQQLTWFpbExpc3RSQzIwEAYLKoZIhvcNAQkQAwcCAToEGHcUr5MSJ/g9"
+ + "HnJVHsQ6X56VcwYb+OfojTBJBgkqhkiG9w0BBwEwGgYIKoZIhvcNAwIwDgIC"
+ + "AKAECJwE0hkuKlWhgCBeKNXhojuej3org9Lt7n+wWxOhnky5V50vSpoYRfRR"
+ + "yw==");
+
+ private byte[] tooShort3DES = Base64.decode(
+ "MIAGCSqGSIb3DQEHA6CAMIACAQAxgcQwgcECAQAwKjAlMRYwFAYDVQQKDA1C" +
+ "b3VuY3kgQ2FzdGxlMQswCQYDVQQGEwJBVQIBCjANBgkqhkiG9w0BAQEFAASB" +
+ "gJIM2QN0o6iv8Ux018pVCJ8js+ROV4t6+KoMwLJ4DzRKLU8XCAb9BS+crP+F" +
+ "ghNTxTpTX8TaxPrO4wV0USgVHu2SvFnxNaWZjBDVIyZI2HR4QkSTqFMhsUB2" +
+ "6CuZIWBZkhqQ6ruDfvn9UuBWVnfsBD4iryZ1idr713sDeVo5TyvTMIAGCSqG" +
+ "SIb3DQEHATAUBggqhkiG9w0DBwQIQq9e4+WB3CqggAQIwU4cOlmkWUcAAAAA" +
+ "AAAAAAAA");
+
+ private byte[] tooShort3DESKey = Base64.decode(
+ "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAODZDCj0nQdV" +
+ "f0GGeFsPjjvPx1Vem0V6IkJ4SzazGKfddk0pX58ZDCnG+S+OPiXmPDqValiu" +
+ "9FtNy2/r9rrf/6qtcVQJkfSJv9E5Y7HgI98L/Y9lKxZWsfRqu/SlYO5zx0Dc" +
+ "2rzDvvZRtrtaq0uuHXWJlbWda2L9S65sv/Le/zvjAgMBAAECgYEAnn+iGMTG" +
+ "ZMMaH6Cg+t/uTa9cPougPMuplt2hd3+sY7izihUeONK5RkHiqmlE2gaAcnOd" +
+ "McKysiIWxGC73mPEnsOObPkaFlneVb5CtjTaTMdptuLNEQkwvtKhuW2HnMra" +
+ "4afEgFZdll3FyRpvW/CDooe4Bppjd4aGn/Sr/o9nOzECQQD4QKLwZssuclji" +
+ "nD/8gU1CqGMMnGNogTMpHm1269HUOE7r1y3MuapUqSWsVhpuEQ8P/Tko0haJ" +
+ "jeZn2eWTbZu/AkEA591snui8FMeGvkRgvyMFNvXZWDEjsh+N74XEL1lykTgZ" +
+ "FQJ+cmThnrdM/8yj1dKkdASYrk5kFJ4PVE6CzDI43QJAFS22eNncJZc9u/9m" +
+ "eg0x4SjqYk4JMQYsripZXlbZ7Mfs+7O8xYVlYZmYjC5ATPmJlmyc7r2VjKCd" +
+ "cmilbEFikwJBAMh7yf8BaBdjitubzjeW9VxXaa37F01eQWD5PfBfHFP6uJ1V" +
+ "AbayCfAtuHN6I7OwJih3DPmyqJC3NrQECs67IjUCQAb4TfVE/2G1s66SGnb4" +
+ "no34BspoV/i4f0uLhJap84bTHcF/ZRSXCmQOCRGdSvQkXHeNPI5Lus6lOHuU" +
+ "vUDbQC8=");
+
+ public NewEnvelopedDataTest()
+ {
+ }
+
+ private static void init()
+ throws Exception
+ {
+ if (!_initialised)
+ {
+ _initialised = true;
+
+ _signDN = "O=Bouncy Castle, C=AU";
+ _signKP = CMSTestUtil.makeKeyPair();
+ _signCert = CMSTestUtil.makeCertificate(_signKP, _signDN, _signKP, _signDN);
+
+ _origDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+ _origKP = CMSTestUtil.makeKeyPair();
+ _origCert = CMSTestUtil.makeCertificate(_origKP, _origDN, _signKP, _signDN);
+
+ _reciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+ _reciDN2 = "CN=Fred, OU=Sales, O=Bouncy Castle, C=AU";
+ _reciKP = CMSTestUtil.makeKeyPair();
+ _reciCert = CMSTestUtil.makeCertificate(_reciKP, _reciDN, _signKP, _signDN);
+ _reciCertOaep = CMSTestUtil.makeOaepCertificate(_reciKP, _reciDN, _signKP, _signDN);
+
+ _origEcKP = CMSTestUtil.makeEcDsaKeyPair();
+ _reciEcKP = CMSTestUtil.makeEcDsaKeyPair();
+ _reciEcCert = CMSTestUtil.makeCertificate(_reciEcKP, _reciDN, _signKP, _signDN);
+ _reciEcKP2 = CMSTestUtil.makeEcDsaKeyPair();
+ _reciEcCert2 = CMSTestUtil.makeCertificate(_reciEcKP2, _reciDN2, _signKP, _signDN);
+ }
+ }
+
+ public static void main(
+ String args[])
+ throws Exception
+ {
+ junit.textui.TestRunner.run(NewEnvelopedDataTest.suite());
+ }
+
+ public static Test suite()
+ throws Exception
+ {
+ init();
+
+ return new CMSTestSetup(new TestSuite(NewEnvelopedDataTest.class));
+ }
+
+ public void testUnprotectedAttributes()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ Hashtable attrs = new Hashtable();
+
+ attrs.put(PKCSObjectIdentifiers.id_aa_contentHint, new Attribute(PKCSObjectIdentifiers.id_aa_contentHint, new DERSet(new DERUTF8String("Hint"))));
+ attrs.put(PKCSObjectIdentifiers.id_aa_receiptRequest, new Attribute(PKCSObjectIdentifiers.id_aa_receiptRequest, new DERSet(new DERUTF8String("Request"))));
+
+ AttributeTable attrTable = new AttributeTable(attrs);
+
+ edGen.setUnprotectedAttributeGenerator(new SimpleAttributeTableGenerator(attrTable));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ attrTable = ed.getUnprotectedAttributes();
+
+ assertEquals(attrs.size(), 2);
+
+ assertEquals(new DERUTF8String("Hint"), attrTable.get(PKCSObjectIdentifiers.id_aa_contentHint).getAttrValues().getObjectAt(0));
+ assertEquals(new DERUTF8String("Request"), attrTable.get(PKCSObjectIdentifiers.id_aa_receiptRequest).getAttrValues().getObjectAt(0));
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ }
+
+ public void testKeyTrans()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(ASN1OctetString.getInstance(ASN1OctetString.getInstance(_reciCert.getExtensionValue(Extension.subjectKeyIdentifier.getId())).getOctets()).getOctets(), _reciCert.getPublicKey()).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(2, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+
+ RecipientId id = new JceKeyTransRecipientId(_reciCert);
+
+ Collection collection = recipients.getRecipients(id);
+ if (collection.size() != 2)
+ {
+ fail("recipients not matched using general recipient ID.");
+ }
+ assertTrue(collection.iterator().next() instanceof RecipientInformation);
+ }
+
+ public void testKeyTransWithAlgMapping()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA/2/PKCS1Padding").setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA/2/PKCS1Padding").setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+
+ RecipientId id = new JceKeyTransRecipientId(_reciCert);
+
+ Collection collection = recipients.getRecipients(id);
+ if (collection.size() != 1)
+ {
+ fail("recipients not matched using general recipient ID.");
+ }
+ assertTrue(collection.iterator().next() instanceof RecipientInformation);
+ }
+
+ public void testOriginatorInfoGeneration()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ X509CertificateHolder origCert = new X509CertificateHolder(_origCert.getEncoded());
+
+ edGen.setOriginatorInfo(new OriginatorInfoGenerator(origCert).generate());
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(ASN1OctetString.getInstance(ASN1OctetString.getInstance(_reciCert.getExtensionValue(Extension.subjectKeyIdentifier.getId())).getOctets()).getOctets(), _reciCert.getPublicKey()).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ assertTrue(ed.getOriginatorInfo().getCertificates().getMatches(null).contains(origCert));
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(2, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+
+ RecipientId id = new JceKeyTransRecipientId(_reciCert);
+
+ Collection collection = recipients.getRecipients(id);
+ if (collection.size() != 2)
+ {
+ fail("recipients not matched using general recipient ID.");
+ }
+ assertTrue(collection.iterator().next() instanceof RecipientInformation);
+ }
+
+ public void testKeyTransRC2bit40()
+ throws Exception
+ {
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.RC2_CBC, 40).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getContentEncryptionAlgorithm().getAlgorithm(), CMSAlgorithm.RC2_CBC);
+
+ RC2CBCParameter rc2P = RC2CBCParameter.getInstance(ed.getContentEncryptionAlgorithm().getParameters());
+ assertEquals(160, rc2P.getRC2ParameterVersion().intValue());
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ }
+
+ public void testKeyTransRC4()
+ throws Exception
+ {
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.2.840.113549.3.4")).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), "1.2.840.113549.3.4");
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ }
+
+ public void testKeyTrans128RC4()
+ throws Exception
+ {
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.2.840.113549.3.4"), 128).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), "1.2.840.113549.3.4");
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testKeyTransLight128RC4()
+ throws Exception
+ {
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new BcRSAKeyTransRecipientInfoGenerator(new JcaX509CertificateHolder(_reciCert)));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.2.840.113549.3.4"), 128).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), "1.2.840.113549.3.4");
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testKeyTransODES()
+ throws Exception
+ {
+ byte[] data = "WallaWallaBouncyCastle".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(new ASN1ObjectIdentifier("1.3.14.3.2.7")).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), "1.3.14.3.2.7");
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testKeyTransSmallAES()
+ throws Exception
+ {
+ byte[] data = new byte[] { 0, 1, 2, 3 };
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(),
+ CMSEnvelopedDataGenerator.AES128_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testKeyTransDESEDE3Short()
+ throws Exception
+ {
+ byte[] data = new byte[] { 0, 1, 2, 3 };
+ KeyFactory kf = KeyFactory.getInstance("RSA", BC);
+ PrivateKey kPriv = kf.generatePrivate(new PKCS8EncodedKeySpec(tooShort3DESKey));
+
+ CMSEnvelopedData ed = new CMSEnvelopedData(tooShort3DES);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+ try
+ {
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(kPriv).setKeySizeValidation(true).setProvider(BC));
+ fail("invalid 3DES-EDE key not picked up");
+ }
+ catch (CMSException e)
+ {
+ assertEquals("Expected key size for algorithm OID not found in recipient.", e.getMessage());
+ }
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(kPriv).setKeySizeValidation(false).setProvider(BC));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testKeyTransDESEDE3Light()
+ throws Exception
+ {
+ byte[] data = new byte[] { 0, 1, 2, 3 };
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new BcRSAKeyTransRecipientInfoGenerator(new JcaX509CertificateHolder(_reciCert)));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new BcCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC, 192).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setKeySizeValidation(true).setProvider(BC));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testKeyTransDES()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.DES_CBC, CMSAlgorithm.DES_CBC, 8, DEROctetString.class);
+ }
+
+ public void testKeyTransCAST5()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.CAST5_CBC, CMSAlgorithm.CAST5_CBC, 16, ASN1Sequence.class);
+ }
+
+ public void testKeyTransAES128()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.AES128_CBC, NISTObjectIdentifiers.id_aes128_CBC, 16, DEROctetString.class);
+ }
+
+ public void testKeyTransAES192()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.AES192_CBC, NISTObjectIdentifiers.id_aes192_CBC, 24, DEROctetString.class);
+ }
+
+ public void testKeyTransAES256()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.AES256_CBC, NISTObjectIdentifiers.id_aes256_CBC, 32, DEROctetString.class);
+ }
+
+ public void testKeyTransSEED()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.SEED_CBC, KISAObjectIdentifiers.id_seedCBC, 16, DEROctetString.class);
+ }
+
+ public void testKeyTransCamellia128()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.CAMELLIA128_CBC, NTTObjectIdentifiers.id_camellia128_cbc, 16, DEROctetString.class);
+ }
+
+ public void testKeyTransCamellia192()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.CAMELLIA192_CBC, NTTObjectIdentifiers.id_camellia192_cbc, 24, DEROctetString.class);
+ }
+
+ public void testKeyTransCamellia256()
+ throws Exception
+ {
+ tryKeyTrans(CMSAlgorithm.CAMELLIA256_CBC, NTTObjectIdentifiers.id_camellia256_cbc, 32, DEROctetString.class);
+ }
+
+ private void tryKeyTrans(ASN1ObjectIdentifier generatorOID, ASN1ObjectIdentifier checkOID, int keySize, Class asn1Params)
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+
+ OutputEncryptor encryptor = new JceCMSContentEncryptorBuilder(generatorOID).setProvider(BC).build();
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ encryptor);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(checkOID.getId(), ed.getEncryptionAlgOID());
+ assertEquals(keySize, ((byte[])encryptor.getKey().getRepresentation()).length);
+
+ if (asn1Params != null)
+ {
+ ASN1InputStream aIn = new ASN1InputStream(ed.getEncryptionAlgParams());
+
+ assertTrue(asn1Params.isAssignableFrom(aIn.readObject().getClass()));
+ }
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(1, c.size());
+
+ Iterator it = c.iterator();
+
+ if (!it.hasNext())
+ {
+ fail("no recipients found");
+ }
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setKeySizeValidation(true).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ }
+
+ public void testErroneousKEK()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+ SecretKey kek = new SecretKeySpec(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, "AES");
+
+ CMSEnvelopedData ed = new CMSEnvelopedData(oldKEK);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), NISTObjectIdentifiers.id_aes128_wrap.getId());
+
+ byte[] recData = recipient.getContent(new JceKEKEnvelopedRecipient(kek).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testDESKEK()
+ throws Exception
+ {
+ tryKekAlgorithm(CMSTestUtil.makeDesede192Key(), new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.6"));
+ }
+ public void testRC2128KEK()
+ throws Exception
+ {
+ tryKekAlgorithm(CMSTestUtil.makeRC2128Key(), new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.7"));
+ }
+
+ public void testAES128KEK()
+ throws Exception
+ {
+ tryKekAlgorithm(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap);
+ }
+
+ public void testAES192KEK()
+ throws Exception
+ {
+ tryKekAlgorithm(CMSTestUtil.makeAESKey(192), NISTObjectIdentifiers.id_aes192_wrap);
+ }
+
+ public void testAES256KEK()
+ throws Exception
+ {
+ tryKekAlgorithm(CMSTestUtil.makeAESKey(256), NISTObjectIdentifiers.id_aes256_wrap);
+ }
+
+ public void testSEED128KEK()
+ throws Exception
+ {
+ tryKekAlgorithm(CMSTestUtil.makeSEEDKey(), KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap);
+ }
+
+ public void testCamellia128KEK()
+ throws Exception
+ {
+ tryKekAlgorithm(CMSTestUtil.makeCamelliaKey(128), NTTObjectIdentifiers.id_camellia128_wrap);
+ }
+
+ public void testCamellia192KEK()
+ throws Exception
+ {
+ tryKekAlgorithm(CMSTestUtil.makeCamelliaKey(192), NTTObjectIdentifiers.id_camellia192_wrap);
+ }
+
+ public void testCamellia256KEK()
+ throws Exception
+ {
+ tryKekAlgorithm(CMSTestUtil.makeCamelliaKey(256), NTTObjectIdentifiers.id_camellia256_wrap);
+ }
+
+ private void tryKekAlgorithm(SecretKey kek, ASN1ObjectIdentifier algOid)
+ throws NoSuchAlgorithmException, NoSuchProviderException, CMSException
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ byte[] kekId = new byte[] { 1, 2, 3, 4, 5 };
+
+ edGen.addRecipientInfoGenerator(new JceKEKRecipientInfoGenerator(kekId, kek).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(algOid.getId(), recipient.getKeyEncryptionAlgOID());
+
+ byte[] recData = recipient.getContent(new JceKEKEnvelopedRecipient(kek).setKeySizeValidation(true).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testECKeyAgree()
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyAgreeRecipientInfoGenerator(CMSAlgorithm.ECDH_SHA1KDF,
+ _origEcKP.getPrivate(), _origEcKP.getPublic(),
+ CMSAlgorithm.AES128_WRAP).addRecipient(_reciEcCert).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.AES128_CBC);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ confirmDataReceived(recipients, data, _reciEcCert, _reciEcKP.getPrivate(), BC);
+ confirmNumberRecipients(recipients, 1);
+ }
+
+ public void testECMQVKeyAgree()
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyAgreeRecipientInfoGenerator(CMSAlgorithm.ECMQV_SHA1KDF,
+ _origEcKP.getPrivate(), _origEcKP.getPublic(),
+ CMSAlgorithm.AES128_WRAP).addRecipient(_reciEcCert).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.AES128_CBC);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ confirmDataReceived(recipients, data, _reciEcCert, _reciEcKP.getPrivate(), BC);
+ confirmNumberRecipients(recipients, 1);
+ }
+
+ public void testECMQVKeyAgreeMultiple()
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ JceKeyAgreeRecipientInfoGenerator recipientGenerator = new JceKeyAgreeRecipientInfoGenerator(CMSAlgorithm.ECMQV_SHA1KDF,
+ _origEcKP.getPrivate(), _origEcKP.getPublic(), CMSAlgorithm.AES128_WRAP).setProvider(BC);
+
+ recipientGenerator.addRecipient(_reciEcCert);
+ recipientGenerator.addRecipient(_reciEcCert2);
+
+ edGen.addRecipientInfoGenerator(recipientGenerator);
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.AES128_CBC);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ confirmDataReceived(recipients, data, _reciEcCert, _reciEcKP.getPrivate(), BC);
+ confirmDataReceived(recipients, data, _reciEcCert2, _reciEcKP2.getPrivate(), BC);
+ confirmNumberRecipients(recipients, 2);
+ }
+
+ private static void confirmDataReceived(RecipientInformationStore recipients,
+ byte[] expectedData, X509Certificate reciCert, PrivateKey reciPrivKey, String provider)
+ throws CMSException, NoSuchProviderException, CertificateEncodingException, IOException
+ {
+ RecipientId rid = new JceKeyAgreeRecipientId(reciCert);
+
+ RecipientInformation recipient = recipients.get(rid);
+ assertNotNull(recipient);
+
+ byte[] actualData = recipient.getContent(new JceKeyAgreeEnvelopedRecipient(reciPrivKey).setProvider(provider));
+ assertEquals(true, Arrays.equals(expectedData, actualData));
+ }
+
+ private static void confirmNumberRecipients(RecipientInformationStore recipients, int count)
+ {
+ assertEquals(count, recipients.getRecipients().size());
+ }
+
+ public void testECKeyAgreeVectors()
+ throws Exception
+ {
+ PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(ecKeyAgreeKey);
+ KeyFactory fact = KeyFactory.getInstance("ECDH", BC);
+ PrivateKey privKey = fact.generatePrivate(privSpec);
+
+ verifyECKeyAgreeVectors(privKey, "2.16.840.1.101.3.4.1.42", ecKeyAgreeMsgAES256);
+ verifyECKeyAgreeVectors(privKey, "2.16.840.1.101.3.4.1.2", ecKeyAgreeMsgAES128);
+ verifyECKeyAgreeVectors(privKey, "1.2.840.113549.3.7", ecKeyAgreeMsgDESEDE);
+ }
+
+ public void testECMQVKeyAgreeVectors()
+ throws Exception
+ {
+ PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(ecKeyAgreeKey);
+ KeyFactory fact = KeyFactory.getInstance("ECDH", BC);
+ PrivateKey privKey = fact.generatePrivate(privSpec);
+
+ verifyECMQVKeyAgreeVectors(privKey, "2.16.840.1.101.3.4.1.2", ecMQVKeyAgreeMsgAES128);
+ }
+
+ public void testPasswordAES256()
+ throws Exception
+ {
+ passwordTest(CMSEnvelopedDataGenerator.AES256_CBC);
+ passwordUTF8Test(CMSEnvelopedDataGenerator.AES256_CBC);
+ }
+
+ public void testPasswordDESEDE()
+ throws Exception
+ {
+ passwordTest(CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+ passwordUTF8Test(CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+ }
+
+ public void testRFC4134ex5_1()
+ throws Exception
+ {
+ byte[] data = Hex.decode("5468697320697320736f6d652073616d706c6520636f6e74656e742e");
+
+ KeyFactory kFact = KeyFactory.getInstance("RSA", BC);
+ Key key = kFact.generatePrivate(new PKCS8EncodedKeySpec(bobPrivRsaEncrypt));
+
+ CMSEnvelopedData ed = new CMSEnvelopedData(rfc4134ex5_1);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals("1.2.840.113549.3.7", ed.getEncryptionAlgOID());
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient((PrivateKey)key).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testRFC4134ex5_2()
+ throws Exception
+ {
+ byte[] data = Hex.decode("5468697320697320736f6d652073616d706c6520636f6e74656e742e");
+
+ KeyFactory kFact = KeyFactory.getInstance("RSA", BC);
+ PrivateKey key = kFact.generatePrivate(new PKCS8EncodedKeySpec(bobPrivRsaEncrypt));
+
+ CMSEnvelopedData ed = new CMSEnvelopedData(rfc4134ex5_2);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals("1.2.840.113549.3.2", ed.getEncryptionAlgOID());
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+ byte[] recData;
+
+ if (recipient instanceof KeyTransRecipientInformation)
+ {
+ recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(key).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ }
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ public void testOriginatorInfo()
+ throws Exception
+ {
+ CMSEnvelopedData env = new CMSEnvelopedData(CMSSampleMessages.originatorMessage);
+
+ RecipientInformationStore recipients = env.getRecipientInfos();
+
+ OriginatorInformation origInfo = env.getOriginatorInfo();
+
+ assertEquals(new X500Name("C=US,O=U.S. Government,OU=HSPD12Lab,OU=Agents,CN=user1"), ((X509CertificateHolder)origInfo.getCertificates().getMatches(null).iterator().next()).getSubject());
+ assertEquals(CMSEnvelopedDataGenerator.DES_EDE3_CBC, env.getEncryptionAlgOID());
+ }
+
+ private void passwordTest(String algorithm)
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JcePasswordRecipientInfoGenerator(new ASN1ObjectIdentifier(algorithm), "password".toCharArray()).setProvider(BC).setPasswordConversionScheme(PasswordRecipient.PKCS5_SCHEME2).setSaltAndIterationCount(new byte[20], 5));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(),
+ CMSEnvelopedDataGenerator.AES128_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ PasswordRecipientInformation recipient = (PasswordRecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JcePasswordEnvelopedRecipient("password".toCharArray()).setPasswordConversionScheme(PasswordRecipient.PKCS5_SCHEME2).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+
+ //
+ // try algorithm parameters constructor
+ //
+ it = c.iterator();
+
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JcePasswordEnvelopedRecipient("password".toCharArray()).setPasswordConversionScheme(PasswordRecipient.PKCS5_SCHEME2).setProvider(BC));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+
+ private void passwordUTF8Test(String algorithm)
+ throws Exception
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JcePasswordRecipientInfoGenerator(new ASN1ObjectIdentifier(algorithm), "abc\u5639\u563b".toCharArray()).setProvider(BC).setSaltAndIterationCount(new byte[20], 5));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(),
+ CMSEnvelopedDataGenerator.AES128_CBC);
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JcePasswordEnvelopedRecipient("abc\u5639\u563b".toCharArray()).setProvider(BC));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+
+ //
+ // try algorithm parameters constructor
+ //
+ it = c.iterator();
+
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ byte[] recData = recipient.getContent(new JcePasswordEnvelopedRecipient("abc\u5639\u563b".toCharArray()).setProvider(BC));
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+
+ private void verifyECKeyAgreeVectors(PrivateKey privKey, String wrapAlg, byte[] message)
+ throws CMSException, GeneralSecurityException
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedData ed = new CMSEnvelopedData(message);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ assertEquals(wrapAlg, ed.getEncryptionAlgOID());
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals("1.3.133.16.840.63.0.2", recipient.getKeyEncryptionAlgOID());
+
+ byte[] recData = recipient.getContent(new JceKeyAgreeEnvelopedRecipient(privKey).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+
+ private void verifyECMQVKeyAgreeVectors(PrivateKey privKey, String wrapAlg, byte[] message)
+ throws CMSException, GeneralSecurityException
+ {
+ byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+ CMSEnvelopedData ed = new CMSEnvelopedData(message);
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ Collection c = recipients.getRecipients();
+ Iterator it = c.iterator();
+
+ assertEquals(wrapAlg, ed.getEncryptionAlgOID());
+
+ if (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals("1.3.133.16.840.63.0.16", recipient.getKeyEncryptionAlgOID());
+
+ byte[] recData = recipient.getContent(new JceKeyAgreeEnvelopedRecipient(privKey).setProvider(BC));
+
+ assertTrue(Arrays.equals(data, recData));
+ }
+ else
+ {
+ fail("no recipient found");
+ }
+ }
+}
diff --git a/libraries/spongycastle/pkix/src/test/org/spongycastle/tsp/test/FileDaFirmare.data b/libraries/spongycastle/pkix/src/test/org/spongycastle/tsp/test/FileDaFirmare.data
new file mode 100644
index 000000000..836a9fcc1
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/org/spongycastle/tsp/test/FileDaFirmare.data
@@ -0,0 +1,3 @@
+INIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINI
+dati da firmaredati da firmaredati da firmaredati da firmaredati da firmare
+FINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFIN \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/test/org/spongycastle/tsp/test/FileDaFirmare.txt.tsd.der b/libraries/spongycastle/pkix/src/test/org/spongycastle/tsp/test/FileDaFirmare.txt.tsd.der
new file mode 100644
index 000000000..1686986ef
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/org/spongycastle/tsp/test/FileDaFirmare.txt.tsd.der
Binary files differ
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignData.data b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignData.data
new file mode 100644
index 000000000..ab51e847c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignData.data
@@ -0,0 +1 @@
+This is a test message \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA1.sig b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA1.sig
new file mode 100644
index 000000000..1ecfd010c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA1.sig
Binary files differ
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA1Enc.sig b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA1Enc.sig
new file mode 100644
index 000000000..2f7e7b677
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA1Enc.sig
Binary files differ
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA256.sig b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA256.sig
new file mode 100644
index 000000000..114c592d7
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA256.sig
Binary files differ
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA256Enc.sig b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA256Enc.sig
new file mode 100644
index 000000000..28bb81108
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA256Enc.sig
Binary files differ
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA512.sig b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA512.sig
new file mode 100644
index 000000000..eb3429ba8
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA512.sig
Binary files differ
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA512Enc.sig b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA512Enc.sig
new file mode 100644
index 000000000..91556c681
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/PSSSignDataSHA512Enc.sig
Binary files differ
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/counterSig.p7m b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/counterSig.p7m
new file mode 100644
index 000000000..7d82b99c6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/cms/test/counterSig.p7m
Binary files differ
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/eac/test/Belgique CVCA-02032010.7816.cvcert b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/eac/test/Belgique CVCA-02032010.7816.cvcert
new file mode 100644
index 000000000..dd2e0e4ae
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/eac/test/Belgique CVCA-02032010.7816.cvcert
Binary files differ
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/eac/test/REQ_18102010.csr b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/eac/test/REQ_18102010.csr
new file mode 100644
index 000000000..15b49e867
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/eac/test/REQ_18102010.csr
Binary files differ
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/eac/test/at_cert_19a.cvcert b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/eac/test/at_cert_19a.cvcert
new file mode 100644
index 000000000..16733207f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/eac/test/at_cert_19a.cvcert
Binary files differ
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/eac/test/dv_cer_BEDVBUZABE006_7816.cvcert b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/eac/test/dv_cer_BEDVBUZABE006_7816.cvcert
new file mode 100644
index 000000000..0e3ea89bb
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/eac/test/dv_cer_BEDVBUZABE006_7816.cvcert
Binary files differ
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/README.txt b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/README.txt
new file mode 100644
index 000000000..03d993374
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/README.txt
@@ -0,0 +1,8 @@
+Some OpenSSL-generated files, all containing the same DSA or RSA key,
+with various types of encryption applied (as well as the unencrypted version).
+
+The password used for all the encrypted files is "changeit".
+
+The PKCS#8 files which contain ENCRYPTED PRIVATE KEY use this password for
+the EncryptedPrivateKeyInfo object stored in them.
+
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes128_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes128_cbc.pem
new file mode 100644
index 000000000..7af858e9c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes128_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,3D7028A746BE6B09694E16A222C543CB
+
+RkTEJRJjGfaMfNc876Tx1hD92cblJRj7TvUafRKnH0J3Zv7l67MSG/6rY5HD91HP
+s9i9Se+H8Sjn/HaUl3QTZv04egloNlL3MPSkI5fusR6maZGPVLRJBLfVKYQZVDja
+9YRe+ZhXMS8jTe/IhYMcTlQLBnnwmmgZC09Y9Wm39idu7lytOl3JBMgz0aUNA+P6
+lN2MtaQyIBXHbaqfNDGFn/r7+MH4CGw6MtrPzGqRJgGMHhV6T5o/x0nEU+loQVOK
+mPkSZTxBbn7xUb4JvFPnLTbsI4Cnre3QmfmDwkCAklQXqAIT9Ex1Slq8qaCc6TEf
+mWJQCYPUkpQOqyinR8o1VbYm3DFFvE5F+CktJrppqkQvAct0dQNjMTBFxUjCkZum
+qGfAslGPBREmmnsExm5GThYqA5LN+qo2prBtvt6Eso0i2jNiXA8bi5OfDzDr24R5
+/RKUdFPf7keaAjg9jSArwp6EfM3y3sj2riibwZlty2ckPJw3SwxIe6QSMwKRbKlh
+GJoi05/cO0NxQYhMmlwVN9v5+YpvWmT3CsFvCA+Zb5rXPx2AZpFv8YoHdQb0qyEs
+b5YuVoavL58+BWIPQpeYy/jttR5pEPpgM+C/6/1o4Cae4lwppP2OYFl1fsqyqbKh
+iadErB6QRaJCnfnhG6511CxY+vZtQE5EM36blOl/op+6G+36ApuqDtfA0C074daV
+uHfcqA/g5dODEJP+ps6yoWtM5lbd5bZZVidWhrU6Skbt0faF9w5ECF0qkYDGqF85
+qqFcaoimq+NP7EtUEFSneOee72zYALXyzjoEU9InktzDi0Oufojzc1gjhh7LbObw
+UBANPHTsbaL6FPTEs4a3JYSyat9m/R5GAaT0EBynHxvdQRGNhtEWFPkpGYUrAz9W
+0A9mNX1as8Jsxkh9wqjgOR6Xpbqh0aFHNnkodwV72H5ROga5EN8/bbuCBxInNzy8
+o9z19AnajR7vCW/p42QwsGfSolQgE3KBdqWsle81LcCPVQPQshXzcjgBHZbH9/mY
+M4bX4iEsC9yeNgoMcHtIagOKipsqd4nuPskutf07Mh71OXFuxsVyGcOBVhhdZCb0
+3ZYzVi+nzORPRZ93nPXipy3+NmoARk7mhXDgX9p1bPI=
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes128_cfb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes128_cfb.pem
new file mode 100644
index 000000000..de088f91e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes128_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CFB,C0CCB782DF620FA388D9A356F8B7C346
+
+DftIvr+HZuCHBanw4n8P5ZajHAw1ldQkSgLxtxY0ZYhhVDLEqEqh6z+4ySjZz5SR
+KY7kYFo6yJnURurg3DAGvJ55s6jgyrRHQZkhiO1fBxhyarOfcBjJauJKDT4uhFtC
+LWZ7dqft3PlcHi09mFKjK+BYjULe1QkdrKQlV5FBpCj7ENuHqtfx//bV+IWWVnbu
+QRx4ec2nNCiS2qiI9Qg7fgMdXWrpJlr8Zvfmn0Mta3Dn9SWR9hK5J4d3xiBtaF0F
++BNuszy9poxnsRaORZYAsBh2vdLaQyn1gGdehlsWG4J2Zb5RHApYczJcp2AoPX4K
+j9wAzlfLRSZ4Lt5edShd1zf/iDxegBKQFFHTfPA6uu+fe38qckdxVyBdGaCCBvUz
+Quu2DjjXdCWWo8To5C28LVoVyAy+qJaX86vn7yw03/6n0y2dkydiB3u6wnucsom2
+HfLX+pdyarFoNvtCeSW3Y/1Eqd54dDhz3GrSTh6c7G+wiRziKpTduEmoZ+l+CIrl
+tWxmh59YTSeX4mi48+fxTA8xaVwD/j3VuA/jTOQWDW+DXU2z6OcAQ9rlOnT6Jad6
+P2El+vgLrIFbC4eJs2ry6bszqFJ4wieBVnazPCUADLSsXVwbFuO9oB4129y3Yg+U
+dE+lN24KV0kC/YIdO7c2PghaFY98CVrBX/oocHy4j122fHfboiPNh7S7n6cqJHh2
+JKKQK1qTdfULAN5ypecl27gWeM2i3ib2C5jJiOFUlwiAkZWLRJlsiJOk+b/rI5FD
+tM7yFanhEtcYumRRoSzKII3tF0h+z2AwzPdsyJDdASCzo/DmhB0fg0O8G0q/isNi
+VV2zL+w7mNmf79QsrGVA39Y+G/uKS2QPf3bGFthzYZwKH1M9hTN/do8wCCJJv7MR
+Ejnd32srumBOvGXnYtGuHnT3qRA1mj82B00bdfwCd09GGUr6mEQwfvsDOR3q4OfH
+eGCn9NkWKYvf/QAxCG9Vh7u62sUlXKS08hJcVAgBOzN10wFISTIOAvedt/q5GMvm
+nRuF/ixs6f6LNy/VgyztHoQ4vN4HBf8teDsbWSMDvlLkU6tQZjyuu8JkTjeDaqMv
+GbCzrRBldS3zMXX2OaWpZohi
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes128_ecb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes128_ecb.pem
new file mode 100644
index 000000000..4f69fa7c7
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes128_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-ECB,174C8C70B397BCF00CAECA7AAF7A0A73
+
+wzs0bJqGg+Scn00TgtgXyV6hopQKVWMEFnMpu6R/Sp1tbPVlr+m5+SppJFVyW3WJ
+YeFSwXzuVAsnbD9qIZpAlco1ZYpmRXaY6IfXJKYf58v2IrqkxVd6AwjGN2FloSNp
+b/DinJXJe807tNAkuBLQ/7QlkCv/BmZMeYBl60XYIH8LDF/T/ON2hREl49zr/GLY
+bwmVzgRpfl3c8QIt6Yl9uKOqCFJmMHD3YS+dT2RwuQwqY+U3DNzVoCci6Zjd+gL3
+eb/S6VstodSR55qF8Fkwt+sy5yL6XmhQaGWEgCwDwArN40MWIEpx4NaBxCcqHF7g
+o26bg6CZwY7Rv42RTHKHNPETegZneAMK+e1lNassSijak+A3ng9bxiBquWSKHe0i
+s265Rptr/GvQX0hLxmfjEjvL98dKVDZpvdBaWRqV2lS26jDPiFAHtVsXvF8uo25J
+1aS8FDHaD2DghC5aXTQRaVy1jlMTm2YZeVfiU6+7HVXBkLsVbShqEHxKylxgtB/1
+OAui+st60+o8lvRmn5dT2xnxLn81Bt4qron4pz0LdzC2xl0DqjhXyRsf7kdxr44h
+YN1YzmdU3fYFzQw+VmE8xECIjPukp+0HSb4n7BTGsWvqzntFIrzWGeRmNhjtMcwy
+YJoWGnz+WbxP3DJqSGNdFME7mNI/kaybIkOpbHLLlmgD7XWpeyGYtsU/rzrh5NXN
+YRj6Nf3TWI1zwS2xx95+/5vc5Df+sb1+/33J4hbGOx9KdfqoVlJZ16puvdTq97dF
+x8TVYxk2PfBJpvpChCsFlYBOB29F+kY2qoBKPbrvmFPsPCgI2q4gFuJ9pq1qyDbK
+pq9d1oewOOxR22VMQNGG7tL0tMmtXJ/z0n3Y1UE3aYiSG7apOhooBAQ8grpuwqbn
+mGTz6sYB8fHdCnedcxEUxxuFjXupmBcT2ulUjFZgFrG0SEMElgTDjtG21eurqPKh
+ZgxfkW+tM251WTi6sqjiQO8WYHlU7+XyO3BKfH5v3kz4qXxsmvKfh4UOfRy5f9YT
+Ft5oi1bos0soTvms0d8ckLt9Tph2wgoz3Sc++4DRcF53Ks9N6iUgtTpkEtmd/Uc2
+5+xewYmlfYO2qfiqiF/6dSVfDPjJYR/YLx8KBZ40/e0=
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes128_ofb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes128_ofb.pem
new file mode 100644
index 000000000..cddcea9fa
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes128_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-OFB,B32C602DACAACE3A4C55B4600D974E5F
+
+w1+kMXURdxpREW3giZg+PooayvatT1Pf1bY/h0Wcm8z0w7zRtQOyjCOdEPNxsdd5
+ZYn3qEIOO+wkw0v0PdK1AaegJfYMbMpSp/iEyFXU/LHS0FpO7o8zmUiAvdeEKAFt
+Qk90gFBiyQyvWEWsp32KQH1/eDSeSLeQbfRfDbh70DkB4nUjYMW/eFL9E/cHCmdw
+0LKUpEycc4s8i/mWCYJF+cQd4J8RHK+Ose2+5z86kHTrbFSlTBEZEXPDRHl8ZsZE
+477A6/Ndy0Mq3+NgMLSl8xacs2v3itdza3AJREVOzvnRmV+NmWtYQ4MQrJrLg2yv
+wfAf4b2r+k8Igbpzn3NCEYolecGfyEWftzTsqTutlFO7RfeW8go4v2MvEsmHTphQ
+k2qaQkdSTFaA7a2O4PKezJap4RRCJhq1d5bw7RwkCpbRshsvrKQqGdTGJxEZZfGY
+6pOt/qRL9LVCGUVdTTdje7fx9okx0LvKo62eKcUBh/AwZGE+ue28g6/77iABuVtQ
+6kgJ3lQK3AQwKislF5cBC9MAkiIomsoVOKiP6+yX74XIa7T+3aWXlsY1oX13+kMW
+zijwOrc114Sus2eS3xSCOWLYN+0GECMrh2NDGDW6tx7i3R20BuEF/IwHob1qjbkz
+hnS8KrRY+174avQDeF1lMSBz4Wfi0O1IDuxWRDRT2z31E4E8EIoJh+73NZr7w6JA
+8usK8RkiJ4ypoOPtRegXX6GBG5UYgI5bn1Ms2X5xSUGIXgG8IwjHDbAAd5xLSWp+
+01HzUsR+6wA3MxYiybTU4eOKNMviM1G4gGsKeuGrDsNnidrHfSzVyOGVVHr51xRI
+9Xie4FX/VX8/7Q5RMsA8Y2eN/yeVwXup65JRhDD5LjILVMy7aA90KX7y/s8KIYae
+n6lB7PtcpRWwhdYSYtnlrJmYmrl55d6ZQtJm2/xjnOBd+igY4YKNjh11xBL8YNo3
+wBjW4/lgrlvC7kbLxO6JIWipPr/6F3bjvmeLclTAZxjM1NU5HhTScGaEA8A4bq4+
+6Jiw9ZUw+TDCOmntkgEublcCMjcAxrawWYO/5EWuOAOkyBsa7BbfsUv3pgPugz70
+qa/CEkshP5e/1VZgFq/BNFtb
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes192_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes192_cbc.pem
new file mode 100644
index 000000000..9b916321a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes192_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-CBC,7FA13403627D9E1FA02FF88F6D594679
+
+hZYB09uY4gjQFEHX8KGI33EzcJijYhBMNJCR9v8UK8IcQIITOfZxYV2BmrfQhuVh
+Kcar1JrQdnc4S7+UDFIjlLV9ErBCvIUQEflP2ByDhxl892EtVcoMKB3BJ2Rgi9mk
+32KhayXo5V2bu2kOv2nTAjp91LebDz/ylmhhJhI86BL0DLjnjTEl99v9OHQsMtb9
+cXZb51mwIynmqU7Wf+PchH83Yw0WOKs4MOrCtsqO9lL7Mf/MiSSiE+S/rpKLPXY0
+4aBxP6fw+HG57gPlNAvv/qKtJu8YgZDqVXhIKNDZRTSRX+B9R1Yo1tgmJVPhk/7x
+mmYUxIb7w9nqa5OrxzFHyNvo1U5dJcXyCEhvUZ3ImR1DZt/oGJYgrPd/8YcYbsNP
+LKmTLUKI5CARZ5KcOjfM8vpKqlfpCg3Yl1FaNIjM0eAhD6XrepLj3faAJW4/YEoZ
+SGMO5atbM0ERT9sNDJTG0iMW6xGL5l/6pzfsTKI/2yMaAeWAyvg1PySNoSH7s6CC
+CfqF0w0VpQEiOPb+qjtmjBDB/VW5kNrRiBQqZAgpO6mED0jAdg9o31tyuuaFDWzX
+41C2viVvxTx5A/xOtPvaDo9EMecc+7MpPLM2VhWhPDiDBYb8PCKqBOEwIyH119MN
+gQEC0IN/itc/J9ybHLCjrF1Rp83T3/XhAaXNVU9msBBpKNjawnwsUUj8gI0JRbx/
+5ehO32sQm8wkMyP/8iKDAqBRkDT3RIEmLi8ms+ZZRmLwGBkSZZzvOK3A5Dder4bp
+dIhOOetvoN6Bs9l1i6Dds64pwsy8IcnLLeNmOag+Qh8+pVUBNZ1zUV3KSizRKh5U
+dyT6VMILd2EAUJYLXs9HNFTtHZglRb96jQ3rkHGmAepeIVnJlNGKByvDUsJQDGl/
+bGNk5Ejz93ylY8JzR1GaYyFVIUU0qY8khbo7bSn/o6II+KjyTTyTkV28jTSD5dYe
+upGHOzmqpGi3Pzaz3DXpbLcMzwYrMP9FuXuqkVWToDs87DCfGqskKtko+zlTV7/P
+eBILwUawtXMJfYntkV247FffKgS3/BNkgEE+iNthOsFMSoqX/3ESBKJdJDfKRH0J
+BkYL8O0I7OwYzfU3gCWVZ8AvAhd+nSqp4H3QUK0QM2w=
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes192_cfb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes192_cfb.pem
new file mode 100644
index 000000000..9dd5b153f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes192_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-CFB,3E445502677C77AC6ED115F8EFD9BBB7
+
+fJXVVcgxhZJXZANfEWDbVmz75ocICvntATRNVgt92sHgl1B2c4cgQC4Xmu7WM/Bc
+ocUlcSpWnoHtWRDumw2cwB+fDb5k3e9qb+aL2juzHkK+kYd2mkRjW8KSG6D8HIwq
+fpvV6NQmVrxI5+n+uabwfil8Ecg9V7GD6ta0QSgt0lc8clp01se+VDacX1uCB7zG
+NtJsr1wUM0SQbEWPEcpLUoYfK0qSO0h8fpnagKrNQLfzFbk85arkpD9XBzxpNO2p
+2fYsc3xZ0RkFauSZGt6ehu0jh1TZNPYDURvSn3uVrseLyR0Gt8LWp+hjIUp9Kpo2
+fLUVaH/7wxpdCAYzo4Ub/gHPfbxo2E5qYmE1oTJyAHplaDqSg8pbwJofiXl12gMM
+IyIC3SCHZJph7xqbKa+W/X4ChxYuN23ZMZ72cmqH4tH/j9IpKrpWEeqjxaj0EwDs
+R06Sz/qAqs9iDMKTkuFTMxGhc09DV9sN4NYczEIEas7gploOdryJGMCM96RtMDS1
+gjW21w0wyfqa7ogsDJJ2/HqKL73Zfn7l0jzmqya7YwcToEfKOSP+a2Q/y3Exr4KO
+FY5PLwKvpBaFcFzJoYhAaPphUzzAQuQFgXj34f4JU9bAXbf7ol7Swcv9JP9tN/mF
+n7z55BbPfC1EiyGyDjeUDWw4XIYF6LtRK3lnvn4uSZFXLmYMJJthwwC/yS+D65LW
+vsW9uuQ2qEfEC3hVbMPP+1KMgRkb9CVbSXBH+B7UoaUkGsJYzdSDeHZHbwiHgxqH
+jb6WcjtUjh7W2VO/MnHBrLg8dnC77OnR4IiqJq/6TenuSu0N/4mm73SH7BtYAugu
+ok/2H7GYfGfWjOnd+QvG/Vjsb+l9gtB6SXYFiWuThjB/sU4kHH8LUUOmGRlC3NDz
+w4pv+cR3tS1zX+evPL0BsZ3ynDSGRbMpss7xVooxIPacFwDN8kHUnWvIBpQKAizq
+blt1owc97vidf9OnZxUMpzw28/PZ+y/vRYSPQrde3kH8mJmu1FC6tLZnqzuCSsgR
+SJSr3/8qqSj3XrAW+nj0Y2P8lItNdFXex7j/RuX3eV5QIyK7uY+z8ZP4gf5q9w54
+p+dQi7Vx8acRjbsU+r85+MRR
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes192_ecb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes192_ecb.pem
new file mode 100644
index 000000000..c7608e02e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes192_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-ECB,C625A2E97BCB192B31A8E33CB0CD857C
+
+jM0PVjU2r063OACSZgLkaS9ppOj4idZ9hgkdMi58Oi+C5bfhZavbjROyxCG0EMGz
+HnAIRJ4pkJeZTnGElmOEFbaNPb42NAvcrYXAP4XNu5FbZ2SqGKwRnjjN8z7s8+Ip
+MrCyJsWycYy2BNaksJRaDNgazjKgqQxGFlQPJ+j99E4dk5QaduOCrf6YQ2G+1Q+m
+2/uqVujTwmverPnHDNhQI0ZYMY+l8+oVcPHIY3TR3ufecvrGkjFgKH0B+/L7gWSd
+ASvldEnWuFtPMiYnqCPtLgJNKSXO2nlumLc4Gz2ruvYKI1qGPXsVLIGnxISVLUzT
+VQz7NrRYwlvSLWdQNqbrEPvEu4q1KstqIkiPRoC98vG4+VRkf9AXAGqxA+vKYktP
+2Ui/SLhoC/seh9pxYXLsmqP+8bxcNM3VsJQoUUFM2PtfyvzBtuQ7mJQTSFSXgBym
+qXvzx749S4xOot+H6r/bCh8753MMEsgsM39jBsRm1zbaBjaNFG0UBdfFigHWh1zx
+4I44pIHu1AQDexjnfaUVrZFbys0CtM/Wy/3y0I3+mar1Wg3Rc1XL1PJzwDqBoZst
+vg1h0L5OPV1c4CekFnAEx+VI6ImxENoYtZCpbpt90kz3GxRY/eS8roS/SRJ7KizC
+p9bWEsUMwJ4Jl+xvV/VtVG96nKzlU13gkI6lMATYzImK4Fh7hH/LBy/UhNVL8X76
+3fo64CCwE3YkrWEmBDdxt/K8Knj4MUPjBgy/ETVRC7ziG0rUwRSd7zLOoEALMHig
+AtNX+juPvPU7yARw317Q9lZXeytf1AmGiFGjYZR/mduAa9M415uWm6zutIJEz+q8
+KV93bm18JUaQSrX4D6m8IgNhX0EfmRYAIFnB3rv+1rsb61q+4USk0L/1vKT/fGGm
+yvXMCA10N50wGS4wovMYQIl/giMEU8e88f+gqImU1kporgESIOUYUm9tOZ80w4R6
+ITlKCzRuoptMQBGZeJIWfWNLxwYq7NXKpvjNeSOeOqQ4fxhkzEetFERG/2hnszmM
+pqwoZBZQ8bb+T6cmJD1GuxoO3ev258WIUkEZTkFYK2Q/+QKymPZO4ATSAO4N2UqQ
+4TXRqUs4i+1f/BJU0ahnSgmzrynGmskUonKxt6T87lE=
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes192_ofb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes192_ofb.pem
new file mode 100644
index 000000000..501003586
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes192_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-OFB,7E4DC037A44E5DEE4E005CED36B18C16
+
+hvLtWTLg0+cMFDo3jN0yZc8S7fE6cDdZcBK0aRy+Eg+9kWlnmR/VYqG4xaich3VQ
+wkyhNpBSAoUHY8OKkB8hYsqbGkuKxQ6Db4IJlahCTFgb0yO2C7pUrtGDTvmXVq2n
+qJ4c+4CILeyzIp5yfy0dE8CAsZZcLEdSpPvaNK0VPZEPhelm4WdqqLozYVibR0KS
+2BbVO+E7yHGC/G3xtdbduuYpID1pLwyaebUCNgblggn6FJ0G2+Iu7lndmMU4B1Wr
+phvb+Fd1kL5421u8OOKRVLS2yMtlzbK2Mz7NclEzEs1m6K/xJUzztxImAxElBiiB
+YfOw5WLy278DuD1GCBkSuAKB4XWUtlq0+tJnCzAG0yrdMloKH1m+XF3MXFiRTXgE
+k08PcZchoNgGP51Rcg77skATP9OMamcjnkMx1B8YxTx9O5Vv/oSIjGQrr+t2np2t
+JU1dHTr9QrCeadSz+My0sjlZrL3ZisAwBbu6C0Zta1P1eB+i8ORZvm9HvmadcyyE
+y5oQWv7XwSfAQup/4uuAJ8bQBunIH/ajMF1WmD8rzLcUjG8W0rnBWUtjaxxBdkWv
+xBzgMPm7Q+L/5yhL/TMH3dkUBq+Cg5VQSe9EspNRGKBUgfKYk67Y343Mv91xKtX8
+8Tmh/WlnYXDv8QBnFJZXVnf8HeSFHsHDzfTgAmWHdhisTNwmgSFvBK5ghvhvkbXI
+UIPi+FgeB7P3ccFYnmoMq5qgK0Ki4lU6v57soDrjRl/NttfXdQEhLfWO1zXNANLk
+lqEhJSvBPZY4/FiOW4kNaZg2oRswz/+Bmp3amsK5TwBcI72rnH6SW5ADqPCcTP+h
+IrH4L9wnhOXw7QLk/h58JwiEc8suj5n0PJPQeHKajizd/EpUzVAuRTAl4GMvxLCY
+rALxeRaEXfJH5i/0UQydEvdU3ZP/LTibAqStXyVlSBZmKOg0GNQ+aAiHZyBnI3oq
+QuD0KuJi84ETMLU2baRydTbVlQDr8O0vxnCNlPkFFOqVpWyOyBgMctUfFJiM5c0l
+1UT6dc2F7NF5WOuoDCVw+Jp974CJuBSRGpdQKGms1Dvjwrtnf0ycstswXHvp2ZhV
+IVeCbT4WWh4f9bp6STkdquSc
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes256_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes256_cbc.pem
new file mode 100644
index 000000000..17289b2db
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes256_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,307CEE18F79CA333A38CA90E75B248C5
+
+qyg9Q1cX/FGOoP0NFzrCRLwmR6bai7JzDiCLFCthciYkMIWLIVzvyTg850YD3dw3
+Wusli8EQJig8DEpFSM0WBc1Rne8U4168nKuRnFUaP+VWuD4UpNDt66cT6dMoqATD
+kZGdd+p8ReO9TK9gO/ZZU4R+q3OUpjxX44szxj/EIVSgphi8R0rRSxl/yFRnGHyO
+xfpM9NxgMvBYlyxl5w1Lp/ictuF3D505nF/uuhzGL5a+WWhSnssMFHF9vxXTu21/
+3Cy0C3Qah9eV/C2oyAU7GGsXHIfqFqsgMjQN+cTFqMyFeg6g0J7hytDAgZVBXIFw
+UuzMbxUUZU9VHcZzwqstkg5BmUI3sgW6gibBUzuJrmo7uLrCvHyj9oehSMqeuPUC
+EXFqhw6Nb+jZMkvW9J9qFYG9eg3PQsDErIdVK8aWdLrLyc+O4gycOdMbR8aq/3Z4
+TlV7Ye650EvQ13bwZghZyKel6Rjt4P1MagGriNqCcLVVsyrRXAiqjq8cyJgYtoXF
+1VMBZz8ob2FH9+kvk2sb4+T22sTYwiqAVaLnCsuJ4dmS5wdBrhfF4oyHYV2KOVgG
+64GqxiF9/whvbAWSM4cU+KslKnWGZwz53LKleafrgeFJ2P1ldqnl0on5EQ/m9bzt
++GSGwzZGRmhf5NoyhaH+OCkq/h1UP+LZ5kDJCqH/l1JZbvJQkGNKzt1OroW17GnQ
+EgihXAmhy/xOAIZkz1XKa3bNvgS1F9yreAxJAvBHB0QzZ1HrablsaTKsZOtY1Qvq
+e2OdpJFm+SrI7RUtbp787Yl9pH2cLEdto+WH8gtgXloS+b11Q7broE42w9MIJrno
+kzs6eDWafSExTvpi+29OJEtK4PNezmhOxzTUIsG0/8d9Vd2WYqrLD34ze68X8qUa
+CoIXYP8VsQLoXVzX7VnMBYTQ+YOR0Ntq6pRj07RbJrNiOt8qcWGslzE17ERuCr0+
+ZFTGy77KOksKjLksvRj4oshQjRhVYZscPNnwKODFDvOPsGFjDoU2Sg+W8kcfE6Bc
+1RQwk4N0cjkC2JXXk61QQjh+efWRBqPN6va+ixUcsZSxndCIoBk4qtqtsyTFEcC7
+LdfCC96RGnXlvroiPHvrmJYN69JAyyRrnhiYfaaC98s=
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes256_cfb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes256_cfb.pem
new file mode 100644
index 000000000..06718a55b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes256_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CFB,337D3978222A1367F5CFE08611416E9C
+
+GVmy9WG3oR1Vpfxnfpv1hFvXGzBgE+c4jplSw2BAlKnbznCPbZLc3WF/ZMv2851O
+iE/8sdcetzoAlm3jGPoDi6Y/FqMFmcbqtro7vUz/SVgi1HDI0FXjOTPtFe6xfzhv
+84qt5lz5VAUueTKFXEZHqM9tV7lHt1FX86VutNObn8pE7nAWVX/Xvq+qWUsEx0ik
+YjZjLY696pyz61hnxZE4jKZLRx/9a6vWYaVfzsEi2FLw9qAsw6ILp+xDaAeKa+Il
+YVkgDPi62NPr7cRX1WCiw+/feNYPgUfGiBNkd2mOnAr1yOXFM+YALw5V+q8I6ZKN
+k8R7skAzRZkwTJ9WaaFGD/UypYmhe2b9Jp2n0BMEn5RpW4o1DTIHmfMSUmUPp5w3
+HjbtdDUWIiuplrz7mUE2sez/3bMbcoiO2Ym9SInJKBrMFSvyasg403u4QESYQhC2
+Lwcocb5ixXoczHjef3CogL6BhL2oZwXCl3OBqpMOJJJKXUPRhN8bvgV41UIsiGtN
+TFUXqYdpbmMkxJNMGiD3mKWpSm2MMdQYnRlxNh0wXLi5sHckD/WS4yFrNsCIMVDT
+W094liK/Z7BmplY4TyqKhsRlFVQ4VOo/W0WNh7Ayp0siIfo8vHDyoQsnUkn/EUER
+UZG1lIy6/y1RSg15GWpdi1bvT9URjElh/U944LSYD28K2VU8aPKaRBokk+K3AyR6
+YhZRCBr6uIVZ8HDkBL5OW0eP69/jdbyc4MnWRa6C0d0boA7N639j+NQz9erYT6wu
+RkInmBbVfxQD6HLkMwiuU23qLP+QQTLkH7rQJmnRPSwAKEE8RiXWi4/TnYW7d0AC
+Bj8oaK6DO+J9t1pdj0IGluf52iUwAOf2Pxwvu44ovaF+yb2n3P7S5maDGLTV/xBW
+D6nEAct9cYj22/aRDTLdpOfG0L242vjQLnjrgezBLraa9eTy29hR5FU5ACH5sB72
+rxUSwoCHCJuNFSxC27QwZqeCFw51epwXxLv1CjqsQi2So12qH+vFVtL/1YrFBct0
+dzwbdNk0S6UyPRqfiOE/+Iszzahmb/GgskPJdfT5Y03FnpDWfOotpaAebrY4t6kz
+/gs8pxupvdKw4eWsxVCL9KOP
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes256_ecb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes256_ecb.pem
new file mode 100644
index 000000000..ab0f64d8e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes256_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-ECB,267E98B92F05ECECABF28790E81DCFA0
+
+MkVFB5/gKxAksBI/g96MmN+ujdt0XFXC+7MI+0/OJ/H0LXlHlLpwfGlx/Je73Imt
+rOZveXf4I8sBCF1Z0Fhzb3TTTDxcastJGKWAVKaPzKkWdxNeUjx0kinbrkM7Spfa
+yG+wW+Srtfyi6LzEsbCduDK7hzfDnLbgKymdDeP0TVeJzEdXgXcV09a01GA+CEVX
+aHesQLNHyYm9nxFxK0fAnKo5r1I2JsozSWNTG3VNbiItxtfoJdXTn25I16qXjKzn
+MOn/A+RBpO+P01j4uk0q0SPJMlIYIX+RjgAoPiI5R5vSeucsdUJo1sWnSfqLc4yP
+vUG5wD/+lYrxsXiW61KdwIg3vy/ty5+GqwNgNvN0FZM8DvK+NQ9K/IpoW5RE4ioS
+ZNm1JpeGJiywsBf3Pi9mwR44tTVY0Jwa/TTQp1kEYGjhYXMIEvf+LUHwG5KO2wmD
+kDediMDUPaUx9K34eSpgIUln5d+1viMpC2VcDIg4tYjAODtGRxzgDUr3mbuoVl8f
+GqusTAdsNoIyilY44XxA2odHa4S8yXsx1f54P8fRYbA4Xo179LY1Nh7PwQPm+rI2
+mERkCsvns9jP1zJRuS1lYW1Dqjtxxq8Nt5RAsEwKQYLO4DfsuMZPblEXPAwSGb/N
+69xNs8ZFHm3KT1r7FdUrVpHk2vmqsetNa/g2wRTEuBmRCgrtTtEDWgdBNtDoHlBR
+pDIWgwNvt7oJIU0EbQkUgW8bmg1p7jxXN8Bk2QKZoOytxA4TB3fR1p92VkXzrkxn
+l+Z815BNfqnNCU5nNzLwk3jLgksZrDnLu4sXykIBC/bpP5fubnT7iJYh9h6ZGFeY
+QLUP//ssuZM2auNjTVykWUtAiglROzxnFZjMXEbujOKbm70Uj3YvAHjoKalkti9x
+MTj/vpR0xBv/iDtTFl12HIg+IEGL1PfX4xy2avvJO+XGFD4zcnrLfTMwtUJQjdQH
+dUMWP8VI266u+B6wGfcrhdCYqtvuLVUvbISU3YD/tP+esXh563kPnXd2UuaS3ErE
+/7Y/hzyUkDjJ2g37Hq3M4wbaEg/a6osDtfg73thDMadsbTLIDjHKgAgBv4umNtA8
++EaP0stzRH3ayHL/f4I5bHC8bMIAumKM6zap6tBiork=
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes256_ofb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes256_ofb.pem
new file mode 100644
index 000000000..7192ffc10
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_aes256_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-OFB,A2D4D65382905DF6EEE7A315B10CF2D9
+
+CpLeywQMv8uZGrgJYM8rZ01awWHJWH/ZKkNi1rpQhaI1BAShQbIUvpY1IsMLa0/E
+g2+oj+Aa1UE4UDsAlzcfsKG9QHS8nOYWuLpU7VAyjC6wUPn0yI0sxxKRd4dmPIgW
+w3r0xO187yqLAjIZCj4y+3ANCjw+rLpZ5Zq8KAN4j6H1NEmzNoNVQbwY0hpsyxwE
+Tg7TkI5IyNKQSQC48EuZh16cJR48l36gzFOmZKr47gzS0zivvED4Vxdaey+WZkoF
+1XW4VbQGHRnLEn/I8rziic9E5pvvcZt6K2NwvzXrkS53ufFYZcgxNRxrdM4yLz+r
+20Unn2F2KqumB1RAliKo/PtudO7XfsPNc7rbF/stGhlxDWTyPU2HMX9tw3JkWDfG
+rRsG4RJOQgsx0Q73/7XPhgu1J2Wp39a/QI/IHwZ+rWIerdUPhs/MRRPoduAfSSZo
+r2z8OPJAlMWLwAjmmKDGhpTp/21n9xLo8tbvqmy8Frz+kAxAHXeHCTWUbxA+URKb
+s5NKQALX3wYHT9Xq0A27A/Zrqs5elqc/IQL58nU/Da3a3OfPB4+MNWeWU781ohhi
+VkBgMRbnQNCC8OPoeMd/At9GDEEj1rDxx49pJdMMwxXS04P43LiuNSmndCei2cQh
+/7cho8YTbdgjKF2kVCZvYXBVsu7Nn834kJw7eMH6slU+VM45jTkOTr2uLzKWrBL6
+YONiK2xdD9NlDcTsX4YRkt+dByJEcDAuvprVdnLKpFXAOWDLW6e0o0siuFIGBtgX
+NR5vA5llpOkladJk+j+dxX4u5Ql9KFPtD9uM05ik5VQCZN8pxy6On3GUeSdoAE9i
+i+rtgZofs39mZOTxhYr+Djnq3WiWntV91GImwhqiXxUBI/fs91+yy+FWphpGORaT
++Rab+cyvauBsdTAoSjjd5cNXXsztfDxEhLnZ1yWMQZxVgV7tcLevVo7e75pSZrN0
+/gMQAH1Fcxtbrdzg1fehLiqTEWp14lFyDCkqAqQ5C9niCqwyf8+6Axaukk4ImmP5
+n9eIykRezLizjA+GCe2oC1jXpVEEYVzOJpbBAwZqk/jlyNd0m01URxvhOaW1/M41
+uWDeQp7ljJrtiyMqD5P3STGR
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_blowfish_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_blowfish_cbc.pem
new file mode 100644
index 000000000..8b71187c2
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_blowfish_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-CBC,B23E9DCDF6361CCB
+
+BTPCHNUVRgsKo1up9Ktshx00vDANb05S4S0LPU/wzG8sj60db3bX7Uzr0PPy7ShH
+1zPv0PECYla1dh9nVBPOS4EQE3uHyzuDMTg0AsiR8TpysuI+a4y8XJeAhkU1DTD6
+YzmaodjbCrhautYUCzvcui/sWWXTUSWH/yrFOxaaxLpccacCssGlPc3Tmr5brPmO
+xaZvO32ii6z7WAP/WmyRoYH+BSqmUBhObolifBD5kg1ilPfCk3xMtz4lbJRWANsS
+r6YWPwo+qh1TIQWw40Kz4oQOteVNiwh/dvYGxMkd9Gs4J9nY5deKYExoWlYcci6N
+VOrGA6HBWzfFx/QWWGK77xE8yQ8HeeZUgkWwYoSyAmxjPWgCj+BT5gbYV3W9E6UR
+T3lsKGtI/lMW9N0DVcLdur0lLIBFiVbzxoUAL1SteLJ0mbu/Vnk4VhI5z5mOmSxo
+bU/HElXdjIhk7hdTU5PMNSKiAsxNh03NiPsTpEASMhz+oP8BuJZh6Zi/K3qMYH3u
+6BYmA+Ua23fFYd/kz2TclVwiQ1HQjO3+9l0aSgLhHFb3t0spYbx1Ld5+bAb8b30Q
+9w/fNab1mB6hFgaqruPErfI0K8BZ845oAiakZBfKnTRQxAlKNY5gWvSiPDWlkfIb
+uSBW6csh62iQM1/bcW0voR21NGS+WdQ3eg16vv0HMhmEXmEvtAuCGb6ZMqY117s/
+VciBymZzwdLKFjCqrLn6enYrT7uneOoq/8PaXD1rdMuKGL4W2LqGH+Q0RU+1hyBJ
+7ipTQqystqi6HUU2R1/PI4K73X0MMTB0Jfkd81S6GmjkMYCFCHmHXCdNULjbjzT4
+gppgVW5joIbLKNPHJ78lw4BuMxcAgptmtQBADnWZQNF/pBnIVAY/pdHgreIBTQ7R
+KL1/ATp3+gtGd37FOGZilhq8C4ML+w18M0iTUUfGg5svUvmtw+NpNWMijTJpu3Uo
+KqjMj3NbwCwu2b9qxwalC3qWOgAJf4Z784+i2GOvACk2Mw2QyXoZV8Qm520M+idR
+rj6DIfzEf/86TWH9IrGukDbJNB74QHgdXd9upyt4sL6uHMxPwz4nnhBB7I8B/Q59
+oB+3CBpYIANihDscUbiNSsw5/AXNtMuA
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_blowfish_cfb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_blowfish_cfb.pem
new file mode 100644
index 000000000..8372cff2e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_blowfish_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-CFB,A39496D20CA5F694
+
+A9ZO/WPm319cQ3hoxaEsmuGVDkMVhCuRzFfSWC4hVBsxKHd3FIw8xZpGSkEI7+aL
+cMtcyxTQn4jVV71Sw3vyb4N1+2i+DAd+63l8LztpTBQi1o2gTBqmqL9esV3shqWB
+JV7uyOi94olPea0Rf5PMRXx1bAZs9U0TV+5XHAQxM04lXRJajxiN9LBZ1OMRiUVu
+SdoHdXh077ylUQmgDaGQktWYuVH6leq7Yc9CF3nre6njFiUrpk61iPki7+/FgWzq
+vToqiYaWffy+1lB7sXcL88BtFaMWAOV5A48Mv05miTb00VbJqdKL+SDmu6j2Soxi
+Qk3k6Le0heXFHqqkURMKOrr6tepqKEjmy8WTELwMnuT5vNngMqDKpNyhdsIEJW69
++L0imi4fWIelCd7PMI1bbPAp2QsB8Rndjlfj3irVm0AtubL/rbep3JT0ezukoScd
+wLYNTlDdaLfEggry/1kYvPBMolU4xqDxg7C0quwYxLuycEFzU2QmWNtRn0xkfx+j
+ruApr4getT6q2fJznW7coiW+OE9Ik7JgtYUGEZuWFUeydDHa9PiJ34w9t/aw50Sk
+arATzKH66zM//g1zgzg31SmziKeE375skyQr2+1S9RajmdZzEUDL5ajsdrbALflf
+UPQNr0YEF92DRHsI4O39L/+k5fesiiU38u0NoKv5DDRb5T1lQeesDZCZBowQP5KP
++6o6lnj8kCeccpGX/eUukPXFl6mdddAJ/vLptHC1zaRp2dlKPRfedZkRm4Wduplh
+vQ+6oGqkjep0Q/LSRcVP69m91CZot86lAn9Ct0jfJu8o7Ua7KBeOB2k/rx1nUaZG
+BOjHQRaSvPA7FVKCP1UlT0GR2hTb/VcW3UQJ7fCY8E4hc1kPfoa/T+mf0JrHtlMm
+364YQh6KLgcsgVjsPBXnTN1+POH0Qy0xp/0VwQIQFWKwU7gsXprfs/uYx0uD2Ev1
+w9kIWLovIGmBh6HKptqTnjtdwhqueez5kb3MkrCMi3kqVmV1TEQoklz6eBbloXbX
+SyR5jivLmuaoCJOA3oQ/A+75bwcvUP4iULZbdTpM2rnURyljKNU9Hwxim0neZ0Zv
+4kiOZuhQKkGfj0gv5bRkDAZC
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_blowfish_ecb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_blowfish_ecb.pem
new file mode 100644
index 000000000..58acd6f7d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_blowfish_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-ECB,6105920EB281329C
+
+ungL+71R1VG+DP1CKuROEP1pESqlLeGoX/vupWbGTWR9VoK4v/9e1Bh96r+hEobm
+LvgsV1xhWrnyRMMw+W5bSJCfBH627SxqHltgxPhyKCNAf76cTIAdxxXgLZAxjtJi
+mjuBDTNHdJ8NiAxJKLL6dr/hh+Vt1Lk9Gr/x7UdocQnhxG+IZLDSOFdXnFb8EBtK
+kmAXXyOL14Rerywi6pmbxaculi/CihuFm4u6GXvunFjtP33eObzKLRub5ktbCtol
+97rbDoAAUsPPm4efu6Fs/3CE/BfvjUf+cmOYu6pIKQil9VHtxXloXwkeykI9Kl92
+uZVT+e9WEn6oZslAzCnjT/r69+V0Bf06AP0zkdTK7lRNBhmcR9fAgHpxz52GC2Bt
+xsqEzU7d+adCy1M73tT+bA2RBUnbA6BoCDHkvtmZTGV4mkAv11tVxU9Zqeglvi/w
+6QVDQYo/b9U8GVkQFo0oh4xNaAUNdT/i1OIy7d+6UR8k1S9+r6SGVwS3er20trWN
+8mAJ3dWiy3yLreggSqEvwHSpwrUQP8uxdTZOlFAy+xmwuEb3AgT4/sHQN7sJjAN9
+ISdzp+B5tBbM3kQgvEXUZckVykM7jgyv7SJ9DoDaYXvlfOVFo1oM3aWf57DcB8KH
+WIV94r4USVElJERYHH9sR61YtTi2lIi1zuAQZKCf3ShJcgU+vh2ZZ3vRPQhAMXjZ
+0Doi5uxi7HK/MVenO1CzNmsc6XQtyTtONqlJVmBoSq3Il8phMkMXnaOeNrQsT/1X
+PzbQ6MpWEr2WkKsQn5hNA9b8BIZ+cwk9zeFbhwLH5ewjO25BWJkFra4gGFJl+HZf
+vMNFjlnxuMjqM+Fjn3YH/O08P3nF/3ZGezqTCV8OJigB4Cdfbf9OrNtJSvCVsH1q
+YB/3+KOO5mKObH0Y+k1pvwZsXMkj7exAEHh+nFLldjo7tBAycqUHK0RaZ29TOjqH
+J6/4SSzMTJL5PF9Ayjtx0Vai4sFrjRGgnvdd8tddA/bWq6JC5i0yWIWjCEu0+b1q
+q8EHdE39+gbANJn2lKsEAOOt242bsjKR+bblijaaEgZXHZyALOThcEXxn1RaFFgC
+4Iv+DftZrU8lOiEvN8w00K6GDy9gbByG
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_blowfish_ofb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_blowfish_ofb.pem
new file mode 100644
index 000000000..2558ae409
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_blowfish_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-OFB,56A8F965C6533468
+
+91TyUkVkBxdl1ZXkXezMngH3YsE2cuXhiEFySx+dWZqFWcOQ3S6izXXqvk9B5sZg
+O95SFlZ917dU+SFACzB8dqwYo0QmxvH0zaAIMBguuYib6YZVCd8/ElX0vyEEo68O
+9V856HAks6w5WZk4zTC/75skb3tdLRWgG42oBlXHW7GsL6y29Dy3xvaWHJ3vpKXF
+HygbvR/TiSzhWj/jJB6V4kCQAAm99yyMxpmo3e4Wis5AwGgf9XyHJx0gUCeyNqez
+i6UJMGnYsHl1H67ltpN13trIXRcXTUDhFTadRz/suaR1R8IEefkpsnBEPnJwBuPY
+tUQzlolPKuwbPXFukpJrhi7It7dLsDsw5DUYvyOnHkDXJ4vFAIplCKdG0+KLaYKJ
+pXI8FH6X4M1YbIPTF+k1dhCAz7Cz+cEBA5hfJfSA4p7L6f9NBPWso3DDsyAbdPx9
+JJkVPtu0ofZHzYuD9nIhRsXjK9zaQXU0szLBdtGw7rfmPp3ftXeBcXDnO2ZdXL+j
+PK6CJm0ktjnUMKY8gpWahUUfImwebQ8+uQYv+NNn61rtfCaGQWMStXaNYgq54YLs
+D5ImRdvWm936tNUCeoik0yhPVlriNC4gKswRSUxD/nNIetsPl4FB4DIS/W5fvWZf
+WYKwW1UlpC/HagbUVIuZcOrAMFTG+zLYS617lzZh7Y7K87GJH+jVwgbYSbHHFWCp
+V215NLfofwlV5pFwq8djbeEnBhKi9SbGlZUyaZKKyDoIIEnwaxg8BoModBEWHyWp
+OUmw/v81TQu6RwJYxl1C1U9n5w4yjtXr5oowgu6WRYXwWXZtevtLkHrhcuWt21ud
+Cq42ojFrb0GqIcYWDXF3Wjp4nLZ4pIqg5kadpJpcFYx+fcL++Jnxs9l8Ohqwn1br
+/UvY+gTmTwnICapIwovVjN6p6cT6MAok82oemWPZNPYXVwVkGewCH3DWqfeRYsdg
+6gDWeIwyk2Eqn4bxFz40NrNZaLqcmQPaJVRReCV7Y0jQuQWqSYKkBHgFodf2GPMg
+DRqs7doN2MW7Is6qjyc8CDDzPcSuaqUz0gzohupDfD1vAtuoC0X6U+m/8NM3yuE5
+CKE8rofcKcxmFAr52CUUsJBL
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des1_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des1_cbc.pem
new file mode 100644
index 000000000..f6fb1c9bf
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des1_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-CBC,7D7F5AED62DF7398
+
+PvrGaVyP4qWxH3LR5bOjrjTZN9KEZ7eujPyBYWV8pE7+kBc01RKaHuOfntMncXPj
+cTvtvPq4z/Odrme5s5fem88QAoxB2BqM0VNviUMcCcAG+hgsYjYWjUDdSY+piAD5
+dhPcTHfSwgkA16c9pd+vNojdDKHEXzIci/gdrkJQXi9z+Orfb++NluGFUjAvQNlh
+n+wi72AVwFaSPfguwAtWAZNmL37dZO8VzuCTkhciHaJSZFtS1G5rLBIo4JzW6AZI
+PLEENN8fE9C60WYkfQB0PI27ksTS2xPF2b7MeaBwdPRU++hwZ2QwXH7nYlCWn522
+8wg3/QWuFIMdqtKaOjjlwvQxApV7OouRCxIFnolM8HvpZ7HvEVVT6oqcsJG339FJ
+Ru60QxuVsnz6ykuP2OoGTtGZNYo5cgBSpXrpUSmOp8HHblWa6+FSatNkBf5MxJvv
+pMRxcYJ7ftFCGgpKI38GgeBPkpv9Rr8PUplZlgnXkZl8trhjb0hzAAJrMqPkMQ2m
+rOgsIWF+gK6MdnZdSnY1DktPYSFCkfJt0BZMGBDXcbr8RKHeV1vJNWAPOcmTsV/y
+nwzv9EA1KHeMnT+wQ54q7jkRtDLIS+zSWt3qW0fJQzNR3BrMBrsij6GfRZ++PL3v
+4y9D+cDFVX6LMXUDLK8kxZ11A5rSuL4HROtNnIQf/MItKNK4Y5c4PAKAMGLQpPS+
+5dgmKiu6jAIKUVT4BOEjMJ0P03JZKQkPxVB9GgLQLGCq77vz6NaTWhJmz+qTdZoL
+JCvAAShdkVa5gl4hzuvKnmY9VftsPVlOUthuO4NYimnjZs6p0sXZKnxQ4J4BpbkX
+mX5Fs6RU0YTQphu2v+NFhcPpYwRiwn15CVUDW61Sb87HZ5xAzwQrlpFY0LI4TqE9
+6ITUYzgpVVAlslKHNePMcjTj78V2MImHlq7xHSVPEGkkPlsDWxG0snZRkmM9aAu2
+g8kqf8MVngWbWhxqXHA35wunnaBhpBxAgqE4r2yAhyfCJNF3B01zwjt4LeTnduj7
+1ZA6EPechsSQUGQNGBoSbO5zVbIQaRZvAl2MwPU1YWCCbjaiDDRp9bHhX8vQbI/v
+4TRfKX8FUSai83qORQ+Ncshg+gYkeCJc
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des1_cfb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des1_cfb.pem
new file mode 100644
index 000000000..c3af8d5e6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des1_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-CFB,6215481F0FAE54A9
+
+4ZA2xcGT6hS0kQObPwTWmluIl2wTnoL2jRMbxrr7usOZSLYISprcATZWieEKLsu0
+kNNzIptFCmRDt0b8VlothTS2jBIh5nlu9LqvaUlIrVuMEn7umslWrLK8JWnHVKOO
+dMfqNcgmYlkbEfmmXLtlCbfQHT2kVlopD58yxf26FTQ+27l+hSX4wn2uD+xFUAcn
++9ZxAWQDhi2PYVKqTTPfhCPaKW7hjYdocADnIZg+1mhH++8fPxlDmBQBmMOid53Q
+WV9LI4Fps90d7GumX7qSUFZTkBKN3v+E2ahnoP2bTBQGkqWamKFTc/4uLCEGlSWU
+qXaGCy1AwPa9As1+B/jLkTstoslJppqvOooWW2R1o7JHqN44luXXQPZ+BcA7dSdf
+zRcMCpudB0AwHBy3mnUNuBlUjsf4rEpq51HPSS8duYow2I127uI8m8OCoZCaUVid
+msxVMSJIiDCiBi18EfCjMfGLtQVxJefMv2hmcAXQXSRDJTEw8Lrtm0Mtp7XK2B0A
+v8Kqpf3x+VBc770Xoy0K1/fe5oLdvJrJOLO5PVcVXIS9B/DTqIQ8ObABJPZ1sCKA
+sV8XebteS8fNXmFrVKBTmHBpUY8H5Z++VfDtKZZUBYSOqbFT+UU/+xJKlKICzFTo
+YWsmPTgFsu0Z7/PMyg/rccrb9fMWRXa8et0JGoF2NlYu+lkRb/nYPe84oS8RzZT1
+dtWJMiiom4xRgENDhV6/AmA9IuyXT3QbDfFB+ntdyk94U+Ms0ODNcdA4JmEa/f2k
+zFjtEGWHPH8Quit+zUt+8JnWSSFp0mjyA2ZtEj/6Qg5rqAZMdlpTo7rcuYOTHScn
+ic/H7V43SuMlRAM+xx1bGrNzjWUugHrVb7Kar56pSRPtSOQ00Dmz7gB8V5LU63n1
+YX3faatiPUNRG1dArcW36o9dZ5x8O5TErPHRJNYG+96UNoAzHMXoi5thuRyVbzne
+FpOqgxsryobcht7fwHuYgUq92QoY2qG6qMwHc2A3NrVFi8lJ0R83SN0lOzLebulu
++zDvrvkkRyH14uoAWi/o5IGBv1yIkO9vYApntrSO2aLnbevht9MuDJqW/Lkb579Y
+LG/sVwxTmBT6jdCgTdpd1ExE
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des1_ecb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des1_ecb.pem
new file mode 100644
index 000000000..d17a90f37
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des1_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-ECB,1040C4105685E404
+
+66Uasevd2pON2SFWljlVyWqmErfZn4XomzLHlUoagIwnQUEgCBCCpUscES98fini
+roGF/iaY59JnUCMieugke7/GZF1C0aXbIReqds7S6VFfu4Ni1OQTkL4rIauHrWab
+vgoE4+18OlWw6Rc0wwJ8NT/NCOmb397yTeb0w8VYERyzpwSLXxQ0BCOq4vOUX7BT
+2ABX0moazjUSyTO9BQZpABF2SshxaWFbAc3QRwH4QnO1bm7Pv7b1rvjrvPZ9LxgN
+fwjXG+yfHFBBojbEtFvgXRsSSyV5WCmAgYLgk5/nIDFSnRQGty0OuP+itX7SUK1I
+PH/ZjdIwezMKbyuon9D1AvdOEC1xiKEdmJCWSokm0djIVNmYbv4dtfrQE6hYdMtt
+C0LbsT7ef+jl0xG3k+WK24OsBVhTaqj8axIPZIVLELOPlx4EMfaFQgUjgqf5vPhO
+x6RSSRy+poFwtjI6ip/xu7ygqmcY9COXCcSffk1vpw9v+6WcMaYmDLwBTrTCNsdI
+7i6VJa1GiCrsn5o6ydGgdRNkF0N0sUfGnSzRUgd3BGd/fvxhBmcxHUnr8srrHYm7
+D54VL0EUsP33F1VF2ELl94GlWqfAj8NGBDkTbpUcqOeL/ERxdUWfX5IEc3h7fprs
+UjjjQ+d3GRliRs27m4ZuLtGeDEhDtlTC6qtKyqgVziPMwG46tcqyFzhbLCErHNW1
+07JcoDRc1LkXImSeWgjjhskUX8nc2/q5giTVtGmiWMQwEc7aYQ1wPbVAIGPQ4PE2
+XB8zvvPEaj0wXs0JjicrfzUBo6cRbdfmWIfp+ZoTUfr+gS/aZm+VYt1G7v6u7Qel
+AtoSdpN623OvqIP5ZDjOKROmAdMbXkxwwusVNQhkbdTzDYNy/yJnJqUUlhsN0VTQ
+y+O8Fz7Q7fEYIk8Euz3Uf/BTVGbLSNSA9n++CJYg1nam1S51WhCXRDckDLR0c4C8
+v3zpJvaQYW+xZUmlzrYRQgxkfzv4+j9W+kZLgvitQizXfTsuDyO8gwIt2csfGkaL
+EgX2+oITD/sGoaSoGknY42ePI3pPXHlhBjPq6ZWZ7uh6Ia90nV1j/PAcOEoAspAh
+pEdIAkFJA76qN9JBnK7lRMFXu/EWtBjD
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des1_ofb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des1_ofb.pem
new file mode 100644
index 000000000..2d36cbfd8
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des1_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-OFB,BB20E846FFFBD3EF
+
+WeRgcZKkDTSxqvtZvx9WwUZYqXUUpY7siLG1Vm5jXPaEFOEQhmvGuNYn2cwwUYKD
+RMN5+sE51urDgI/xk6jdS9oZE6IlfkGeQSUoEOOfPVyVD/0/E2G0QTcKAAWB56K3
+setBb2ORbM2ZhetYUp1scaLObMEMQ5LrZaqtA/jUd2Pbs9D2MqafEH0Gde8e7mXy
+1fGNJWlj8XtAdmi2BeDKZHx5Hu0r/BOTic++L0Sv66wbjHw7RDji9Rdv/vyq6DIi
+0v0ZCexiNVed4mqD/3+8eGQ2z02UD7aZPy6T7E+b8kBuBi2ouB4HqgexVtz1L9x8
+VBBOBdpOLefwCZlNaeceg2kSIP9mMK919hlH472BO615YB4ugaCilUNLpvv9T85K
+s4hTB5oDcQH6W68mz44vWqSwED8JcdMYvivWY+3/zBSUvkyI8+8AErnVr8tvTX29
+aBhfegKV0MbRRRirj/EcxhUhtfgbAtllZ/Wpo0LWpIsHT0GeUfWdUerbFyh/8Tfr
+OQzC14xoLHdACDz5IDrLaLd87hZrKDJOELvzoSugg2W9NAzGbfoWJGVlvZ0miZcO
+teULyYcK/A7Wcba+jmFaXMrKVhNH0IuGcU+Pf1lYcchjAsdnrFMVRsNJ99QWlN0F
++dTyRgaiCInnmJqT83fI58dMmaJPpMeW26jItPWZWAA0vlQB1RgZ8C7i7V4keuVc
+0PYolX8WpLrrpUpJKOTdW6rmeHokJC46gOZoXEwZCSKUUgreROLgRN79RMBHKjoj
+0vSZWowgH82fNWYWQbJk5z4ldulWEVye3tQhRNsZarAWPFEteiKDTSkawmBpaA6q
+dJWiA+EdrVvnNmw5+xkbciMX0nj4xKsjRgPawdMFZaZNE3xu2LkrfGKDa1ne3JdL
+nDeyygGRDsl93oJ799maHaTLDyub0CMdyf2MssPLFklJdxwbtxNzbI0gt0NhZu43
+FDg91Z3hlAjg/Q2h1dVM22m3pnju2ygF11HUQdNExHlv5w8LWMeqWQ5j7WhSbM4c
+s2v5JURZ+jXFEf3jCs9h6pLlQNaipDkUQA/6DKHf0VbZJzKxBiRCwSP/YuQ6H3yP
+dHGRAd5CQnNc3Vv+yyRqQT56
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des2_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des2_cbc.pem
new file mode 100644
index 000000000..98d36821a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des2_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE-CBC,89A720DEE88FA71E
+
+ozUacsBZx7E1NCxbVYJJHQ0VTWl8RX0z/JzYNP58zcCIi3Cab2qlUshZP+Zb0Na9
+vlHabEqQCGsP8uLzneN6LDDaLmf+ucxKvCRrx5h8wl7DQcA5cAQhGofZuqChPqLj
+1lExS4ZaAi9lRL6aZhf6rgI/apkj+9Ky89sOqJxNhj66NgoOOh9XH1Uvrffv3jT9
+RxeVv5qYcAgfX4aIAM6KjC6iTZ8NyWmIoc8izYQycOsSAn6cqtdjmyc/264OZUd/
+1Tj5PG0q/Kinh9UBJ2F+pQgU4pDlWczXEIwtnmJ2mWyHBe2zuGWtP1uQFUIfwkEz
+KDTTFB0lm/00Xts+vGXgy2q+IvhqlOXfCkJGcP+OArLoyE8cu2xU4KS4qXUITSr0
+i3seUuTrda4aqrfyjNuM0tL/cUSEuT7aSlKdqSmRtYl9fTsmbCbndLKKuDJnxUrB
+ocXfuCEZNMQ/q/8DvwIX3l7RRIiJwqEg5+Ue/s2FTFJh4Iar/1gNQSApwToFHHhV
+XOU0pLY899B+1z10Nop7ELgJEKBK5+zMMBhB2t6nlMU3YojAH5qWEPa6D2Wr0Wu7
+x4DHqk0wEB6cDZ0PZGlWNOBP5bDB85GehAWKy73A73wYZCi9eCQnLh1Zjcjl+6T4
+fli2K+944sUKaUnY8sVT/20aXm1CRqNvgLknZMsg/eGZWX5F9+Jn/MviXmsH3LfE
+6VShEkNTFEsRUqF44Tvd2BZ6pObDPRDOkMgapzqdubujUesvb7LU3yNCRPBPngRT
+ZTXQynnbH0yfnFm6+0BYWtD5NeIzILwZfS6IRMSsCBMas5rCc7O2Iv0yhk/8K0f1
+Og1YH7pctbz1oAPmN/EgKZ1K36GTt33zfrwHpmKZ0jOWF90BQMgZ9dL+VyOMJYjL
+MiyetxwDdiP5TUUAKxXdr9t3AvxVPxL8aVjLb86kJ9HD+IgWUDqiROe88sD30Vww
+7R3sQhhl7drDGwUBj5MLCVhtE8Uli7HdaYC5CvuvlCAQN871whhk2gN27eqp81ou
+RB4kNaDK8qSn83ISnueg1jsQhUGy6B2Rx+rePxx3QwDsrMGf/u/tFJ1VcLlhmOJa
+svVKTMq88OAnZA1Hg6QlB03obSF9U6lJ
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des2_cfb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des2_cfb.pem
new file mode 100644
index 000000000..edd5d8b3a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des2_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE-CFB,AC1BA482ADC9EB3E
+
+tPu6t71kZlKyKaRiXgAMCmyxL/P6dVH/sPVY3KDFI0FsAGoPZaD8s7BkLLOy30Y1
+66kmaaWiaPjQN2g5zMrszrXh4AXazrjMrmIJ2NksNXz7aiySFafyYjyCPA+LIu/n
+KnfoE42KYEmENgMSUV9sh/nlwYS8I6LWva384BIWaG3qnFgfZ4gwgiI/R+1/lPXa
+olOpnI5szYMiV+som2E+I8lgd+Ahf2rempMnuwyWTDmUvYWwst7F5bz9XbmJyeWY
+HDDaTPy2Q1yRYBRvLTm64iA0J9j1TpJnSNm0uIRTVOEIZfOwOx20tFjo7RREunAx
+mEm+kmn4AIYhw5RQE5XQQvD42X4MLyc0M94k5pQHvgJFypXeJ4VsH8pkd4bqfy91
+qiPiKdA7nWnbedExwiwSPOhjOLkmQrXjsMVmoqqexhckJfmNOaXYtnQ8cZc50HjB
+6ccsjyLdQbLx1KT3e/NgfH4VxW4/hbbt3p0HMIxTnwt2lNG3AoKmLlOYSecuA4PB
+EE6oOauIKyJM8pwMV0hfBQ/MUQOnhHG+dbTn0kW91fRZiVPPvJiJ4NmEwD3ks3jM
+pLYZRot1Cd2ksJ79G4NXDFakB2bZ8EwtlQUrQHwW/ykPwiwpqCCha1PUzgsmG3hK
+U8bDWWQMqXtpSmItno1mF0H2TZzdbLpRAZe2lu8/mwww1qZfPE+MLPnCp050+BCw
+Hbq8fF1WVpJvsE5CKzi7Ll7bSrJ6BslrlzL4mFnnGmuz/mbBIL0MO24FNyVGKQlI
+hEzGu8lgp53pG4oSUZ+79CWBkn8mesk6iEOWcFojLKrlhnxZ7mDxBYfDp/2Bmna4
+lFt53zmQHJeYiO4J2TEXOQxvDWvcOK/SnAoLXEhUCRP9vTQm2Ahj1QMmEVvEybOd
+mRpcaJXUOgirS7Ulwc6ZhW7MoFFnS3UluI+gS0oXRW6hCm6l9poDem4etU+IsG2m
+4k6MoMLrak9lSheB1uL+xC0S9k20CZH0X8Hj5atb4R7T5+lTle/fVw1RGdfil1NK
+/ytD+CLpSV15Z6VGVGlzfXTIXYgCIgbZpFxOZk2tsdUm0dPBjR/ZhdUh4ofaxA8K
+jE8HLuW7kCkvmEfdsJxuRVVQ
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des2_ecb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des2_ecb.pem
new file mode 100644
index 000000000..35c220f7b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des2_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE,3D3D716B17DFBD33
+
+XDCVsv17xsOpLWONR8xKRYxnxvWs+bdU+2XCqoqH+cM/vR4+g4lqSPSAco0/LkyX
+q0/C7/BE7mN6fzUMiECYUKS2c739CBVwDJZJBVGbMNFexaQRmlSxqhmbQ60oalaG
+HZfpCLLHQvrOZ3O82aYuEfsbqJTEPkGm4lUn/5psQwudmu4qyv8GFR4wVpNcg9JB
+rDzesxi1aU6dgHSlLHrG5ot+lAITh40SCBQdwkcvixyDIi6l4FX2AyNrcQYmFGp1
+C3XaOn74ADLyo31Iy6rCb0KId6J+S+1aPUW2r1Xb6irI13/QYzIe8/fDfuyV7Ofq
+BKtHdu/oIfzl2X8BkuxJ0CEFxyyEE9majfItPnUEjX0Sn2PfOEwzq5LYYExpNuxe
+pHr9gtB+hSXC5t1b6ifv9PHErMNmBLdgLX/FT4PuL6URrn3LtydPcfW6XMkHtGgH
+zD/nnn8Kl1qXmkRbWHbREcOJB/O/Q53UwD26BsX+Sjwn2cfsgwQvZFzvmq/RwsCg
+Ej9FK80Tvn3ce+Kdt7LGUc9+KaH1OIn7qLcYu0Fhid/TzPCBPQffxpUJ1HylDaUz
+v1txJe3C//rg/42e5GUlKqf+/nzCmQeoaqZDG+VU3UKlngIYitlpwEq5fq/E8V35
+JeuHzFjYj0k9VNsOHY/4AqmEm9qi1yxb7WGINsysO+29RvfRD1bm2Zqhi/Mg7YBo
+8K1GowhW6uGFf+VCPORihMIxoT6xBU4xn2kX09EKrVdekrAi23QzslZXM6Ze0fxH
+7LlktJwah4/QFHwB5qXwmHq3lN4Nj1id+CElVZXjvbKvc4+mRd7VSn++05IFjTK5
+2r4FHifwpkGASJtVbF/7ZseaoOz9sHARx/MFSUp8kRZjOCzstWj6I0Fou51BTtRn
+1ZCey4e1eKVnV4F1XNdo27Aw9aZjF4Zn5hZfUPuUYBwN3W33l8FXRdYEoT/JpiQO
+8LS36SSZGVA0c6nanZoeDZsrPNtPJa8ANHR0QMwBDOwNr22uuJEG/nLvBfquG4HL
+Iy7nxBebe/0MXvsxK4OjjDzmYQL2msMlYffOABOVLCbtaPC/HBKUcmcpZ28WAzdN
+ArkPEcJFTgzI+hCAVG//uV59MkDnUZ+e
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des2_ofb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des2_ofb.pem
new file mode 100644
index 000000000..d06c31f16
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des2_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE-OFB,0472499818A0CFA5
+
+A+t7NfS0c6IsREc9+AzXRaMGW5GR2Ao+WBBxXdxNJZ2n6DWTcNHYL1VZsnVOoc9z
+N2PBfTjYQkNtehp4LDnypbooUI8gJ98T33PLkJ0/L03fs5iEiULcrpBLGc9gsNoO
++f0JcI4xNfE7bGvtveliBWBsn6KeCdwrdcOXziWGQCge0pftf7m4HZ/t/0ISfjXK
+x3ftgiwrvLSnCHfp50xXdN4FGRaIj/V+C50efu/hkAaZ4rCcTxgEcvi+TKdDjmcy
+MfxWmUmeGiT0MRongCZB7XH6g4sI3nwiDASLzvZ2dBysLD0wOhR+g8yumSH2RW5V
+rTr7JQANZzdZm4MpOv2fMCHzDcKEtPd+OlYMHegwE3p0y4CLeYByT4IdyKHVLiWx
+lwAKtZ15VlREgXqBIgrtG5ooEIIjdlabIckAhRc5yOX9sXsMePRyPgQSnG+nSbQ7
+6Y1l+3XueWXjsnr6SIXI5wbszM+TFbZAU6d9tb7B63R8ancHHSUgAbmSL7QpYZxD
+oNYseUzgPv62oMbX9VxiWJ5ZgwzS+D0zGALw3Tb/YVTxI+/VZ58ITZ59I1cg26HT
+H3P1thNPIee0zz3zewMdILgQLh5RWkJhn8/oawDhVVPBba72uw2nGF2aXwbLWx7G
+eJ94GeikGHOJby/J4G+0D2lLlI90jP8KB2fVqHxENGKSMLjZFERGvpiPTgHxWcgI
+SS3ORTxuJDzqG3qFfMhFwQnq6tbOsny27scEQZeNMGecfqGLWE+oclqfKKDQDm11
+JUQnsnFAT3cNFyd2bKefeN9co9NS1UTUw1m3gDH29kwmggFLwSccTFobrIoh5/le
+qiaHdEdmd1Fvp2nMAVufwmb6G1dizT37benyr5Gzc8CHZUMibFEIhjkmG8RQ4dyb
+Byai6j2gf6rzsbKiVtKqgCgMCw5LG8xypzitCBc0+DsYBnlAyS4hXYm41eqMtMsF
+vrP5uS50iDbAMBjuIpWdlRewjxEqiLPZofjbMGwbrvDu45LQ76rwLww5OUj6567b
+FJRcXQdyt/bWqB47GnAZq8NABCtY9HG77nTgqstOqYOOsdkuZC33JHAwTwa+b8tq
+2Y7Zo35CmITqLxfjr2IT5Yeu
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des3_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des3_cbc.pem
new file mode 100644
index 000000000..f73edf131
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des3_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,9BF24F7ACA100D50
+
+71AQTQlq7BkcUMR0+Ghc8O2ykT347aaFUD9BYHXBW7SzEq4th3itEQQ4QxflbgR0
+2XZQE+dNK+s891XnEkf+8ZIIQc4LKr4m3P1t8UeAQvMbHRfAQ1u2/fMf5xwYMqsW
+BscjoQ0lFOcb69nb24E4taRu+MRDF2+eah2hlbHGbsTezIm1VzFRX2C4mnWyfffX
+2WyJQPlZpvOY4kkv8tRvW+nbZ0P7bRjjxrSbCeUVI8X3m0fiCJ0fMVg1MMaj8JxD
+AgIKBBIJV8SYRw3NqiGk/mIlMq4Qtl8PWEFBRf30DRD8RIqOO0yV9Czu/u1hcmxN
+x1/ZExbwOFAFwE/GU+NMegFRXC4toNIU2Xo1C84URpAvVAwwe6SiqWFTSTEHnRu2
+N/tfJlaL2yFrfRnp6mcNN3T8Rk376skXk1zml8Deh6rNU254yK2CFRgm+79W+CeR
+Gb1wxDw0GQ07Zr6/hNBfpAND4qEdyxYAfJQYOCufXiFFxWp+99TGKN4T/+Ab5D2j
+zKmpYFPJj2vuULLPGIJPnCVNjM5v2KwbFY/95Jh3JEF255TORfj2P6HETcjZr0pD
+TCk13jxgKs3mq98Vr5LGEJ4nUcm4GoZayIbeaM7heJTWmvQyP6PRZIDWi5mHs7K2
+wGUrutGZcxzLtaQkavQPf79xt+0CI9D8Nuz4FrKMS2ng+rWLzT3be46f6hJaX1KP
+cy8RLQfaWpFGBPHr8UKhicOpdbGjxxfBUM7Jlg2o1hQIWmSuj53SygZ/EQnqBV7E
+GG+Gf3RDl1Ab9ncOr2WAA5TOQ/yVBEYXy2W3TDmxuwf/fWvwF2z4DLq/J7pieEM1
+b1IuOlcDWNu6eKAhsrq0t6I/wYNB/7qOmIcMxn1dzDHjic3uO65IMH2swXmk7tuZ
+ExdHGutPDZKYG3TgMyMYk3W9YeoEZAjF3TodOYNpmtaDmftjIuxlaYzmtkQCFHGh
+cRlnPXJwaExSYrySX+1zsuqU2QaLB0AyTlAgkUdiLQOzfmHtiHt4Pgyv/o1z/PgJ
+VTVyu2IFh75H6CnSQGgNHIH6QGN3mcMIZQ5G0U2r46X+7+nnodOky09H2Gq71nQf
+vSk1M2ZoaOuo437zG8SlEuPKimz/d+PH
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des3_cfb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des3_cfb.pem
new file mode 100644
index 000000000..eb957ba43
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des3_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CFB,DDDE26F919588654
+
+ulZ1WOcK/yY3ugpb4uN9s8ejFImurz+p4en3zaCfEMdv93V0JT2T/49e+OvIMaOz
+4ShAD3AO5zOXkZd5AUDI5Oi7mMIH2sUmhiJ+0xZMWITbAduYvt69lCGFchpQ/YRD
+G4jT1PY4WQX9o7nN1EYyPnH/vx4Rk6lnOZz7UNpK51SBSBk9lkF/d3bH3J2+pYaN
+G8VET28OIVTs4nqNdu8nxoE8u/Y3aW3FVsFCA/ZhmBD81Odb4rHAHCqJl00ApW91
+nvpTkTjfF9+EfdOE3mfLA4R7CEVWaqnfzvNrVCOILs3qSFGKbIBPBBBJbc4d4pEm
+G+8g5gimV+oL/Q6njSi8s8yV1WWf/nqK6EKd2JJglW700V8dbGHjhGChNTM4Px+C
+RfTF+kXcQZpcsax5ULUz+4KKD2Ub5EcWumg+LAe36VVTz/zDTxhTzsm0/iN68KTM
+jzKjIY9PkVIhZikVkp4s8pL97rL9Tota4OGMacPx3C58MSwJSg7fdUehAcnj+GC6
+Nfi+iHxVpJP4QnFi4BotFxlb2FoVhoh51YdaUehqD0IsoBxrQCmT8nVaz9asJMCY
+CRXNO/2pUpNJY0iGjHfvdmT/aRf+gmat41bX/1r6Xxujf09JF1iS5v/fpYQsshZc
+N+xysjZ8Bps2Kx57XSUTz3NrwMuliJgw6ZbDYBHGSSl2lueUanNArE4iLakuf5BK
+zuf7iVNTZEww904RhnA3HnivRH2b+Q1mWxTezSYZTs2Qr62mJ5ewiFjOlv6hPUfx
+T8/ka54Am8dHsgc3LUDK4pFFR0Nk82yU52FJPbGsggKZAde2tUnDgup6gNmzEjA7
+rSWxEfg53fHda79SQzrKaPGsuWr5b+cl20rGycqN54qZafKFah2tfCzgGdVZG+Yn
+Wq5wvZK7Elmjz+URvKitFhw39yscj4TLlEQ3K/jZVu5/lsyyu3imiUholwMCSuhV
+fg667XbT1qSw8KPWoloOSDQr60d2cK8Olg9DjfMgqmDxVHMuALB+O/dhJq4Jaa9c
+e6ycERign27Fv6j09/aAGrsaB9gMXCOmMhYGSoBUptjb2dx8mN/z3fEG9ykvaDiq
+i1+9GnfRKIYzfxTa3PCpA0B+
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des3_ecb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des3_ecb.pem
new file mode 100644
index 000000000..1dc818296
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des3_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3,695F5DA31042DDE2
+
+dzOyRB2M6CfzgilwOWNhrea/0Zt1EmJSCDPXO7kQz0LpP3/keHgFL14NqxQU6puh
+gYn8TKE+H2f+l8xoNhT6kdRI5OZP85NlC/RvzcIPJkriBgMeLwsRCvhxg0EujRa8
+popm8yF2E8N9YPdz2CcrUW0mttVYeSy2YO/pi5rTJBeqqIjqFYjHPEmlnoNqboQk
+aflRKFw/rZgsE4gzoMKR/yso/GmSIXj48h9G9CyLWPFIDi8LdiiBG62wxK1TDFDI
+FIcU4KY8QyHSYc3DdYJJM2kXxvSy5BxbvWkD9cZS9+CuAvDyGI9dfF6g60f2tCA2
+AxIHRn78StCNbRN1xBfkqw0BremGo8G3H8w6FrdeS1rKzzYqAe3XhDO/uN/0aRAz
+Yact4CIYbZgMRhTJh6YhWma9UfYtxslmTNkxmMptS2SvOVSbhPFSQJFIVWaN105f
+HGmLwoRwV+Xd7nLX5hcR0Sozr58m/1FYun4c4797/bcGA5nDKQ9+u/GvOtqGhIU4
+EY5mkMhqt4MdDdKozQvATqWeSlESIFBZgG5sAQWuRJ9g2Pn1N2GTveY0ofIXV575
+WsharLOALP87zUur0E92LoBrbFAS7/nJ7T7F1Ye8ZoG88qs+vJy8SUVCrDjUqfgL
+90YHTKvmq3fJ+DO+40pLU+aiRBPin65h+5J0jW7f+eGpJV1S5dxIYKW0D1+PgcP5
+URVYuN+cGWROH4DN7zyIFPh1lls0GtAf1to+zBy9QYUFAjt2lB/oL/d8RRso4rHG
+8cUdXilKzAApI63nq0pKN2k9hAH5wGzxg3vWJCbsrXuqExsgZ0EFLR1IOX5ISCCZ
+g6TKiLDDSFBfWKTsix169JzCCptFwE+u8lY1b0A2ApCClXeS5+HvWlC/vtkuqCKj
+V51xSR7ltzosktG/gSc6wesbp0RlldK3Ee1l5Ld3sgoxFZd8aBuMVVfvqz0Li0ac
+883Yr9+nSvc9WspdytrfjcbUxmWtBxsDtVqhuIM4eNusUPY/L6FJhfX2kgjc8RNf
+MNJXiMOaTmQfVCTmKZDF1EN+4IZfdrudL+UoesTzasdlDXGKc5gCecWiQpn/hKto
+6YwKToh84r1R4gDcQGM+DL6wa1W5bVbD
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des3_ofb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des3_ofb.pem
new file mode 100644
index 000000000..86f201939
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_des3_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-OFB,BB994897E99A8F6F
+
+Gx0S/6H98EIJK9lM7TBQrFejxjBVE0kcbBTVNTCJCuJ1Ik0s6+OqG1OFOLdXJWva
+M+k0WEWKhTAXtrrbzPiu01u+OVpIQ3xhgzt0rcU8UigfLLvMdqXoyuUTzCYHBraA
+ByJ0+Z9nK5r/OAJkq4gnRfhsDajZgOy8rZAdyIui9rom5emcx1GsnpW8WdRCuu5l
+kHEyaG5nHtUyZobZk1kNbkqelByCAFndV/eook4kycEytZWNPpFP+tUaXma92vDV
+sg3h2qODMr9ElrbvKYujOuFoO77BYM4oxlE/WtWpD29hmxaIgmnlvwUI7HerpZg8
+DbKYV/8ncRolxoE1GqO2dM2nLKaNKra+n5REJBpUDjwe/eV6dwcj5Uvk9nocEt55
+3qtmPbevuXga9mL5iTN8dm5RgrkzCX4LBu5fB3WviuseUBAqpKgq73RCutNM2gDm
+5CkV7Iar6tV+LgiUcgoo8RAnJbysFT6jQkGPYhABFKzdzrFFDDQUBpcLo6hgHpyb
+uQqjVXR69JFxdQpJSuc6cH60jzRQOvgwpCzpRiJL0mgXNXv51K87ucEzM81Z0UpG
+O4GYnsbo7PQfeLAE1PjP2B3xj8kgcRxWbHkQ/vIHTEAtJcXmAquULi+mNKAFb578
+qlBs77sLICgtpqBUzfoiH1ozcKHOJ3XB3yPYt7WKIxn3/rwqrgRDrPbyrrDmV+FC
+veepr8m8ZssbZjKy3z1js+jcvjKJOY6U/7Uc7IfZ6AjBXrkJIDEtn9RPoexG+av/
+P/LDsCF0ChhP44KZi5q5TLNvAmbvNL/7oogaSq9nw5hJYLiu2gScOAAv1h/j9yhE
+f2mz/xTHjr35m3Ax6wLPk2yS53PATS7XXQtWY8E0LJz7gOkSDvolwnyc5aRgS9WF
+H8DyqWi8vYzVLNd1qM1mAR55qrVhWnmlDmw+f2OJmP+6MNAoptW9nsUaeOk5xJVy
+QNSwJCjzp6ujIn5UhmrS2u59HW3hiW0J/O7aalBXYQxUv/qllKkrNmX8HlB/1r2C
+IniTw/Rd33TsNTBx8tqq9IpnAG4s51xHBeXT0+Sd4zNh+fIqAYLNuMllHMlM/oFu
+A7+h4TYAxEccchEha3GD6CMl
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_128_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_128_cbc.pem
new file mode 100644
index 000000000..8a7d018e5
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_128_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-CBC,B0CBF8975CC514AC
+
+eH3gBb3Shpdi9fkBr66H3xWR0XnIrKhPU1KABtoaYxE3N7su3duXHlx4zpc3YyO3
+s2YwjN64PdGYgFdwrznf97SjdI+MSJgu2wMxxTwJwOltEPBdbvNWEpq8SLdfdlDv
++zndoR7YnMIhQPp5Hch07dhwpY0hn3RELxYf32ALEbe4+xG8/LZWUBoKdgOn+trk
+1Oh0VB3eupjtsdxDWMMN3Ar+l/1AfdBoaQcHg3UdO52U+mTc38QAaMA+9Gplkz+Z
+YwjWz4tyltvTDWGAYGuhxTPVt3IoSewGVHWxKezFujNEhj6wuJBTlpN5T1pALfbD
+JUiGEmBXOPcxwa3QKmVKJFcA+p5eOYY15sqsIhcaXxPgzjO6JQWMErkaOnyB9sHg
+fQTXHwMau2HqzjOM8Qa/lQyv9nf45IFupKoTT6Kja2WzAVxd9KGW+NZSAa+okRSr
+GQrsXrJBFl3+wKpXN3alj94GK6aqCBiyd3d+pp2NyM9TorZhfWxbQamPmQVaU4aF
++nJjB+lW30wPZM6Ik4UqsgXolYXZCtV4cOaZ7g9ub2AYmYCA6yIagRFfjuEs0/f2
+MNN+qu1Z0sg0oCCpqO9kVcnnC4jIaXvU0egZVlGZ51GP7iR5VsLmi3VTbebnsvT7
+x8XYI1WHYuANsSBNRJj7vmrolzVErsX90FInNcnc7o43KQGyeR4E+vSdqoLHbk3A
+2HL9YLDV5cdvGafL6faVKFxUaA5CWCFVtrV6MPJAm/xWs5nu3wr6aNsDk/0R4mqi
+vzQe9EjkMprrihpXqFGpTaehJQFgLaE3FwnxPeUFawqdKIqaKf+stx3i24LkDSPs
+ukLiYS7cPcDYXN9kI6a0fqGtT/gL7NVa/jxsrl5+da/alvm/Ai7TJsUUi8dMzqIy
+85Hv6xWyPrwCbar4Ehq1CopxWvINo1AnvajIkBHvh4EtK7B51stOO6yNEV7spYxb
+nze92IMAtRNWO/yp/p/nccy9PB8/e2v41T8EN4MJuDxGX4k4cG0k2IGzBDcBM1pC
+YfmkHzMBGPsq3CQ85balLEWQTgR5nr/8+TabxyloED/Sw7mLM4gqMmn2KukzMxT6
+qeiFiGtmv2TbD7OWkaLj1Mth/ns1Of8U
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_128_cfb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_128_cfb.pem
new file mode 100644
index 000000000..acd0a47a8
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_128_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-CFB,CB9482EEE6EC0DA2
+
+Bo62wJPRVVYQKoP0egdW3dLX4yU/Dbkx8TtIsNxNFhdwpGWtEGzervoU73+6aaWF
+LME/HVPUh+iZPKh9HuwSiP0GtwJzCv8arDp09mxGJ7XFcqz3AS7T+K9A1OclVa5o
+LwQ6ynBtCsmgiVlS/haNjeONqCtpy0kERgathUclwQCLTnQBZmu/l2Pk8Gdtc1Tc
+osmKc6BDlPOyofTt/UnrhVuZxasrS7tKEnVn/iZr5mjUZAqmC2mJcWT5YNahJpfO
+rawRjukIUOm0feFwov45+joTSIGDsNTYD3OV/+BF4ZgBMm33ApAE31JFoweUcI03
+2l+WS5qtmcwuOYGp0Np0BWg09KVwNbIghfiVUEjnqy55PCVOFH1RZrmHhPndCvHQ
+BwAaac0yAtd5vFWjeUf+pTbDmkA44g5f5aO9uQuB58WWkB8JCFpGZLizK4ISy5ay
+dE8+SjVGiMSZBDfAmiEokoYymc7L8bkTIl5Jo4TuMmtFcHnfohZd6Nue3aRzNZHJ
+E/V81IxIytHRlMl/dZjSujPw9FgmXSip/U1s8ESIVOVoy93HnaifgRfkkGggxp4l
+S8QqBvJTAJrQ9ygO3PBjgdKGi1XWvhH1Y5EwPJ6Wor4zzltftELEs1O9xfBT/zeV
+GENfUZZU+5V5ICm4K844WoiTkH5OIWAi/ZLK9XRqchaGWvMpv9UwBy3c0KOx1O4f
+j1/8pbXDv1iey2USNL/Nbw3nanIG0dIbUZ2g2U/FeKtfCfVHu5LJY+v6njKl58X4
+mthqvCZyyJy2U31MYUUDN/lgNffwLnzFc1AxYyxDZwviKmAIN+Ylh5jbxuElCS1T
+bpVd1+4aber+qv9Ar9G/PJEt9ZdHR3RB/tsEXv7ORke+fVzlKFQu9PKo4k25U/mn
+qfBcwlut9rMu19xsjbowqHyYJbenyrF55d00pp6P037cOKLStJECtpgir6HgTpo2
+Oyavx3OIH7ypvcyaqhFUqZI2EiGOdBwbSBp/jCqOrnAwTKo9uMcnmrsKj6EpjJzO
+VGK0DoieTEQ9VzGbqZKK34NHidE4j/MYW9lGKAADSy7Ey0CllvumHiICWOn9aJYy
+ObB64C3p8NFEcW5SrTzPtXeD
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_128_ecb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_128_ecb.pem
new file mode 100644
index 000000000..1ded3d7bc
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_128_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-ECB,4C5CF049EFF2E116
+
+M9XRNeRQW2K6U0bfpl3axdvsuTmsiFLkZ4C/76MLePY0HxePs3icSW82+t6awIpG
+gHfei8zevNlF331hGPW81XZAl8OaXWi+iGhIfKAInLKY//DBVI5dMTQUKTwBa87k
+oby7hLD+V4lVKr9o/tf2A43QjEkScVlxcofEnWUG84LkgXalsloaIAt7iu4qUMTA
+C1gTbkwex6bId97wvPQLvhFiOyrpsi5Nm98vEeJwMdb6dMNfLAd3Stjvhh5dGGaR
+BsRwDqgrkycYj6pOT0Zvg9fBxwLYeMk7PPo0bTEdY4itvpHXaRHcogsBJ62qnsFM
+mxk1opz6U0W9xKSNTCwLzg9xinRPXGDP5jz0zqE1nlQ1lrsPcsY+omKdaL/SGYlN
+vxDbm725eOoi1H0jsTGJsgcKJ7sKd6LTUEIAEsUvRAN+ro2zLhxteDP+gpCxTNRr
+ElOLddlDm6TB55lBkZVrH/0k/QQQ+L0lBi5Kgg/hE6oanMRGeKQvxhxRuBbK6tZB
+e0b0lffgZR0m49i3A+fTxa68lb6Lexggp6LAkheh6qOVAzSDWbk00fJ9SWNWO4oC
+9FNqu1yafLt3Xiyqv7iD1EOyGhYF8NDvbMpu+gM7qwbTPMjgXf9N9g+AxSbvrmHR
+5zGtJd+8BtU+139ZlsEv+cux1yxkYEypKm5MHfaa783b2zKuyOTMgOStvSOUgGhz
+c9dlWYPkgdgRkAMHzfIigHr9rQssde7pR7ZMlw75PxI7BI2ZF1Vj4weIkwH0SKFE
+fui/C67Uf78OHx4cVPANDk6cf4Ow8buH/vWjEX0p/jpOfNT9ZA6Otj0CyIQ56MjU
+L4nwFU7GqCbVkJtsHLI4sZmP4kH/3zuqVtwRTzQbQAWeTi6RCSwa8/amAStTPcX2
+WPRezgAtNzS1MBhileGuTP+opGdGOOp4AeCCJdFBzkEacRXylxdY7PUsCZI7mRSZ
+7AL1n9jbUbbgnl6zmqn7fybigjaTpLNSkVPOvVBxnNXxOW4n2HD4vA+q3a4d212X
+fWI+/y7mbYLLRs1LPPgjSLfPQ7Ye1Cj4KWy45Z9YBUtjdsEbaaHNp8TidgJKJuMJ
++sDQ3lvtJdIZZy26tzLf3ryE/+2KMTwG
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_128_ofb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_128_ofb.pem
new file mode 100644
index 000000000..331542c4e
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_128_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-OFB,F01B181DC9520301
+
+azqFQnexfYYO2tX4qlC6XLU2tPX5EdwOHsruz4uzVJmYFyRLlrgG57KkahVjWupu
+AHkkjhr9d9m/0/t2vFy5JEnF9WWcNA1nxqzfsaIKmnuCULzYzMWu1cFfTV2DZoAn
+npdxa/eYmcGRZ0u3aZHRGpGtP1y2sKvWmUInYCc69oigiEn1qyDkRE/tDAREh7C6
+DWRcva94GLj1igIHc61lBugZKBlchv+q8t02Ga1slM10QRg2dgAlF8uCPZe+NLUk
+8uOifATkKTsA8OsUgn9nRK9dH4FuZeD64NMCszOw7mYtjJ7YW0J0wYgC9BuEUcNm
+QTxellBcs/qSdi4pZWsO9JXxvoc0lTmvoiS0rL+JlB/UfubVQYq+C7ScVJeTUNKL
+6fF8hvfQzqDDjqx+qP4SgboAmIbL7tTJBeABnnhCOtaY5vSuT0l96rIQm/EZdlWD
+hXKcrhawaq6pqh/mV2S16e2gDRQyUX+jKvumTQhjN1+AkIb7EMR1ZLJFX1l343Fj
+5/V4D2+H3EZhbCdkz4uI6I0swDasUjtigcn19kOy5t1r49zpTJ3wxQptLRx4AXUZ
+zjVXVebGyFYSdu+Lks1VC9WDeisBW18kCg5IpOz3eo9ULBBQZnzSKS30OXlyO000
+/1Em8FPKSKYeST3SmI1aDObXOG/s4tyKTCj+e2VKROq8hDhJQUYUP0AgYkAnwURR
++XylYEfUrW9v758Kk3u82ZhEen/lLUQhWeXkzhVi44Lgih3Bjsm3jP5f7KO/5KfM
+UqECKIHR/p/H/klXPNmdFo919AFGcnxFjQCyhlv0Bl8FSc5FUkRl9TTLu+h5m/p2
+ONV63odsVGt2q/HmL+3hojX/BxSEP/8Mq1JHR4Dk0qqUpSxRtDw0XE9/LU6s9NZp
+zm6lkr5E2U6EN677bmem5QoxObNvc88EXGr0EvoWPnhh20lD3vQok7GBucnycoj0
+9NMmRUIflnj47quAGXI6LuTSzKqOOCZC4yNvdyRdil3DgyLLefr99m2WEe0HolDu
+pIyUsgHMlZC/YRVzqP/6DklhKDcvgWbBeqqhV1r/30rRkegHdsWiAEjmJadlBrJF
+szJZpa9obMH/q0xUH3AXXCkS
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_40_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_40_cbc.pem
new file mode 100644
index 000000000..d44bc8631
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_40_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-40-CBC,7AFE1927D7FEE9F6
+
+WgKt23n2XggL+3rzABzjmOq8sdOYfFuuYUzP6UNH3zdXRt/fh24/WRgRw+WCa5/l
+3Tt0/spkkMsgkkDwPPVLu0MUhfoUQyErK0F+8HeEdA82C7uGIgst4E2MS4bRXPR6
+w9U2R88xdUaljjahEbSMUG7JXecjL0WG+zLVDpDqMdlKNcMz1tnQbO1JNLZCJlfX
+ZlVPslMmTTxs1sqYgDhkAgh3FwSsKMj51nvedVCq2bAtSmgnz/bFDLT4c6N4iLf5
+MXP5ZUMUtWCac1hXayVw4koOkuPELKi2/1vWe7qDWJfqhKmRT2DV0Z1GKPjQp3Q6
+kGnD8oVxbKfCQDI6PSMOeBcWu40Y1yTbBHBFJO5+MdWsNOQI6CZGJCHNu2ZbOd+w
+tIcxZZjy5d4uY869PxxVxO8TmCRUn9hham6qfTw5Mmh7bOyxqID3fXlyrcE7KRel
+dlL9eQuLcA7wtH5vqpy6V28yWculvP7qmXAGUd1gqSYHUs8kipf46ecFwieCNPEH
+x/6hDl38UsuixchyyJTp5u9L5cKPy5PWXv773xcPguk01YhlmqrpTNZsdoJ/CTBg
+gal+o01rXd6snhp7IwSAppCPwh4YJumwdPjF6jUlmB/2AStF6kGaOA6BbJ/lQlCa
+cHAUaVlTZEyzSGShBGJUAN2AughiOq+2POgr5IgeoC0NL8ieMg7bMYjn7+Np4yZN
+KGmT1jZo7OmyVdh9mheahXTT4Axihfmy+uPTECuGjq4X3DVv79OvSFRpHXIXLnX9
+QkizsJKZc6v3FM6o5tbMDbJyelzaj8Xn8ANrugYMC1R4XImDSel6Bgxni2gHuTEc
+WrrILWnNSmNjz/yziFdu5VuQmYaJ1e50uenmOxiSQhL+53UzhhGCrw4ooAOSF5or
+s87oY1HO2aYq784A5UZVYGA6mYFjDDQSsbwp1LYomjoTrwoJML3P9x5SnaSrkEEC
+3Gm0R/t7SkdMmJhRc28uYarO2qdwyBuhoYRxw9Z6bXeaUN2WhJ7hILCL0KKZE4vB
+DuKxE/KgD8ijKpkUn+6fizWau6Lm5mqxyMyEDnCDkvlvv7DMoqZRJvVWSddNMd6t
+T94SaIiCDOY3SuQCi1361GGbVH2dXH+X
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_64_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_64_cbc.pem
new file mode 100644
index 000000000..4a1ec9823
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_rc2_64_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-64-CBC,6646FC6A291EFE41
+
+KWLSTeo6nX30rQ3WbgL/13WAEMCtaC32ksYorVhlN4ijjiDu5gEnmfLRNYK4c3LH
+IUJawIdZvHSVxjrKNjmKA18w+4kedYCCL9NbNswd5eO18wldFR5NlSI2FGggzANN
+OwJoHUOXggYxhc2/xbYHpQpl7gvJqZtAjyewyTDYeTC3VDFoB/JywQ/8vv1MN8Ce
+Zx1k6preAQrnqo/LEIm+GPUa9flzWZlCGTIC+obNkjJGZPuUKLM/1TqNsrum33aa
+gFwnz//khQULylIRwxfuOMCHTslFmrs/7MLLbJQyTa99S9kc+s2VDlaKWUn0BVe/
+MoCseykcuIcskavuj01SYySJU1YHBTu7RvhuYO8AQmnsAP3gWQUMvKy9aXmzsoC2
+0Nk3QCZiG+1hN423So4NPOh42OWbqrDls9PKhXvQ8H+58rAxW2s7OTN29Klo39ek
+w8SFjMEtt9kLNpwBCJrIlolXvhD5WQu6XbqI0CtoOrh2Ote1c4uN88HyIUi1Y2Op
+QsfLkKyx7yJcJrz356Ab5lbJKVpKJW+frEHI7rLlfJrj88uzsh1B7oPL/4fhaj84
+vNUfadRJ25ZivBiHHdUTrKk9CLsIDS/1DWM6sDclYjXiA7kgGNwJupOb2L6VEKPv
+eimiJ9ooKq00E96Dc8s23FteQqySNaUAcqDnAkS+ck6pXQECZs4uD79k4pck1SX4
+O20OIPo79pzcWrmYOrTIXH6ttOcB3lUQtB1fmcMT5RSJYVSKtgBxLPKhLcL18xfb
+1HbDkpdUqS0R/nK7ecMd/LP+UmMKPUyMUTfTUnlXZzsNsgIBkm1eDn9RkOGaV+oc
+wau6FWmxVSPs9Inb+7A+B/2bP0qyYnciKX41I/PClKGitm52ScJyrEN0XJhQ0O+C
+mPp9weJI3IwpDn/Mc46NQO9uk4rC2P9o1zfJXC38PlEDEC66a1Y6SEQOVN6iYkYm
+rVytxWjD4o5vC+GwYJPYrmkOg/SQK1AlK8TSpNC5TeRcZ8YIbPLRfKRUQvUVtFS0
+fyPK9zdariwubkiG1a9/NWCF9gN1/DPKFYy+p5Au2ICD0iTtOND9I/Yw8dqsjzsF
+4jhYQ+No+ytLYc4Zo+8s1RO7yduFz7XQ
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_unencrypted.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_unencrypted.pem
new file mode 100644
index 000000000..ee815db16
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/dsa/openssl_dsa_unencrypted.pem
@@ -0,0 +1,20 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIDPgIBAAKCAQEAyKItMopMK218pcmy6PkrMVXAv5dt07TdGBuNhVWpQ52ldK9X
+mL7CPKpo4Dy85EZRPvRNyOnhe+LRJZ+ReKntpEkEiar/ZsKVkUthPsiUMpoM5S79
+JK8iT8F9HdFjIFKaXGySBZ4xcrj8HQ/v75iolYCso+66Ybgjs9/nsWS0UQyGE6rc
+ibx7xPAtcbaGZUBaBtdkNER7+P2ueJwej89aNZxj+AKuvrWrArq6/5zOIhGR12wQ
+EQQjj7FQ66ZFivJ/AYsv1yXDS7mZBNp5eMuxk8Kmis/++HKcP7tdbVRnlfTGdBuN
+BMyOcBTIsE11jwikcI+KIbr9cEZoaikkm4KyuwIVAP4DZEC+/JZJ0PHSEtJTt6uz
+yn1hAoIBAHhLbqDib7zqaFBrNnbaBSNiltY3GxWM6uQT88NH9YWz3wXRb6i4KJFH
+9NtLbK0RF7MoQVprJY6LuGQHZ/e61Fs2EabDwT4vB2HT619fVUvDndbuSW6qfUR4
+y9kbG7zLkE4Mnym/ikmUwLABLA67cZUS9yjtcRXGpOkiTAQfCGBeUH6nWOFEaWjI
+fGNMQ5awKvZhIvGyN4Zvd+mE+199s/kAsCKFux2Sq9tYw3qS0Tw2IEebHsHvX7A3
+bvxV6p7czVxlO9+O0w7bBTekPpw1BnCYmPyy0H36g/7aF2V70UCWzER8zT1Pfh7d
+3P0hLqHYzX375l/7oxuDawtcDAV++iwCggEASajPdllHVQ8JvKdPH6qDkjC5XJTZ
+RK46mYm1cCu8Q9Dy9ZfL67CcJBpwKVHNC3sXmk4XPfs91AZf/t01qbMJvCrR8NHs
+jRyJkNIaMyDeWcFmO0KmMi374BQpFyIDQ6mK1y9BilneZ6gHDdfHMsKniLFW+SQf
+9hlwlArIPYuELu7riJhNcuRUTJEfybDHwM4/ht0IFbyUIFl00mMdTrozk+e/esEs
+QdWbx2UBjNs8meZPivFbT2HpQF1I0qZhtn3e7jcR5YatBQ3e4abnu1RrDc73q7d4
+g2SYQK3PmIWwxiFhJQTzeiQtl5rKzEn76knAydOtPVRgjXWzHUoW6Az0qwIVAMvw
+thRrEZxNdxELdnwW3rpYBm6B
+-----END DSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/pkcs8/openssl_pkcs8_rsa.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/pkcs8/openssl_pkcs8_rsa.pem
new file mode 100644
index 000000000..8111b0d69
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/pkcs8/openssl_pkcs8_rsa.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDIY6+Wgj6MqdEd
+Yq6FgH5xMgTBmFqAonR/eshjxY2C6MHs+WmCmNSDik2NgZWIaODvOF9uOEK2U0Zf
+JEG2LcZxoeIEgg/mfII2f4DLy1JYajm/llzwFBzAd/Rkcs3qwP2ba5VKn/pSqNLl
+nKHMXkXO+9SjfHDx95x2dK1dB8eGQGculOMcTm3uK7UlWNO4TSlwG9qHZ1aoM3GI
+g5C1fIpbxJqDVjFq6fFAapE3KRIWIQmKd3E5ICcDErqr/AapxnfO8UFNxVWSOLW7
+ZAfis4w/c8/EAgyQHw42R0dNyjUOZsToF8McCsOpRjGolSU8aUyqspvd8IWJPd5d
+6HBHueXNAgMBAAECggEAV3q9MpVVPQ79TTjBO2Km0D+nt+QMzk8dUHGHfZbGejmm
+Pw96shqJ24rK5FWHs+8lEwmnD3TcGsAr3mjzjtZY5U5oXtNwoYwFRElRLqZqIlLt
+NugrVltRWeyD8j30CuGJVQoYOGWyX9d3ielg8NjO3NcvMtembttLoKK68/vrbH11
+9W7wr5p8/xyMfyl9curnmCFk5QqJ1FBpjPWY05NDIBCUJB0tGAqViCpxEeWPSlvb
+xcElqWfdbtnsYUxYU+iOTHHotoKnz4nLHYK2/njMhlCEyMXfu1DJOd8rg5yXewJF
+v6NhXgWStSexAT1bZ17LROazVcHfWB9QmXF1Fm7vOQKBgQD+dZxPDOi3Y4gCFegn
+Z+epNyl2aPTkseEZxrIqPKLHsGxUfYjQqkX2RdfTrq2vf4vFlN6uCXhSlZKXfLH/
+iQ8FAzqenhVVHK2fv5xB0SE5zNmcHDrHshl+/zUNI2u5AMFECVO2SVbgoFjvgkou
+FolK8XUXfHfb4f732LUyYI0lEwKBgQDJmkWHhzekz3P5iWaAt1SH8bZpt2hqa6Bx
+A4VvMdtmjCxEDETN0Rb3CPYxw3qa3xGfW1y1j/49xi4gr69yaT2Tbca7PFGUmWRo
+OJwfCUB5uBUi6UVytK19OVKReOm4666x8P3YO4cxxSI/HeoSU0HR1kkX9rGmrsGN
+MgUQ15+FnwKBgAKf6/DUzUG3ARwkZbSiWb1hGEhkZMJHI29EoWnWHke5BiUI9nRQ
+jVAxADzqvFfnFOYA1xssddVEPbLaUmu0WjdPBTfFoaqzFQdkzpPPOGyENGpr0B9n
+MuQgdceg6eeKnnO5NOfYcdD3VnOCAInhKaFgRDjty7604hBkZ9oRLOOJAoGBAIJ+
+dmUMlGr80XADjTLh+DhqsA1r542DDv44LkXUetS9BOYjHuIuZnQO+/UoOBNJMsn4
+xGDNzN7FihQkRCeFkZL9arbFi3TpeUGw6vV38qEXE69eWVKvOuEkmpqJLphBDfom
+KNmvZopDtTAvt9SWybL+xp9ZUpK26ZfwebD2MU63AoGBAOa2Kt01DxoqiWiQP/ds
+Mc9wOw1zJsSmIK7wEiW3FkCz8uw3UgjF9ymYY/YAW3eZtuUpuxEzyENb9f21p4b2
+zYoZ7nCUo4TmVXxgCjiEWglg3b/R3xjQr1dAABhTeI8bXMv5r/tMUsnS79uKqwGD
+2Gc1syc3+055K4qcfZHH0XWu
+-----END PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/pkcs8/openssl_pkcs8_rsa_enc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/pkcs8/openssl_pkcs8_rsa_enc.pem
new file mode 100644
index 000000000..fa3cff6b3
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/pkcs8/openssl_pkcs8_rsa_enc.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIleYNcQVMEocCAggA
+MBQGCCqGSIb3DQMHBAjb8ZXri5RWRwSCBMjR3ICOxCzBu74U87lV1QXPNlnlHD2v
+TlRv2LNLPseEBAMiJkgP47rYwpzMmJjW5bNzCLxT0pYv2Z3/pXPUqy6aNJmOgCmU
+HvVGdz2jS+WYBtfijc1J6MkuvkhRIBxL4CYJidVurc5X/ebRu3BHbj9Kg/j5Hjx7
+DV4qTxZR8vbRFH+ETdnVqj3pCYNOeYXvV+S0W7IN3rKmEk2su3u19YhbwnZH7Ny2
+YMjAn9FaYT8bK+zlPBZBiQ8TuZxm/jxvW2ScQPLk1pRUs8WkDsaYY1gdg5XuKDND
+xA+mq5xskAMUliQmhJaYxlmv83QZ89JzSd44lLvnNeiaP2xjAhj10ZSVQ8eOXP63
+NfHr9Ehqne5k0CI2fGg78pp8vIihw5D4WjHR46NvmbL1KIlxuYi4nFMtc9aK1zgq
+3rhDL9m3fZZ9Rdd6lb1LN3ZOL8e54tL4KKVkl5jxhrThHujACB94remv6da2z6K1
+LZPuDwI0njzC6Y6LgyGgAP75NKNAH0UzbpPncZxBdhyI5mOgRZnTMNt1XoToXOHP
+CMR5JfKqpczhoJnfcQJhFy44E1NH+qBOsNQTpypDe7Qiz878e6ebfcmXID0OyU/j
+o8czO+1BVT1S2LoN+xpeWcyNYoT+BnRVC99G7vKUoOeo90zNzQQOAEyoAjAg/52Y
+JWnOqnaxDqa0uJ/BPmESFvxeYZypJtoTd/g7n45J4fGBSwiH05TB9PbLHD3YcfxR
+NorFiq/RVXMXkgOGv+2ovJ/A6GK5mS/r1xr4qKnnO44zqwaie/xdZpXuQfQ8ZS7H
+XLVWgbdGP7fbTW72mAG5UzUr6c6gwPo8g6aiOaOnRU32SswhLp4CFgiKFhhgZ4YW
+tLmWc1Lz92D8ctTMvXhV+z8NEPF+livmfANpyhXl6ErCr8jEnhGgj4r7BA19dUXC
+Tttq+Gpo05tMXqom8/6PbQ3Cg2iCT8RGk6v0p2ne3Dg1LlbnklEfV8/DbYO5tUD/
++BXZhF1otr/ZaSdz/jJ+GzmD9KvhheQHBikj1/KicYp1KHYfo9oZJT5ulBO1UX/w
+JbpLaarntLOqb5im6OdjkPFkklVV9m6EByrfd35BTEfowNaasEvrj/VpchGPo7yf
+eFB6HGeIFHNloG7xXn9rv4npJLJOleqmBgyb4cQAk2KwjEJ38LHOyXQL/+tfI5DK
+NKzoFH33dtHnP2ZwaAE5ffMYv284y06n09yOFqPi8YkeFs+UiFeV4Kcht1gUNkPo
+IOLhwfVxoc9H5CbIBC3emckvbpnuBT9+EefGU3pU9e9et60mQ8sp28vtx16rN/e9
+CiXhRXcLyQZxucmoLKXnyXgJbf3+nXcr4zMkNurqUisc+YVMALePkJCCsqRWPCvo
+vDqwMl8rkG3jAqmMJbtZCx7+vvnRnFQSE4BXOlzEQNPZK+EdlfvY5uvksIt93FF+
+E6CIPHW4ki/X6gTIR6piDKiNEle+2e/fJpYqk/pFuVfmiN50QXzrnLrPCznhzQ9V
+GN2j9/b8iKzBk5y4wMNkOS8LT2qdcJoJRzZBb4VV981GwFxhAagwM29wko4sdNG/
+vU4hrrm8WAfmp6d3/UdG6VdQj0O57z7BX6Vr91OBNw5RZKRkQvMu3Q5vCH7ZfYEj
++YM=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes128_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes128_cbc.pem
new file mode 100644
index 000000000..e31505333
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes128_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,8DA91D5A71988E3D4431D9C2C009F249
+
+ZUo4tso7YF0+ayrQpLsgM4TN2H31b5g5ryj//QqqVG/WmvYgl56Vu7fDbYXytgnb
+PQoJLo+8iUI1d51nirw3RrtAx7Z9lrBu6mX+JBE7nwCVsjBVVlAx1B6d6Jwc20wj
+935VaUkwT3n0zZ1dwb9HLjEGUp82TIbiZ3KjWKnfER2AhFXJl3SzswA5Fvwe0AYm
+KTAEYaaxigTTPgltiEQDIvA/Pnh9ZHjh6rbM816Fa2hdk30wjU4U/KkTYbg4hdoV
+vLeQpYnMT2uICCuvNXq0cXXetfbgdMFsLTxvVElUZrjyMTsw1QtjijeM+gj1dbDj
+HGzR0k97Xj3q+84m+SoNW29zPLZzSaFDX4KdKKG2cHs9BTYJmzb0h7qP4pCXjGgF
+8V2iUDMs7BQlgNnOa9gwT7x7DN4HM6J0MIlNIiYQZnupqqYQTDR0rd+fhdIsXHkA
+qNZKI/4ep7voVIufSS8ZyoISES3f7dvs5nnM2C+QAtL+l/yaaqRdfUyn9BL1djaP
+akSRPXmHrmed8s8YamuhLHyf+GPL2uYpd4i1voA2KKYSx4PnfjH/F/8fXPZr3dNh
+sDtcjhgXHTNAEVVek9VOaHtlUNZEY0UcbP5uqBZta+wP2rBTC94DxIbN+k8A2SlP
+cKGkaRltjnPJAXWmwKMRm1J7vXngXYq0r5VUvnGPiUhFlQwAW5TUml4+1SMEUirZ
+y/Oh3AjhOus67uiAXAQoqlr9KykueXobFrhZjLCgRf7iDmP/t1eK40UyV83w85yz
+cORi8FNfqvCARz05qXwfhf2NBMTRbLNzKCGjS4iY0dLNk+QYNgJGoM4nFVkHYgbM
+pTThzpYgtRnxQf1mYTZFtqr8hRJqiRfexzCyk2JC3rDtEO8WUmNdvdKNN0KwCd4+
+dcVS8KzNov9fYMqiiol0dL89WBN1RN+hs7HnOJkNZZgaNVspOLCT4+SN5fLgtbJI
+BzbAgTK1ILrSom5fyzZcRkYwzIqNc97YhRYnxDp7vJFlgsBqySJgtdGUkTPrrzAO
+CCYyi/ukSVphPe+qRsvj9L4syZgpLRgDdZaW+BR0pbTUg2WQvZuKL5iMhfB8cbAC
++FjoKeSlxI68jukrAYHBNcco+qaAYrUaHsJFUsbf7j85DzHxnaA3M+P0i+LWJwOI
+3G751QR2CrjgK+QD7XUtUjBMrsVGlJmfaQsEm7+rtuPynXq+ArJrvgha4lc0GRD6
+yNDCTTMafuBnJ72wop1UEE8zGOsqERsgvOAL10J1s5KCcPHGwrDhjhr3/x1GI6/e
+H80zp/E9mPgzYQMfhl06s9SwyvsxFCIZAfrKIhq7lVqeEDiusYbe15kCLmTVNZ6C
+c/BhDc76vwek05AOLaZLGbdpMRwevbOn4WvUHV0o5Yr1h1IGZKx9BQYwFS65SDCg
+uxfM+dKulE6MWD2hPUP9s47+R812cBnHu5BVV+Cq52YygAiAP1+nfFw7TBKzqczo
+fnIsoL69JthqtkZiwl36uMmcoWwZM621ZqYFJI53WO57uhW0uuoyidQj8HoNG/re
+o3OyAgVO6sTFsw/Dwxo4WX2AKuIt9W2IJMFNC7aS7lH0iPrtiVC3FFXvuY5agipH
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes128_cfb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes128_cfb.pem
new file mode 100644
index 000000000..8bd32ace1
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes128_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CFB,2F7AF90B0C0A420FFD62214EBEFC4CD5
+
+hciElffC9lqjzOx+aBT3DYY0/oZrI0Q34xfQg7IOTUPUAxrrT/UjHlToX56VIbRm
+PH2M5yoF88Ji7BI2V/Y2QRAjAYRFVjZvPO9ke4IGYI8xfnKRivfxLtW/YfaiKnqc
+7VyyO2UI2tYGm27+JJbGLR+GdaHmcnLmencGdS4Hn3KDQ9IK4eLLXrBPWyzGnxEZ
+qA2OWdzqodjppFCjlx892YJUsq+w3BXu5lkPoooTEoxB5RywZfngUY9Y+raN60S6
+zhjkaaJTEqAfnAsdVMUvzpkYpoH5LCO1vl4+XpKdeUu3wJ5p3D9TVc4kt6/V/MeL
+rHJVN8FKJKYddTlaP7xOmh4bivrJao6LzRUdnyxGL6SkVQ4ipitgWcSwFGgRQc1m
+/MzFmTATtC8tocSqXMY8nblp0/sabGhUSTGG+uBGddDr16D/8J5rb8cMCfR0KLPF
+3uwV89PbbqpS73IUKkolRjxslO74TPDT5ds0i+UV+J+AJM+9CnyY7WI3FgMlVvRn
+KwYJuihDzFjozJfe386XWYs2Joa3Eo0vbaVvp4hbHq5Gh7S2iiBpqy2uN0xxuZA9
+QB1XpLd+rOC0y5l1usuVc9kBlGsTiFVyBoZo/pWVlTU3z8Hzgv8p1TAJN6jgqVH7
+oMVgubXsz1XPHrrjjgZEEpxqzXtKJw3DKchGDfAn4VLTSrOINwMC5sR8l30OZVtD
+IdlmftUBhv2AeVUqkLsSMKGdeagfwoqOlfL4FKvSt4n8Vq+Hn9lY/S7n3cjM17YE
+YAgpBjX4PJqXsp8K5KmBHPQMB08jW+NQFABOprdes5bwflrERogdLZmQH4vxqUvs
+DFhHVJxo1wxeRDOftVgtxnmHzU+SaB9MgdWWhC/4pxx5uzqYi0Q2kSOZ27EXZNdh
+MgVX16W6jLUw9zaR1wJIJZU7SmhJOL1fxvt85RytaD28+JvPTNs2ffDpjPu0sXh9
+n0gYiWztuBNUv1m+LMpi1SPtHvtoZLhc++9g4BXoZevtgNl+FqvHs2Ob9w3yXqkT
+lyJQbqju674MaKXDoQ+3+tnXad8MRGCvIgmIUzmMZj3O7QcrBbDY/pbcxoEDOaKI
+SygvYvKfrBIKq6PuGsN1KHSMrjc2A4+wuTYy75xsai9YtwwT1tyIIeCv5NXbbtJq
+vW+nbSNYW+khIicBc+Ye+GFfUh2MXj+iC1lK+5i+1leKo4zLNFDmnXKgZ4jOOPMa
+FMYPZkwANQ6//tyP/qzLWGyBucIC/Ym9hUvi0HlYjjU3Z+Zv92vM+2+li4mtMy7M
+tdcm72bqsT3+1rtJKKRaYG/FiQizOGTDyhgV+JX9MEVwJPa+61V9jwkIPPR6iBrl
+u7NoFfSp666XbD+LurRh82vlS7KYOB2zimHFxI6nOHBsypJynqtgIzLg5N1+LhVz
+t+cxucW9eFvkEEXmjZwofqlxq9BDso587kKY+EpOkXrlnG/ha9XeZcyUipn+jQ0Q
+64Cb7LfvcU5UEXTcMh6BKkoeNP07O1ecpD1LXMGYFn2HsfYHigwwcZ7sm9oCCC9q
+vF/rjXg/oIMagmc6MZOjRE2eT9tpLRAaMynLiln7XS5u+Q8O3RexEw==
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes128_ecb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes128_ecb.pem
new file mode 100644
index 000000000..b6def0873
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes128_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-ECB,3E3ACDA483AAD613760CC55C7DBFE582
+
+PJupElZP0QC92uiYotAm/CG6i8ypU5SXxc3zmrk7sBdxVU9JQXsIE/oIUK40AlFW
+cGuHWxxYkdYNtTpuwG/CVlsrq20YfpxQrl525f4pz8ETWt/P5+aLQ0TemEKr+LVE
+921o6LNstZpftQJbe3yMz0cFTjSfsxsHbadfUZUQzobr1XcbazPyhr5rrSntgIMy
+rJ5M4G6QrOEAIHfVVZ1oizlFnd4vjGOKk1i6APgEEqJTIyFWoCXEzDtaMcl97GEI
+EWGusd8DJrqpJKnohVoTZdOzLrnerJXEUEJ0cz+UjvljAYg2MBSJk5v6HCp8aWcc
+CCoWUbJp2933n4nLBq7EXTVmJ1pwbB4cjNM1oL2BznW/pdznrSRcw8qut35ikEKW
+mB97+IMVr03orl0uFjHBIch6cPLYkXKi5w7CO4vvJeqqPK+mCtckzgIlzsdTL7Pp
+tp+wrMBtG2Ibh2HeJuvvlFCgoYBY482aPu/4NMei2eqfs0p5g0bf67R/BiG2Sxxr
+4o8hmR14v+dzLsQeoKrr3RnMqfmrbqgdkUfgBomlsunHUu9u7jB70TuYsZk/COPn
+SgMM0T1pxEuHdXfyZPSS9u2SFGEhbW4zIuVz79Lo7h3sKdYJqmwmgOk1P3IL/nra
+YpcacWzmV0g/GK8O+2CSGvEh1+m0ffQac1Pd2Abjzg9jghshsBTVTpkcFI0UfkIm
+gpP/hwLONl5a1KJn7u/ltFPdZkJ5CWPe0ZQ1mqjhDaPnc8j7iuFzUilsWITLRof0
+KHUDsAZSV7gZ5G/Lh6DGZdlwfkD4b+2GOPayQ44mr4p2hdOque6Z/LEXtOv+UvvF
+kR9azOu2RXVTiDLL4c/ntltS6laT/nCg0goMs5NAis+3cxKd7Uk/yXBAulwR6wmy
+MIZuSM4gk2pqbt6TJWIfxl4ZtPwp+jYIpMZc47XQ7w5m7YSquJzjilaj+IDVPkhF
+TWTMf+Ucb4duBD39HZjBWAoLkF487M8KDtcxL60uHuhVJsKyYsb8b20ukA++c6aH
+0VqU3NB8VXH7De3pA08G51P+XLurlLUUr118STaEd4r7GR8FddFmSh5x+PSuVXut
+D2p2W7pfvS8OTuaMF0PZo0KkUq/TbTpvMcTax+G0DgGJqFFhqxNur6WoJyYbQE0M
+nX8USnuJhS+BRNPEXc5i14dWmZEeE8i2KGm8RlL3KZfyrpBk2zwnGs+WM8xAlBSY
+KnGO6bLvRaUl+8IT1nKfY30HLr2tX+F0fEM9Tn443VgsXkYnMoaPDU0aW6+J0lLE
+lTeqJn8MPVRbU0Ss/0Q2PQLpayHrR+ly6yxJPOY6Nc1eLkhXoB1DwiGh5Mp7J6+V
+R5UL4nRr40hZy+35sH1lf/+1mY95Rb1hAYP9r5K9dAvqkdUMSPz8rtzb/4gevLi2
+rxB5XyOHM/qZL9ySpJWjFPBwOtJ/EJioRTvnG+/8jdxXWBiGKdkGLKV8k1z7gOee
+ewq2/8n4HnzMm5YKdTesy6LuaO5TaOAUe89Eo/CxPgdM5YnxSxRsxunrPR8JMLYI
+V6xyNRRHLOy2ffGdJZ3nqbSOxCNiHW+Glh5I2jyrKG5Bs0S1jbt3l0hZKWSU8k5k
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes128_ofb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes128_ofb.pem
new file mode 100644
index 000000000..2986eb219
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes128_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-OFB,271025C313E6EFC0403320C73382F15B
+
+/L1xK2Hx7pYQBTuhHX1P/mkXqLAlbSSz58hL1E4oxsDJODiVH+ueTSKajA8+tbxG
+eBK4p0s5j1fp7SJ9m4QXBwvhCnis992H9kQws6U9gGFrofrYAniRFhX6yzvm86ee
+deQ2Pfcv+evGRPigkoeRSQGxSa40fJ+5cBs4G22cfrKabaEKxnLtQpqPG17JQ4/f
+LdrHz64IyJTgvV6LCzJxShO7vxwIXaA82HNR6Qp09WUXxLB1/pfQ8oQfZbTUkvWi
+CBdXWT42VZklPl7StNiAN9U85K/USIYkKG47CpJvWMYbWJ3Dt1EFiEFi/wmYTinv
+b2K0xUrVUKxAMfmVtr1wGSJA9P9AT0/sBO2vTn5ibXVVHibtAET+vGXLtpGqf89/
+RmcqNEFYxvLzoTyR2FONtVluAC2yk10cKHY/pzZwQyVfjcgMlbnrZz9Pp1Y6ntR5
+AfXpVR/qyYOaQ8BeMCXkfR79GPyCPV6txy3KE2mbajwamvL7eR0+0R3Q0lhVcWGp
+g91D1nbgVFkHGOugO+2yb8vLq9k7K84Za+TY9NCqCG6g0S46yAgZD2rqrAAO4UIf
+6+nno8TS41W5wmsdEarbRoIg7iIKaPKzEmRRurSdlj/s7MKHgQFoet/OdZuAQkV6
+FumyDmqekmPAgIIJEO2NdrWo87RWKCzc61Yl52qmWsqrJIHrPORMGdjdlLVxXXIE
+XZQot33Rx7/f0VZktYB5fWk08kjWQ0sKTDiHEp8Xobq/RDyMTm9TFIkeFm4rLkl6
+Zt2bzp7ssoKeYuJgpoRzUmGP83wgl+AaJZpupARdz5MlqXd5knuPTETFPaFIf98d
+r/sl/V4E1nh0x83HNOBrLlpKbeWocVV4zv22q4zemALPCOQKUPWulINQWAYiTPDA
+lBQhFRnJXSZYFUqFWpxjp3yIWCvTZd4wgX5IQpaJvG+ehRn0H4FR0hJukMG7Pn5y
+ye0M0XlvVYWfxhLRDK23iNkRzVIbIxZfxqaInpGvatcTHyb2vnVFateSGlXIk0wU
+GxgytnTGW2fZtCDOqeQxCL66nIkpqKhB2hJKaD5WIG7SUikjBblvVcN+gkj9IWML
+7LB7xjE+4cyt27Rt9QHuLchdgSScPnPTZhdX0iK1LVELlJQFx8WPZpfXwpQR/xz8
+tqAKOfyhOX2XxYYOoaNN+ffQ3mEnsVFx2uQOp7PvNjL06XdYP4p/AruzVnbqsDsG
+BIo+oo7PfepNw1jRxcmeoaMotIZ8Feq8H8QEARqQSnzRWAJZhV5D9ztmUtaeqyy4
+QDbgxBxdV0nLAWG7e54FMn5yJfjqq2pkBl69ZvR3N+F+L5/eWlEpalIoq2l8AffY
+gDxlGgp030MAyFYSLJNYj+UUwq8k5INaC0QKjARbBMblf0HOX4U6RBqrpzn2xyvU
+mlM6pTiO+mOpG9WLgQS9XTUk2te8n0vAVUTk4Camj94Vdl8JWFNsfJIgwE59hprg
+a3Pz4FosIcBbj1pYtlA9Lz3kIGe9U3z9rHeQHNxJ8agW8NKGvlzY/YBdb115UhnM
+WOVp5TkpF2MyE+TGWqXzwNo3GutaNVs5YO5nX3Mtx4ClRrsmQYVTMg==
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes192_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes192_cbc.pem
new file mode 100644
index 000000000..b80686d8a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes192_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-CBC,51C73DF9487965B976234C88321E3F30
+
+6yLkX7C2XTX5AE6KqWsB2Lmt+TMGsoHIH5BDl+o7Yjx7aBSzB9X9KPTsVoPmTCOg
++yhhV6am/yBImCdyuY8d9Q0A1kPIJTEkshgk5vc2KpW08blLCHSCjokEVbQ4TJDH
+bMtrEBVMU1g9KBTMuBpbu6MLVaFth2GTsqExX2gu7FB5EAKvEGhkmLudo1jKkgvR
+aiiyMd2CH2MTdatZtw5PrJmkhV/6RMZRKP8r9wkez8NN14ehmk5QDY2s/hj5uaEf
+xK0GXY6OcwoRo85PsOYhmOeFDqHKGRo9a0pPBy5ZaV4udj0QZekE1fziOxiPf6K8
+0BL50UUzQBW+3n0dIZbzlOiJQScQkjoxi0kc088FHXHf74VBoJUo6pckAu4OwpXW
+L4XLIGAr2Kv4OMiFSJOcaihyawE312B2URcAzVCO7skhTYHaC0fMYDJCGTc2D9rR
++V5tVfT1dG4xdB+p/b9TQyAu8PE10jT+tVNJqGsZRI8I3iOtyWsBcn4sQInpYFYU
+R/v2tgG4hDdq1beEY5N/ZaLsoSyFYZmwbzB+BVhPg0W/9s91/nYAQgOL6XrExQjF
+lZxS28ujAq1LDNzg0NDA2KsDGJF2TuST2stnxyvf23h8+KV2nZLOZXjhlVl/Nr5O
+WPm3gCmuPf8F6FPqM+zI4YBBRtvLRkXafUNuvc7PYVNiaPyuMh7I7U1EUUzTpkqi
+OI/YD4xv6DpDand/WEtLHaYfVYU6PAapLV0T28BoFITp/qxHYYnXVfhn4htSgiwW
+R1btcxWyNjsIedjb1LJ2EwEfuXqZmzDz51uDLBq3XQ/dbvDkDzfZR3O1KGaACxAT
+tAeAdnTnAVliWYQiJ7BHn4LTJZ0ERGL/R1xpQs4quki4WHtEBRRzP6BbmUYYhigO
+QwvTK9darP1Ev7miF5BkRnrzWqCQHNTlDB3i/RzIfIDChQbSZtrpZH/V/quPuPlO
+1353Q6D221UiChhw0+8GmIszbLwBkDq+Zr7/poUBAqHmTaA3LeiahACM55ATbg1+
+FKf0nvUL0SaEBAqFxSdQ1mnW83VCMlCE7Luh49BDl4/nufCdF+iv3cYRW2SDHPrU
+HELYYLz+b4QLl+XO2SgUYEkU9s1Z+eCKcVUXGzz6vZUsA8UwvYIy8b/1cz4Y5sZ4
+MLpEXnQRMwAjArh4fvmosAG+diC18H2asLWpUS5HBBrSb8lAqKPLl+n72SlZkFjE
+WP+qq3koz3EyJsjwH2qbpx5BLhTPcEVHl3DZ1eOQmCXcpSm/cqKp2MKQFubCC4rr
+nphTD8uYKCP3mJXB8vqIIO9ho7+GVlCHJdZGu+3bw1L89O6ZG6WClbY56eGz2xUn
+DBmikb9sppeYSs0eX+yQ9kjQRf/BGnRab2dSTGtDT7jp6cL+zWUUOawLHWS72XtN
+3XYSEvvAWPygwbBuAuw17pwPPmTXduRiJosR1lRk28FGsMwzbj4byXm77IO3vD80
+cyrAQ/bmSpvlmYEHvmRn9N7QT7SFANY4a03aBK2iuqZQUz/zeo3eyrJudBXIiwUz
+/ZRteBa6SQagqDsmfeuGCjgTFGVnutCokh9lajm9BZ1pZtCmHEDd7yz4Odx5CmxG
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes192_cfb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes192_cfb.pem
new file mode 100644
index 000000000..00cbae570
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes192_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-CFB,58F8574921C585278A50F7A2EA529595
+
+RQtPMTKDNttPq1R+DiwHrEK33FOfxK1Cst5x1jrDhXe5MObLhqbz4Ft2idjtG/vC
+pemznnZqQYKsuJl/Th6Ydsthkg7HH1pYLRstc/tWQTESa0RseHDtdw3e/Wxhm6DH
+pSqymOfRq8R7PQKPxboj9fjxeooWlA+RQxGdyRJ6gki6PljOD29C2hxZV4HuL2II
+tUn/cdzaGu6bCvpFDvDuFja3TRtIrHSbCq01uZg6XrFui7BuwJxxR5lERsauJ6RX
++lAvhwXqN4nsEQefvZc/GeTFzklsoJ+c3HJy7pN15nyfwNzmmH5EK7C4CdBJQymv
+MRwe9hY/LGXB5IFEgXvop9bh2qYk9tb/zb8aAHcLS9rwFsGOo+5+Yib3ds4GC5fx
+ILKH234g+hkhutao530kmWXFf7qup8lvTlBZueAWcIFdmBCsWjm8ejxQUZaPCqEY
+sZ1UMDw1HPX7/4TXdVNZWrxHisv0VWnhwJNflEcI/k/GR0/qUgkHnUPycWTtg0W2
+7ivs7D0EkIJy2OyFj5swWs+eqhsSDmd0BgGL0VduLB0voi1eU908Af3PllsTwf4D
+UaLFvOkllIbul+YweImT9TinmkWIFMZuNDR/PHjpbLN/39YkvSub6oS4LOgKEu1Y
+Xr779QOZHMcIP+PXoaxqOWls9hgI6M3PAH+gAjwF77OWIQIh8JZCibR6HWYcr/qo
+iFTzJGNN7P06s3IOek+YoHG1c0GoPsNungPOzthNnaAUcRyvZ1Yg8cy/nhrA8Eeo
+A4G/I241jr/Ex5jooykpeotV1/AMIF7qxFeTARQgObRi/fiR0r9rjaSMbOt4PlRv
+Ln0ZBqedtkkRBPRGO0VViSbUAUOq0oSb98FWqPFpcFl8tXRyqe9m/W2zACczZplz
+OySvRuASdKYpGk4DmMlQtS8wjzMYTesBx68OiZfw9W2nkH+Xapc4cH8hyb3+aXXb
+b53nbp59+mx4UwPOcrdzVHdKhDT3BjYrJTv9kHAY8yA4Nr08ZsO5tOeI7vF+bUKx
+kWu4AIEccB030iu87/xHXUEOBzsV6HzzT1TrZ5GKSh43vhRwoasYON2xlO6RuKCD
+Yv6GbcPd4lv2mv4lAaDXk5IThABHUL8yhqfwru4L43av5AwdslRKIvBM7UWrlXFe
+A/Hipy6jjcusGiOyH7WfWBFV2/f6NtX6lGuna03F/yMZcHI/HEK5RyhqOYOmcxfw
+A1eGKSqOnq9IJ6vXnF8PuRYKB9i8Ha0z5JmWkh/dX5dhTzwH6wOz4+bLgkgXBdhY
+jptSs5zsvrxGiLCbENPTjArsBbT5NISh+VTrrUtmA5BLPWx6d4NNJ5eBXTnpOIJr
+rxA0halZtFYKj0mp1ZgnVylHC45QDiwzDnhXra83RVrcgQjcX4npjKOaYZRQ5cKR
+2F1QdvoLvE9YqhjH0QFQWMWfvmLHGIDIDkSB6EyFsgzWdv6kIaiYsmdir5FzE8c5
+SvHvu28j1X4OL62AquOFKMXQVns1/jLp0KERx1EhrQChHUxpA/cbqNJbhjHoRQK6
+0zXWP9gNlyrSIKY4egyQmjcTDvNXVcSDu2o7EfnprNCYirFgsAbw5A==
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes192_ecb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes192_ecb.pem
new file mode 100644
index 000000000..106704e94
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes192_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-ECB,A3A4C4B92548B906A635B84B3D67591E
+
+E4I7KvCs0qknDw8D9ISQev5oQCNiHskfB/SvuKJ/qJoJP52qk+ajN9pNMp+011R+
+MRaMlK7tANTrQ0L/Yc6QNUZW2aHyiex0aoC4ien4ojgvqHfaP12dMxFhOoLctN+N
+zrAPSuQg2OEBiWxEoDqpgA7FTUbxPiJ3QdtwwOXS5kqAKIEIoNnCPCL+45uKBrP8
+encSI+nrZIXLFqGEukKZuFH9qzdF2leOKSmEW1kmwxMOfQLMVQMJyVzd19cCxU/1
+FZtPRRIzFlx4PlNYLKDpypSUavgo5V/o3UHk6vbP/Wd+Wy1ERwNliV7CTCCpOrBH
+qJezvhkbktiHQQ7+5zU0jsTzTlZcxATdm2ktyfEa5GKrCNfrmUYNwNSi8DC2Dn1x
+4z9r6OfKV3dKcSkgmFS3ZI97ZhrnMqpvo0h1kg8tuiboI9pPWp8OsLIvw5+jz707
+GLsl6hI0EX61YFc7bqeetnObgiaJMJxQJXHi0U+Z01GjZ+qgGb6USmQ1D8r34nuj
+4l88VYW4jBhxa/IFpzUoxIioKG58xQT+OK2Fi7BF/OJLQpj+3RA3YLqry0D+AOT+
+f+nDJepwrQ/CZtoQl53ssct+mDY0D1IU6u7ah9WdIuuptV7+WxutFfDpXsmErKcZ
+eILXaH5zK9iNVnVNQDmnVacjQt0x0Rm28wrjI5N7M8jGWKWi9PMLElx3BTo9EbON
+pJ6x6xshjmdCR3gOLo86CZGkoUM1eNGhJuihrl6HelcZxeFnuiNYnLb5hIaqDd1v
+NpFUQBRC6Q3jz85zIvVsiN2vIyak2OGDRs7r5dqb1x9QVz5tMjxuKe3t+rfX1FN1
+vCusACQQzOl6NdTgmm5Of+pMniOL/kRF78e7zva8vM1Qf31/z8wtq3gemt+pZstW
+WV/kRhIvY/p2Nm41TtltlctThbYquFTEy8gxhB/Cot2k7Z494+8UBVIn7SjsdDpU
+X+N24itXM9/sd1LHrXBSbBT5PzSBJFC5MS4Nt6qpvSKIRbyWINjUoTvbbUwoCo6g
+soYBPJR9KeAcQ8YdBOEXtFScq7c5ZPOGCj/+3p++Pk7yMmlxNPvs6HLjdHchjAYz
+jycK/uWYNLOwKS/AMxwi4R3i45pPgIRuwGdRyi17Z8kOKATdyQwScbPOShW9/066
+OA0rEORx3C9gMoKa9QYo3O9YLjA7NS1ERSY9c3X9anSgR7eSs+DLRwFiB3EHoCba
+ULqd3n7qBKgkQpVF60p34yKb3K8o5s0cIE7oAm3VdoI/O/RSs87rDmUbpuYzAA24
+mXRwBvPpwEhke5PoPeFIYmcWa4wUZOJWuF78U/tZw047vcLKgr60Z1s+DlQJvFXI
+tXkV3qS45f9UDaWQ15YNev9fq+x/1JDO1LjQ9AHANBjRQSzE9K6YpyIw/SZlbo1O
+xuFrE077EL3hrRNh00O2rtcrK53mAOKMX9D5xifIcN4/uD9AdwU24YvC44gij47m
+hSg5wz0RokMNGLKTXaJxJGs4+ZK8JWQs/Kf/V9j6j/i4iDWuy5Ra7+/dIU/Qy1ZW
+cc8Uo2ji4i2z+QyzbpbR/jBqO++lcV2byEVDy8Xp/0X2G9mY0ymIbm7ATTlzE2/b
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes192_ofb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes192_ofb.pem
new file mode 100644
index 000000000..88dd91a78
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes192_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-OFB,9797077D8AC3052C37DE4D719CA8FC00
+
+SU3g1XmkcVhlJpQSWXdeHcHI8IQCQBg0oenT/35NKgWnFBlysqwGwl/pwgdDBmm4
+jLsPaE5Vanm4aqWv9DNhItOQokIbIkxF6qKeV3wNSNbTsSaG2LNphwMiLs9rw4G9
+3aFV+0THPLAy3BDTsB3NPuRqlOSVcwVrfaeMXQGhCOPGmsGDeczai1xH7eq1C1no
+KUqNMGdf8g1NuCmQnvswuTF9BCi6rIO0JRqLPTxoz/1emKfHhJFefpSj88zg3ucm
+cz6ZOAlsmWm1MQrktXd+odzpmjHtd1vNsgr4GSYUeVxxWQX4o8pVFqWqiQXii+HS
+ubtMARXAuFIGoM1RCMN8o7sJG00RbG7zNxfhHqe4wSkKgx3qEuusUDewXkDeYhHJ
+HGQCD1epByGHCZkLwBntccOqbCQoSNB0/PcFU6vJrtgVFl8N4VsNMRuLj2ZJ7uuL
+/EZ3qkLTk/Ek68++m2dtAdyj2KF1O4z2SFROSh7MCqWl2rYh4zZcBtGEfmQe5Pwz
++kPycc76ayzHO8Bjg6rl/16Ua5Wx7d6vy4Hg7JYb5eDmj2UGJ8p/z83KBdQnb1ku
+84ZjpYgmtjZ1vY8Z5iZqfZro9JBjWM4wFZIKNXcBniC7kBV9fRC5nzpjs6qWTPRb
+bd7PLMuyRZz9PO6cRuhqYlP5tYSGYYVhAMVutIqSrQVRDV8AnmblfPiOtT5lHC48
+GR/xPTIFxxVqsDmeyBzyXn9gzAJKgjTVCXNksXojM/ZMfDDvAF6m/Ntz/izp2CbI
+f2lcHgsm7SwVn2fvHikAugA9B6ixMCXygO0L5OEUDJW1e1fB7FMasjrwRorDsxsj
+JUNDW0KhUXWt/U8lNyfRm3oNUjQQU3x1iEymjQZV10ZO9DTn28fZOF70moUWnl0y
+ffELY1vLtLNP7Y5tcGNtJARSGnMUW99P7OKpLNXkhL8zE3DGEL1N+gDS1n81kzTH
+7hPjM6yR6gJQVsQrQmXrEpIlHQeGA99LYchzyVog14qMhvQItDlCsr5UIPwVwhMP
+LTA2LITZOYieRAqrv3vn+yFHYG4k9/C/xHwKHE/4pDw8bLn1o8thGv5ZW4yDsHGx
+n6F6vqJrkPW6vXkmwcgO5jK8JBbEpyzAPc6aSsibH3JF0ufsfs2hQ4bwb96OmU6v
+mukMLjQoi3BJC70Op1bpe7wtCELJw1oFvbZDoXLYsa3c06HK1M4rmzJQTIEBjqxd
+vs3g4L4CQ4RHAzlkjLrCF+wcBHt33586bDrt03qBEA7GSyAUu1NSM3UKjjM0OydG
+u8echgFIz6XetqDICHdN0r3ZWyICM/FgnVQhs39fCgafVJsy9C4p5jByUuDPvebP
++gvvVqkb+DGwfkKT3RUFAcYiNHdtIob3kmp8OJKTFk/nwdUwqUTEu3VFCmWog9ps
+oe/0KOL7j1Kn1xEFkOt5MdSFCcpbsYjQNi7F1gWAr1vMXDDPsSizsniGSvXZIYBt
+Pk5AH4MflqbHFofWClhGczSLi0FRiVPqWyudoU7LOesQhhN74Dn5IzkeAGtDL8r6
+4vC+G61PZdFXhLXQfOEL99hgJ2mjQP4rVqwdz143YE4/CUHmpq6d8g==
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes256_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes256_cbc.pem
new file mode 100644
index 000000000..7b032036d
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes256_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,1876F5A50C9046D504D47B2BF8951875
+
+BAPOppBjFxMrMU+NI00PbmXXutKdPAiP+If8JqX5xGQDB9bSt5Q9R2QkaMx8Z94f
+trVbp82iERyPYnwcnA1Av+pcZhKi/mYFgDBPP+dDLp8qKRFAWil0zc0U2jkfo0U7
+v8cpO5+oipkJ9RtjaTg3/XmrwCUFZH4KA6G+SUFc4Oxj8/dzQ5YUDtJ5iyArRlnr
+v4nsvP4OvsI5UFYwp/T97ks0KSmo6YLMpJwUBwcleX2vOhX8fd3thk9I+EbVVt/f
++JztCTwr4EsLxWe4XVmit9AKfLU0AhmcA20j2YXE1VFvRJdyr+gOGPD2SDoRgiZH
+rRBhfi7cou3QmZ5d43jFYoYCBc98blEV07umH0DXMTL8XSrfWNIjZf8uQR3+ZbHt
+W60jVdhOCEb40KoRTHQAMBQdgVVkrbXCFyc9NeVzzhPqyKXElGxLBjRB9u0h15DV
+WCJUdc9UGuHzFpVFzpEaehdm/7vl+SZXUzAOgAQDtL+ATsvZglyMx5y2UA+5L1eZ
+grA6e3tQFdBcv8w+WgYW37oAY2VkHKjoHs1TnR8z1t+OpVovnpcklawybh9Avv5J
+kXyZGc+lbbb2gvUw33VeYR8yIE4zBoePuhTFM3K4NfkBbKavBBXMjQlsdRzlt48r
+RqdFnpYc1XB4ZLP2VparhG+Q1UueVML8uBcd5F6X/0u9n78LfIITwRUpVoaLXRzs
+94Us0pbzWFDxqxtqKPZHLAVJOYvEOwZD5Haw/bwho73EHEx38MY7mk9T5PonsBko
+7Op6aEmKK1qfpJ1aPvy74UmIlVDHu5WEMkYx7nQL67gnFXHY0yKjmP6dc2y3+nfR
+qNK95RTaS9VbACRS+re+P9+Z3aAsQGvj3MA+4Q+qlscUmb8uk+M7tg9ADk0VSe1u
+Ts2x7UZroI61c+WzgsQzMAwm2QLPoKQcvv2b+iGD82enAtleTTHL9rkoS+KmNNU6
+hWL+AJ7HP9s/5+FJ7/4CD84pcLECXQ+f185vvE42TfdZmoq6NgSKrGVZPLxYnyjO
+qa2sTRzImZrXPtsnFEL9OBflWA+ZHaAGo4HJNxZW4Z90HJlAZN3isSZnE3jPToKP
+YFdHsPv5m/KpNa5luh4L3K41QWzLmPlRR0aygWM7/0fYkgxI8PnBeCp4OjoK6qHx
+VYTWMKJQTLyji3YwMr4CufFAVty3InUZzm+ALMFHqEORB6JqPTR9mtnR145FHtxE
+1z0LnEoDFEdGuLjtC57yR+lYS/vgMbtj4EqQ2zK93JaXvI2HxxOiZCZEDww262Bx
+QZo0vBoAd5vkMKmz5eAMpRVkguF1wN1RPvao7I2auJIHp/3zoaUowpZgtbmDHZFA
+Kddfc927GQRxtUH3QQVe1R6FFAa7JBHNeJsBvZu3bj3l/7BATzcne5OPhjZ/t8Sl
+hMqEBZuo0svrEc0w+e8dpbPEjuj8UwBmHYZWlALby5N+YJ1NEtLYmyHe2PFNXwK0
+2fo45CCSyl7YJrHD1ONJ0M804ML4nMwmYq6fOAaV9ufQBFqQQj/hyyE93blB8f2E
+I8LMN/SUKN06YU0nErN0PRdm7CkrS+kutn/Pz2H4oSbUZ67z4Ee1tpnVQjoDYdQU
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes256_cfb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes256_cfb.pem
new file mode 100644
index 000000000..a616b68fd
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes256_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CFB,37639E4753C0E4CD43EEDEEA18AA66D7
+
+HKuYoKfUqTRf4sW12EzTuIFK5J1FkeJAD+ajYnKeKYneNiDbmDlQv0kIk12qBv6l
+LA0oBH62QKjUDKi/sg8NAO5CqYkN2ZB0gQurTgGT/jrvMkkkkwE0x1n69bGNScCN
+mkqMnAnjQqbo1xERzwqX5OWNTTb4iDLiPyjiUlQDONl14pe4x6zGpVziCVCQh8Q6
+rAPDryZBg/wQtPXNhNpk8MiTiSwe03wq10QP6W5TmUIKp3kD4OVfBxpW1N4znyIu
+unJDVcRdBf6XA+aL7plAsETL6F9Tx3Mxm5GaeaJcSOWWzKMvqYhAcEYwM01lx0w8
+LMMRUogny67ZqaLywXZWH6FCJGCnJK5oaJE+jlnKZ6xhbwAxMyxWRCZC9pF22ocI
+3IY602+shDOWZQDoihhddwPJejh+o3mVFEglco3YEByL7Cy6GvqxhctEEH7uKvlQ
+gXGb7srmOpeHHfP76N9afF2hn0mqyToakdZqgnlgT2jm4UDHJ1vQ+onIksV56I07
+tVMEmPhXQCIHhfKdzEgI/v8CiLL3W/g8r+20/5qyKCL5vPBLAxmRudYKbGkhm5pq
+GkzaSp1cKe4ipUfVc5OEUikOMCuadal0TUQZ+h658aBCxLWHNPdZCzNdY/bZLN9z
+XPhAzml/H6VOZyIxb9hm+FNESvqNKdlU2NaE7HW0ILKaDif7gsZhvogP4qNDp2P9
+xPANQh9UxpA16AUTUNOqk78t9aQVpbjZfAeGmcw6AxJ77uK649JgkEnKqcuxcDSi
+zn/8NGeaKow/bTW6jJJj7b4cMys32uxRjeeeClC0moQiy28OIJpRRCRJIs7Muka+
+dMBoNyftBnCONH+oqj+F5au3QPMwKH4v/4VpO3hcByXcqxegH+BPEZzzYJ1OnI3u
+dh9VlpTdC/CD+Gn3ZRqYbguSaqow1ZF+nlpD0xcs0IQjNEe2BVR7CULUFVXIgF44
+pTv96/LvbG1J9b0VuBr+iIp30FG9azd2xyn4O3lW2xk1uzvo/Wf1vDGvT6AYyXNG
+DQS1dGtIm3+sy975sNTlba5gWgh0YNHjeiQq19I6ZzLFhkvLKfh7zpx+R53YcqSY
+lXj62N0u2s4KUygqg14oiIUoEnNr+n7Pq0es/gYs34mY/KvlqA8Prax91BaoqqLW
+qHN5bEv90KdKaJlvdWsCUjA3wReeaQa+U737GMXaON9/oOJ02bWC8/OIzUPgfGRH
+v/8YL7kMnTd+Col0f+XxnebWSfJsAzT7mjfly+An9EjccTeiOon8submd+L8WySK
+lVvWzBD3l4HKjQkr/3/YtmpuymVZyeTzngVuSdw+iXWPmOOuXHyjyD2Htn5iNWch
+Zlw37a5sHhiFtpNZtOnhpmDbX9sgt68KJMB/E9Mh3JuWCaKZZ3Cv/22KA4KQRlNB
+FSvDDKJBrM1m599A6GPJisR+iC7g7asJQ8hI1OqaY69v8nP0Fo+Qk8+Ac1L/n/Vm
+RjksignkKjvqgWENNn5Bf9A9+zZrLLu9wJJLae7wIiw4UgsNob68sGjWdLyg+tab
+QTxd15H5VUIuD6pkeAI2qC+0sSw9V6LKm6pmEIIbp188CzApcsGBXA==
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes256_ecb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes256_ecb.pem
new file mode 100644
index 000000000..f679d6dcd
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes256_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-ECB,C5DF56EE3F83A1F8C1AC805EA73D4D24
+
+ac22chm8+bxXpppAKfsrFJwCY0S4VPnXmFRqlAPZRuqBH9ylFcG+F8TuHdIsLeof
+q6s8yxkXa8y+/3hyqIZeMwN5Ai1Cas4P1iMwEtMUCMeaip5t0nf+yeCyx433hDSW
+dVnsdeuiFCiBUPUXfp6dCGO9kOLUEwu4wM4lIJkJ4QVyauO0/DwObQ6s6xEMFvQH
+GF1AFFTfW39CpZuS1rguG4hTxW6aNxjEaSKHJnzWu+kduMLJEaLUiL5+i/tUw937
+V8DhGdWU//1Q6KKLMr+5w0k9i/FhVxAGJZoZ5j79ToYORGr4jpkDPOvHaCydM6Iv
+JH0epC0wfG8L/dArNGLEftTpVVlvqHMpAlc0Rgvn+LtqstfyWFXqbQ90NBxC5Fs5
+xiGxKFGpkX4stoKIaOvFVw/hoCI/oxs8Eihz8u4QjBsl/3TdYQ6AUyfBGEWImy/y
+hh+QKCVOfzAmVGcffXYf7fvZETVgpo6tynxKVlSRXO9ZuzANJCC8jkUEOjc7jSKl
+jyMKQMNnQxyplgaFxnWIfs/snvlLQW8DlpMPH8xSkHkUgLKMWrSLB9Cisv0N7V5t
+Zl7Xxm3tOteLG73JxJKJkSZ9djlhkPvlvS///mvLQc6jse8EzY8peQMI1pYQu87U
+CvHVDOYn56SFVJmo2koER8FG8a1910NqdCKpNkzjqTl1Qbz7Z2VwghTslM7sUA2L
+AJP6PgdCkiGbi3oU8moPy3Nyg908j/17Bj9VyCXiegMAOxI6Kefim5Nn/sq+2/7Z
+MHIucQX6ka8KjEp9jvf7jvNC5WYxJkKIl+yzwAzqRQ395Lp1sun6jPfngnPQmkXY
+toeOeFvKlxaQu3QgNY7Hq9wwGbK/uo+rLK+Jbnt/75w7x5aGHQF3kf36epr3O/0l
+MyZPPx6sLblYcNQhBV8rnSey1WeO6105h61xTXdKV6To/m+RDZYvt+qs4z5SNQlj
+oKTezoQUh4J4QMg0EPhghyCS+/+cPMdnVnwX6Ds6nD2feX2CpN27xieGEp5ZhioG
+qWi6/59B38kBW2e60eQyL5f53bhWvywBg3HeUsXCD0ujtXBqPMuNnO6FU+/5Ohg5
+BAJ/bXaWiOkobmppBeaViidGv3NytL48ZIuQ1PZsYQajFb/k1SkyLebmeC2NYdO8
+VBWxAz5glgIKP11K9DJMD3n6PVl+ZyvlYZUGXjfUhOxHKVmNDHv2o5Pv8jf3WEhs
+yuWEoRECvfNlkDrmda0MxMhEYjeTysbxeX6fvwD2InzuFKhfzwh49p5LdZLurEm8
+DI8KBIXUx8g3svArJRvbVLyW0deMlXBY7h8Yc/2y7c5qBwfYrYhgazxVBfRqS3lt
+EsO2sa0V0GaGhPh7LUt+n1qDDYmaOfxOdpZoSLm/surciEQIQVNXt264YuFJS+ot
+vHWWVHzS1AZIgizu7NHRVeUmu4XEgT8vRsJYeogyG9o3U27L/lF1L5ysvYQjtvkd
+q5idZxCnY5RctE2wa5gjxPjmgbt1sUN23KOiPyz2cmXGBh/dwqEhIV6j7+WeS4/r
+SFBZBeGRHi8tACblT/6G9UB6FcycyD3hf317Zb3jXZLve17ozwRZRQ8aBkz07+iy
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes256_ofb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes256_ofb.pem
new file mode 100644
index 000000000..34ed53b55
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_aes256_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-OFB,E6AB8D4FECB44185E26505049A97B0D6
+
+Fg8Nq9CxyVZmBNEiN9vBI+gsZL4lvWqCPaR5E+Po7acLxYGos4zIcmLCBa2X8lvM
+UInn087k98OAClm+0PvhZ64/AdDE952UclD/xiNvQCH25HGQy7wk/BxuOM5/FT0S
+rlV6RGMibelHpnv+yploYoHD8CSo77N4RHdEuepPwod2fGTKu5Cbbt1FBGU5LXWJ
+BrDMOlSN8P/rD5ePADhDsYnh86g4cBVHTb3MkrteLa0m1Szt47E6d3s+Ued8Cg5S
+7tiJOTFnXkmG87LsLZ0HDp6yML3g2gpTL/1Zhn9zS9lZc3cnkBfRJmttLBPjVCiB
+mStjlXnuJTDBdgQhJPJ4+2xJiR/ucFbCnUF/VICsl0hdz2Hd0PCOdhzj6U3jbRk4
+uI2sv5TV/E+e/Ppvdh2W8LISSBdIwp9CJf3se8RFz1dUXwTMGM50LKr/dpvy3T4m
+NMO/Cf/LyA7HBFJxjqf++wi5LPDXzROm1QHncvXNUjypNPND3RhP53pMeQ/Ffd04
+dw29zrmbyQKQOOac5Ss9Lj33Q/WzBgw5UxxxMxwRVDyfFpdz6JRfMrnj2c97auLI
+RI3euI9A9yRNxneBKTobS0EjYyqAiU6b5MbNwrybqvavbA/+ZMEg9Ylg7vtBOXpW
+YLLYFYPhWNEambOfNJi4tHcX8znGACxO/W7v3Ir+QFhw2IzSvntcMODKGaNKMGys
+HJ6mqKbmYidjhtKen1qHB5u2bukaGWUj2kjkv7jjuDK3ExsvB2PjEV5d0foPEwW7
+9QQeKc5pY4tOxFVA4qCq1tTzUhWr0mBkPhnFjc7XOLbu0sHYdr6ArZ3SadaNT12w
+LG2yg5r8BgmaUVTTQAzIiHhAQYZoCHAq+ohNocIikIh7lPE58DL2GPpEdXZsgzTi
+T+EUSkSw4VtIMmnWw5GNE3zCOxvx5qzhKiXVcnB+2+IF3nlHkQqFXcYNGhezZjnJ
+4FlR4FPzumRmMj1x0zmdbp7eTFpipUpKqJtC8iuea29pEl8opXDNhvmpmrT4/429
+7x8eJOjZhm8WL1dVpV2/Ikc9boEsYzHcBkY7kuaTqT8I9tdQ08ODo8UE5aReaFuZ
+vlBY4J+A4lltQ7qQ+sAk6gUMvlY8h/9L9gZiGbLe438Ndizskuwy+jAZAEx0f0cK
+YnTsZxBHPkWQXgBHMhe3BAAA+CZaXPps0SjD0yMQs7lkAgag6zBXW2vqttoJLU9R
+f6uP+BLwZCFDF1NtkROLV1oROnaGvMbHWcar2tw5qNe3BAsPQqGk8XnqwILz4IwX
+MN6QrjzbBC2jcL5jsxPZ/Tis9+wfI3t1Ke0EljYqA9RVWuC2KtRK+X3xOK6tWEK+
+QlagHRDI0Z0u0slCLjpB/ev9Ajqwlr0h25T5ucdsLd3FFEKZbzspdfsJuOXPM5la
+Uv9gpYIcuFrKcVbvuBPzt6NX/rp9gozZv7ZOnujjor6RDorHsfbgbEfcerydvJGu
+PRk788TkAB0LOE2wD2J2UO8+Ufp1qK9GWmtr0WFCazqFfeiorTh71iS7pwUt08so
+0BRkqfrfP6pXEcnh4p+LKh+dnbgIBD+KH0qHsyc0ci43byoOSDDHnQ==
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_blowfish_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_blowfish_cbc.pem
new file mode 100644
index 000000000..e3f6e2443
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_blowfish_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-CBC,E59962EBB3DD3C74
+
+1FpslA4+P9E8HcUUGpkIMWeZYV2XxCgOiSgCe2NAUiutcRkVAg9nPbzwnsQTbckx
+d5uOE/w53BURpxPkz3nNcike0sr3fa/MzaoRUDo0P4MU5bmAihjnZqhRllqvw4Zt
+BsyxjHVn54RaqZC4RNQUqwIHYZwJmHUi7Zk3+Sw7fivMZBr/AWqa66I2hk20+obB
+y5ubRjtjw6uaciPLIoMZksxoEwi5xv4KnQHAQnaihQ558RPpUwweqHXyOZPEC1Kx
+gNQPrTGc4Zm+CKqR4CceACSYzcYtechZpSQqn61emmtyhowDqXpqqjG2nimNihcI
+hbp5O+O3fKZFkJllB20xuaj0rK1NFF4aLiS3BK6aWeCZ6aXFawSvbQb6vGx+pQmP
+eQemfllRXXkT43CHUmMTaf6gKnz5DaxDBqdVP73dBa6UoWnxTrZcUNKiPUCvB3g1
+ciJePjBnsijb2Bh6jIwr7yghIbS65AYE/0V+5Duw360Fa1OqJkMuz5pKeJIUcYEZ
+3yuI22CZeorkvymKhrt1hUn5xLIKRZkWg7UbXG1WXCrGtPdJ+CxnwupHMdL8iMLi
+1haNeJ3E/PeMjehQRzSEEFwDljn/b1JtoWsEwnQPTPKY3505OWIhYRwRXLEo5n1y
+QEfktZ9UtIsJcIpfi7hMvbpp/7Njlu2MJKZ/1ZtvwVLoaXFTSivqcAkDdP7u5enb
+OJ4EaDWrRXS3Zj31fpYTV5p0fRaejFPevRNnYvMLRiSoFobd5MUrKjxpxPRCLiW7
+24BF9QY7C2Nso9yR7gNkzLw5x/725lGxa2ZD16nJmiECOaEB8ORVlilmjX2OQi66
+hpGVtjHMaoGr5IvBrtc7Q9aM0bdoFZD5I2mOm0hniNHG9es2IMByHWRAQFzOOLGH
+IFoIyW3OIuzK3cz8lMLsh/Hlbzo/3bpX0rbrn1XZULWAJ1oNzRJRi6a3Sw2YoIMh
+656IJB/fGRbG9CMVMl0T7onDUhZYLA/mV+xy2CjkQdPBjFpQUTn5YHu6zMU7gejo
+YSV/4esuUfhogLiqw7sPuCDqLL2UftN29xloQDTY6MlrkFb9jCciAwn02DAmsN4h
+7Utus3Z2N7gJnxt1dRecqr2o/agIINm3tMh0LK3/CydmlthZQNpsxMD7IqaWFfQR
+Uq7zQUfYZi0l2J6iy6FUHUokskqwgiNhMP2Z+uZ1xHUnoP7E0IZMHnVWEKBIQZ0d
+ddDucux1jOBlMwLqom3jYPjPkxoeSU2E0ozVNSOqsPnoKkz2qKnEHhea2sAPg4eX
+lsZ9ENQyQMZVapjic41BU/32pbrE/+JkK2Cc+dcLlrnHo+JpFeTdbleJhZ2JgXHW
+8r04vZHA7tQOc0KNR522Niu7dvOW302lwmfp7D5xfon62/AxVhos1DSZuNpVClm3
+V59lqeCBDm1yJwdM/946Eq45YJiTNTzYsPPFl25KNv+3+GKkhZ20GuLiaqprel3S
+MC5XbMJg4nc0LiAfDT/q1jO/EKZ5LzRRtkVvx1D8To6DAptyFoJSMKyFu79tQdfN
+371+sXEX1VjpEGxO2t/DUmuERIBdc9X7rPNOXSl31QxsXy4s73zcAhI94X8xrqYZ
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_blowfish_cfb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_blowfish_cfb.pem
new file mode 100644
index 000000000..b3581daaf
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_blowfish_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-CFB,A6C793D28C38F56A
+
+sjmmZGwl3qF65MFuXEtiTkltbaXuionUsMtzc/XzyPPaIxcdl/03iR5Fix0hTY2Y
+/W9BntQGcycH7uNcoYwOUScTRr2BJncyoDXZaUx/WOQ6cDHuhRWWwpLpmitfsn1B
+SRvLdKddL1GE2nfG2xhCdN4N7pVPUwIahHye1AkaSJ4gur8tU0++mJQTjDo63xKB
+oTh3mZB0OCnelXtoYFKGFXNh5ouAPZgcE84breDJBoGReH6f4elkigtSx/J2QhgN
+vXERboYz/HHhHSRCtMSp0qLEQo+uLcFxZcSMQE12eglOOucht877V5n5RMLFT/3c
+DeZdg6D1b52UzaSjTvLm/jJCdkYqZf4SFuBgLHF/rEALQ1vBqDiKQ7QxuWz5ApPm
+P0ntscETngWuJ2g2M1EoxGehwNiJJEslYE/CB0Aky1XeUmUAUm++Q3QVfUA3G3C7
+pP7whQSr1Y7gL44EmttFCX+dX8GWXuZDXa399wijphVw+6bl0gp/hWRWriTern1D
++/4S78ddrci4slA+/Kkq423wjLNGZtOoy9cXRmFdbQlMfVaeu5U7LmrTQRrgGVM6
+GQjgNanXYhkCNubQ+v2Q6FflAdri8Ac8ZvFXxSIGZ3JG14cm072vOdp0/rCNkzSb
+fmtyzXUGgNgKzfp/GFvIXD04lLfeipzlUhNvDK8AKUNIctrMHZegpbfSm6HD6BiV
+rUFNLvr58WDK0eLeRxg4pFTCf9QXr9Q1v4MWehkn+LOTconhJtRictdlj+G2ymOQ
+LYgSRPPdXVNxlBI6u5WRtMxzZM6G3N8jkEvFfFsyeMtE+R0OsXiIwvGzdksnI/1F
+deQJzav9uMBj4A0bJuMQ3Ls8ydZNFU2RDofSU84bP/g6TzU8MpT7QXQXPD2jKdLp
+JouxtbRw+YY+9p0sk5PFYxti+T17jZN//pqiBrZUzvspwr5sWoa8BbA3bWE2gnXT
+cmx98wREJ3wWRx+t0k44084kD5/cvVH7MsAQ75XxGa0ofVj3crMCL29c+/QaUnhR
+GrdJ0sVJeIthiOQZZ5zBqG+IhJfG/jkKpweA9fkQ5gm+FoasTfDnAdSJjah7WfoO
+C6LKzNBB1FaOHqy4X6LUN5wraEOP+0OI3hKPdOB47yUzPF6FGneGk4BajDHG4RyT
+F2ZnG1aa+FRfakQ6l7ok4j+VPtDlCPY2jnT7muj2F78G69abNOS7ASXg5+PJzso0
+liaWo1d8TDfEazlDQvglDAKpzYw2mSbpJVmmbPSaVZxUARcIIaBqxu6xWepfdN8v
+qZGrOp7vTOuGu8f2YmWKd3+lcNm2CwwGYIPpuTFjtUuF7guKEdTffyj5tpOdo942
+RAy/F3tCy5zfZrI8SkSkx+wfZAnkUnI3xQNdKKVLCXcpBtQWht2UGO1G9W84OmFy
+eg21zeITIwPJZfUif9WHihdINSlfm0CiS+gDRzXukS4HgniPfS3NPo6HAepc2Gzr
+QUGF/ENern3v85DCEE/AebRaQN7liM+6Z55UZ4GOT3Tj64+Nth7MNQXqBYEmCS8P
+ndWvlalOs+vlj2Rl13IcSUOK8OOr6S7jeZhoutej1b4lbw8RwYBXGg==
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_blowfish_ecb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_blowfish_ecb.pem
new file mode 100644
index 000000000..bc3353eca
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_blowfish_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-ECB,1E15270A7DD42BA2
+
+zz3p7Ml80hSdlJsI5RyvOScQlsGC1GLg3AK0dC/Hh0IKPTDF7a2OITL6H/y/3txz
+LJ6jAcobjRfVMWGAJUwFaSlE5QF5W1+RauV+M8oMmv+Mf2K/Urha6m63EauLEVWu
+IDtxj74qfQgyd//qWHU+XmWhhNEGk5MrH163VITZqpG3Qe9dYHdalh4TB/ILJqfN
+URKLjdz8L4YbL48dwK6UxargixQ3tfrvIdTr4mkMiquNlayTk9g5qXWnEXy+I1DB
+HweXveJeSUHhYRXdx37y2I8Bz8HcuZF5wODEDJJuYXy7a8Q+Ar0Ll/uQ4NXE3iI0
+NA8RA0caAlc+Du/xfzKdUgIPQaLt/sjhM4gPBDLlASUmO+PJfb1VYgDIbNbXiR9x
+92ePzennPnbhKsPcuZzXoc/jH2BiQwwRT2gLscZ86n9O1FNoaPAnYERlyNIVrQoC
+0Ll6NnGBM9Ls5k1royQQtZU2x5Yu5Q7DGcNqX2yI14AZrI4e9/Y0nEa+17WRD6eO
+fdaIC5dVrv8HZxlfzwFs33FpufovP2vlINWM3IqDjMf4FIQsoLdnmTsgoLRYm4JK
+zfcyiImXPt2iUrcybZHKa0EXYjrcoIVBS8YP1UTcG8WHnj3ploMxXOw0AmpXcznf
+sbLsaehbs4ugM5G358PMeWFXTv8K2YXRtArXHtkIYzA45zqWzpta5E7LiTQJfBRL
+VNtLja40a0gaajvROCekEzWhezZc7bu6RQ/XZXxBYHx9m7nhzKRkDlBrrJVpWSW7
+QmS0ptXblyt2tbaUtNLsi2SP7gP9ggTlc5hCpwygT+lxrcr6j18CiPgMYOgDmFY7
+gZ3jZ+HHd2+8GnimOai+r8wh1aW06/tLfIZxpIn4T9yGh/EMW/R1RTJjN0xe6oqw
+wC+TPUM2bMvDtAvdn8bYh3pVVLXnFa6LjhhgNvnx6wBoiBCJ4E9R1Ec0QA4jF/97
+B4e8TEv7PAFB+VGhIPnQqfsAqRfM88FwgZqSfZrBXKMVWA7I4fBeVD0cJQq8TwCz
+TY9Fi1YnomqTfacH1hf9KiX3j8OkfrhIM3+w26nE553/wOcO42YJ55NgnNXlQL2e
+e1s4uJ9lroATY2WqvgLy5Th8n5y6kVkjuODb/8hk3KXqiLqbUOmZCYLuT4ZHZ+Rk
+xtWuFpmFiuWgbg6Nr2t2KYXwD39pjGBRmmwMX1mBxmUD9NK28yO4HEgiPVzfn7sU
+1PWC7HpgPf797M2/N1gyUfrBbfw4OXWpycvmtJLXHEJi/p/H1bz0MuMJvPtNhzUO
+CP4jq0xbu9nT5eW9rD7kgvv10W+aUf314RcWKaLkOxkk2dTENjbviASce5X3ZU4l
+eGG2wtoHvCvHnNVj2ImKf0jbAL7dymVJlA1XwsLANAmk+9RGyVJgHn7ZkOfRVJmW
+VMfZ6AVeFY5BeJ0LCq1uE6QMClVx8fLN2iBEqamBNekcZ62Qz3b1R7ZbN2tlPKee
+JnLSouju6Mu8U9twVI2tr63OTh/a0XAjtlO0OAXuVcOmYOHT9fSjPdAAt3Rp50Sj
+PDvgN8s+qSkQKpx7C2OA9Wisrr71UrBrCfBhCOmN5gyWFg24PwwRKUnc1a8mT5Zx
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_blowfish_ofb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_blowfish_ofb.pem
new file mode 100644
index 000000000..acbd8da99
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_blowfish_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-OFB,B9F95E282FEAA06D
+
+StEkcUPp3txNaJlYBP+eVabWYcEzAkX64aj8vaDX64i7bVl4ospAs2stac7uXtXG
+IZLTqNNACoqC0jWWTDJca9vTEoqjDRKjN9yjXYfrovj5oKi79wfsSU29oH1dcKG8
+G4y8qNsA9TexRQDWTBxYO6EiQFVie9O3oXzjhO1hYwxldSWOV5ZRWoVmg16vAOxX
+Gx2W1twtjQXG/hp0HxosPkZteUDdhMZLWonYuqEw1oBC4iDG1Tjp0p5uSnb1gaIr
+pzZScikP0Z4/8CxiKV9/C1VNE70EHdAUYKjUx2PAbPaMFyO/sAXOy1INI7Wis7jh
+U2wKeXgCMRxmca4OMITcjDp6OGmKf41uWyTFwjO1scMvjSJsOZxNjAjcrZW1PPRA
+tvnhRpU9h1G9BOH2rM7VUI6zJ2FSNKG9R6M0WOQqxRegJzvK+YNLhw5lUzrbWOR0
+RdkKL15gfnuXqLTDTMuLX+aCDS1Mu/ZRmDqLWkJH4W1HJ4l2rBojX5fcbamueMyf
+Sbd1S7QtmF/B9LaGDEPMT12kOQHZkRBUYpyolK6BoMuRPYnGS0RkUwvIuPZA8uJU
+vHHuYRZsOA45YFEipyB/sek61bvqYy+8TaPxzpfj0fkh7AUSQmbk3qQRkQbltzqq
+/MkFShIzS7SUkyiowOet8fVjXDJPsw2bS3uOHC4zy2QQmhVKzCYWd4yCFl+WtJnZ
+eEkrZH2BpoCDEzKlex/NQlH9KBLOor221nJEVd5tkdWWZt71eGld20eFL3ewtDqV
+GJX8jFmR51vQL6NZ2Ehp/5zhearuBJ8VKJfFxIKSrbPjyCbEwUgYOyVHHyvYyMR/
+6hcflrUu1IFFwFhryg2bucAkdX9AhsO1dimxSgZKEFlZbihPBysCdUw3WRea57iS
+n/zqLrOm786KiWh0ndBgJ973g1x+OeuUvbNl/0yiO4Vjny6PkXcBOORu+ILEflzf
+UiEKyG8+cYzoYZjeiCFBxsA2+gZMdgjxVYF/lKzTqFkfpwYV+tF2K5N8W51cL8Is
+yhz5OHiENobjx3QeFCZ4LWDEXg1H8cA34i9oELbXtyG7W+hkZp0B9tRDrXcDwVWk
+4oYqWLNCQXqr1lL6cCuctKLdXbc1ibLt1nYGpJrPkPCbOshsI+iCMmulT23s+jqW
+TMW0RNb3wFjR5z9A1YTWfiqMKEcyzRhP6bEM/+WNmHE5LRefx+dnvZrVJzGZA/3k
+JAOpsxEPKv7YNR8N9yoAopRfFEOH4HYtLbsAA2sZfD6iVAXAAeiZ2Ehn+Bvek5lV
+5zIOtsXswRgzXvxXCPy0V5GWqMglbkUS2HGsWaHpxDSMbvBJuaSi2blZ16p3IICM
+7YcCLolKUaWqpXjhb3UypoYRwJs+40EiXid7aJ8rKoeId1SeETOwVWkz95NMiVK9
+5K37/OMvxOAdjAUxtmz/+v+twKfrUhYqP3Qkapy6FgA+qxnzpCFZZXrMKjpr99Pc
+QVNcvM/SKWB34jZGTo+Styc7d+iXDC1BUS/43Pvbka/Aa2IV/LPQA2pD44aP5l3V
+/tOfQFQWI0wCqpBPV8aXqGuqZU2ES0yc9DJ974a8NvS1cNWfsMcvNg==
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des1_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des1_cbc.pem
new file mode 100644
index 000000000..2d2233e45
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des1_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-CBC,4629ADA1FF55BE00
+
+2093wYtiVZThSK/Ecf2pxfukmymwYi+yaWhMDfxz/O001tbrlC/emwfU7iprUPeD
+NJyyAV4GLjUBA51tfDqia3ATKaBfUtMQoC48+q/Lkr5KhLZEU0LLVuGrfvmDXmPb
+Ne9Ud8XZGnrDmvAFkguzK7cF4PFWUX3l5oYKinm8he7pA+t9RJ6QX7+BHKQHlWcR
+cT9e1iN7MykRD2Hh7YjSxg1uRlJ+1H5zIJBDjQ/WIUMj4EdNJriurt7eYY2XrP9M
+fyvTOBgYRHn6uQU0tdV0619j5yjEBpPTRf2M4RGOeNYGfvmk4RcyZPdnccDq5bWT
+w2XhhBPZMdCHmDPTCOwgfSvqBBX6OtH2EKd1aJQmtudMATPjA49Q2v9ZrgIQQxmA
+ZXIXuYH8wNPlzpm+abolucwIQhWJqr5TP5q7IKfYLD7FIjyrPBJecGoDuPB/Qp8x
+D9G73DKYgu3aYEFxcjs7tWwWe93pn7glEPmuybK2HP0iD5/YhXy9OUElAUZVBHXb
+WNyFdcdmyP/hcex5nI3Q27yM1auTS4Wpmvg9I5Psr1NN5ilWFNiJ0fr/YcOMpVsz
+NqQPuSLqxX5sg7X6m7MkE0/k8PfFO+tpy1cC/K18nnka8WgH4SJ+R1I8WXLKFznU
+X+mWcOaci2YBUHT7TWRzJ9/5bL0CEWlheabTjqbaV/4kiE5L0Wcbh/am56c2YAzi
+6MzassP58vp4hHXTyda94+Kj4ymYFbRBLqh9CVspolwDhy6e7ydcspGz/RRbuWrN
+Xc+lsExkvnLkYvkfmaAU/C5ME5PNjgM0kH0qXLyXPPtdKmwWrkGjElzaY2iajzpP
+XEmnYu4E8AsNdNg3HVcQfoUU7jFq1NeB4uibFrq8vh6VLmqGvK6XCul0gxJsfsh+
+j/38B1+5I97I0oplDZrAQMgek3BXegw6HZVqADC2KH4Jir50rYNCFrN1un9aohHG
+BdTzB1wGkjW2fJ/yrU5nkkTYcNhl9zU0D09XvFvXyeRdLzJL5eFqqZluwsPPw/TM
+CSwjTZbbeS2LvvstAsoYGfQTUr/E+BOXVpFmNg+94DBxwM7lCy57nG2Y6oIy8Qcb
+IfmF+wKMZEVJxy8O2uaCYUwU7qpucq1tz8l4bTo8wUctxw80Iflq7WYg/8V2ilro
+F1nSJ7gF0bn33KwlLxLy7akXiol8Rg6aOg+cAiMi2Apfg+5DXWrKf9YOwebDLOX3
+LWvDuMYRVccwVWsA+X4zUezGjVNuxjnjtsDfeiScf9QyliK8kjlMP/r+chrhFFzc
+LXARzcVfYCQhF6heOOY9YTHvcySV4NmgRKC/dlzvN4NMGh8VxWiEFDo7Vu8XTXpN
+7OiSd/BvmOism6emrC8zRMD8c1ZgCxuY1MOMVXRir/Qy1IWZXiYmI71mmJmRhE79
+Gn5JJ3aZ9xZmr34l296CWOBY/suTRvkrfyMRoSTC8Z9K5nbd+cm0MLzWMgiT5PAg
+cy6PHN9zVWInz/2z00qf+3lx45ZmMeVj2+2h1PFapXaCwvek3VgsXL2HUV/mKNcU
+ZH7mV8imvIopRSS4YQXB0Ophiv6i7lJWdKrSYd/Ac+Bt2E4z7q7y4wFNlZBvsBoO
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des1_cfb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des1_cfb.pem
new file mode 100644
index 000000000..814ff8946
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des1_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-CFB,07BD7DC7BB2EAC98
+
+yH7T+ZIRWmzcMociF5wV3YjHWCUMs9C/GUrnBP37vvJrBDBB3x0u6aQMaOs0U1Ih
+xbGOweaw7cMag1HhafjVK9ZFZlYsCfXRZk6JdOvzPchDctQrnjkDxnwpOllmp0w4
+Mg9mYLuEvN968Tx2TS26va/rPAu3xxA8mrcCuSfyt6O9HteT1axwDpZzOktmnbYy
+xHQDRcpDXaXspP2sVTaZJ3oq/AMGfrFXCu2m9jFHcyZKmEm/DW2aLmfOI5I7gCLP
+1KMekkauODnQZEE2Iyi1SVbTBKH5DPp7yXAXWOtugBcWNHbMF9QHqKlMs5Hd2MYg
+doXtBSRRBc9pLdF1FMwHHjPFI+GZL3hurqcD+YyZJqYvzEgnI9dls2K8MzQKYKDn
+6VpDCNbEf8aC0QmvCLIjqei5fH2RVYeV2M4Db1GDmpRAIRJEq0fXf5ojAD0Mhv6p
+DZYsz+f/MLTGwce+HCWxZyAyfptdK2ScfvaH8mUr1OHd5IdvRudh5+9sCtch5xQL
+DFIp1eBRd+2gvLBMja7gBE/xHXoFZtTR8xORCwgYXVrLLf4wG27XLdKQVQiS8dpi
+E+xCtiZmZfxb/1Ly9yHP/ehWD9DmxRRr/n1QeGMjSlLSzffuLgt/0tftK5yOSZri
+Xc1T83n5rLqhBglNEvwR1ewsTgeIxkgZo7q/LFajrnGh4L62cIoLkLX3lG0jaEC5
+VTa06i0b7U1nJ6kiqjHuXzkZWjTim4V7p7r/SQtAGuK3s8AmqJH53EMmiK0zFq9Q
+ao1ewixzD4NplA2HY4kAAVRQMR7WWIRrV2wXRTqoKwITMbZ8Yio8PwgSjsYhuzwv
+Mct1CmTc2FcCH/+AZOqc2HNS4qwQVmwLnOLmsr7L9kgf9aPIl1hkn9KzC6GAU+fZ
+F+N0Ti7d+ZkNAtAUg8fi2Bf/rtPvxmyJp6QICI4Tj4MFpGIRWP5rLwU6XXNch0l1
+nAcIYFvzLNL1v0TDnDz/CFW7XSp4IaDl0OLyAt+JxnPuFOAo1wJOhUWHheGynEBP
+U3K4u+761XMdqHb1n14OSgfyynIuLM6WtnBDoevKX8v0dYjO6PnvcuZoRqs1sYKr
+D93XsV8uMv79Oo84xQPHpJrUIJVLDeE5GLFimD7rUPvMURg1IrFnGyfcMGTvsv9O
+us/B1dNmOHjG7eZwJ/8MDNsYcpwm7CQsTOJUZkQDN7MZOKJZJr2gQK659eULJwaZ
+lEkR2p6A51etvlSPZ2pjy2Mgxk/T0mX/mVprEvCkxFWGlAxys1UFWKHDOOP4rUZs
+iE7nxBMyW+4zHAcco4Nly5gryqWiW0gn99/I7+qQHkb5X6ydP+GKOHmUdcb8RPIH
+Ec3bV7mBtfYxDC/ouStuQdVC7jWGwU7PeQqoz4d3mhK8dfeOvpudiTD1BLw30LKE
+Dt8/tob6zIHMEA5NTu6g5cbfa0lhRH1tD+O/7RejWPwOTc1LbY2igvHoh5uWTo8G
+ufvYO41PElmJoujef4njSZHcMvHArinYdlWlvMIg52d7Y3lQTTztY2UeO6DKRHx8
+Qjda5g8SDiqgFktkl5r9FYfqMQFqheSgKnHaJ2oPPbwuJyuNdy2Rug==
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des1_ecb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des1_ecb.pem
new file mode 100644
index 000000000..91a3f4900
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des1_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-ECB,451BC59702897B57
+
+lYkflQyHR1brYuUKx2oj0+L9fRwOhpKR6NMeH2nlLEMz1yntUt9DGuBRwP4RJs8o
+AHo7amQ1YzGpQCEZx3p+tMmk/hHRcRmU3ZeuP3SlGwpUmbMe3NI8I2dvh/qDL3Rb
+QParp+YK2vH/u/N2VPB11NvgwoUQpfS35vOhoLk3GUcupSKfbsbl/gn398DsgfoI
+d0qD5VSxNutst5I05pl4JFnL5+DBv1s9w68TdvAvBqWmsfhb4ei/mSp81e6ndxOR
+VLF5hgXauJjEHvI+c/ITF0roIyyxiMMjFd8IuIHbeznIjOWn4P5YcNcSswSG2wOz
+1wB0e8dlskukcUGqFS6W6mJzqb2TK1Eo+l0w2B2rNGX/MlGV9f6r7e0DQQFH0nCI
+nLS76C+WB5G6RA/7OMOWtsMnYSLldvXBxxZktcD1CNjyvuCOI5NK1KmG/Kajho6S
+/+A1mTs274pI6sIsCNl4ay2pfgwjZSWh95l8+YNt7o0C5lHudZ4hZHCDT8U2uCoe
+7dhj+KTuIS3VPI7lzruMZBGAj+haZ/cAEdqYGXizOle4MwKM5+lS8E5gEviTABua
+7jqhqbBE7CkN05Y3QmyE48yzi58hzSmiTOuAJ6jhB47A6Vsp/FpKFzfsK4BoD0Zh
+0ujT2BeJhtsFmPY6+RLtGITnl1498j9FTfy8ZNdrXEMxvp8SnEzlIKytLQyNoz7a
+tPCe1od1w+MUz0PHqDO/Av3YMULGLCUgnuZc0YjZv3P54FdC6si6KFEEqotIGD0j
+C24TXqlBpn8Qqkht/0TmzVHq6U7jynOjD1VUeB/gudPlHGLs468c7HzEzbpE5h0G
+1e5o6D5u9Nh1ItMObNrjt8NUxbi2/FX/Nkm3J1Ogno0ngzh15jZUfWFPAGkI1nho
+12F8Sf7YTBizPW+sd5hDbVejJURyoj/jt6UfiVKUg9iUgOW+ZzgkbD8RvC207xis
+QoF+2Lr8mPsNabUaFbsXmQ+6F0Pn05BzyBN2fyTxRt6u0CKmLE1fqkIuQywk83UD
+hBJfeewGoOGvoXDSy0ggIkjaRCsk//Xvntt5HEmKwc/wy/1Nzuu9H3C6n7qLqyNJ
+mPhrOGXt6C4LG1JscqS87z4VmhV7mol/Umdg00HRHs7l9qKRTePdlq52JL7oUws2
+CJs/UTaBHdbV2vh06qmymtEyNmQ+PrweEL5U/neyeYyrx6DsyUDdY1h1n+aKSEyR
+eittKv/pouPSLlIiMeY/DzQwN1ifoGsfYgJRst9Ry4MdlahpCTX+K7X6ryEOoJ/H
+1IEOm2aSlC3qEABUGo50IqiNF/PWugS7Qf/JzXAyjtcgQdW3cskNDCR7JVJDtATu
+0817ST0QXBL8qT1C3z843LcY1HpnQ1MiQvM3maDHCxuoEoUrRILWc59mc14gmowq
+g5XLMOLC/y5mX5LDqkxoKhoED9eM9/9EGSSy83dWWVZlGNLzu/JHBiWa3tVhas0U
+LytNa+kN8UfTC8KPe6i8euhauunLIKkq+MUBWy6agFR+jflE0zd0Av7Ox8HPbGe5
+0fraChwokeFM44fy5cOH7zENfng0jVUUreTpDtcfp390QW5Ca59J5/5P2aUBLZHi
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des1_ofb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des1_ofb.pem
new file mode 100644
index 000000000..93766e7b8
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des1_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-OFB,62D0879F9BE636D0
+
++iyQyk6TcPldmHOJyjJjsJ4BgdDqqdQYRzQWC/WfDLJyw3CXLquWDciAw5aCof3k
+b6R4PvJHzvG6j9jdlcv+yD5M3j9ZVHYkLL0fTZA/LEODUOTX74gNZfoz3FGarYIV
+TabFLgwQh4YJ0+Nb5N/oISaNszC+wxf20D4N445kvuHKbak7o2j+5ZzGId9zYIPU
+Jat1HygggKh9PtE4NildizyVVK5h8ws8qPWbe2/m00Hf5R2oP2YC3Afn6kqMuueJ
+RrvP9l26WboAKFED91xY3gJy8r3KkkLOJq9856BlndtgkA3USqRM31W6RvLqHUDy
+3l4ZY3wSTCdZIX+iHV6Qm3xYaIHNzYjHRcPQKdOVmEYiUSmAZmcavcsPC7sEfD7d
+OMEbrYrztF8iO90Myey/lJxo9RaL5PfWbtXqnXKUZtbcudEQd1fXM6gzdMm8AT4F
+eUSayg1/3AGEEHq2PH8kKtxnWAb7xBOgLbjTuC68f38dFw2P8iWZerG5lbLsFuwD
+YZ5eItuDhL8+dbFxisBX6H0lzcm0pwK1HCHOvSCcYfpWC4QrU08WbtI7NCqIuRWv
+4QOHU6SoNGW99BSnUlsqgLdIcsWsyTwiotZqusZV9AusdsGqU5ixwal4YX/8JRg+
+93EwnFnl1Y0Bj/yoAwNfvPlZhtjevsMnPEbrXbFEm0Xw1kdhOYokrx0hQWUmdt7m
+cFdmFBYQGsiKucvRpmInylrS41VQNbNySqQ5iGa+vDaPBMKZusvgPgwWSchotkzT
+qTQ7HNjszwR4eIjBOiBSvY5YXoa9H3irdmLn76mOyDMjaQyC9o/0tbAagLKADuF1
+Ui4Z/3WV67SuUoawqDJsYEWbOaNFX04wFby0k7oACoNxqoGFM3ITRzmxnz3ZyiPE
+DV/grOZICMLfTQ81VvE8/w+w697F6EJ8rY1yOznglP4GXrtIiXAaJbxEOhosyuN7
+HikpDQ3GRnPzXeg/Yngzpp8JMVdxKdEItcXnWd9uhB2Ok1vXH8LjhVkhrL76bJe7
+bhagz+LphPaLnkE5BPHKLUwL8bQQguz7ITfxsEFpWIHG5zCtpaQwdMEj2ePVubN8
+sfZ3qhDRNG8DdwXgCbCot16SKGuOawMMC5tsoeg3DFQ4MBDrKUv3C9nF8izTs1Zr
+3J7kWYrZg6+hVcJDgLS3t/lbFIhaNAULmep6wl4Vcp6nBqr395r8/uDroOpoBxoa
+BNjvFaztkRy3XmNHp3TOYLg5HZPWsK3KXOs0FvdTMEEsnoj3PXz6+hw0gMV6huYp
+o24r34gKiwdbrkbwLRnyh0oF6d3bPOZ9WnPgA2y2MB+slulA47+hOMcP9+WiQxE/
+eGd6TTRjMPopQXJw7/tZEf6qyVYLWfKJmI0tljsea48NocZdsek+e4ZsTW/iP0oZ
+wPDYNt95V64APcDZfNtfzydp0516KY7p624TanOXsxNNiBV6Nuqmd0dGhbmcRC8Q
+KNgGNvgjF3rhqrXZyFpnZNQewE7a87bgmO1O772QU6GmPUZr3nzPRwE/8+TNA9AP
+hHL9HtItZ3arx7eJ42obFrxj3uzpQ8WQo/cGLgQT0lz6u91xJyWi2A==
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des2_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des2_cbc.pem
new file mode 100644
index 000000000..9dbe30d5c
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des2_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE-CBC,A48C2683D96452DF
+
+dRu5UKxN6kr8aSBwZnynPwIA2y8Dgu6Xf2vCf0JswuFMJAwFGjiHoZTmIHuAjArK
+GWhiMl6ak552D/Nugz2SNgC3eJo/LOP/g2NIJnG09GuWOGXkiagjDKNbPCiIBPww
+STIBg5ilKV07lryS0FxQSUWsjI/2c0yxk/6MGSzQ6rrAWB4Cf843u482w6Hidr/E
+euPsqXJDtlQrKQ1gaMTJiOY9Y2H81b485MBN9BnKfDH4WHp49b/akcditst59fty
+FtzwyUTee9SGY6u7oKaUUe6sRzFOeeRR2TgWG5Bs5sne1AFFen2/q59Va/7/iXRd
+TOKKUGR4yj9gA+9EIpDF3n8Vn3G9LnTDFK0Xh1m61C1mQmXgEOqJGLVreFq4u1xq
+0J1yEZKoXreZJH95+gYAW5lmG+jNCMy0RO5PsTClx7G4XcIGFZAXi8sXfk3FYLT8
+nboMgQ8IXFjqO85FIVMt+xCpov+S8yOfPMOU63zxrynaXD2eGv7y2dTpeF3Mf4Ek
+be0YrQEWpCtYUdZ9AwA4N0/vkdp84/WZ3Aw/i+KUqYKtK2agkJYtarqj6iUweUvW
+GgWvZqNiTAd3sGcxffSbcdSRpuNttnBG77qAFgFiPXtvJu4wRkGlaxhwVTyUWK2E
+HvCEsssbzX4tZ6GUXScXv4zg3YaDP6HXsnBENl5SGXK8Uelett6PJhwH7bfpWysG
+Z1TD75uk6twThhtPURGG4GUaQ6cZ1RUsL9/y06v3ZmfUBxeVGLKwyMzlr2FTYenU
++LcvzriycweTLMO6llLVQH8XwlbAZ7JgndCjZodtFXhjhrS5Iu0sO6J2D7xFvL3q
+/Ym8PhhRStcVjijX+5+9aiA8AkXK3khP14T3yhPLu7iayl836Lh1+O1BHiYgr9Z6
+DdhCmO2Esa822yxyOdiwVlF+mYQylEZQy3D3kqqJytO9pn87cSvR3WbPtFOStlcs
+Htms8SdqLAamuWLGZiycPr87mSH2By2JED//80fNHdR1D7cvPU7oL/ClFMX/F3EW
+UJAwSXswmUxqccBR2hOJ6K3OvSIULoUn3awM/qPNTQL7rg++dSzUDbIiUywxuU9N
+nXkqfBVjoJTjafgWd39G3RdoK0ohf9QFj1nqYfaQGKy90cPVw/FdjRyszJWDUBTq
+jlKXnap6ZS9PGztjEoLqmFaFT75RUR49NnNtmcKmH0i6anjwFWEYBM61jox7gH+g
+W0r+0R2yijAspXHVpuibx9vdgkq/WR4A36t6DEMajOHM3SVzbPzkHTV5HyYQKnaw
+SZLSdUk8VwYkGSylm3f64PJLxBl7TNtrQhFLgR/9QXkhN7U2Qc7WxRQzhLQsLbtL
+qcBLGH34SGQarQZ5dfo3t+B6IIW2HvHNOiT9HQsIJTz4Er1SbLNH6bco7hud6aOA
+eSifKkWLp3SXXS6wjQZzsSGZ7Mws1DRcL9gEhb4tgIvopQK773AbQ1SJDEcmBpD1
+NmxrTbb1TngaW6u/79Nng84YEUiWNDKu3ovoe/HLVZoDr3tGmy5ch0jfA6NOxEn3
+KXZCiu/PjU005SLyLql5dcGzagjnnURDi7TLue/97xtpI/ac0vL868Cqfm0+e26H
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des2_cfb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des2_cfb.pem
new file mode 100644
index 000000000..451670c08
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des2_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE-CFB,36E0C8A965F07E25
+
+L0GHzT9XVnA03q7rlchpiD4JCgzISj+B9GxKCrKSJJBC8bRTgjgrwySMQyhdX1nw
+DiCtb9q7UCxQ/j0VvHuoA3OS1/Q95mwCsnjUXYAPiXeR0NMJkLgv1hFU8EjAJHY8
+ZenlgfC1RNoUONucq7v3F7jpsqBWrxjyDXFnWwe3edSfUzkfkG27NK6LPScjqdY6
+kJWAkHGpoGog7cYVBJ78LbYYHSBR+xfeFzhVMqB78mH8/Y/CGlKvXnPFpiJCY7Af
+zpd4/PJRVubXVyANc42k+0/E2oPOSKiwiKV79BxFw8g+NxkhRzXeCDuzvExKL457
+cuPNB0CQLSVNmOWKr6mA1bIBiJXgASzijsjkyoH62D/QoBo+kBT8W3hiHooSzJ89
+flhyknT+rVuAbFdPGqriS8siN/r4Qq/gbQIFhNe9jsSQesfr7lM3oK2EPGpDxstf
+eKc+EhHBlT4S9X+AilnjK5il2X5szyhOFZQ7RdAiqZ7X2KPNNqbeS2L530ZvlL+W
+Yw4qco88cilN276QQWCcrp3YcWv+MzawlNvfOOAb4GfUlR+njPxRAxM3rGVXiMn+
+6UL3X1SqZfADJOn57S4cDoP/A0i3FUfoPTwQW77LOAIzLSeMi7brQkZi5J9s5Izm
+OMcEi+GwBrkbPl67fKMnt3cHeFGJmOftrLZCt8HpGEdiQzP5iiC828XvLLxby5Ue
+BGoBILGIHL3OqkTVjBbSODKFZTIOQdVkqrWKyXlrfoI1meATptP7/GhdQP2DTW8B
+ppmNgtwIbGLg/AwNmGPdpL2mP5SZLIDJHd81BL00xPJFCR9wxXLk3hgm6auzAsZV
+FYjaIQ0Qza5kBCKNqu8ad8edqgp5Rj1/ZzfCWEkPRHD/lZ7nj9vuC/dMnPphohKz
+q8/L1+gbp8dwER7sEVBiWDE5u3lpSbx+1qkk2CwOjE9eBh2Mr6qLL2WIFb4YUvYI
+OAWIU1ftenOEjgjvYZcdeEOYT0UF6/avfHDPvkTIwl52UUhunbnqCjQM3qr18rbV
+8vB1bC64DxetUPhDymLqJCe4QVQajdO5BxQ2wwRjHlBi94nlAS/uOFV+WwqtFKZD
+TakruYhw3VjGxtnjukruMzNjDSqxd8Jabp1oTHY57C+aYQcBo34XAr+j+PQTPXEj
+GNL19MUMHJo/yk05NZfkyf3/+YtAV+/Gle7TlWWCV1nvEwrHPE4yCGi8j6qtCzBC
+TgpXl/lxJendZgVzIGGzMDemJgyrLNV6ar8TbOz6d5GDV3S84g2S7cToMVHX4Z8M
+bR53pt/KfH27Wdn68z3Zd7sT8R0g7yCVIc0BJgRrZ1aLnyKLSUk7iJULg3+B5NwK
+JNucRiU6mT5SUiyS5WjD6vZVDjggAx7H74DP04rzgzcHvTB2gzx1hFzw6WW9wcCk
+7+RiY0j13M/nD8UjW+pp/Ugk4Oc/bvxsA2tWQ1BeyF+KSNj/zjHMwN/sp1/of43X
+D+lcWS1hCwMiy79KQudrkc2DiYKWSIiXEFlblSJGiQz7SxybtO+D0PpVmlEYWiDF
+AAMz3hM+CrWcXIFNw86mHSsJHvYsSjbCB3ydG8L9OdATYsS3tZo38g==
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des2_ecb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des2_ecb.pem
new file mode 100644
index 000000000..c3f285f0f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des2_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE,8B0E5396F9D19442
+
+Ym7x4lqzxkC0K7f3nTtR7/ZVi0Vj36NLORWiJig0qvSmH1rhkkmMjssQqc17kWRT
+ttLj4D4s1ueQBlDFaumMrXloVp8c4zQS5jbHNmf+bUsom+HXGFHbjPC0usHm9TAl
+pPBWMCON5uUxoqJhw2mvrGSlkQhkkh3+Oiag6fxNxnN8Te/yTPC1XXCqIh7zRjCN
+q3wjkh8+0QP8ui2jK/2zrlbwvCyggs4q1YhVzWYiecFro1llb+CDCz0mzKEXj1MM
+MLyMdcooxXTb4t5PhkW87N8PSWXeJEJTxcWYbZ7bf+Bf68iHm6JChc/HTXZRLUfo
+3lACV21KTTI/614rLl44l/Ftg4HDSE4UV/J2JoenbRecljKXneeVj48Lmurc3zZa
+rj46e/pXEGfeEGmkuVnriWhRBcK8Mq33XfY870RsP+4bfxd2ykJYyxFZyoTT0sAU
+LJ4KIVZVc3/jB58CRBZDV4s6/cA0uHPhprtzEHSxp7vI9N4dQAWaUBMnDtPVC999
+QjVGYKRUUNp2S4XVLtMH3+jZ5ntvCTTabjuie/4TAxoUY45CwKjEFpWtDBEWBbXe
+zmIQYCE+o8hSVtt8DFWdz8+PGqF9QgWZ5iQtnp5hUKA4rVeaxF7+ktumTrwguZcZ
+6ZK+K3t4lcHyPZMQBoiWijmBLoRsoQ7NIFEE3sn9muV0XUz3hMCRapWsqS4fd3N0
+LRXrBmZuizqzaNBcDku7lBbembdW7EI9flzY/0Q0xRl7WjOdK6Nj4V2A2MblQoh1
+J+pvV9Tc4PANApNLcFZSPawOJVyUtmpX8QZYTe7QlXQrVIQE4HX4od1S3/ZlydfT
+DL8Atfec1sabrRFs1M86lJGnYxsvismLVH0VmkigWe+4sClAl5QrtCfGQepYmsYi
+jyVruF3FzbOCjcv04x4a4HyKRHeCVlsRlSq/njqCh0WSc7OMacpQJZVvsUYRCaS1
+7WhmzeiVNjgKXg5lPwta78Kh+XbQUtUGryQQrwOnbj0SDsho2hBTt/gbWDpxoQjL
+LGPHVxwqm0GZ4bw+4IXwltfei7MG/ceWxLZYk8ZTkc6r+w0+5HQFKZ3JuSKB3OLm
+rK0m87IybLY/Zfap/WLAmreRMUz/FbsY9Vjh3gt6NqrDhqLFYCyyUKZyKrWnVlIj
+j5vohFGbq968UYVavCZ2eqmtwWywsBXLOabypgrIUQhmCxOUBM7Mi2NVrTqn8uIO
+G5+mwzsy8imChv3Zk2/LafxPpajlu1MuC6CtMdZjV+zrGxJBEUxADaTJU7tTAWef
+lUjlZ4l/XO3vxSvv/F3yONmgKp1t3naS0ZxxYalcMRi6xTznW24r5voOAsVqIz5y
+Nl5FtPMSCBE4FONoUI4Gq1GAen2h2/Dz1Q3CMYAvJz/QfpZFu4DZ+jAUISU7URfL
+7P/lXQhg3onHVy5tgXhiXDhCCxY4pUPSy57eE32F+sIGeltoXU2Okx5/ey8ijr+i
+5URStFLeFp90ke/EhdOuhDoE++7G826ky3twqtSBTt4jU9IemH0agFU3PWIJffm3
++Ezce6LusooS8Bqs9rYXHHGe2q0oUNY3ipggOzx4Th4mwg1HzBQnD6FU33M/WyCw
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des2_ofb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des2_ofb.pem
new file mode 100644
index 000000000..c34872d3a
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des2_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE-OFB,0A4E382F6060AA1B
+
+hIbY73AFUCWIkdT7MEKMhr7+uSoSMO9wihHjhiHn01cq6kTe66Vy/z9dmTcgbK2q
+edRngIRyiTqyul1dhQ2ezVDisowHAtdiD7O2/Z+YiXc1hsuC/uELnYV1hTUg73Qb
+v760pWyH5AXNpqGsx2LLw+hstiiWVO+/Hs+CqtM/RgONfvUCzbyOQknDfSTDoVXB
+W4gEDKSDj+ydXm0ZmMS17DLCXgk4HBsJxyiK666l2TzB9pnzj6EDA6hDsiHfy3z4
++MxfcnLxWw9TJPxdLYVdw8WNWsXQd1JHQz/BQ/Hum4eNoYxLGgsV/hWQmkFil1XO
+GkPjF2z44fxN4FJjvQskrQox+5/gvnG+KamfvQt62qN16Z6ROZu5buPijxmXoecq
+gW6SyeFbnYFn27hglllax9awEEUtcJwi6OxKAkWD3REjqCfNAwcqoFqwkxlPN3IH
+00Rksn3P7cN5IqePVjSdwIhZtCfeBW2267oNxb870CDon7OlrUdK8KIjp/x5jKUs
+Pjehw1Ovtvn2YUQnTPvIYQsgdq3BMb9ETcnPDneCVweSxHxpb8ao2hyBMyYtQG8f
+LNqvLnjh7FUyRenf3XRbqka2w8B1CFTTErkMm9E0OPD8tMtDyakI+8fMJDkGhGI5
+jMwY2q98Z+Ef4wDifOi6qNklBlJwjvvybeqhqWOoXKbQMhnQPqFnLGjp5GQMczII
+m9a0anYSvmNKjRtD1LBL0KDMUgIx35U+7GKQfjrRTURYtAK8EITKUqYoWJWXUevR
+t9cikdwQ2yDuDH/C+a2eaEHJITerdW7ba/Rxzh50VdPq03uUNkN21VZEMjcU+GPB
+sLQ50j+gSFRMMzMfDx0G3wHoEJNAul8x2+umCUSpzPfC5D6kjbyREm/fWEuQkvL6
+AUCheoD7ouRR66R8syjIbeCKhjZEXUOvxxNYHSySrxHyiCGE5xCSVDlTzAutvcOn
+kivQqRlO1C6ZoEWbGr1SPoIoi0iMoh+TKZDgMy6/pRWVbELW5P9JnH8K+IreOIXd
+IgnCsqKZBVN4qRPrW8HtEwiWW7MsoXGjhpVl8wer8cNmcfPTo3x2l2+mjV2r0xEZ
+Xmv2LEtjDfIUP6yXuID4OrV6kpqSDax+wmujr8jlETKf0uEi4PZAXqhrgh/fgH2p
+VE+Ey0vnDaXcEhS0ketOGmBIYaKzWbMH9iX46YSkA++5/PavhlbCqZZN+906jwEW
+6MS7Nq1UBoUiql1Xa8AL0p/7QKZH2mgxpFcBeCHF4q6HhebbQbCpveJgBSR7/12H
+fJOIubovV6AOx2kBRAf27bii5iwMjfzC9IBE+GLCX3CXR+BLfOWutTcqbaBRdmQv
+K4yJqB/WHYcjlLKf/Q8+B6elmMc59NVUfStMszkIGlTzMFIkObLHH1NYPSC700rH
+ZkrdbRGfcncT2OcyFbWZ/tIvUER/aHjh/BvZ9s8UyEVEZzsFJI8HA66sJzZ3fKaM
+8P7nXXagyarILIzO90JIwkX+ip//QtpSDPkrUtii6Wj7n7RO0REe5N5+NA3A7WUs
+Aret+KXgmsOi2fnTmCFjVN2QgmQvOg8PGx0yYx8gxWog/NAmLCVMjw==
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des3_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des3_cbc.pem
new file mode 100644
index 000000000..6a632f23f
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des3_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,6D7B3D8B829964B1
+
+mw05Vw0Y4gDohoiqd0xLN6ZKCalPCK2F0QFSyAVeoPY39y1RyKdsg8xt/qDx73jZ
+rgZb/fQLKs/W6SqCAAk/7EIBNTCWf+yD5TTdG9n8viNDSNXWdyq172rEnRV1CWGe
+beo+YjNDh6UlZ1FcXLj82TpZ9EokUKLabzNkY/coVPLlytqTSO5oZmbdreuUxOyJ
+ktQJUmGBmBY0aHJmV2wCkOFAXbzoSfo+SNPntEUNTa8i0cSIgmZd4/QS2Xfa8qRZ
+c2R2hNyVZygru5t8eckKj6uvj/Yszg6XqQby4ktK/cYfveS85CNlu03WfjfI5V78
+vY5efs3+NVJi2+ush4p4TfgT0PAKTWjXwpMEiGVlmxBoPoFGtTXY3Xp+64QICgTa
+MdrxPDDBw2yxmWAOpm58eeRqAN7Jd42qBxerJFiOUZxYPyRrQvro6fkldUlbPNon
+53Hzb+zHXv9xM5aUqfEjMO4HyprhKT/8aZgQiDE8fHgJhI/S2Ho6Fzqz2/uOHzBB
+gx0m8fM8puQ11eRxO+oSE4OSKbEQG0Uj66cHXY6FbJUhsLkGo9HdjLSGW67vx7RY
+Q3PQApOCFcXLecfkXrUaAEeRPNqZXjCkF6s8bfCOXD1cr9BulaGpiGxdspu5Tk9Q
+bLtoX5VHnW9VoIoFsIWs1G0h3WILs7ynCE2ttDSnIjYZhE6pRBiDHRs3J6dH/oOh
+c4dFaapkisk0BANJduvB7vLvvbJ0Xs42q+sRUCWzHNnJ3BqQZtL5f0dqu1AXafji
+qwxcbrEqJc1kOQ+iRAZ83nVlVkI/UgWzTceYPR24Q0PnAux1LkoIO/FWbhm62j3u
+xS669GX+GS9urX8oC3JUYT2n9dnPL8ouB77KfP6c0GVxR2hhiLYmyP2600C5q5DU
+6rdNm6fb75nrAmD0cgPxbdOB8zbgVvQuPXG8QnTO5Vvhp5ETgifIXPCIWwNHg5xL
+o2zrAdrNaio8FZUVPHOvMKE6Wl9QDMqnnShH+8VhLk7+LQpVDewBnWaMd8pK8qGn
+robl+i4HWtn20uZIDFyI4ioSa0S3Kanvd9TkchEbDjKAVi1QXdcD+q9O0AYt/X6n
+ygx2DGhkNYMrQmc+AIt7dAPa6RdZv50AAc0R3S0DBaxtd36pWugT4WIEexmuYj8S
+NbRNLuyjQMYCeFs/Ff4df0gmfeyH88YSlafnLyFhvv041LAbU52e/yExCEUvKr5J
+Oj2qVHJVe3eVW+FX8hsoUAte/a5foVe067dThfZDVp0TirozHAycgfKI600VF3Rh
+rvQiHzmXRoMptt5g/yLsTVYiKAF1n2hU9556sJPARFrG1xXoFFwhpzCS5t8ywniN
+6wwV+V0s4LSJFQJBFjLrreu9ZkYMdEOrekzqBohF5wG/BJILkN8hBmnD5gckbLIM
+QUzGTGxu+BIUi8JNkso0hwZDAKnYit+FVAs+5yU0NVQU6e3fW/+m48YI5gqFI+k0
+gIGmAyU6zaUJBJJQ4wc3+dOsy8sokqRhVmA59Tv20IKHh54zWq4ouFAg4Yc0bwK0
+1ua9GJMGTXN0+Trb7MKZQVKokyNA0RVCDN9AIfwCA5hDhJTahsO8Lp4Eolz2TFaQ
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des3_cfb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des3_cfb.pem
new file mode 100644
index 000000000..129e02eef
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des3_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CFB,B99E3DD88C3A9D7B
+
+4Dsk+pNUGsgEqelOveMyrkoDb+khouKf83Yt4/qxX8CHs5q6i70NLViQWwqvIqQP
+g3h8Gs8cYKZfkEAFKP6BRFPy8EttnBCzhAdvLKrKFCZoDmhxC5ia+FxPLtNaDEb5
+6bgSoZ07KUMvfMZdnG5Kogex4DedqENVHBi2Rl3Dck1pAgxwzMntgHsluT4ht3id
+SgyUT/xAaMSwIklsjclR998N6V8Nilu8TDDf5X12RHOq/MSqGZ7yJC3Wb/dsirNs
+7jsEQwg9tIg5B/5hxjN12E4Ov7orIuO/WHNVtLznx1w1t/umPjLFn100Kln8GvfN
+jiGSB5TUz4t8r3deN7oDrGjoyr5OMnKWSsIwKcMsNSh9aTdkjIJBUUhIB2PStdX7
+WbeNXicNMQeteIrY+ZDDPpMbjsH1Kqcz5y9OWnvaXso5lSHLBp1IamCv/XbQcAPR
+zbnbN8DCOYAMcUiwcRAt0U+BNc1edX8VmCB0d4RQq5BTFbjGKqzo6yFVUOVLhiFg
+E8G3v8sTqUhJyH4Dmjn0oDMtfdplk30Ywg2wZAahnI9w+cZFvzqXshL3mGdu+rbb
+h7PkiJE5vS6/4VKA7pngsVanCRQa3btL43ekShth+DXwsziQixGD9HhTb2iYeF+u
+9niDPI5gzi9IfxIpb3QjR1xDJYAzKDDBA4gHhbEBSObByMsVzjS0+dwP9N6DV60v
+3x7RfO094FXxlVWSh2SMvz/sB9fsD9dCp/gadqHxhk2aJf7lfSU1C7EmM9hxGZku
+vR3J1QcSu2FMrvHyRzFZGKozSHq3QunOLno/KmY0ja1754NEkntGvPuB7LhGBNB6
+14NvQsl7qFw5wJxmEdY5rhVdz4PxLfjnMyvCiWlku83QIC51I5DbhRP7eG9rJSMw
+b7KFSQwmp2yzDeX+Ipd0JAgd14GvtmICKJVushO352O7mVnx3Jy1ZtJsonhzySz6
+1fGIvJI8jxZOdO7q1OD0bfrXS/kwdXnxoxn4pkjw3ZN3hdFTfAerVQ+qYJ7zIez5
+0lUihHNw1C/KRsggraOl9rTUNppcNtMYwKXCJOGXI2UEn8p3JIxEHLwXyOjTDfg/
+5oK2nPAmBdGsLb5ivJLPivmaqDXf7fdn0XBQQmtYUQRotlGmfpztujt/b2pL5YSE
+Uqginw65zyedjL6Aff3crvP8/CUR0JARx9vF12R+v2iAnDqVk/yqYpRqOp5elm1t
+yGB/PtpoRFsNU1hDnPZDu7kZV9oSeXaBDFOnHmX09qE2r869Aye1xOVmxiG5tm/u
+KGA+zlJVVpQSwnPc/qk17S0dvNAlgt6MH+vYlhKw8zk1nDCuavUK3hTFT+9w31cQ
+yjPdV4/K8seK4zIqpH4LZrC306/1/7BT5JXL6ZChATHaI68xwEY2GsEl/Ze0JrQv
+WpWSN/I269rUfaBDE6eFaiSDzq1xY+qyApHSTNPSPDHbFeCXz+puqv9lw0bJFnRJ
+nLsK2fUAKNvyCF18IydyhiGz42LYbwwjlEWuVsfWtgvftDebZRIfQFlj7DJwXfZU
+zcEOI5YyuQs+wFK/8b/bknF4xRpaXwt9Il7tcV07h96TDJV05illig==
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des3_ecb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des3_ecb.pem
new file mode 100644
index 000000000..bcdc5d3f6
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des3_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3,9675E5342C359F94
+
+aqJHsie4Ls1x3Tk73mbL7VyTembpkhx/a8Mc345TuZOZEkU9XYrkFMvhEB+jcVoo
+9ydosCL2d8xjDusry+vn5yF3iwE9HFHQ52M0/a5IH3sTtJ18BzAOi72ykGb2r6ly
+FzTq7xdXNihN19wHHnI98GKdxdQmNR9uITx8VRBbZdbRNGdJopS8zT96+AV1QAE6
+lyKKLA7qbATHR7JWQN2OYz05vGt48Vmq+da+qs5liEtx+GtNUxS5x8lAC6Llmq2s
+/Xv8X6kjYmxHSYWM2JyxsznGfdXKXe9f4Xxwyhedei6JgrTHa/JN/+tvgh5NWODK
+er1tLBRRA7atlSoB2AAegJC7gJRVOxRF4hiKX/19cfEpq8hF9+6EHGYm/IQRSI/J
+F0RGcnSdiddYbEb667qTkbLZi/d3Ih3KwKGww6ZzkHe/qPi230/cDR8tac26jmG8
+qoCwj+XCNOe9IUJsCN6RmLcFp4Tr4UVSsswxReN+xs5Ui+S3AY8IKscLSo+bB8gq
+DVBvVFUBTiF5/zO8q8H8Xv2c0aA3S9UQla+l3yoZygiUym+Q204Li+tDXiM602kr
+GGDA5/cGpQuit/7O51KF2OSwnnvLdu96qz0f9X+rq4QVNAy5PXcr2pj/y88UfSXN
+GAbogEXqpQzn0rmV1OWM8hsnOpN2DLcuZICCJFJc/BHO4elt65OfBjAvbxjhFU6s
+nJLUcR5EopLex46WwuucR6W6wjAuO8ET3cDV5L9wQI6DT+XItotk+yJyYawNPda7
+wfmxZ0o3qdcpRp7aw0ohfshRGJMuLnGVgLczU4hwO2/1LgRMnCywldacAfo8Ot8s
+WnC7d0jVOre2K67Omh4gLQTzikvFoxg5kjmFFxF+QOFakT/B3RMa9mgjtOlX0boK
+HepTxOtCaS+cZnL/fUCbWdnPxqooKid2DnVTNIXXBg3S97ReediwpSn6v6gU8QXI
+O0X/+syPkCRAOKLjCdgxFXRB1UA13v6iqeja9aXgzbUnk/MrT6G4ivAMsNS1cEdA
+KVKVpbiKchEpiiSiPyo7buZN6t3m4JnupU+UvcJAEFgdbPvP/kFvxywpPBcAycAM
+HgujJ9bE3OR1lfyHHTGF/f5lXGDzB0/ND8h7Pm+Bd0AFde79rCswhnR4oJsPLuij
+Uy499ouKhoxFTn3WMF6at2QLf36rfLHl41uSN0tky8trT9SE1PjX6yQUjl48bJh3
+MWUFPYBDfDPGTddENYo7hDmwoSLbE5WFxbAeJa86wgV/P4/QcDF0IPVa/wsDTPKR
+RIy7eNqxXBYhFeOBCkTKHMJ0XCawi4q2CAwo7RNuAmTrHOBN2hZOwYd6yoEQ4ALq
+70cflG8+rITJHOdAjXYAlcuuB1FjDWJjO1E3P9MwMfiFZBnJBsYkDT6ablfwgpaQ
+z9ngnzRqxIjqAxrRY9GdR3BEWgRIiKXljUgkk8qFSRIS1i3w+nHAipreOwizTVUw
+otTU++EjpQBracFsuGP6w9vcyhHOp3K+RzGYEQoh2vJm25lzUWBHvmVpCw5BBTms
+RgurNRdm1IlN+qSzriotjPuHr9Ucit7VFV/gXtmyJiNNPjTLpLQEZOUpz15eaFs+
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des3_ofb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des3_ofb.pem
new file mode 100644
index 000000000..dad36ead7
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_des3_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-OFB,C8F1482CB09D61BF
+
+0GfYpcSxvnnRri3s5PutcESsHTuupx6UcprKRS+B1neyPR7Ga0Z3mZ2/X0trJVpM
+cxJW4g/cU4TknCZLjIJlClYQenpPRH69yw6BTi6/pgUhKeGmQK9Oob6G1RMjS9lO
+MTb8DKz8P9GmDR4/3SvJwPU0aEM1EAmwGJV2beB2QWRhaPkAZBzeijYf+uYn0mgm
+hZwjU8tdwnNnCdUXdaHeRkeqFcL6OjJHV+U5SZaMbaky1U9lyIJL+GUQZkRfZzJD
+41Qt6yVtetTgzljtCtd4ix+RX6EYsWfZ3OVtwHGYpg28IdfJ3LVE//O9EkLZoBeg
+DyU9c0gDnQ8Dxl9VHGFwQvgdSEyJLvWDv+6RXvCX4Kb2Spy847yxqcfqDpjUhzgv
+C7FoBwswS0pkQzGXKgdM+WlBe9/GYOrzW08IYwrX88aihf50jXi472th6ILIkFHD
+6m419YsrmOeEMXGW/VIKxk8H8MGHwdvK82xewu8Ftgfx0WihfA70EyI28VLMQTAE
+MMHxxCWtdWWnmd1xiHQSX6vedPLXQKKt2AYxYmHQYfqNFMcvDc5uM5uM+mNkX0qt
+VL5PeYRYtdDtT5Xj4/acZD7X7DhqcOwvNll3J7PRdadNXKfjHR7iRP62YkIiESE5
+sCHhYXmtQqK2JUJr8a9M1QPhmAIF3FYr8wSFu/eWw8ooBaTxVoGCw70lT8LNHVql
+TYdW9sOnvUjz36oz6H+z55CNldor0tS/Bu5jNPOZ8F6j5r4xpTWi3d/UWLW7uBbw
+VTAG25EiFvQBXpJFqgRCBdD1Gcfoc+ZefLXQ1l0RJpRf1jJMkfSWvUWDRNm87PSs
+qTeDBzuLNx4A1wYcJ1H+R7ds5QK4moNlvv0hJrsqbOESpLv/XPcYrFgzms0b+Q1d
+uJEWjz38AgIJQxBxmoglzDSRx9OBh9D8HQ+aJLSVcz0dBmEOEtPjZn2AmxxccwCc
+NkMnAxXyNPEJhecTp2/lOOupQqMYTGe8aoiee3m01QPzfgL6m5p6IJdKzOKi0TGJ
+xNW6fD486B7i8d+VOnst6vnd4xiQ03gNNA654mrXIM881X5elqmoFWyup+Ct9lw5
+lxllAJGh7w+hf8P6mIsezOkZGieGhzrFnuLVM2srRDEId+shTV/0lZi4LhfDYroN
+VAbZ6bySn9fmP4Pn42zu4XjoZJffF74u8gFPo8oSFYg88tzjbPN9KAPInNxD6lBA
+cwp3vc1n71CEepmfeZFR6pm1wKRSupkOZNL/PV9rqsyP1pmPE3AEU7WYjNbf2ah0
+GE9f6dtLWcDP/3SssoSnZGy5SdqcNPymG9vOR+QD12YNxn7yA87HM3+swparlSYy
+Mhg1BuDXb5Q5XFVFdajFwAnXJblAIbuJAeHQ/mNCAnR3HNv/Qic2GF7X757MA+dP
+z86gFzJJtb7dtZ0WDQzzEVHgnfVHP5buXnHdepFLsETw9fp4ZjqPfHjLXIOvp9/9
+G9pmSzB1JL8kK8sexWgsMRnl2j2hUDYiVJ/LQjMzk2YLF5I0D5msNTAJvb/gFBdv
+ynVKUpIoJEfRaY7pxR3tufbzADNiqa8OUCGxZ8jo26j7XWDkunfGAw==
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_128_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_128_cbc.pem
new file mode 100644
index 000000000..176334059
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_128_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-CBC,C9CEE2FFE7D795D6
+
+hcUF0vilpOxap0mbziQfS/5kPdXsFb59D6myNYdLDAvBWUVAuu5g8iDDJIS8KPb2
+xvmWdXRhbsnfeQGcGWM1rMc7brutqefFp/OAJVymI0TpILMgef0abf49PEqNUa/N
+rYs2dd39fsyrJ0rcEWT2lBA/+GTLATB+16/9aCwjHjQ4L7d4Soh1laMo2K2Us6Eq
+pB8f6an5Y/vSIlnljl4upKOlcLItd//2ehQnkuEhI2Vafz+kX08Z3+OCLZfdNEq0
++8b5GbOvygEZbG+amZDB/tXnR1HB+AI7lR94PmM+h24COWAelatj2uPOGov54gXc
+iO7NDGoouysqfkfcMpuy5SkLVW4FoCAxfOl+LOU9p4x8+iaJt7Np+TO16dvX8MOL
+4WcIz4huaT125V38Q4UiB+WbsvQXrHRM4WCyJBGBhakr+FpNFdH1UPb9Unb+8UQL
+BeddEGT0l9AiSebT/JMKgFUOInQdKxOjg4NBp3asVEUeTGLeTN3o06zUoopzT0S3
+CHrpgvpZLf+4NATrFMw0HkcUK4GHZl/Q68C67qNGTc4B37eGcxzGo8QOyjXzKxL8
+Lh+Ry3eJpEXae5xDUn9yt8eqYI2vdwjA/3+XE6mRhu1sbPNJCcWo2kLZ0ibYgqdB
+FLsXBT8aoeKrW2p82OpehslbmswOKZgrPRYmNh1GAPz2jwBFfCEOLQYXAjCFViiL
+ipFLKLGt2dhjk5RbCraN6eYRn2XcIai/7dnaYxXkjOsNH4mmPzlzjhvRh/2E/r2Z
+hbTOoa2uFUtZHWtDXUz7ZzCJErJaA00ont37BksfHDdDw1HIt4z6Ut8Jm1cR5zPO
+pC7s7ohOS5j8Vr8j947bEXITC2ozcvVVZOCcHwF/PnUE1zx48HBp2m9NAZ8Bz3LS
+Zn799/RrNtJLnkheG0wIrizk72M5L9PZQ4FXlupfJ9c9XniaQ23GQFszagceDN8j
+z/MR4tTfdWRy/889lqZ6ccNmPAXdwwijC6Tw6V9HooN9m3++ZlbPfHpboQUp6+V0
+Wwq8gdnlYW/i++9n251xBsR7mQtFNXaYwFmLUTt9C8OobyWSsX/OaeQGbWiVnmAv
+vPkr7mh6g0ha/x+1vKgEOjqItJsGdspf8ePHQ3FaTkfFwhQ4eN9w4QR3uzM/7fnj
+ql3yA+G8ftpaU9omFbs+VqIVNej5tvjODQ02BbjSuRklAGxnReCS14vLwjg9BV6t
+Ow74oIttwlZof21BWsCISgybkPmMhkIhUNAAkHexzY3AiqjAtEGnpmvfZAX9zN8+
++Kg58DxudjHQwUO4cwP9p50NndrilBShkotdYIqekXn6h0frYuhspJVWwIVswNjX
+BuEZE5B+Otswbt/caj9C5tfsyKmnGToG4fpDdk0ItxRq2126crKQd49zZybyR3zR
+phLeduyS5h0oYNwTjq+Fg2Z+f6d/iyCAE8ynfqcAPK1WpM/02DBoLsOmve5BCSPB
+YYKdrKfkGbj4J2klrptGmqgctyW5jKGddE6NO4XFYV174rsdPoErNWWcfptHEMLR
+BWfopqdN/HMrpRLTkjx9rIeBJ0F+wQEEH1JehnWExSSSAhm/gzQc1kU/wihOStU4
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_128_cfb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_128_cfb.pem
new file mode 100644
index 000000000..4284fff63
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_128_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-CFB,AEA62B1564D645C9
+
+NX4iex15O1Dwp6ADN+uFIycPB1ELvBDVRGh+OZnisNU9h+8dPO1cb3j2tkwLFK4i
+Pml4zz797d4I4GqdF2Y23dz2AoBrl2Lj0N0W01AlOGagh92pZ9dKjjU+S5N85OBw
+buDbADh16fSPW6Y88guWFXYBlGJ6HZFK/9D4CZmEfI2Pt9AwEIZ/JvWrs/zW5eGP
+YMFsLslsNu9TOIKF8iDnfcWM9MFpgwcFCIqTwyQ/+dka0hw33WsBREhFcNleLxhW
+NKBIMC6jNjpW916IClH5sBu7T8ps/7JVw4DUfpl8NAOaqJSicPGpZrGIZ9N9cfLp
+KD1XEy+yWc9ahV0mfiyOuzNnP2x9IEBdrk5uqJwIT9RuiFZixIH9MRuqAtrA5BIP
+dc2kw50AbXRghE0JdUEFfUm9zcRKdG366SgADnteNk/77gqI0OZJDD0XL9R/N3Tn
+uh3EI9joJciWDbEX0/751MfcLaa/EkI7quKMEyFGWvox9sKLLEKRUV6SfO/YX8ZM
+RV7ebJdW+Mxya/beG3Yb9TAYkrG2TT2+uhRqZlZllJQFnX7k5MxyfN5I+WJP7SEs
+Uy5PAkNv3h7DTV7dBFMy/gPYAooY4JzBnbq33af+w/VbhyhVid/hn9UAONahw7H/
+1Ao24IlYMza2fJ9yOn+ejLhjvwYIP5992cmElneqMdBfV+oaQTHtWUuVF6g4gJBw
+9QucqxH4JbYccwA1UiKIqkmOlePm5I57RbBw1OG/Un3SiPcAwiAW/UpI5yv8kNwq
+kZeWnD79kMBEW2pU1CTvf5f8aBmcgQykC0M8H25Jj2kVvj0EsRGx1LuQx3ZCSM9y
+sZejgZouYA1WuZaIsz+3t4fgYFiOHDxmSvPt6VtZAMJGmLB/Xa/PVI4rsyNv99wB
+UinlINhzeGKpYYHnUgN0PrRQl0LBR0TdrJ0eG1djEvflXsuAQVP7+gP+oCckkT2c
+pIVm2IzplT2wzsza6+o1SA5BF7RKI3A6IxySFEBJTeaiZnYeeJHxE2DJvU1Fe29G
+ML/lM02waLJNbIs0Vk/i+hyE1wtMwZetptG+En5TDzTkWlVSLSqW6LXVJ53J2E+q
+wypuz4akL8CaYRm4XTmIH3Tom3qSf7rdbL9gk8llZacFNqAl7x1C9zDUzKU0DAOg
+qPKAtD1s7Rtg+4p+5cIEAWD0TKX6DlXKC/EdYO1w0vmavGSvQrr+KENE4+/gIRst
+qlTCiEW2U+PPyOgpZAFF0g5y5Xw0Fea/0HwBBLfCiPKRmDHQIzWIEW7RkkNfQlHC
+iCTBoMRFDbwXJEI9XUu2N4RdmlP+84i6fSRWuzZGUACvzEnRJEc6H0FaaN+fX0wM
+Op5O2hcdA0YTGGmTLUAeajiQnqGRobC8jQL/WQRVwOiFU9rgy1K4Cu2T6eBubvVh
+gk/R12LezvD/KwLgQz1+vXa5Vgjp0xhpnLnJVzPqLG0Fmj3V4uRDc1Lvvl4uLJiR
+VFjFYlqxP6w+ToRqnrfbmUCuiq6pS9FQi2Tghd02P5TnZcyS2xF2X7o45gegMplS
+skPzTCON8140xpx6Flep3bHwzEI0CEwO8goVMc6x4a2Ggekjn/Nz2A==
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_128_ecb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_128_ecb.pem
new file mode 100644
index 000000000..d9609d749
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_128_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-ECB,270AFD04879E8434
+
+u8jYUJhoDMDNI5cHXhnJJ7Pm0lF+MrOl84maQOwfwZ5hBbjpx9s+z5SMYpWfz0yQ
+WlgBuGkaY1UNBDrwH6baA9/eqUzem9ZK+mYmjKC30OaumjKVJIB7cJfJf6Itcaom
+SH1W0kJYeDn7ANdmstOGxbr2TDCr0BXa+7j8cTo2TZX1rfsXcdmjQ+8Qa8zfQ3Q5
+FbrO+VNmAQwO7HeFjms38+ukJRW30EPibmbzx/YTCZ7XtCsXt6t6ggYja9Kvk/eI
+khwvFFk4g6Dv9YU+x2pyrkquIiTUo+jm3Vqhz2m0cGcqfynVEYn4fNPc27Ekw3uj
+CrprMgnfaX8QVx/EkpDYp7gpjcLYJObpUTcBo5iA7R3lpQ8itY1Ky7u6MMwQ2VHd
+XZcsS6b06mp2EW1CO951ZaPyma4AqoLl2gZ3zH4qPygp7uxrGdFdFSqrapVkDee/
+lLtj8Z+/g1IyVSIW2FP/SCoustCHcqeDDq70GKY9qiahNFybWn49vZAPB3HPM22f
+mCcw4ALiKr0S9oofxrb8PKxmDQMZAJqjc8qRMLktYh9rJLMoUG2bmQqpKmLLpx5q
+3CaKi3wofc005VcILyRgjumscAcpbTEz4vcR4jTwMPNP+WI8+AHtg0OcF+7hE8qc
+a9KTSsx3eJNbqq5UYxVjV/DcttNx9ENllnG+jEdttkaf+T9rJiayc0WPd+Eg0XlN
+ByBG0RCPQVJ9YH1Yke9HGE0FXv7FV6x4c22ePePcyE6VUNBoxdmXw+KRhRlvtXtM
+1fFMwUrY//jEpfbf193avTVVctDTLxDSmwY6eAMBm81uDTlpUm0q7l2rRuKzdgFd
+bG/MTOd/j7wtKJbQpbUfUNFtF6zjssPdGhJ3l+8Rg4xZyHWHgU5FYGodp9RsxUhm
+8AzoPDcVbbvu5YlPP+XvyEO1860fX6iSZKuOV+owjh2i51CPzsgX6OrOEb6/1rc3
+M5AkLVl4insmetdTqb9PHCgfD6bLYcDBj7Qnf4HEDQUGcRFe+jogOoSH40C5UgPq
+F83nXv6WYBb2Y97lhb44x7d1MzE1kkzQXlyf3QuZ0ZjOvm+LuOWkbQWmLj5JhFJv
+9CqY2MBL39EFamKjmmBmjrRsI9XMLHvB7VvT1hJPzxbF3UwDZ5BsA8IXSps0EjXR
+rZXSwo+vqTa3NlvysgvuJJUjwyf6mN2SVrNaKnZZ1OGFY1oQ3bmOgdI+SW9cpGzY
+Y8eFpaG2RAiOfBZ0JIyBUoHUH1MMMPw+Mh7KzIknP7O9htwiAWEvkcjWr7X6jpG8
+sBdBmszX3TMDTToQ6DvyjVRP7mJ39dV83bLI3EA+N8bJcTOcHijCvbzQM50WzMu1
+2UA9e6rG+ouQAgwaAHdR6bwm+Zr3e7MswZ0Q8/Snd1UdpyMyJ9nb031NSRSvkEyB
+ipu85/738J/g7tAIOJwwHeVWjL4lnrLC3CwbtvWAQ9Ox8Sjv848608GzQxFwHBHJ
+0NWgt/AfLYsq4bmmFWtqvqTjWeAeUsM+67UY8m6/kxhfRNNN3zZcckq2zlF7TRNU
+5AL/3KbVVLQl/7fD36m8AK5eImR+Gvom8ryzNacbNCL55ks0sycbICulXbdb0Jgm
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_128_ofb.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_128_ofb.pem
new file mode 100644
index 000000000..cafccf9ea
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_128_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-OFB,E5989634C878E65D
+
+6o45POmHfE72UAdMBQrRIm2+oZCd8GmkmrFZMXYnVWP8ciNiGVQqUxVJS9j5Rx17
+8qxpNrzvcWEGWcgs9AOqog7YXHkxo/s/RIOKjUu0WhY59UrYcbkN7Rjyn3wSSD8X
+kN4Z2tz3iR8LnfljD2ApbR3yEYz2NvmifZzsac58R3LvuFg3Tsl0QetPSC7PfMUh
+B7dezaycDcx8QJy+nRPcqpGzeL/VVk3F4Hppc15gfdWtVellGcYsT0Z2Iu42I5nx
+HYFajRliBukH98M1d905lk1aNLDj54BBcq08JsDJN/V6DY+mUpJCFOK4DfP5WLJb
+/HCQg0wqsUmRHK3dVo09ilZa4OfrrRD5qTWr5boDngAqyD1r1fiHxcv7uU/HOSvt
+PU53frz38BA+w1pHtlE0TSG0oBe/+741kJtpvj/1Ts7nUeYJ/DGR4vmLpg4rnbZJ
+Yky5TaDV2LVLFR4syqombb3eiK5xbnjePCQFLwxYLQKZFINiS5zDr5mdjhWbIhpA
+7wg9BKNpUeXRDtntWXvEH9FmyIicbk670riEYEo/EniwrxW9f7MFhPUpOb9ktE56
+RnaU0EK9zUx1sIvcu7LVq1G2EVG8IrOKGcj4LHysBtg6PQW5mvN4AA5PZlc2Sux4
+L5Z6mJfwgBbBB4OuRXAYxHZbnfMTs75vL3d/HIcvSPcvb+7nfvNLiwlaBxaUfBFh
+fyDurHkMG6tBgE6OORgWraNEINJeOYcG2WK60qC4E8YfYCmc9V+28A//bsyRWyku
+xIDup68r+Os5RMRAaZrkIqaH+h4Oyd5RqcjLnAFF/wLGnNwSttYT8o7WwCf9ZCCy
+NFvHDWyWMUxonaWgvuSm9YPfh9/9CEsHkKh2RqBffFcZ1ktEiYaI+dGyty12QW2Y
+909pnCZkKsm1Lt3ts/xie20/gcwfsnvUC8OveKPaiCnJxDv3r9pMCNFPdcXo0GuR
+oadhn9r2CqNCDo+l6JWVRka2t8+yCAskZC7bKJnSeKlEDyn7A/2SLb196G2k9cve
+V2qQenhzuHmG5PEVfhLWQ7fL1BmJcRDuQlSmMGrdmOD4Zb0Truq0zpFL2qaMBQvb
+58hG5YkYehE25j8PpJYovOQA2hih6v9RytR2VKlTeYNFbREf1sdLfeIphB9tlHlp
+qZ7eOFAjjVzLsC4LmoCzWMaQuwNO1f3WiNdGVvulHkWqFnGS9bBBTahUUWI5SYiQ
+90vhSmJ7R7461rqWwn34Om5jlgRV4+2LhUbp+XdOyklujQYviHsOs8/wlg3lKr76
+SwrU5oYqlJ7FJoDq4IPpOnJaxsRjkr9foecgdqrU4SJKyJJDbkHNfoYq9r/aZJ21
+ruPFv5t021gJmWa87199GlhBZD8dxeXo0PT298Y3pmaaSdQIWLPeDAtc1R9EJLwD
+6+ydhg3ZVtSgXU0zQ2SRVMGhqoEXHDUrMtjKzuaZsYL57tqH6At6vWS+xA0CJBCw
+7GkDpM/lLGjyisFEQL73F0YmJPpb5s4izzCLUMxZQZ3u4T3f9OPRvAIUf8MiFJxh
+RJq2Is1gD7M8+dySkFeAbQ1STvLy29uIxKTE6BgNng5NrY03GuK/5A==
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_40_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_40_cbc.pem
new file mode 100644
index 000000000..5a9eecfeb
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_40_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-40-CBC,BA10EF99A1862AB2
+
+/CfoFtIX0zgNckXzuODWoCYVY6NoXOvu1jt7J5/BfSZUydRWKa2lpR3SWAUAesQX
+H/IK9Wkz4um0QgrHy2fmVaAS1G3ifwgQ9dhW1EMiCEAmuNwPsT2YBatSyxnzWjHa
+dv4eZ0Snk4DsS/Ajwn+Oc9uZ3u5gKnfYk3tXoZ9BDPQbgIz01UI/AyGHttB43brl
+e1C+zKgCSa5WB8wfxCJsKHDSEHx+qlipVvDk/pntc9m4AM0sp5wsHRw3i1iirQOw
+AG6qRs3Ro3jwajlEWPmJolhbRQWyA2rUfSIajElYFlFgxPLI10m0tO5M55VYXpWe
+cprQNe/TxK+YJTcBvyhFmP4Ha9NeC0Vq6aHiECpZ1uObH1brZ1bdYUsSGodRzGMC
+ucOkFDpsp9We48TAHqEGArCsKexxe1dDe8b+cxdvyv33ZI7dyr7DfHek3X7B2rHv
+tZYjgx0cKn8SNl9qdRync9wLqjL2R99sHgphkXUA7qLP7ZdvZEeAGs5NEuq5oyDj
+4aybPFJu/xvByOEZBwEtrixVJ/2h4KYF6g2vK5CgmnYrq8SUNGobt+oLv3FywKhQ
+AK/YvDt97wXNdPNqPciqCP9LIeo0B0cgxFIbOOE3mvYgPaUoTtZ48B/hpkY4flKR
+U7opVqbNl/pnh1OCI1ce/K5KPw0rvYgsEQ8Q04+dipPdmvONYGhcgHflS52xju6s
+RbosS+iET3a6BB8ydRS8V4oezbr7AgzoSv7Od6geru87fYpVW3WbGag4w+Xgil7u
+C22epy/AX8naBOsMa2QMCZ97avi/qhMFIERzhQJcxULff0lHQBq+HMGsSI8jMEiH
+d2OIERTWasAEPdoBnELO3l4oywb4NmSp09m9imihdgocDAQEXyLkjmRqkm5H3Tdm
+ALFIaSwU5SE/dk3T+BTmnfl+Anx7QNWTdg+ykfH8VHbs10A/K2zt6RyJGLdStfKq
+VWORUG7gYcVGIQrcJllxt3Jt4sG3t3rSKA5dukM7+D1d54ExiJN5DrnaQ4kX/v7O
+nENonLRtV1KqrH32R+tIuBVA8rbmyseVequTBQpkHbG/IczTG1k6p0Qye17XlnPl
+kEPE3CG8+1RMLvflA1rTimSh1WafHsDwvwmTAgdkG5btLlfTpPnoKDy2hPS4Pd0P
+mF7OPVfA0Hl/oEqP7bqyUxuwFrz7pZXQrKDS02nXaqVAP02nKsiEUZNo2kprAO2v
+9ceOhXP3M+ItlWeNcX5jKRaaLddQvj1ntOKqDMfRk4yWm9ro8/E56Fkrq7GpKrXL
+FCJJTdrWk6EcSfI6grVjPbZGBJiA+21G4IPQWskPkr9gLuE0E9I1UAdliYKXOrPK
+F1lZ1ZBpG1ZBe9H8Gr2sK42pzJoFJsOvGRjCxlHpf/gBoOADH/hcxvQqBGizEr0F
+kKraZWJnlL8qhDzfJ7YLMqzFsOu7uYQRqfOcv+66FqT/by9rD7dR/M03YJReupoL
+lynJfffGCG6aeM8hLZ8iizjIc/RzCY0QS4lLPkRVSRNt3Z8RNX/nFuYhYgOx38pu
+6dflN059kTC5iyjsI5Ka/Xzq69kR21qCcHOoq6IQqZ7q5RM4Cj0SCXw8/4jeT2xY
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_64_cbc.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_64_cbc.pem
new file mode 100644
index 000000000..7d0960811
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_rc2_64_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-64-CBC,DA39EAD05DD48A5B
+
+mil5OpL9dVqnEoKF7dNjIRYLgDjCBmTDZ//Bmkd4aqkPszHaCoQqgyGYOuqWXdT2
+FAluu/fHMLDTizyr2Jh00ekcR3nmnGM3B0oDiEtq84YMHPWYopWkpId1ZaoqluUe
+6NP6Zew4DZ8mEQvOxIxBEZqk0ye6srtLszByw/dTy4i9S7l4oR8hx1i6Jj9lLXS1
+y24lC68igFNeIecggG8uwZBVmnHCldZGn6DBBqcC0b415+59vwGuvc+POy0Hog/4
+ADPuZcXEO2whVGyOjCF7CjhEFfo0CO2niwS9PiUIYNsUluwfS+y1qhw4VJ61sQ/q
+7cNHrD4NfZHGwpIRXk4c27YHS+JsxH8Kh61e/dQPoeTf5NBQs3PthFcx+hzlTBAq
+VK/4TtRRlnqTVFKRydpKo3cNGp8qm9Kvz6fr/yLb7CJvdoGDyHVO7JvT8nYL5gC0
+dvN2RySKXMrgmPS7uMAWjpnDCdNoOX4pRTRPEdBw8WsdXqnBqXM8tvrkolF9n3//
+lldN3sSGLiYM1cwD4dXlYJEJNaarelHk6vpJIU4A6gYyN9MQnv061jd7sibrTAjZ
+Rx06R0FrYFbfkp4yAmUbrPO5gdwZPBGS9XzkZmZr+S4u1fH7tTFxIlWNgxwSzsZJ
+P9LXM8Iy408gDn1AJlbT7WbdWfcFzqIsmauRIXE66TloS+485ro9zX7O27MumF8S
+hjD+cRMieUEREuAAlpNxZj5kcT3SpxfSdaAZtJv8OKeRHz796LRxlLmx3ZDAjgN5
+0H37gSCXJDP2a4YnsiI7th5fNba84t1Qt4Q36v6EZT2kscv0TB04ov1+4UX9jCQI
+zn2zxzJk42kkxRSEBP3BnZf/qV5t6/+BKmg1QGCmS5AkIIlCDjTPpAom3n7YH9LV
+ykAQ6Wcdo/7dGtghgaHbPGl3cXR1u7BI97GCU4vzRbW58ULh7KSC1xptDJrP7tPE
+6OwwYk5YZ6lmg54cLbQcxeFwYQg1dc4pYAgBppUFUB/uWeQrbJP8/FN/GlW0HTOU
+kUIz5pbI7nstb2hHrRMTtG4c0oGO1ACD2LigQo5Cl7jR0sBC3I2MB/JcBBwAHPVP
+tePpIdSAZjAYI+x7LFxxXvT7eXe+BU4ZLGLcTISGJjtsbJG1oJ/e7dPP5bLL+zjJ
+MrwoE6awH5GKOOxB0iUGce8jg8566qY4e2vbmVL4a2qRiKyLowr7Lcz01VzzE/RX
+0Ec1I8noUmsystH/57UMBuhZNFjW3LtTaw6vuTrrmFtdmJcGwars9tBtH0LPip9X
+xQbwIiTJZCyDjql7Ecgu2ncw7zHZzbHrmoEF7VEdPT4z21utXgzJ3HubvB7Agvyz
+sB+EXeUqwZHnyN0GdGd6sqlHkW7TP1XxMrjewUHjXuY4SvsosJ/GqMY7uKJXK/Lt
+0kqYrV/YDIVsJ2JqyxwXYYIqmZfQ2xXTLuESuesT7omKFh4cgwbYHd33YWRCsZJB
+7Og8d3ciguWDutd1LOgx7da2ZA+3UVz8X601GRpFD8YoZTo8QOayXFvv7L1F3oeK
+b0w11lT0npxstmeMQUkbxAyCnKrwpQagiwBzKlr9ymJvh/ot6sJ5bAFDvZBBKkQU
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_unencrypted.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_unencrypted.pem
new file mode 100644
index 000000000..f540dccf7
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/data/rsa/openssl_rsa_unencrypted.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAyGOvloI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7Plp
+gpjUg4pNjYGViGjg7zhfbjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc
+8BQcwHf0ZHLN6sD9m2uVSp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTj
+HE5t7iu1JVjTuE0pcBvah2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindx
+OSAnAxK6q/wGqcZ3zvFBTcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfD
+HArDqUYxqJUlPGlMqrKb3fCFiT3eXehwR7nlzQIDAQABAoIBAFd6vTKVVT0O/U04
+wTtiptA/p7fkDM5PHVBxh32Wxno5pj8PerIaiduKyuRVh7PvJRMJpw903BrAK95o
+847WWOVOaF7TcKGMBURJUS6maiJS7TboK1ZbUVnsg/I99ArhiVUKGDhlsl/Xd4np
+YPDYztzXLzLXpm7bS6CiuvP762x9dfVu8K+afP8cjH8pfXLq55ghZOUKidRQaYz1
+mNOTQyAQlCQdLRgKlYgqcRHlj0pb28XBJaln3W7Z7GFMWFPojkxx6LaCp8+Jyx2C
+tv54zIZQhMjF37tQyTnfK4Ocl3sCRb+jYV4FkrUnsQE9W2dey0Tms1XB31gfUJlx
+dRZu7zkCgYEA/nWcTwzot2OIAhXoJ2fnqTcpdmj05LHhGcayKjyix7BsVH2I0KpF
+9kXX066tr3+LxZTergl4UpWSl3yx/4kPBQM6np4VVRytn7+cQdEhOczZnBw6x7IZ
+fv81DSNruQDBRAlTtklW4KBY74JKLhaJSvF1F3x32+H+99i1MmCNJRMCgYEAyZpF
+h4c3pM9z+YlmgLdUh/G2abdoamugcQOFbzHbZowsRAxEzdEW9wj2McN6mt8Rn1tc
+tY/+PcYuIK+vcmk9k23GuzxRlJlkaDicHwlAebgVIulFcrStfTlSkXjpuOuusfD9
+2DuHMcUiPx3qElNB0dZJF/axpq7BjTIFENefhZ8CgYACn+vw1M1BtwEcJGW0olm9
+YRhIZGTCRyNvRKFp1h5HuQYlCPZ0UI1QMQA86rxX5xTmANcbLHXVRD2y2lJrtFo3
+TwU3xaGqsxUHZM6TzzhshDRqa9AfZzLkIHXHoOnnip5zuTTn2HHQ91ZzggCJ4Smh
+YEQ47cu+tOIQZGfaESzjiQKBgQCCfnZlDJRq/NFwA40y4fg4arANa+eNgw7+OC5F
+1HrUvQTmIx7iLmZ0Dvv1KDgTSTLJ+MRgzczexYoUJEQnhZGS/Wq2xYt06XlBsOr1
+d/KhFxOvXllSrzrhJJqaiS6YQQ36JijZr2aKQ7UwL7fUlsmy/safWVKStumX8Hmw
+9jFOtwKBgQDmtirdNQ8aKolokD/3bDHPcDsNcybEpiCu8BIltxZAs/LsN1IIxfcp
+mGP2AFt3mbblKbsRM8hDW/X9taeG9s2KGe5wlKOE5lV8YAo4hFoJYN2/0d8Y0K9X
+QAAYU3iPG1zL+a/7TFLJ0u/biqsBg9hnNbMnN/tOeSuKnH2Rx9F1rg==
+-----END RSA PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/ecexpparam.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/ecexpparam.pem
new file mode 100644
index 000000000..1dc0d9a91
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/ecexpparam.pem
@@ -0,0 +1,23 @@
+-----BEGIN EC PARAMETERS-----
+MIIBVwIBATA8BgcqhkjOPQEBAjEA////////////////////////////////////
+//////7/////AAAAAAAAAAD/////MHsEMP//////////////////////////////
+///////////+/////wAAAAAAAAAA/////AQwszEvp+I+5+SYjgVr4/gtGRgdnG7+
+gUESAxQIj1ATh1rGVjmNii7RnSqFyO3T7CrvAxUAozWSaqMZonodAIlqZ3OkgnrN
+rHMEYQSqh8oivosFN46xxx7zIK10bh07Younm5hZ90HgglQqOFUC8l2/VSlsOlRe
+OHJ2Crc2F95KliYsb12emL+Sktwp+PQdvSiaFHzp2jETtfC4wApgsc4dfoGdekMd
+fJDqDl8CMQD////////////////////////////////HY02B9Dct31gaDbJIsKd6
+7OwZaszFKXMCAQE=
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MIIB+gIBAQQwQqOzUTcWWPBe9Kzj6uouD+1KZdEZRPWaTLFTXF8JGOoz+5SRAe3I
+ButvUDWYahuToIIBWzCCAVcCAQEwPAYHKoZIzj0BAQIxAP//////////////////
+///////////////////////+/////wAAAAAAAAAA/////zB7BDD/////////////
+/////////////////////////////v////8AAAAAAAAAAP////wEMLMxL6fiPufk
+mI4Fa+P4LRkYHZxu/oFBEgMUCI9QE4daxlY5jYou0Z0qhcjt0+wq7wMVAKM1kmqj
+GaJ6HQCJamdzpIJ6zaxzBGEEqofKIr6LBTeOscce8yCtdG4dO2KLp5uYWfdB4IJU
+KjhVAvJdv1UpbDpUXjhydgq3NhfeSpYmLG9dnpi/kpLcKfj0Hb0omhR86doxE7Xw
+uMAKYLHOHX6BnXpDHXyQ6g5fAjEA////////////////////////////////x2NN
+gfQ3Ld9YGg2ySLCneuzsGWrMxSlzAgEBoWQDYgAEsnHT26mFzKjQEBo5yAt4n0b7
+CdnrEDW0OUTnu7010BIpvbvBK0oVzGrdD9dsgAF2e4zkZN5TllLqY3nXvaVnWeJ9
+KypglBwFvo1O3BrTtrsEe/oSe7b0mJm5YWZEg8in
+-----END EC PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/eckey.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/eckey.pem
new file mode 100644
index 000000000..8ceb3a8a3
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/eckey.pem
@@ -0,0 +1,9 @@
+-----BEGIN EC PARAMETERS-----
+BgUrgQQAIg==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDCSBU3vo7ieeKs0ABQamy/ynxlde7Ylr8HmyfLaNnMrjAwPp9R+KMUE
+hB7zxSAXv9KgBwYFK4EEACKhZANiAQQyyolMpg+TyB4o9kPWqafHIOe8o9K1glus
++w2sY8OIPQQWGb5i5LdAyi/SscwU24rZM0yiL3BHodp9ccwyhLrFYgXJUOQcCN2d
+no1GMols5497in5gL5+zn0yMsRtyv5o=
+-----END EC PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/enckey.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/enckey.pem
new file mode 100644
index 000000000..137fab345
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/enckey.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIpII67Pp5Vs8CAggA
+MB0GCWCGSAFlAwQBKgQQBpkbyKLxdtlBlp6tm6lZoASCBND/h43o5NNNmTXWHN2+
+N9ncoFknxohgShAc8WHKMHt0SCEJab8E2IAxVkYFMOMpvi1KVldcveLlg7hcMIDm
+74pJmvXOW6b0bENvPMOxFadzr9NjO7j5ZT81dwNLz2pBLyiUMYElWl0LVnxKThQF
+qijJTDPcmTpFwDiUyTxzHxMx4DsoFYQulRBsZbRCAjsFpPM+OrOekSAyQHKMSbHU
+LvcdWCrSDRtKOyCeCPbBA4OzPJFyzep6trhbQii6rkddf9o54/oJut+LMuUblrHE
+2yMStfW0G5ZyI7AeOxAy1gKG/CQrvFHn/yhtyjkvPa0sYVGtR4pGew+cs9iIsdFk
+nXOf9frJMA2agQZKc4+rf66NPv+dxVecm40HIR3omk7EnxR8s6msXOOn4qnY7qae
+aq1M7pKNqCu6eW5560mW6buLpOkpm/kDbr4v9rfCX41b5rIRzOdfAt71FSJcHp6K
+FNojK86YsNJWYh9pnfDbjEk7346cCIeJVgICGTmL8Tg6TUy9wIB6eKUXmIG3fKjI
+Ep8OzYAU3/ae8vdmZqD12l3v75muRPs4bP1RdjaVrux5Xlq8TkzU21ixWG6Odj7I
+1jusSUjz16iR29XhLP/HI80GKYQMc2yHWcYQ1YVXyLzhnHYydrqjW5OTKZW01rbe
+9BC8XlRzKZJ4IOQMfSiZxcdERtImO86Kprl4du7gvWaTUGTyiQ721Q08GfFdVuAn
+OO/J8stTLv2Ee7ugTeAFA2+qpz2vAo5JIPOmqjNqI2ytPjLRb80B3tSVXT41OodT
+D4v5YbNpySMDpw2F052Wx37hl2wNxIP98U6aw3ZjJdM/YfLdGOJhdoRTBDAvygRU
+Di6F56sDvX8bdXDUZURMg+iMx3Noc5G3TB3JpYunm3BL9lwGWesrkDzg3Vs1J/6c
+4AMhAsw9+5tzvyGEDHnGZRg07K0eyWskDK0/Qb+vjSLOj8+QphM+EPCmugNnXRNo
+AdslIFoVfrcKruS1/DeSIesXvMd7sj2RH/xYDcAIGzmwbc+Ki4JTPuoZlF3pGMYE
+YkkYj2KHjJeX7CeUjCmU9Y7/jHp+fzlKsQAMQLVm8bRjDpvLA84RDJRoCPav333F
+YqRciZzMjfx2f6AJTCT+/8nv+DBiWcRtab1u6f+p1iDUa8bVt0Y8PB71gwAyonmY
+gp4A3fSilIlKEGsP2Hb4aU9V5vy1EZT0K0PuAY4yxGPmhedLCKdBqOuwQBxsLDP2
+YmXR5wQOsI0dVE8zogpgOGOEE9RXNAf7QV7pBOPNu4HQLNuZi22dKi+wkyMLsIR5
+dGEz7uDIaGQMvlprtOA02RON3gBnQTJAp7E/YMd7OldSBShRRGeIDw7yTrLoHwLI
+YnA5+ZwFLBPnOrnBC47CwgB2X/+ooL8/+yigoajZIIE5RvzuKRQGjC/ZgSHXSHrt
+mJKGerOR/3+OYYCTctTa3wTPVRc/vB1hZac9OPmnKpeywCJ4Q+jX+ZOhHOM671H6
+h9fLPd0tSE75gIkSuJqBuLV2TB1cp7BTnrZxLywCxC779lZBTVLctXu60kiIoW46
+zgEz1dyf22vfMN5ss0ybvBVCl8ROmrVr8ZWObzkj1MUyifDM8Tayd3uZ3SdHPo8L
+2G24+4bjyVdFjUvrBdzB5dNzAQ==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/extratest.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/extratest.pem
new file mode 100644
index 000000000..f987ee762
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/extratest.pem
@@ -0,0 +1,110 @@
+ 0:d=0 hl=4 l= 862 cons: SEQUENCE
+ 4:d=1 hl=4 l= 711 cons: SEQUENCE
+ 8:d=2 hl=2 l= 3 cons: cont [ 0 ]
+ 10:d=3 hl=2 l= 1 prim: INTEGER :02
+ 13:d=2 hl=2 l= 1 prim: INTEGER :07
+ 16:d=2 hl=2 l= 13 cons: SEQUENCE
+ 18:d=3 hl=2 l= 9 prim: OBJECT :md5WithRSAEncryption
+ 29:d=3 hl=2 l= 0 prim: NULL
+ 31:d=2 hl=3 l= 183 cons: SEQUENCE
+ 34:d=3 hl=2 l= 11 cons: SET
+ 36:d=4 hl=2 l= 9 cons: SEQUENCE
+ 38:d=5 hl=2 l= 3 prim: OBJECT :countryName
+ 43:d=5 hl=2 l= 2 prim: PRINTABLESTRING :AU
+ 47:d=3 hl=2 l= 17 cons: SET
+ 49:d=4 hl=2 l= 15 cons: SEQUENCE
+ 51:d=5 hl=2 l= 3 prim: OBJECT :stateOrProvinceName
+ 56:d=5 hl=2 l= 8 prim: PRINTABLESTRING :Victoria
+ 66:d=3 hl=2 l= 24 cons: SET
+ 68:d=4 hl=2 l= 22 cons: SEQUENCE
+ 70:d=5 hl=2 l= 3 prim: OBJECT :localityName
+ 75:d=5 hl=2 l= 15 prim: PRINTABLESTRING :South Melbourne
+ 92:d=3 hl=2 l= 26 cons: SET
+ 94:d=4 hl=2 l= 24 cons: SEQUENCE
+ 96:d=5 hl=2 l= 3 prim: OBJECT :organizationName
+ 101:d=5 hl=2 l= 17 prim: PRINTABLESTRING :Connect 4 Pty Ltd
+ 120:d=3 hl=2 l= 30 cons: SET
+ 122:d=4 hl=2 l= 28 cons: SEQUENCE
+ 124:d=5 hl=2 l= 3 prim: OBJECT :organizationalUnitName
+ 129:d=5 hl=2 l= 21 prim: PRINTABLESTRING :Certificate Authority
+ 152:d=3 hl=2 l= 21 cons: SET
+ 154:d=4 hl=2 l= 19 cons: SEQUENCE
+ 156:d=5 hl=2 l= 3 prim: OBJECT :commonName
+ 161:d=5 hl=2 l= 12 prim: PRINTABLESTRING :Connect 4 CA
+ 175:d=3 hl=2 l= 40 cons: SET
+ 177:d=4 hl=2 l= 38 cons: SEQUENCE
+ 179:d=5 hl=2 l= 9 prim: OBJECT :emailAddress
+ 190:d=5 hl=2 l= 25 prim: IA5STRING :webmaster@connect4.com.au
+ 217:d=2 hl=2 l= 30 cons: SEQUENCE
+ 219:d=3 hl=2 l= 13 prim: UTCTIME :000602075621Z
+ 234:d=3 hl=2 l= 13 prim: UTCTIME :010602075621Z
+ 249:d=2 hl=3 l= 184 cons: SEQUENCE
+ 252:d=3 hl=2 l= 11 cons: SET
+ 254:d=4 hl=2 l= 9 cons: SEQUENCE
+ 256:d=5 hl=2 l= 3 prim: OBJECT :countryName
+ 261:d=5 hl=2 l= 2 prim: PRINTABLESTRING :AU
+ 265:d=3 hl=2 l= 17 cons: SET
+ 267:d=4 hl=2 l= 15 cons: SEQUENCE
+ 269:d=5 hl=2 l= 3 prim: OBJECT :stateOrProvinceName
+ 274:d=5 hl=2 l= 8 prim: PRINTABLESTRING :Victoria
+ 284:d=3 hl=2 l= 24 cons: SET
+ 286:d=4 hl=2 l= 22 cons: SEQUENCE
+ 288:d=5 hl=2 l= 3 prim: OBJECT :localityName
+ 293:d=5 hl=2 l= 15 prim: PRINTABLESTRING :South Melbourne
+ 310:d=3 hl=2 l= 26 cons: SET
+ 312:d=4 hl=2 l= 24 cons: SEQUENCE
+ 314:d=5 hl=2 l= 3 prim: OBJECT :organizationName
+ 319:d=5 hl=2 l= 17 prim: PRINTABLESTRING :Connect 4 Pty Ltd
+ 338:d=3 hl=2 l= 23 cons: SET
+ 340:d=4 hl=2 l= 21 cons: SEQUENCE
+ 342:d=5 hl=2 l= 3 prim: OBJECT :organizationalUnitName
+ 347:d=5 hl=2 l= 14 prim: PRINTABLESTRING :Webserver Team
+ 363:d=3 hl=2 l= 29 cons: SET
+ 365:d=4 hl=2 l= 27 cons: SEQUENCE
+ 367:d=5 hl=2 l= 3 prim: OBJECT :commonName
+ 372:d=5 hl=2 l= 20 prim: PRINTABLESTRING :www2.connect4.com.au
+ 394:d=3 hl=2 l= 40 cons: SET
+ 396:d=4 hl=2 l= 38 cons: SEQUENCE
+ 398:d=5 hl=2 l= 9 prim: OBJECT :emailAddress
+ 409:d=5 hl=2 l= 25 prim: IA5STRING :webmaster@connect4.com.au
+ 436:d=2 hl=3 l= 159 cons: SEQUENCE
+ 439:d=3 hl=2 l= 13 cons: SEQUENCE
+ 441:d=4 hl=2 l= 9 prim: OBJECT :rsaEncryption
+ 452:d=4 hl=2 l= 0 prim: NULL
+ 454:d=3 hl=3 l= 141 prim: BIT STRING
+ 598:d=2 hl=2 l= 119 cons: cont [ 3 ]
+ 600:d=3 hl=2 l= 117 cons: SEQUENCE
+ 602:d=4 hl=2 l= 36 cons: SEQUENCE
+ 604:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Subject Alternative Name
+ 609:d=5 hl=2 l= 29 prim: OCTET STRING [HEX DUMP]:301B81197765626D617374657240636F6E6E656374342E636F6D2E6175
+ 640:d=4 hl=2 l= 58 cons: SEQUENCE
+ 642:d=5 hl=2 l= 9 prim: OBJECT :Netscape Comment
+ 653:d=5 hl=2 l= 45 prim: OCTET STRING [HEX DUMP]:162B6D6F645F73736C2067656E65726174656420637573746F6D20736572766572206365727469666963617465
+ 700:d=4 hl=2 l= 17 cons: SEQUENCE
+ 702:d=5 hl=2 l= 9 prim: OBJECT :Netscape Cert Type
+ 713:d=5 hl=2 l= 4 prim: OCTET STRING [HEX DUMP]:03020640
+ 719:d=1 hl=2 l= 13 cons: SEQUENCE
+ 721:d=2 hl=2 l= 9 prim: OBJECT :md5WithRSAEncryption
+ 732:d=2 hl=2 l= 0 prim: NULL
+ 734:d=1 hl=3 l= 129 prim: BIT STRING
+-----BEGIN X509 CERTIFICATE-----
+MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx
+ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY
+BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB
+dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ
+d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2
+MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW
+BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM
+dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l
+Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv
+bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re
+Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO
+Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE
+7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy
+QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0
+ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw
+DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL
+iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4
+yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF
+5/8=
+-----END X509 CERTIFICATE----- \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/pkcs7.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/pkcs7.pem
new file mode 100644
index 000000000..6104acd72
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/pkcs7.pem
@@ -0,0 +1,54 @@
+-----BEGIN PKCS7-----
+MIIJogYJKoZIhvcNAQcDoIIJkzCCCY8CAQAxgfgwgfUCAQAwXjBZMQswCQYDVQQG
+EwJHQjESMBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYD
+VQQKEw5NeSBDb21wYW55IEx0ZDELMAkGA1UEAxMCWFgCAQAwDQYJKoZIhvcNAQEB
+BQAEgYAikb9cD39oDYpMHzLuqA4BonNpPx+jYtqlUIaJv30V03nUz1MLm7IH7TFt
+ZhL6BXAbdC2iwk62KVS66ZCLBKdsqtD3w9N2HtxTEW6AdaNHKNUb6z83yarNQGzB
+67llZjeCLeipP7RWIvBZcV0OoqCgLcpZkpZqzrmz5MjxTCmB/DCCCI0GCSqGSIb3
+DQEHATAUBggqhkiG9w0DBwQIja9nGhuQE1GAgghocswhe5MZRov9Zo1gnB25S0P8
+Mw3463VaOcb+ljX1mXkT3fivkBv0plLlmVT+m+CRgczup9p21+t1OqsdaITNIyrG
+hYSVETWyFA/Yn7dQupK+cdCaVLKC3lT8f13iPrU40wnbeo4ZKi2vbv/X3uU4fRMZ
+wSlyczFozcviUYURtA5MZaS2e6/2r1eLZcUlcZ0BDcuD+FNdryGbKztSWa2ye0Ym
+Uilu+GAZr5CQi3IxpRxDqrS+RUQZNllcg8nGZ2UP5W8FjH+Z568NJ7djoziCX0EH
+yd4vp+g0LRG2dkhGXIff4ufO2U3QOAgCIOuZmG5YSpRN2U7F6T8W/FwShFO1u+QH
+YduA3pA/5K+IDfCbEZDMWznd13lTEZQlLSXV7dLNCqpR30JWpGg956rJR0k2bT7G
+KFTXhSUK/Puac5y6IVmJwPxqAkjH+xjXpE32/AcRHi77La3nKp1aQEKo5uHg7HEg
+w160S1LUenJSqcmOuk5XWvM1wdsUJl5Qk4m9a0VyovLPm/RrnulMtUjRugxJLfZK
+27NivOrLl9h/Wm6BXYq4PohM5d+5zPYqupn5ipKHsA68Ps7rnDEGS3VzOQ32hqu4
+kdm6xI2zLWK0+6mQnusBPO0IAxtja6BPz8vTMlWjZtWZgEIMppQMhQJKBEQG6HTV
+z+/gkFds2pFO0v8pLcMBy9+8nqhzwGacymnupXJzB6l3gon2t/e2zJjAPKUSCbHI
+QhCjW2JK9tGKTbF40uYMUGMIPhxr7j1u4LKNEhKCNhlUz82NSsdJ00YNQdwuDMWN
+CTAE9/STmRGF3ZHT9KWmz5MQECp/pGORD7LtOQslbUYiMH5oCYP1jD8eM+KxCljv
+1pFPf+sZdpboAkdaXKcZVnKqOuPBP3Y1jBkLCZykgnXkVbEYM7gSdvsCGK52GcxH
+yi/gOhfOIgywmFB3B4Yk4mDtU84WpK5sVlrZ2vZuTaAmOHaTIkVMvkq30F/jpVy3
+OF4v9/EbEAJGv6rqHMhKmuIHP530CKtWkUUfGv7qQilZ1Qi6NyFJJTfb1bhyENJt
+j8A1QQFIYHDzMolmUoQgqOXJ/6xc9AtCv0fU2LijLUNFjB4rapJggo5UnZE98+Iq
+UAT7tWalpbFisOdX5Dy582hhvcFn/1DDpISXpF0kgE8TV/swkJ7zuu+hO/Yj1HNd
+cwG6NC9+wUCjaRqAobBtvPQyK666I8C12pnW0AeuqtznnZve2B0/a83ECS0tUmxC
+PO9zv9RNwcakynklrupw7B4PcXEaEbxpvHE+/zNLgfrPRggoFdqSIRFS9xQRPE9T
+uO7jEh+tyh70eLqce2jqKpRwxItZst3ABT5XarJ6vfGxxcs55sJG7xjv52xuMikY
+gOagSKpETRdkeE1aAmKwpa/vEFu2J4Oq1Aiv+D2Gc7G04cOsdc+6P+N9EEv70v0R
+3NA4vg3gTBcO3wxwnJZAS7GwUJOcrqC1cAaQkc5NR0lUx0lMzgWWDDS5qKX+YwIU
+7KEQiyhqQ74rkf6hxQyfesaBxqxCZZkikbwBHlDZwoPfwnfrV4X4/xyo3cqCqbhf
+FFlHOAXissz14wsTPh4XQumj5RZSnwj8gGK2xou9H9wMrwuZ2eAT/3L3OtbIr/Sz
+Cbp8Y95Tz8FgmrJXvygMVO1xv77PA1DzE9SLiLyB6TL8lsxFQ1ZF2D8JhpDeIPpj
+L0k2vTrmCgENJ+tCc0ngZO55ZgRbo1fbB/RUfkTRgEKF9WmJYnlXUVoh77kZ0cc9
+Y+KsueEZp1woSTywJb3tc/jXeRGSmcaWe6pa0DcfM50coV0y4lw1ednEV3zkA1r4
+zVtUBw8Xvr9GKcNfWdmqgIJKsQraq6WCeIxCPPJw708+/RERQBoUobXI4+Jatw/z
+XiV9SjrjK9nJ4H1YKyOjyz3SAbeYrgdgrTGvkETCPAALb+4Rg1FHymSMfDquwOsB
+63Mdl63DIkJpicA6CY6yk/LgOADQzEipjcdKqzQOjlb4hsQZxN83kzGJiWB0qZOL
+XVLrGXP4xRYS2bUFB0T8pon0K5qsZ9oKKf+HZaHMYkni43Ef9IRA0qeDl4FfAupA
+kL0lLnBjgGRHc6rMBy4qL18xRjTtR9hsn4Z/pYhIgqMm3QEVkK/aOgTOlwXHdIwu
++Hvzx0Y/BgMdCZSlrspPbQBDgrlWzr+PjcjEvDf3LYj9whtRJP5cXVxiYqi/SpCk
+Ghy47RfNYfkkJs/gbojlO/lDvM8oo+XPi22zAN6yFLuxr65lJZK7QIvabHvTkEIN
+wmpnWcRH+MwcFZO3yKt6lxY7nJWuW5hh8O7k4/oN0pNdGtv1/2XgXFOCREQ4CcPn
+Zm/vXULLCCh7oP+RyklnwyedvfeSfY4lpldwyHCIsYyYmfZHMw32zqH5jCnSxZA4
+fHBrblr4Mj/5jyHLUF5xGsJdm5RtDfwJWe6NelO/kJMs35UjA6dhSOfHEkw73M5P
+jcRo1OtYZGu19x2QguhILpZxuAvNtLpOt88z3PtsxA6Fc0BGpQXPJTYwtXiPf1lj
+fUd5KFsPohPJOIEJAaFHL3GTwmWFtK1dHofPQukiOTb6pC6yKlM/zGWLOyzTM4qP
+UvuUSwg1UY8GplCeqhCJNTieNmyY70vzG2CWcotAwRPeVbpa4MEWRXHf9ft4Mawb
+qn2J48iW4Zgh82vFHNYcGRjKRJqLzp4VBn/qpRaX+aWEsdXq4shRgFOAOKyQNMex
+GZyd9amkblqjEOOEzzxPUdmt8k+QEm+JC80NR2sv1mw80PqU/his5zUJ1Aj4tzkF
+fi4jy2nPNvVSpjWiAI6cpZsbdhdh9iayij4YdQg3HB20+1K9VcFnTmBqLKiBbG2o
+4oX2oNPE9Vr3H9Y8YaVoeUU+Kiqo5g==
+-----END PKCS7-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/pkcs8test.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/pkcs8test.pem
new file mode 100644
index 000000000..17606931b
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/pkcs8test.pem
@@ -0,0 +1,175 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDBvYyk4LsBVS3S
+34GZc8uuddHq7cUJx1lZaxWK7C6nnTNKJmJEhxW80VIukpo2RODL1hPFlgCJY3ch
+/4437UoG8ZNAE1BfuVMIkS1AX/l/KAyqUIX/bsXgvZch0Joo92KaPfDB7QA8VCGd
+NCcRaOnusDdsFDdF4/Mrd7/x+Ipkd56FXVEk14QGizFc86aNJrzXjy9ent34PTcS
+uGPXUX7pbiZj8gK9f77pDuH+JymqXdfBKz/x0T54i8N4QFfVp2LbGzeRnduaX4Ff
+79ikdo/XQYTPOYoDwgdiAR+n0+mvDNkI5rbukSLcz+xbWdkJ1ReHW/QQAiqQWK37
+4D1fFNrZAgMBAAECggEAGbH+GVAE/WRCs5kZIzUMapMNyE7It0dNPmLJdKdmeKyM
+xOTaW6Re6bAJakvfUBtKhT5bWPVQFOiwQD4Yqqo6Czm3AeSN4GQ/8v7uNX+FI6w4
+Ic6UNxCGBgyfIsj76TsGRNa6O74nLdkqrCLim5iCjjmo4Bi+S/Kzqaw0NO91y2Um
+9XyCzM7Oh4LukmF94pd5gZBQjjVEkEsw3+oQlOznm3rCNIhYSjfStnFZT5stvcIw
+BscQg386Wo+UvXV8zDI0qrAi0pNepVGsdpGGGUIHkogaF9HHElcSIAVBOQLhxvf5
+S27j3bvHBzWmmR/MgOsBH5+ZqQCTzVGJdzIzXkCRUQKBgQDkQIQNsRv0V44UriNr
+nageBkbjVFxczl5k2qN193qb0GalSOoeKcT9jsBO32mcaBd84vuueSNS69rGlj8+
+7rKyMsRAnjhbMJ0FCWv2muQjxZWEcTWV38wgXkbzos4fon19wQo3JPg0ikOjmGbK
+Z4EIJE0PIw6hjGrTXqc9wK4kgwKBgQDZSv2KVaTX80ZyLIOlbs5+CTAzlEde8+u+
+7LcFOvrrzeo86i6+65yvu395Dlm6PAhz0KocaUECeEDakdQHEDfvEf29BsU+p7fU
+kfNPotacAD7kNo2WenzH0mIhtBWchSUz1P3cIbq4Rxm4XPlAzMEXcDtFRqf+4wVV
+d8Thcjl8cwKBgQCKVGczfRC6Bo3/DoI86DFI8PjpMOlA/XjLmo3SIofWAnkS1pu8
+aAgQuwDlTBTPS25gq5doZ9X2nSXbkJcH5tW5lXbGypzQ9ydSNCGQNNLqswYoXAvj
+ptwpCbnqUdKl7W4sVl+AiBE8lkbj0KsLI6tZadahw9dMJLNhIk4s6KchTQKBgB4f
+PCh6GODq04AuVY2QX8WvBmSQEJjEHZEZBYIPHAumPut010gWJ2FhD5m7eIrNmapc
+aciIer+Z5fumrYrRH7/fcZpLnvpBi8VG+kC25SM5EX7XZSdQEY4txva/HSPWfULD
+KvHiJx02lgUttkvaVoYmQ8Elu1IlLG8drEhIalmrAoGAKLjcIIAcAhuE0QkstS/z
+ZiFhp7tCCrH5sVvXPJfxuKtEC3iTfgOoMywaX3SQGkOP5kVngziGemv1b493Vmek
+T8JLbnNbkooCvPsbMlMgcqZcb/5ckymabMaJBTqhYP4w/uRETNyjmb0uxX2CqXk0
+RoIdgWsw0IiLCNMn16z5O5w=
+-----END PRIVATE KEY-----
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIGQp1RhqLV50CAggA
+MB0GCWCGSAFlAwQBAgQQhMfC5lWjUndHWVmSgLGLMgSCBNBZEZlGvXV9XjzWo0di
+IJof42XSh+mrOdRvUPUS0uPzctmnXZjhKdu42v5jrbyNdruqZsMXTnnQC/UW7Fox
+fp3JzOM5w7wEmgrJybOZgA5spNkiWDdlnmqKme34wEPKv+GPEuHj7w+Z4hc7MSdg
+T6Q3CJFLJDCEvfK70Gyxp6X90HN1riQQVxFOTSg9TJsnsvkOJ9Ju3VCTOqt3jlW0
+FEzrC3lV4AcxfWZct7tkqOTXygWMGinz7OqLxIcmlrF3oc0bLxEQzQuGCJIzrhKo
+3Lb73Xto/kC/uqbCdU+v1zafdKLI/0Uj3/GOGLUu/PeMo7VaHbAj/AOX63Yvj3zm
+WOgJwnOis5iP5rqL3lfdeJrkmE1w7xTLn9fUWXXr+qcVBLeZY30TE9wW9gRCDCka
+09ZVw9MnrodTgvWVSI3xHxjYin8GcxQ+VZTxQMQFHA2cyR60yMG+eGm5t3TZNHVW
+h3uqVxjbN7tMYbjUo1NdbINntOQZhqMje39ai3mWIhGPO09yfsw7ZRX9hhKlrIYo
+UQ4LcEgMZsZDDtAY+Mol7pYB7KpM2iftBT8KSkBLSlqpndl4PJHLUaNBgbNDP6py
+PB8FjPO49qPybeVCIgg3AswxJwGE9bXtO9SLcf/p6S0IWvVcWn+VV5sX+9Bav0eZ
+nCO0WJYrWcjUBzYJLWIDcPviYkoMkFrsFGUP0DA7OneLlW84YUh3AeqqJppb/qve
+UeUXZipLEHf+Z/ToGW+RzPQmFTVDqIx0FdQCi3EefBr3CbN/KtLdRjbP4kyeRGlw
+CUS+BWQ+W/NtVUfVmBvsSLtVfW1pevemt4FE9rP9qUa8KeRpOJIzF4kHUmHyDfp6
+rvQTSS6d3a+N1GyJA5/N4UM6g7FbVnbngPvM1hMNfK6xbIcxQJudBQa/bHqf8DXu
+61npKQYir+TmgDXlc9iD23M+TH2VgeunrFKuVMNVl4igH3+mcHyXpZ/EGM0KyIhq
+PJjPRKD0qcCvs4mPRiOx1wJbCYMdYfEF7sIlkQgKjbQZQyRlDKLkLl4pGWXxaqUm
+iyo6VpK2phKcA/hPYz10isRfy1WrKdNHW0B5DPyreko2H0akapfqMjROE0JHtVGs
+gKg0FrbZXUP+QuKm0V91ShA7c3mRfN2XNbxEc9JFzkDJs4JBxj2H7MxvPQyRrWE3
+sKsQWtr5AFpFb5p5kqCtyyu7ag9pGicqlaFuLda/PR0ykMrhMU4RBO0OulOGl8ZP
+9RC1GCArbSSUYH9xvwthGdaDylONVmHwunFMHs8pblTyo6FiKn1q7lIVXYO3AJ/5
+NfKgryp50SXq0p41i8Dtu+4R6CKx4xTMilPYKYDiDPCRtnwvckI/PshGMA/CHLzr
+LLZUlRt1iup5SDjqRIjquw/aDRe+Wy4AXXniHOnlSrNynHcJRWz+pnLT3Bi6Z2nQ
+ERY4pCIQ/ZdhAHHldFZ7WJ2wrwhf4MQ7sF20HLgXeUN3qj4xYcwR3CykU8f7dfI7
+TIo26asqsVDsVL02tr4dUrtm4J8yQsH8jD0nCpvGwJ9gswUBPmo9YreN82Kt/LSy
+YZISyo2BnoowEcAEGnZBf+PLwBeePeXC2/vrxHlMl7JPkPesEHtTuET034woXELi
+wO/DuStXmiIydT29G1n81zmdVw==
+-----END ENCRYPTED PRIVATE KEY-----
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI7ITJ8AdDrO0CAggA
+MBQGCCqGSIb3DQMHBAinsLeB93eJ2QSCBMhi3oBwLoE4PNYkIpp3FVk6VHzs7SGQ
+u/KcyYQk0Shjbe/ykNJx72OVfzYemlcNpr4p9Jt3VbXxisiZyRs2m1Edqxzdt3zb
+AcRSVNIbph8V9mSZNBl2hR3GAsrbSTkwM4xzXCQRvA50z1DIABlVFR9AB/52JQ/f
+IQx9NrG6SxlzcNjJMzHpR46ELG0Z5EqPLrdyScVX7TEFWl2ue9P/MOhjfZH0/Wgk
+fFCFNoPsABQ6az/lTj1f7hkYMOIw2tayHAuAXTbqyuOVWhVfAqr3H/XuJvXspjDC
+SmIr9jIdJKOTNrJD1/rG4wnh9U0OHxceQqf+TJisWd12WVjwMZ1jIqjk0g+BQeId
+JJvuJTdVVGee1C3enPjG5qBiSJpD+BEsfk7YQFRzW5TzlzELIdkjru3k3cqSp+dX
+Hp1LT6E8TTcdX4wdhKWf7VV6sayleiaiB+9XufqU7FwnOJbe0sydnn8L7A07qFcs
+9WrXmCSCpB2bH0MYDvuauqHjpIZmaHUAUpXYUjjj8EnuhesJAz2bzO7fQ9rZAQ0D
+6Gq4SLbjTtOlpS2LZeNio5ibyeQkgNs76Tq0zdS+5fFnL/6tIIsJUbdZdLz/5isq
+j+SO+7TiGL8a5URZO2pc3Dh/TtjV/lSiI8qb/MMUAmCL0vWe/FKx3xx4dCrRfDX1
+GyeclEl4pWFqnwSQyHadr1nvnvGrG4/pcwrcnhNNb+Y80RIw15A/kNjsKP1f3XWr
+eHAp+YGqDbJ/RuvoVunoAx3PwA56NTQLMmzYakgQFEPtModtvHTQnLkGozg0VjWk
+TdkB7R8GS87IHpOUyrZcxKYDwOmhR2bHgtosvZ4XK+GAwjIGUzGKtg6MyMh3ynsP
+68Vaj4PgkvmItmdZKrvkinophdFqFlqCLLNf6NtaVUMfz3Ap/vmX+EK+2YWxezNa
+qFMNXO76xoKj+piF47vN7zjGsJ59yLLWZHO9J8hFLqSgArhVcV69j7JVMD3XugbG
+YEFudiVEwE8Kl190CVP1BX8DXYhMrrDL/4QD+jccgLfK20bWdaCtPOs6SxahhsvU
+wRX8hwf3QLiuZxfAIlVCn2eL+9QffJYETjfhAuvPK/HwM6+/n+9GpYc4Ezs593KJ
+9/mZLuMKc0b9tDc0dQ5ld7aNiWuWyP46Da9FWBdbjoiBOHIUp8h5METE1NuH2d1l
+THWYaD0OyOgyi2gosRkjJxqDp0IVxIymsKhX0K/EBcYuKiPKZLL8lCTdrzGlhRC7
+M7N99j2elk3k6BJYewdiklmWHEXFOFo8NWwLKKQPi/rSQHcJy1o4WBiXV5UOYJ2b
+50DAF52281ao7BZhYTt5JKy+KYvP9Znkk/Kklx79SHx/bSrXHZJCLoVJaWRFp332
+vQASx042mXMeNDPy7dC9NP3eSyv/niIUWI4t+ktUds1OmWIAMs+2gQqD0Eq7gAfu
+i8SKjiAXPADx57dg7loU0O9IyErJpY4HrvDLLMQaxLLpJxl3YSrgEVkrkEQvP0vv
+ktUR9qQbIJ3BGD3YuQ3cxAgKWaaZWdEJjKqalTYACS3mg/RHYAb0xnTUX7nkUch6
+D79p6fAhhWe9KG2f8tJVuHfUOnEBi1XR5755Vqt4xgUqMI82z4iqAU8ieBvYpy8G
+ImM=
+-----END ENCRYPTED PRIVATE KEY-----
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE6jAcBgoqhkiG9w0BDAEDMA4ECBztmnlgZpEhAgIIAASCBMggv6vLTkuAj/y7
+wLaJLezGOWe1JyFmhxfn6FMMNIZruIYUdoVNpsUzeOhedtawTszOOLtDtprsqvNz
+/oDWQs2B+JqpLjalfRfkjJjtzkkeij3mVNZH69XPabO/QXnHxjeW/S0Ps5gsIpsf
+6+eklLo7LI+KgVMWVIdZ5bC0P/FFi+Bf+sI20NQN3RchJMT8lKcV+2PHZQIb7diJ
+UuYPf3GRg9XtBb0pXssAC8Do84y1kKYj8xil3g4oe27jn1wlQ0+c8DeqXrXAcnIk
+/tFAfvNyO8EMfaP74vlDC4aATXY1O8UEAStTothbtahFNpFfB/9UbvKG0ac0KC4x
+43Ftv1H3xtyn9vVA4qDCmLK0cNDFKCRo+A41kEE6AKYKctbthhC0GMoj69EYPMhE
+Yg9+1Ev+qI2l8jB9kGbN6YlAkM4bUDHT98fFeS/wrCnzxmmiDD/rsHzv6cdkNw0z
+G5F+Wvf3cT1sVGd6RexVydmfzjEeP/6z9Xr3oMqW2CVY9mHFlq2dBkR1LR8Kju+l
+vWspR2YjzggylL8CpCpeCWzd7O0Q3sni3onHFwEen9fQ0GxM9FS0bH7Ty0+gf0jm
+ZFxwcHnH1mMOS5W4yg00Ri8QDgvz4M9BT+HLu+yId4QwGQFlQqg2+tLKsm9mVAnP
+0Ew+dV90r7/cRUCV0kUmbYissi39OHw5sOs0GDMUiNck77E0paBnTb0s+UzBIdnq
+wy+ojiDxhANB8iabKnfF/9fJ6XB0pxUQkXmKfFJZqpVzEq7ZVQLFPfyjJhQD4vTE
+jOG3PdamAFOjiBBqtxbBF5s+pLZL3sZhStugqJ1l63E5tgMcJ8w0czifLjjUULtG
+8O4V58yAkuqu8ICyhXXOA7Bhmn/vymBIS5VmxvR6NZA9qK9XEh5it1ngNZt3oc/e
+vclArrVbev8Q+Jz6X6aAbTsDleihsRrugGkWeZCjkFIYPKlA58FKmfB7xRcvkpYn
+8iuI1DJCiT99mF0YUjEkKWsbShUElR4ok474SsXt5gHtCtykXrncAPtouYPnXRuY
+MS9pYhgtoMhNPXotZwMsj+YvoWJBbeBgc7WgxZkcxbum3I3ns3E0+RCz1gAI6u7F
+ZUfLogdk+Og/wbv7B5NRncRT2UnWfOyyxlGtxrwqXxaOyIF9007F+Xe8NbRO/EAH
+1yFMdL1jA40lacQdbxrVDQ1nVXRGL6l0O51zWC2E3HkZMclTdWp1yoV3F4r5EY7b
+OLjdZ3ip/vWuMcaHpkP1lp41Q00oZpxkfhq6hrw5agpv1o9OTUr260nmHALDZ6dy
+2qWNqyFYyDuSSGB7spbBeuLq30WuXNO7kLBW3Z1MGq2AmOimUR8r79OkMBkZzZol
+IHgfjedxE/1uOmU5vcEnW/rGrFavTu9BvjoDLVV7/5Gc9z/q8CQbYW/cK77qD8ZC
+J22oFudz2qjl377LRIjmbZp5FvU1fIPy29/7LnuB1b3xfYvFwk/6YSM2FlT57HIL
+PmAHNYzW+Uwst0khEkzcagqqMDERcD/2WKedXUDNwxAm5AU8v31FYLLjeZfkmeNj
+NVYXzstYWgLPtUhODf63pGuILuxQFth4YrdZitda3RRCFI2F8NVFTADbwQWKZUMg
+KSVe9u9LXFxPNijyRpk=
+-----END ENCRYPTED PRIVATE KEY-----
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE4zAcBgoqhkiG9w0BDAEBMA4ECMpfoO3NymimAgIIAASCBMG1ImpwNjYr+SIa
+FEBPpj57UpoC8FqFKe4bnFkYK+KVapykY/p6KRlo5GyZZHycWbLhQ6LDwCgsgPcp
+x/BTghqMvztLDtO+jIaEqcudX/dp0VhDZazeFJ3hYhjgmPCfTSEBYXAKmtdEPCri
+eRqO1FLw8rAX+n1dJg0wnPly6M8kY4KE331G87+IAynsbieaAVkVAFm4T5+kqLXz
+dC36WzcrpaXln15ydp4Ok7i0/TLcTCfVh5zGvlujKrogJ4EJyFzThyByrRWYAx+H
+3RdtjgL3zoMs7s8qXDVcmActX+PCdDz8w4lqkuG362TTdewDnEc3PQNJPjzWWhWk
+QZ1vbUa2lszxAnBSxHMEs0pvXy4Owboh/FCRJ+0kpZrnEzdNumn9jWWkFxkhZeZU
+BD1QHEyuVN4ZzG4Vr28uZham74RQOHZwv3hiLMKXC0K8A4VSfnWZGGXaa39J58N4
+LpPwORBJOv5haLzi1VZj/IzfN6oc5PnCS51+MYOFcLYf/2qvoQbB6SNw9PxpNf4E
+cgPxXMYJQcgSf2uDJwjsRLmAe8ChD2xvo357fhDZ/y+j4viB8pzKhX9uG16c1Wbo
+7BHnXdqrcbgeNgk4s9elWSr1kKb0gTSkqIRh42s4d51Zrb6qQjgwM0UfydfWyMu4
+y1acFtQPicFoIfvrKxnHEjwDLW3nOhxGL3ORL42U8ICJl8XzLRLYKMQnH6k/Idod
+thZO6v0habuoPp0ozYml77BmmFkdSoR9CZKweoA5Xb9KjeLGIoQk0Kg9Roxw/KV6
+3EBLrP6HLTex/QhhribaHUoz9i9tWKKWGwOl9JXeV/BM3P+JmW05h5LY4THBG68w
+7P+kFvmUAXl4SOd7AVMQCJeUKIbif+Wr7UnRM/G3lJtg3VSp3IkINW2WuUgfWSVw
+T/OUObFOKRZUKqEmPd3HYvlguVJM76jQ0uVi9XiEJtpNVo7UJWw5dk+V8obANxcu
+qNldaXJCDspJe9Ep0NqkfQIuXMZGQo3hcbirH0y3HlBBXdE40Oc6WA0fu/L2D/Ff
+sYCEaGZ0mBOuOi9CP9HailwAEL8Bf/3LsYBLSqKR1vjSC8n2bfD+Sy598QQ8Ti7C
+7XpuKBCAws+cVUnMQVuqckuEm454tQxlWNnmTqoKnIwlEw7atE3Fi7xd0Yk3xO2Z
+m/1+jLMfvUsYr9uYFWYt0SV7GTOHyfc9HWFb8Mtz9XvlA7RQ3gx5hNoovJeeK3Ho
+3f6h8S0BYFWOOvKXk27ZF9OgEqeRryH+B1y32n6AtgeZspnOLPlMTgmvjvqYiocA
+4iaTAoX5PGZuNKRqBhfiCLUT2AI6Coq+LjRdHn1mwLqBnagJFYsaXcTjZNKUr47M
+7kbXX5JC12d1lcCxkTqkhV88SZhgvPzt9J/3Kvx6iOMRinWfxGGFQqiTFEwvk5zI
+64aA80Z/N0jkhiibbsl/quQqi9Tlvqd1wpHcJ28t25H0eKWfiktvuxWRNj86JzHk
+ZMKv1ReqWrihQyfwSG4nvMKaSJSlwuzbb7D5g71bMCHdj9ZddgsWdu93mR7xv8Ok
+tatasiU0x4bZvqaOk7qjgHJCsK0dQHsfF5kIQJ1eC0akqRP1KfDs/Jskefr6e/PX
+1hql/nLztg==
+-----END ENCRYPTED PRIVATE KEY-----
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE6TAbBgkqhkiG9w0BBQowDgQI3TbGvnzF0LACAggABIIEyLCaObV7h//eWCwg
+detit/l8jaBe2pHs/JPd1qJjnvAjqnSBVQjkbXjxU6ERAXC2IhQzF4ZlW29RrdLC
+ocxhHHM1Pt2+E2T+wiALFYidQIfawiobru3Tb8FN0QaFoyVZgUHzxeZUdot2ceW5
+TrP3PaNSWTnPl2boYy/TBlbw3W5QvmApHvA5RFR0uVqO6kASCPmThVTrutPVPsRo
+Z5QZCTgZWrPXzQmyUzF5z0uBY2i2jWDwZWso63UZh3A+7Au7hn/NAqKNDeN+TZqc
+nniJXD8PTJ8eNtrwk758lhbbrh7orAzy85e+WmHnmVWuZ88kULBiDdUFu+uUNaqD
+gukACGRDe0tGEq/CFKJVkSDvKPKrnBLHo4uBootK+Chj5iY8KMVVJ/IWGjgYL7Bo
+R5zZYos6qubuzfycRCWXHnR5cp3qqgO6oRubRXvWaYuOx5gf/trCK7dDVptYHSzB
+dK5CtlgOQY9mVM6THkgzPNKlaoaWXcAz2YdROMkqEvhGHWTnREuDRmqlsCQKSDkS
+ljyBFHVLEGFrqChnZmIi5x8M8rMQHTjQYYPatIUEr10suWz9So2fSNtrlbzXrk4c
+rQR3XFedszYSCoBVofW4Nt5iSdRldkYh+DGuKG40UKltCfu3EYl3xKgf6VB0quqI
+l6CjQY/XlDirwLVOE0zPTqKeMGsi4UW6Tecri07/48JWBZtYPLEj7LWTG59GmLPl
+LFMZd8JO0au/8UESxFBIg8lBVjGpNV8F3YdI0x/inZFaESKJqK3eNccBMSCIZVxY
++gE/8iNIn/bBGFWGxpJSVAjaGMjXnkRtYCcriTKchvWq8gljhRpTt8y/hEvHzmaM
+rUbY6jJyAJ9Jeso3nzpBetDUImZ89iN9LC6Znz0g2ot1iLEL9Lvtnayn4Aik6wfA
+Ha7R8qy8JjCpSJtV8/COtRrzbzcuZw5I3Hsm3cTCERP1zmNZbm0MFM7WJVMdXPUi
+1OS+vwlUvXt12dfxtABJG+wbsTQ9lPVGph+aixG1QvZVTq7eq0MWo+dJRev2656a
+5VcdmtVo1YiNCG2TniZjcIugksxbjwRdmOaxei7VPn0GuD+4oi5fon8IlpjosJJW
+FEc17IO7rqidXmeFttnnPLooAO5wajNVdAyuCs3HKJsnVLXZK42doWnNm7k+/uca
+K+ai0RHyQLqWfxcU2U78cVVhdgnmFU/9d/+gHhTfhzpCW029NlIgNuQTgU+mAiug
+27Mbrm2Q2f69SNXwWgKw2h6MfMsQxDNZI0vqbA6gvcmkwgbCrrZJr1rSl7dZaZuI
+ek7l/yG/dqyzUWKcHko6jL2OM16cKkVWTRv7o7Au8RrLA2G7BA+FpHt9ZnthzX6K
+LMPr6an9LMwjvnxD15YfENWphVqx7r0VYQnL3AfEinuJ9K4jyGZ1nny35jUHg1tF
+XQbVIBfxoMuSLUjDep9E+iyfL5Qogh2hlZ8HuXcRXb44BucBlwruDuJm8Ft6Q84k
++pw93biUrfEm/7SXIjC5+Daf+49fCrJbMQjfGUAxRxB63qkEtNo5AbLZMlujQxFt
+ByA2F5l6hq5cT97uCDPcYdW+QRr7Q+rFVy8sqxtp3K/D1LHX752yRqBl+pnf1tJA
+Dud9ALqr+fQhxbd3Hw==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/smimenopw.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/smimenopw.pem
new file mode 100644
index 000000000..4fbc051fc
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/smimenopw.pem
@@ -0,0 +1,29 @@
+-----BEGIN PRIVATE KEY-----
+MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDH3KYztc7w23de
+H/eCb/a9GcKKJhUMegKaBy8CqEbkMB4ft+JRnkma/z/xZgrcqw3GOjE/iZTV6+8s
++FZlMpSY8h0Zqs4c/achV0d1QwI/udNgB83iI4KtoOf4BYDmehp0MntBLL5q/qZ4
+QqZdSI4HeNWVSUZPBVqtDjd2qOmYPgxPPg2uqDM2kus1kXaXXrGx7bnNSckwNiMl
+c270sM7sZBjE0Kfspp78cAHbBkTwUHIGtohwxsC89tShXK9lddkX21MHCsJSm7sJ
+URdbrrimt/gHeXzHMJ4dJCY/kyMUealAVYgPHGpSzNOqxzrg06rptpwEP5S/Ezqz
+hxU13QCrAgMBAAECggEBAMOYc6ejxHT/s+CQFGC5RpZmgXdGMc9WEPnBEgbdvRNQ
+7ApKodkSuiJQr7mGDhdL6F0ZUl1GPjzle9tc5uB/EeJlAInAGZtRuqDsk+h0vdyz
+9ePDf4BTFG7sTFj0uePVl9IkHW/5ZBm+Qhjr0Xj1qtoxLYW+gmqPaOB4S1t7j7EH
+PGbPeGWEYkMpK6qHuu18/YG52VrEzeYW5QoCzXn5m9tcc3xQH7AlE8dQu9B1oxoB
+Yiau/FSt3wrjhSWAAf390xDqF+4G9nkpdqv/jjLDxoY2HlFojrc3YysfAHzbVqrW
+vckvzW/h/kVACghrIZRucRukNuBEewOp5HOdxx5HkDECgYEA9C/PzD8YYfa+CXJ4
+a7NbmBuhZ4k1OrCmuoXnVXzhOA0+wWrV/w4sHEb9L753v7hldmr3F2PFBgGzwABY
+af0COWB0mdICtbBUPjbFdZHZzMyJU2YmmhrwAs6zE6nvDjYLSa5SEAdoT/DgDqMZ
+P3zE7dTkClriwZDk7LWneOhuEMUCgYEA0YfizrYSFNVcAt4vkncovihKN7JerqAc
+X0mpPRupR9aUQCylfcTXv/WKT0DAu965asbDNJcsCg+3uZTKWZzJnDmYjHSF4Ulw
+ZmivTmgroAw7UVDSZN1zKwjSuDhOkFaCtgIeErCbCVegN7NuwBal/YSfydWjQH8A
+wyxI1ChmAq8CgYEAgLlDnbQVMm9UNr61ZHEkc8b9Cwt1l/7Ppbw4+wPd5iJ1Vpjv
+PolGD5IMnkKV9edK9WXl49qgXk4/Z5PHB/hsV7rVPNFMxGKzxigxZ4z/d8rLCb/r
+0YkpxREZreADOUacJLdUY0bEYn/kXVL1WFZ5qbZ0kFDhAJFVXMNWCZLdktECgYEA
+pmEIsKvS38gsL/rOO7dzGsxTYra4iGGLJf8P6/4zBWBWiD7rilrsFvmawiPg502M
+XkVGbFQ+HB8u/KYxp8bgMLVrdNxyEtqF7kviKJh/S69qyr8q0f0mnl17Nd1ARUzs
+riowRxcFhP2Xs6M/pjhVxmGxoEuMPoKa0GAx1IXfuvECgYEAgu23j5zdu2oR+/3k
+dcmXd1bs41RS9sQoYrb1lvQILMvKqJG7HUiLs9bKdPjF+9Vd6T7jyf1Ay5CL8ioA
+NxU3DkmF1fZOByyQJRbGXhMhlN4ldzFiL9TsA4ZUUlH1ZmHHZuZUF2yJwtn8NpIl
+MuSVFLFRIjw+o2GuDZ6/7cafRfk=
+-----END PRIVATE KEY-----
+
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/test.pem b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/test.pem
new file mode 100644
index 000000000..c52453c61
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/openssl/test/test.pem
@@ -0,0 +1,133 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,079DD7CA8A9BAA19
+
+jIqIT0DIvUlwvkREv6gnCTVFdOsoVwUS9nxcVuQ8JOwg+TB42GnhgZ5x6MFczgNd
+Dw9L60zono+ethYfYB91CdIcVULzvg61/DCAFDjIFPgOIYTVNmteUq75Dmt6wDTV
+4A07iMwjwBk+0YHaeVwcr0AkdvXEcVySOGdGrwy10K8Eq/kSndzm1Sm6tUCJ45+v
+zSUelLlT9fgRTmAbeowT1/tlt/q52bGTcXJzIWBxDuOxK5ASCTjk28kri9WeRUb/
+iCnXn+cqR3BvkDCdlhk2A6A6Q8U9vo0m1MPtwwsolz76jnxbtBNr6Sc+zcny0brP
+jCPMP1qF+IIk01N3YsAZ9mbJmXYoFf9B0VwNUjPudWlSqhvmzzanatevgZ9TID8G
+Mnltd2XsqIgdvu0JhhEJRC6n7hBvn+l7iwYKtBoK+rJmEWWttkoP82UGgjzjzqKa
+rEtdaZPUCEiBLqHPyiIaDWm5Pe4sZZqrV8Ix8vDLKK59ZUkgmYXyCul2yL/cfO5T
+gjMqh9EeQCrNsu3hJGuEEE3MlskQkCpEspm9qDGbKPkMno7CE37plVopx0o0oovE
+S8MZn0v2lIzV8yZ6krtcEA==
+-----END DSA PRIVATE KEY-----
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,9AC3CD3B4ED42426
+
+AzAvQsDkxXGdPMlFjqO0lYXSlypkfGJWIMqij00cZI1B6K7pMnBHo3wIYStlKDg2
+SMMTYwJfsbFA8+cyCyzsqVBQC63ZgEnStMrDOt/U0SGXNb/C4mFsf1ksnAI6y/3J
+3lhuPAZbMKCmANslivbj9gp4hSe828btXDhvIPKKJgKHhwHveeW9JDulySAN5KYn
+s4aeasvSWVBOYtefFaS+NzrXjDnPtOMX6TQDxd9CE8es1RQbU9Ze2CEa9S7l4coj
+0abWVTjxu55foDCDzbukkQm+eU0aaI4OoydoOCz6bcOfADgRx3/fJ9Z9IuS5w73O
+BiF8Z4S8e7GYpgsPVEqj06PuNH7t6bwzKC9U2FTiNcejZIYPqz21d9iA4hsEfFDd
+0DlXqYUKMazE+TjU8goss5cEqyLNDQmWLYLKUE2p8QmSZC/UqEsZ9pu1VZz3xpFT
+k2sju26HCV14XPG5oi9LpxDQaVRmXBMFxz5b+RmUwPfZuWntTzHQXuNyH2J3B9FN
+el8gaskt4hxHI28hB/eF0h7pOIBUDiR9n/BB+feOrNW8y7/ThSkdI3OK0+dyOzLg
+go9s7SGz5WLyy8FWevw0k2Is4IpCueTwclDrOAPixW+paHhDGIasnvvCsz5jGqQz
+4F4JPmA2ZYg/Z8dYob/ZeF/3KuJqFZAm9gseGS19sT7UzVvvmSf5IXOFfpb7VdRn
+ScFMRVr8PY9ANGh7zYg/8w+G3JJj4C7djA3RB/yOhK4KwbTz/2cnEDI26VREjKs0
+7/WPQXxr/oQ+XEBTnYuJZfa7o7orGL+6wA0Vk/GJqjA=
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE REQUEST-----
+MIIBkDCB+gIBADAlMSMwIQYDVQQDExpSZXF1ZXN0ZWQgVGVzdCBDZXJ0aWZpY2F0
+ZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsO4slP/KdZQsZyYn3asTWDtX
+E1YN+QQbbHELK7boPQa91YHv5DV/SgucThoXXCtSA45d3dQhrEbZ2+HRBarZIylk
+Nc+VmcV1qFX5KsD9wCYPMtdAYYog6jz259yCOKPDXPm787Q5t9h2zV3Ml1i0eWhC
+cdRYiWHQ5g20W4Bq3GsCAwEAAaAsMCoGCSqGSIb3DQEJDjEdMBswGQYDVR0RBBIw
+EIEOdGVzdEB0ZXN0LnRlc3QwDQYJKoZIhvcNAQELBQADgYEAZGPA0Jyw49cHPJjG
+bloqKAPNlBO200AiRFsHnkOQ1DopJff3mW+FdszAc9g6rTB4/YAiM4r0E314e0vm
+XSlW2q8sp+c2XJO7PUIdJIuAUnvSmMb/uwXFP2SzLdjLcmymMsnFfjvwkht0K2it
+O5HuUDuhLnxEimGlUEBrfkdrsH0=
+-----END CERTIFICATE REQUEST-----
+-----BEGIN NEW CERTIFICATE REQUEST-----
+MIIBkDCB+gIBADAlMSMwIQYDVQQDExpSZXF1ZXN0ZWQgVGVzdCBDZXJ0aWZpY2F0
+ZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsO4slP/KdZQsZyYn3asTWDtX
+E1YN+QQbbHELK7boPQa91YHv5DV/SgucThoXXCtSA45d3dQhrEbZ2+HRBarZIylk
+Nc+VmcV1qFX5KsD9wCYPMtdAYYog6jz259yCOKPDXPm787Q5t9h2zV3Ml1i0eWhC
+cdRYiWHQ5g20W4Bq3GsCAwEAAaAsMCoGCSqGSIb3DQEJDjEdMBswGQYDVR0RBBIw
+EIEOdGVzdEB0ZXN0LnRlc3QwDQYJKoZIhvcNAQELBQADgYEAZGPA0Jyw49cHPJjG
+bloqKAPNlBO200AiRFsHnkOQ1DopJff3mW+FdszAc9g6rTB4/YAiM4r0E314e0vm
+XSlW2q8sp+c2XJO7PUIdJIuAUnvSmMb/uwXFP2SzLdjLcmymMsnFfjvwkht0K2it
+O5HuUDuhLnxEimGlUEBrfkdrsH0=
+-----END NEW CERTIFICATE REQUEST-----
+-----BEGIN CERTIFICATE-----
+MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx
+ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY
+BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB
+dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ
+d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2
+MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW
+BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM
+dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l
+Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv
+bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re
+Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO
+Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE
+7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy
+QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0
+ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw
+DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL
+iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4
+yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF
+5/8=
+-----END CERTIFICATE-----
+-----BEGIN X509 CERTIFICATE-----
+MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx
+ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY
+BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB
+dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ
+d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2
+MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW
+BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM
+dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l
+Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv
+bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re
+Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO
+Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE
+7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy
+QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0
+ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw
+DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL
+iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4
+yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF
+5/8=
+-----END X509 CERTIFICATE-----
+-----BEGIN ATTRIBUTE CERTIFICATE-----
+MIIBuDCCASECAQEwZ6BlMGCkXjBcMQswCQYDVQQGEwJBVTEoMCYGA1UEChMfVGhl
+IExlZ2lvbiBvZiB0aGUgQm91bmN5IENhc3RsZTEjMCEGA1UECxMaQm91bmN5IFBy
+aW1hcnkgQ2VydGlmaWNhdGUCARSgYjBgpF4wXDELMAkGA1UEBhMCQVUxKDAmBgNV
+BAoTH1RoZSBMZWdpb24gb2YgdGhlIEJvdW5jeSBDYXN0bGUxIzAhBgNVBAsTGkJv
+dW5jeSBQcmltYXJ5IENlcnRpZmljYXRlMA0GCSqGSIb3DQEBBQUAAgEBMCIYDzIw
+MDUwNjEwMDI0MTMzWhgPMjAwNTA2MTAwMjQzMTNaMBkwFwYDVRhIMRAwDoEMREFV
+MTIzNDU2Nzg5MA0GCSqGSIb3DQEBBQUAA4GBALAYXT9zdxSR5zdPLAon1xIPehgI
+NZhjM7w0uu3OdzSV5sC31X1Kx9vi5RIWiM9VimRTwbQIod9POttD5QMXCwQb/fm7
+eiJqL2YBIXOeClB19VrQe8xQtMFbyuFpDiM7QdvIam9ShZZMEMGjv9QHI64M4b0G
+odUBlSsJwPPQjZSU
+-----END ATTRIBUTE CERTIFICATE-----
+-----BEGIN X509 CRL-----
+MIICjTCCAfowDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoT
+F1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVy
+IENlcnRpZmljYXRpb24gQXV0aG9yaXR5Fw05NTA1MDIwMjEyMjZaFw05NTA2MDEw
+MDAxNDlaMIIBaDAWAgUCQQAABBcNOTUwMjAxMTcyNDI2WjAWAgUCQQAACRcNOTUw
+MjEwMDIxNjM5WjAWAgUCQQAADxcNOTUwMjI0MDAxMjQ5WjAWAgUCQQAADBcNOTUw
+MjI1MDA0NjQ0WjAWAgUCQQAAGxcNOTUwMzEzMTg0MDQ5WjAWAgUCQQAAFhcNOTUw
+MzE1MTkxNjU0WjAWAgUCQQAAGhcNOTUwMzE1MTk0MDQxWjAWAgUCQQAAHxcNOTUw
+MzI0MTk0NDMzWjAWAgUCcgAABRcNOTUwMzI5MjAwNzExWjAWAgUCcgAAERcNOTUw
+MzMwMDIzNDI2WjAWAgUCQQAAIBcNOTUwNDA3MDExMzIxWjAWAgUCcgAAHhcNOTUw
+NDA4MDAwMjU5WjAWAgUCcgAAQRcNOTUwNDI4MTcxNzI0WjAWAgUCcgAAOBcNOTUw
+NDI4MTcyNzIxWjAWAgUCcgAATBcNOTUwNTAyMDIxMjI2WjANBgkqhkiG9w0BAQIF
+AAN+AHqOEJXSDejYy0UwxxrH/9+N2z5xu/if0J6qQmK92W0hW158wpJg+ovV3+wQ
+wvIEPRL2rocL0tKfAsVq1IawSJzSNgxG0lrcla3MrJBnZ4GaZDu4FutZh72MR3Gt
+JaAL3iTJHJD55kK2D/VoyY1djlsPuNh6AEgdVwFAyp0v
+-----END X509 CRL-----
+-----BEGIN EC PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,ADBCD679C6C6363E
+
+MmYmhTgKNKwwnA4AIskePMy+gp3Ch7Pn/UqRGjQypIyibbp/UFY+aSbQmvQNG2R9
+6Zj6cbBJGt/C2EYXk9UonUTA9Q+FVytkpR8ON6NHlSc2twrvDpqi7lpeSB9ywlH7
+WLffwNZMNsNHfcNK2slHf4RCmpqcGsXffHe45dQG0CI=
+-----END EC PRIVATE KEY-----
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/tsp/test/FileDaFirmare.data b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/tsp/test/FileDaFirmare.data
new file mode 100644
index 000000000..836a9fcc1
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/tsp/test/FileDaFirmare.data
@@ -0,0 +1,3 @@
+INIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINIZIOINI
+dati da firmaredati da firmaredati da firmaredati da firmaredati da firmare
+FINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFINEFIN \ No newline at end of file
diff --git a/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/tsp/test/FileDaFirmare.txt.tsd.der b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/tsp/test/FileDaFirmare.txt.tsd.der
new file mode 100644
index 000000000..1686986ef
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/test/resources/org/spongycastle/tsp/test/FileDaFirmare.txt.tsd.der
Binary files differ