summary refs log tree commit diff
path: root/Crypto/src/asn1
diff options
context:
space:
mode:
authorOren Novotny <oren@novotny.org>2014-02-26 10:08:50 -0500
committerOren Novotny <oren@novotny.org>2014-02-26 10:08:50 -0500
commit176743ab5faec2dd275b5efd3a2dd62c610f237a (patch)
tree1d2e50c534a479d749c266d7c52434d8f17f86aa /Crypto/src/asn1
parentAdd git files (diff)
downloadBouncyCastle.NET-ed25519-654c26abd79e9451e5a9bd108f1358bc2849fdbf.tar.xz
Add BouncyCastle PCL files v1.7.0
Diffstat (limited to 'Crypto/src/asn1')
-rw-r--r--Crypto/src/asn1/ASN1Generator.cs27
-rw-r--r--Crypto/src/asn1/ASN1OctetStringParser.cs10
-rw-r--r--Crypto/src/asn1/ASN1SequenceParser.cs8
-rw-r--r--Crypto/src/asn1/ASN1SetParser.cs8
-rw-r--r--Crypto/src/asn1/ASN1StreamParser.cs232
-rw-r--r--Crypto/src/asn1/ASN1TaggedObjectParser.cs10
-rw-r--r--Crypto/src/asn1/Asn1Encodable.cs78
-rw-r--r--Crypto/src/asn1/Asn1EncodableVector.cs93
-rw-r--r--Crypto/src/asn1/Asn1Exception.cs27
-rw-r--r--Crypto/src/asn1/Asn1InputStream.cs339
-rw-r--r--Crypto/src/asn1/Asn1Null.cs18
-rw-r--r--Crypto/src/asn1/Asn1Object.cs63
-rw-r--r--Crypto/src/asn1/Asn1OctetString.cs119
-rw-r--r--Crypto/src/asn1/Asn1OutputStream.cs35
-rw-r--r--Crypto/src/asn1/Asn1ParsingException.cs26
-rw-r--r--Crypto/src/asn1/Asn1Sequence.cs255
-rw-r--r--Crypto/src/asn1/Asn1Set.cs326
-rw-r--r--Crypto/src/asn1/Asn1TaggedObject.cs178
-rw-r--r--Crypto/src/asn1/Asn1Tags.cs36
-rw-r--r--Crypto/src/asn1/BERGenerator.cs102
-rw-r--r--Crypto/src/asn1/BEROctetStringGenerator.cs121
-rw-r--r--Crypto/src/asn1/BEROctetStringParser.cs36
-rw-r--r--Crypto/src/asn1/BERSequenceGenerator.cs24
-rw-r--r--Crypto/src/asn1/BERSequenceParser.cs24
-rw-r--r--Crypto/src/asn1/BERSetGenerator.cs24
-rw-r--r--Crypto/src/asn1/BERSetParser.cs24
-rw-r--r--Crypto/src/asn1/BERTaggedObjectParser.cs71
-rw-r--r--Crypto/src/asn1/BerApplicationSpecific.cs15
-rw-r--r--Crypto/src/asn1/BerApplicationSpecificParser.cs29
-rw-r--r--Crypto/src/asn1/BerNull.cs35
-rw-r--r--Crypto/src/asn1/BerOctetString.cs135
-rw-r--r--Crypto/src/asn1/BerOutputStream.cs36
-rw-r--r--Crypto/src/asn1/BerSequence.cs69
-rw-r--r--Crypto/src/asn1/BerSet.cs70
-rw-r--r--Crypto/src/asn1/BerTaggedObject.cs108
-rw-r--r--Crypto/src/asn1/ConstructedOctetStream.cs102
-rw-r--r--Crypto/src/asn1/DERExternal.cs207
-rw-r--r--Crypto/src/asn1/DERExternalParser.cs26
-rw-r--r--Crypto/src/asn1/DERGenerator.cs107
-rw-r--r--Crypto/src/asn1/DEROctetStringParser.cs36
-rw-r--r--Crypto/src/asn1/DERSequenceGenerator.cs40
-rw-r--r--Crypto/src/asn1/DERSequenceParser.cs24
-rw-r--r--Crypto/src/asn1/DERSetGenerator.cs40
-rw-r--r--Crypto/src/asn1/DERSetParser.cs24
-rw-r--r--Crypto/src/asn1/DefiniteLengthInputStream.cs90
-rw-r--r--Crypto/src/asn1/DerApplicationSpecific.cs237
-rw-r--r--Crypto/src/asn1/DerBMPString.cs115
-rw-r--r--Crypto/src/asn1/DerBitString.cs248
-rw-r--r--Crypto/src/asn1/DerBoolean.cs110
-rw-r--r--Crypto/src/asn1/DerEnumerated.cs100
-rw-r--r--Crypto/src/asn1/DerGeneralString.cs81
-rw-r--r--Crypto/src/asn1/DerGeneralizedTime.cs305
-rw-r--r--Crypto/src/asn1/DerIA5String.cs145
-rw-r--r--Crypto/src/asn1/DerInteger.cs117
-rw-r--r--Crypto/src/asn1/DerNull.cs41
-rw-r--r--Crypto/src/asn1/DerNumericString.cs138
-rw-r--r--Crypto/src/asn1/DerObjectIdentifier.cs242
-rw-r--r--Crypto/src/asn1/DerOctetString.cs34
-rw-r--r--Crypto/src/asn1/DerOutputStream.cs160
-rw-r--r--Crypto/src/asn1/DerPrintableString.cs163
-rw-r--r--Crypto/src/asn1/DerSequence.cs85
-rw-r--r--Crypto/src/asn1/DerSet.cs108
-rw-r--r--Crypto/src/asn1/DerStringBase.cs22
-rw-r--r--Crypto/src/asn1/DerT61String.cs102
-rw-r--r--Crypto/src/asn1/DerTaggedObject.cs72
-rw-r--r--Crypto/src/asn1/DerUTCTime.cs263
-rw-r--r--Crypto/src/asn1/DerUTF8String.cs96
-rw-r--r--Crypto/src/asn1/DerUniversalString.cs107
-rw-r--r--Crypto/src/asn1/DerUnknownTag.cs80
-rw-r--r--Crypto/src/asn1/DerVisibleString.cs111
-rw-r--r--Crypto/src/asn1/IAsn1ApplicationSpecificParser.cs10
-rw-r--r--Crypto/src/asn1/IAsn1Choice.cs17
-rw-r--r--Crypto/src/asn1/IAsn1Convertible.cs7
-rw-r--r--Crypto/src/asn1/IAsn1String.cs10
-rw-r--r--Crypto/src/asn1/IndefiniteLengthInputStream.cs166
-rw-r--r--Crypto/src/asn1/LazyASN1InputStream.cs33
-rw-r--r--Crypto/src/asn1/LazyDERSequence.cs82
-rw-r--r--Crypto/src/asn1/LazyDERSet.cs82
-rw-r--r--Crypto/src/asn1/LimitedInputStream.cs35
-rw-r--r--Crypto/src/asn1/OidTokenizer.cs45
-rw-r--r--Crypto/src/asn1/bc/BCObjectIdentifiers.cs39
-rw-r--r--Crypto/src/asn1/cmp/CAKeyUpdAnnContent.cs60
-rw-r--r--Crypto/src/asn1/cmp/CertConfirmContent.cs47
-rw-r--r--Crypto/src/asn1/cmp/CertOrEncCert.cs85
-rw-r--r--Crypto/src/asn1/cmp/CertRepMessage.cs94
-rw-r--r--Crypto/src/asn1/cmp/CertResponse.cs115
-rw-r--r--Crypto/src/asn1/cmp/CertStatus.cs84
-rw-r--r--Crypto/src/asn1/cmp/CertifiedKeyPair.cs114
-rw-r--r--Crypto/src/asn1/cmp/Challenge.cs79
-rw-r--r--Crypto/src/asn1/cmp/CmpCertificate.cs80
-rw-r--r--Crypto/src/asn1/cmp/CmpObjectIdentifiers.cs106
-rw-r--r--Crypto/src/asn1/cmp/CrlAnnContent.cs49
-rw-r--r--Crypto/src/asn1/cmp/ErrorMsgContent.cs94
-rw-r--r--Crypto/src/asn1/cmp/GenMsgContent.cs52
-rw-r--r--Crypto/src/asn1/cmp/GenRepContent.cs52
-rw-r--r--Crypto/src/asn1/cmp/InfoTypeAndValue.cs121
-rw-r--r--Crypto/src/asn1/cmp/KeyRecRepContent.cs115
-rw-r--r--Crypto/src/asn1/cmp/OobCertHash.cs87
-rw-r--r--Crypto/src/asn1/cmp/PKIBody.cs186
-rw-r--r--Crypto/src/asn1/cmp/PKIConfirmContent.cs34
-rw-r--r--Crypto/src/asn1/cmp/PKIFailureInfo.cs73
-rw-r--r--Crypto/src/asn1/cmp/PKIFreeText.cs97
-rw-r--r--Crypto/src/asn1/cmp/PKIHeader.cs237
-rw-r--r--Crypto/src/asn1/cmp/PKIHeaderBuilder.cs223
-rw-r--r--Crypto/src/asn1/cmp/PKIMessage.cs140
-rw-r--r--Crypto/src/asn1/cmp/PKIMessages.cs52
-rw-r--r--Crypto/src/asn1/cmp/PKIStatus.cs62
-rw-r--r--Crypto/src/asn1/cmp/PKIStatusInfo.cs165
-rw-r--r--Crypto/src/asn1/cmp/PbmParameter.cs100
-rw-r--r--Crypto/src/asn1/cmp/PollRepContent.cs66
-rw-r--r--Crypto/src/asn1/cmp/PollReqContent.cs59
-rw-r--r--Crypto/src/asn1/cmp/PopoDecKeyChallContent.cs47
-rw-r--r--Crypto/src/asn1/cmp/PopoDecKeyRespContent.cs47
-rw-r--r--Crypto/src/asn1/cmp/ProtectedPart.cs58
-rw-r--r--Crypto/src/asn1/cmp/RevAnnContent.cs86
-rw-r--r--Crypto/src/asn1/cmp/RevDetails.cs75
-rw-r--r--Crypto/src/asn1/cmp/RevRepContent.cs112
-rw-r--r--Crypto/src/asn1/cmp/RevRepContentBuilder.cs55
-rw-r--r--Crypto/src/asn1/cmp/RevReqContent.cs52
-rw-r--r--Crypto/src/asn1/cms/Attribute.cs70
-rw-r--r--Crypto/src/asn1/cms/AttributeTable.cs231
-rw-r--r--Crypto/src/asn1/cms/Attributes.cs43
-rw-r--r--Crypto/src/asn1/cms/AuthEnvelopedData.cs203
-rw-r--r--Crypto/src/asn1/cms/AuthEnvelopedDataParser.cs145
-rw-r--r--Crypto/src/asn1/cms/AuthenticatedData.cs270
-rw-r--r--Crypto/src/asn1/cms/AuthenticatedDataParser.cs182
-rw-r--r--Crypto/src/asn1/cms/CMSAttributes.cs14
-rw-r--r--Crypto/src/asn1/cms/CMSObjectIdentifiers.cs18
-rw-r--r--Crypto/src/asn1/cms/CompressedData.cs96
-rw-r--r--Crypto/src/asn1/cms/CompressedDataParser.cs47
-rw-r--r--Crypto/src/asn1/cms/ContentInfo.cs83
-rw-r--r--Crypto/src/asn1/cms/ContentInfoParser.cs40
-rw-r--r--Crypto/src/asn1/cms/EncryptedContentInfo.cs94
-rw-r--r--Crypto/src/asn1/cms/EncryptedContentInfoParser.cs46
-rw-r--r--Crypto/src/asn1/cms/EncryptedData.cs95
-rw-r--r--Crypto/src/asn1/cms/EnvelopedData.cs167
-rw-r--r--Crypto/src/asn1/cms/EnvelopedDataParser.cs107
-rw-r--r--Crypto/src/asn1/cms/Evidence.cs47
-rw-r--r--Crypto/src/asn1/cms/IssuerAndSerialNumber.cs66
-rw-r--r--Crypto/src/asn1/cms/KEKIdentifier.cs119
-rw-r--r--Crypto/src/asn1/cms/KEKRecipientInfo.cs106
-rw-r--r--Crypto/src/asn1/cms/KeyAgreeRecipientIdentifier.cs92
-rw-r--r--Crypto/src/asn1/cms/KeyAgreeRecipientInfo.cs141
-rw-r--r--Crypto/src/asn1/cms/KeyTransRecipientInfo.cs99
-rw-r--r--Crypto/src/asn1/cms/MetaData.cs94
-rw-r--r--Crypto/src/asn1/cms/OriginatorIdentifierOrKey.cs168
-rw-r--r--Crypto/src/asn1/cms/OriginatorInfo.cs121
-rw-r--r--Crypto/src/asn1/cms/OriginatorPublicKey.cs87
-rw-r--r--Crypto/src/asn1/cms/OtherKeyAttribute.cs70
-rw-r--r--Crypto/src/asn1/cms/OtherRecipientInfo.cs85
-rw-r--r--Crypto/src/asn1/cms/PasswordRecipientInfo.cs133
-rw-r--r--Crypto/src/asn1/cms/RecipientEncryptedKey.cs88
-rw-r--r--Crypto/src/asn1/cms/RecipientIdentifier.cs89
-rw-r--r--Crypto/src/asn1/cms/RecipientInfo.cs145
-rw-r--r--Crypto/src/asn1/cms/RecipientKeyIdentifier.cs137
-rw-r--r--Crypto/src/asn1/cms/SignedData.cs282
-rw-r--r--Crypto/src/asn1/cms/SignedDataParser.cs112
-rw-r--r--Crypto/src/asn1/cms/SignerIdentifier.cs89
-rw-r--r--Crypto/src/asn1/cms/SignerInfo.cs175
-rw-r--r--Crypto/src/asn1/cms/Time.cs118
-rw-r--r--Crypto/src/asn1/cms/TimeStampAndCRL.cs62
-rw-r--r--Crypto/src/asn1/cms/TimeStampTokenEvidence.cs65
-rw-r--r--Crypto/src/asn1/cms/TimeStampedData.cs95
-rw-r--r--Crypto/src/asn1/cms/TimeStampedDataParser.cs76
-rw-r--r--Crypto/src/asn1/cms/ecc/MQVuserKeyingMaterial.cs103
-rw-r--r--Crypto/src/asn1/crmf/AttributeTypeAndValue.cs66
-rw-r--r--Crypto/src/asn1/crmf/CertId.cs58
-rw-r--r--Crypto/src/asn1/crmf/CertReqMessages.cs52
-rw-r--r--Crypto/src/asn1/crmf/CertReqMsg.cs106
-rw-r--r--Crypto/src/asn1/crmf/CertRequest.cs82
-rw-r--r--Crypto/src/asn1/crmf/CertTemplate.cs149
-rw-r--r--Crypto/src/asn1/crmf/CertTemplateBuilder.cs125
-rw-r--r--Crypto/src/asn1/crmf/Controls.cs52
-rw-r--r--Crypto/src/asn1/crmf/CrmfObjectIdentifiers.cs23
-rw-r--r--Crypto/src/asn1/crmf/EncKeyWithID.cs103
-rw-r--r--Crypto/src/asn1/crmf/EncryptedKey.cs78
-rw-r--r--Crypto/src/asn1/crmf/EncryptedValue.cs154
-rw-r--r--Crypto/src/asn1/crmf/OptionalValidity.cs64
-rw-r--r--Crypto/src/asn1/crmf/PKIArchiveOptions.cs105
-rw-r--r--Crypto/src/asn1/crmf/PKIPublicationInfo.cs64
-rw-r--r--Crypto/src/asn1/crmf/PKMacValue.cs89
-rw-r--r--Crypto/src/asn1/crmf/PopoPrivKey.cs84
-rw-r--r--Crypto/src/asn1/crmf/PopoSigningKey.cs115
-rw-r--r--Crypto/src/asn1/crmf/PopoSigningKeyInput.cs115
-rw-r--r--Crypto/src/asn1/crmf/ProofOfPossession.cs98
-rw-r--r--Crypto/src/asn1/crmf/SinglePubInfo.cs58
-rw-r--r--Crypto/src/asn1/crmf/SubsequentMessage.cs27
-rw-r--r--Crypto/src/asn1/cryptopro/CryptoProObjectIdentifiers.cs48
-rw-r--r--Crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs179
-rw-r--r--Crypto/src/asn1/cryptopro/ECGOST3410ParamSetParameters.cs86
-rw-r--r--Crypto/src/asn1/cryptopro/GOST28147Parameters.cs63
-rw-r--r--Crypto/src/asn1/cryptopro/GOST3410NamedParameters.cs123
-rw-r--r--Crypto/src/asn1/cryptopro/GOST3410ParamSetParameters.cs87
-rw-r--r--Crypto/src/asn1/cryptopro/GOST3410PublicKeyAlgParameters.cs99
-rw-r--r--Crypto/src/asn1/eac/EACObjectIdentifiers.cs50
-rw-r--r--Crypto/src/asn1/esf/CertificateValues.cs85
-rw-r--r--Crypto/src/asn1/esf/CommitmentTypeIdentifier.cs17
-rw-r--r--Crypto/src/asn1/esf/CommitmentTypeIndication.cs95
-rw-r--r--Crypto/src/asn1/esf/CommitmentTypeQualifier.cs119
-rw-r--r--Crypto/src/asn1/esf/CompleteCertificateRefs.cs84
-rw-r--r--Crypto/src/asn1/esf/CompleteRevocationRefs.cs84
-rw-r--r--Crypto/src/asn1/esf/CrlIdentifier.cs110
-rw-r--r--Crypto/src/asn1/esf/CrlListID.cs89
-rw-r--r--Crypto/src/asn1/esf/CrlOcspRef.cs111
-rw-r--r--Crypto/src/asn1/esf/CrlValidatedID.cs89
-rw-r--r--Crypto/src/asn1/esf/ESFAttributes.cs25
-rw-r--r--Crypto/src/asn1/esf/OcspIdentifier.cs77
-rw-r--r--Crypto/src/asn1/esf/OcspListID.cs88
-rw-r--r--Crypto/src/asn1/esf/OcspResponsesID.cs92
-rw-r--r--Crypto/src/asn1/esf/OtherCertID.cs93
-rw-r--r--Crypto/src/asn1/esf/OtherHash.cs88
-rw-r--r--Crypto/src/asn1/esf/OtherHashAlgAndValue.cs94
-rw-r--r--Crypto/src/asn1/esf/OtherRevRefs.cs78
-rw-r--r--Crypto/src/asn1/esf/OtherRevVals.cs78
-rw-r--r--Crypto/src/asn1/esf/OtherSigningCertificate.cs138
-rw-r--r--Crypto/src/asn1/esf/RevocationValues.cs165
-rw-r--r--Crypto/src/asn1/esf/SigPolicyQualifierInfo.cs71
-rw-r--r--Crypto/src/asn1/esf/SignaturePolicyId.cs145
-rw-r--r--Crypto/src/asn1/esf/SignaturePolicyIdentifier.cs64
-rw-r--r--Crypto/src/asn1/esf/SignerAttribute.cs96
-rw-r--r--Crypto/src/asn1/esf/SignerLocation.cs144
-rw-r--r--Crypto/src/asn1/ess/ContentHints.cs92
-rw-r--r--Crypto/src/asn1/ess/ContentIdentifier.cs65
-rw-r--r--Crypto/src/asn1/ess/ESSCertID.cs93
-rw-r--r--Crypto/src/asn1/ess/ESSCertIDv2.cs138
-rw-r--r--Crypto/src/asn1/ess/OtherCertID.cs132
-rw-r--r--Crypto/src/asn1/ess/OtherSigningCertificate.cs109
-rw-r--r--Crypto/src/asn1/ess/SigningCertificate.cs108
-rw-r--r--Crypto/src/asn1/ess/SigningCertificateV2.cs106
-rw-r--r--Crypto/src/asn1/gnu/GNUObjectIdentifiers.cs31
-rw-r--r--Crypto/src/asn1/iana/IANAObjectIdentifiers.cs18
-rw-r--r--Crypto/src/asn1/icao/CscaMasterList.cs83
-rw-r--r--Crypto/src/asn1/icao/DataGroupHash.cs86
-rw-r--r--Crypto/src/asn1/icao/ICAOObjectIdentifiers.cs34
-rw-r--r--Crypto/src/asn1/icao/LDSSecurityObject.cs145
-rw-r--r--Crypto/src/asn1/icao/LDSVersionInfo.cs61
-rw-r--r--Crypto/src/asn1/isismtt/ISISMTTObjectIdentifiers.cs177
-rw-r--r--Crypto/src/asn1/isismtt/ocsp/CertHash.cs121
-rw-r--r--Crypto/src/asn1/isismtt/ocsp/RequestedCertificate.cs186
-rw-r--r--Crypto/src/asn1/isismtt/x509/AdditionalInformationSyntax.cs70
-rw-r--r--Crypto/src/asn1/isismtt/x509/AdmissionSyntax.csbin0 -> 20844 bytes
-rw-r--r--Crypto/src/asn1/isismtt/x509/Admissions.cs186
-rw-r--r--Crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs170
-rw-r--r--Crypto/src/asn1/isismtt/x509/MonetaryLimit.cs121
-rw-r--r--Crypto/src/asn1/isismtt/x509/NamingAuthority.cs214
-rw-r--r--Crypto/src/asn1/isismtt/x509/ProcurationSyntax.cs232
-rw-r--r--Crypto/src/asn1/isismtt/x509/ProfessionInfo.cs386
-rw-r--r--Crypto/src/asn1/isismtt/x509/Restriction.cs81
-rw-r--r--Crypto/src/asn1/kisa/KISAObjectIdentifiers.cs8
-rw-r--r--Crypto/src/asn1/microsoft/MicrosoftObjectIdentifiers.cs18
-rw-r--r--Crypto/src/asn1/misc/CAST5CBCParameters.cs74
-rw-r--r--Crypto/src/asn1/misc/IDEACBCPar.cs68
-rw-r--r--Crypto/src/asn1/misc/MiscObjectIdentifiers.cs48
-rw-r--r--Crypto/src/asn1/misc/NetscapeCertType.cs54
-rw-r--r--Crypto/src/asn1/misc/NetscapeRevocationURL.cs18
-rw-r--r--Crypto/src/asn1/misc/VerisignCzagExtension.cs18
-rw-r--r--Crypto/src/asn1/mozilla/PublicKeyAndChallenge.cs67
-rw-r--r--Crypto/src/asn1/nist/NISTNamedCurves.cs102
-rw-r--r--Crypto/src/asn1/nist/NISTObjectIdentifiers.cs61
-rw-r--r--Crypto/src/asn1/ntt/NTTObjectIdentifiers.cs14
-rw-r--r--Crypto/src/asn1/ocsp/BasicOCSPResponse.cs131
-rw-r--r--Crypto/src/asn1/ocsp/CertID.cs98
-rw-r--r--Crypto/src/asn1/ocsp/CertStatus.cs94
-rw-r--r--Crypto/src/asn1/ocsp/CrlID.cs82
-rw-r--r--Crypto/src/asn1/ocsp/OCSPObjectIdentifiers.cs23
-rw-r--r--Crypto/src/asn1/ocsp/OCSPRequest.cs89
-rw-r--r--Crypto/src/asn1/ocsp/OCSPResponse.cs90
-rw-r--r--Crypto/src/asn1/ocsp/OCSPResponseStatus.cs41
-rw-r--r--Crypto/src/asn1/ocsp/Request.cs90
-rw-r--r--Crypto/src/asn1/ocsp/ResponderID.cs107
-rw-r--r--Crypto/src/asn1/ocsp/ResponseBytes.cs82
-rw-r--r--Crypto/src/asn1/ocsp/ResponseData.cs158
-rw-r--r--Crypto/src/asn1/ocsp/RevokedInfo.cs96
-rw-r--r--Crypto/src/asn1/ocsp/ServiceLocator.cs95
-rw-r--r--Crypto/src/asn1/ocsp/Signature.cs110
-rw-r--r--Crypto/src/asn1/ocsp/SingleResponse.cs137
-rw-r--r--Crypto/src/asn1/ocsp/TBSRequest.cs151
-rw-r--r--Crypto/src/asn1/oiw/ElGamalParameter.cs47
-rw-r--r--Crypto/src/asn1/oiw/OIWObjectIdentifiers.cs29
-rw-r--r--Crypto/src/asn1/pkcs/Attribute.cs79
-rw-r--r--Crypto/src/asn1/pkcs/AuthenticatedSafe.cs37
-rw-r--r--Crypto/src/asn1/pkcs/CertBag.cs46
-rw-r--r--Crypto/src/asn1/pkcs/CertificationRequest.cs81
-rw-r--r--Crypto/src/asn1/pkcs/CertificationRequestInfo.cs123
-rw-r--r--Crypto/src/asn1/pkcs/ContentInfo.cs80
-rw-r--r--Crypto/src/asn1/pkcs/DHParameter.cs72
-rw-r--r--Crypto/src/asn1/pkcs/EncryptedData.cs104
-rw-r--r--Crypto/src/asn1/pkcs/EncryptedPrivateKeyInfo.cs78
-rw-r--r--Crypto/src/asn1/pkcs/EncryptionScheme.cs49
-rw-r--r--Crypto/src/asn1/pkcs/IssuerAndSerialNumber.cs71
-rw-r--r--Crypto/src/asn1/pkcs/KeyDerivationFunc.cs21
-rw-r--r--Crypto/src/asn1/pkcs/MacData.cs96
-rw-r--r--Crypto/src/asn1/pkcs/PBEParameter.cs60
-rw-r--r--Crypto/src/asn1/pkcs/PBES2Parameters.cs61
-rw-r--r--Crypto/src/asn1/pkcs/PBKDF2Params.cs86
-rw-r--r--Crypto/src/asn1/pkcs/PKCS12PBEParams.cs63
-rw-r--r--Crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs256
-rw-r--r--Crypto/src/asn1/pkcs/Pfx.cs65
-rw-r--r--Crypto/src/asn1/pkcs/PrivateKeyInfo.cs126
-rw-r--r--Crypto/src/asn1/pkcs/RC2CBCParameter.cs81
-rw-r--r--Crypto/src/asn1/pkcs/RSAESOAEPparams.cs145
-rw-r--r--Crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs131
-rw-r--r--Crypto/src/asn1/pkcs/RSASSAPSSparams.cs165
-rw-r--r--Crypto/src/asn1/pkcs/SafeBag.cs70
-rw-r--r--Crypto/src/asn1/pkcs/SignedData.cs163
-rw-r--r--Crypto/src/asn1/pkcs/SignerInfo.cs154
-rw-r--r--Crypto/src/asn1/sec/ECPrivateKeyStructure.cs118
-rw-r--r--Crypto/src/asn1/sec/SECNamedCurves.cs1192
-rw-r--r--Crypto/src/asn1/sec/SECObjectIdentifiers.cs52
-rw-r--r--Crypto/src/asn1/smime/SMIMEAttributes.cs11
-rw-r--r--Crypto/src/asn1/smime/SMIMECapabilities.cs128
-rw-r--r--Crypto/src/asn1/smime/SMIMECapabilitiesAttribute.cs16
-rw-r--r--Crypto/src/asn1/smime/SMIMECapability.cs101
-rw-r--r--Crypto/src/asn1/smime/SMIMECapabilityVector.cs37
-rw-r--r--Crypto/src/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.cs44
-rw-r--r--Crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs428
-rw-r--r--Crypto/src/asn1/teletrust/TeleTrusTObjectIdentifiers.cs45
-rw-r--r--Crypto/src/asn1/tsp/Accuracy.cs149
-rw-r--r--Crypto/src/asn1/tsp/MessageImprint.cs74
-rw-r--r--Crypto/src/asn1/tsp/TSTInfo.cs249
-rw-r--r--Crypto/src/asn1/tsp/TimeStampReq.cs164
-rw-r--r--Crypto/src/asn1/tsp/TimeStampResp.cs80
-rw-r--r--Crypto/src/asn1/util/Asn1Dump.cs378
-rw-r--r--Crypto/src/asn1/util/Dump.cs30
-rw-r--r--Crypto/src/asn1/util/FilterStream.cs72
-rw-r--r--Crypto/src/asn1/x500/DirectoryString.cs75
-rw-r--r--Crypto/src/asn1/x509/AccessDescription.cs83
-rw-r--r--Crypto/src/asn1/x509/AlgorithmIdentifier.cs110
-rw-r--r--Crypto/src/asn1/x509/AttCertIssuer.cs86
-rw-r--r--Crypto/src/asn1/x509/AttCertValidityPeriod.cs78
-rw-r--r--Crypto/src/asn1/x509/Attribute.cs82
-rw-r--r--Crypto/src/asn1/x509/AttributeCertificate.cs81
-rw-r--r--Crypto/src/asn1/x509/AttributeCertificateInfo.cs156
-rw-r--r--Crypto/src/asn1/x509/AttributeTable.cs73
-rw-r--r--Crypto/src/asn1/x509/AuthorityInformationAccess.cs105
-rw-r--r--Crypto/src/asn1/x509/AuthorityKeyIdentifier.cs211
-rw-r--r--Crypto/src/asn1/x509/BasicConstraints.cs133
-rw-r--r--Crypto/src/asn1/x509/CRLDistPoint.cs93
-rw-r--r--Crypto/src/asn1/x509/CRLNumber.cs30
-rw-r--r--Crypto/src/asn1/x509/CRLReason.cs61
-rw-r--r--Crypto/src/asn1/x509/CertPolicyId.cs20
-rw-r--r--Crypto/src/asn1/x509/CertificateList.cs108
-rw-r--r--Crypto/src/asn1/x509/CertificatePair.cs160
-rw-r--r--Crypto/src/asn1/x509/DSAParameter.cs77
-rw-r--r--Crypto/src/asn1/x509/DigestInfo.cs76
-rw-r--r--Crypto/src/asn1/x509/DisplayText.cs172
-rw-r--r--Crypto/src/asn1/x509/DistributionPoint.cs161
-rw-r--r--Crypto/src/asn1/x509/DistributionPointName.cs130
-rw-r--r--Crypto/src/asn1/x509/ExtendedKeyUsage.cs131
-rw-r--r--Crypto/src/asn1/x509/GeneralName.cs418
-rw-r--r--Crypto/src/asn1/x509/GeneralNames.cs95
-rw-r--r--Crypto/src/asn1/x509/GeneralSubtree.cs189
-rw-r--r--Crypto/src/asn1/x509/Holder.cs257
-rw-r--r--Crypto/src/asn1/x509/IetfAttrSyntax.cs161
-rw-r--r--Crypto/src/asn1/x509/IssuerSerial.cs98
-rw-r--r--Crypto/src/asn1/x509/IssuingDistributionPoint.cs247
-rw-r--r--Crypto/src/asn1/x509/KeyPurposeId.cs36
-rw-r--r--Crypto/src/asn1/x509/KeyUsage.cs79
-rw-r--r--Crypto/src/asn1/x509/NameConstraints.cs118
-rw-r--r--Crypto/src/asn1/x509/NoticeReference.cs138
-rw-r--r--Crypto/src/asn1/x509/ObjectDigestInfo.cs177
-rw-r--r--Crypto/src/asn1/x509/PolicyInformation.cs80
-rw-r--r--Crypto/src/asn1/x509/PolicyMappings.cs70
-rw-r--r--Crypto/src/asn1/x509/PolicyQualifierId.cs28
-rw-r--r--Crypto/src/asn1/x509/PolicyQualifierInfo.cs91
-rw-r--r--Crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs82
-rw-r--r--Crypto/src/asn1/x509/RSAPublicKeyStructure.cs92
-rw-r--r--Crypto/src/asn1/x509/ReasonFlags.cs46
-rw-r--r--Crypto/src/asn1/x509/RoleSyntax.cs230
-rw-r--r--Crypto/src/asn1/x509/SubjectDirectoryAttributes.cs142
-rw-r--r--Crypto/src/asn1/x509/SubjectKeyIdentifier.cs141
-rw-r--r--Crypto/src/asn1/x509/SubjectPublicKeyInfo.cs102
-rw-r--r--Crypto/src/asn1/x509/TBSCertList.cs274
-rw-r--r--Crypto/src/asn1/x509/TBSCertificateStructure.cs185
-rw-r--r--Crypto/src/asn1/x509/Target.cs139
-rw-r--r--Crypto/src/asn1/x509/TargetInformation.cs123
-rw-r--r--Crypto/src/asn1/x509/Targets.cs121
-rw-r--r--Crypto/src/asn1/x509/Time.cs120
-rw-r--r--Crypto/src/asn1/x509/UserNotice.cs104
-rw-r--r--Crypto/src/asn1/x509/V1TBSCertificateGenerator.cs108
-rw-r--r--Crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs137
-rw-r--r--Crypto/src/asn1/x509/V2Form.cs125
-rw-r--r--Crypto/src/asn1/x509/V2TBSCertListGenerator.cs201
-rw-r--r--Crypto/src/asn1/x509/V3TBSCertificateGenerator.cs168
-rw-r--r--Crypto/src/asn1/x509/X509Attributes.cs9
-rw-r--r--Crypto/src/asn1/x509/X509CertificateStructure.cs129
-rw-r--r--Crypto/src/asn1/x509/X509DefaultEntryConverter.cs63
-rw-r--r--Crypto/src/asn1/x509/X509Extension.cs79
-rw-r--r--Crypto/src/asn1/x509/X509Extensions.cs451
-rw-r--r--Crypto/src/asn1/x509/X509ExtensionsGenerator.cs81
-rw-r--r--Crypto/src/asn1/x509/X509Name.cs1189
-rw-r--r--Crypto/src/asn1/x509/X509NameEntryConverter.cs89
-rw-r--r--Crypto/src/asn1/x509/X509NameTokenizer.cs104
-rw-r--r--Crypto/src/asn1/x509/X509ObjectIdentifiers.cs59
-rw-r--r--Crypto/src/asn1/x509/qualified/BiometricData.cs112
-rw-r--r--Crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs19
-rw-r--r--Crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs84
-rw-r--r--Crypto/src/asn1/x509/qualified/MonetaryValue.cs83
-rw-r--r--Crypto/src/asn1/x509/qualified/QCStatement.cs85
-rw-r--r--Crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs21
-rw-r--r--Crypto/src/asn1/x509/qualified/SemanticsInformation.cs124
-rw-r--r--Crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs91
-rw-r--r--Crypto/src/asn1/x509/sigi/NameOrPseudonym.cs177
-rw-r--r--Crypto/src/asn1/x509/sigi/PersonalData.cs210
-rw-r--r--Crypto/src/asn1/x509/sigi/SigIObjectIdentifiers.cs49
-rw-r--r--Crypto/src/asn1/x9/DHDomainParameters.cs116
-rw-r--r--Crypto/src/asn1/x9/DHPublicKey.cs44
-rw-r--r--Crypto/src/asn1/x9/DHValidationParms.cs62
-rw-r--r--Crypto/src/asn1/x9/KeySpecificInfo.cs58
-rw-r--r--Crypto/src/asn1/x9/OtherInfo.cs88
-rw-r--r--Crypto/src/asn1/x9/X962NamedCurves.cs733
-rw-r--r--Crypto/src/asn1/x9/X962Parameters.cs53
-rw-r--r--Crypto/src/asn1/x9/X9Curve.cs147
-rw-r--r--Crypto/src/asn1/x9/X9ECParameters.cs170
-rw-r--r--Crypto/src/asn1/x9/X9ECParametersHolder.cs22
-rw-r--r--Crypto/src/asn1/x9/X9ECPoint.cs44
-rw-r--r--Crypto/src/asn1/x9/X9FieldElement.cs69
-rw-r--r--Crypto/src/asn1/x9/X9FieldID.cs102
-rw-r--r--Crypto/src/asn1/x9/X9IntegerConverter.cs48
-rw-r--r--Crypto/src/asn1/x9/X9ObjectIdentifiers.cs135
420 files changed, 44900 insertions, 0 deletions
diff --git a/Crypto/src/asn1/ASN1Generator.cs b/Crypto/src/asn1/ASN1Generator.cs
new file mode 100644
index 000000000..e56051736
--- /dev/null
+++ b/Crypto/src/asn1/ASN1Generator.cs
@@ -0,0 +1,27 @@
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public abstract class Asn1Generator
+    {
+		private Stream _out;
+
+		protected Asn1Generator(
+			Stream outStream)
+        {
+            _out = outStream;
+        }
+
+		protected Stream Out
+		{
+			get { return _out; }
+		}
+
+		public abstract void AddObject(Asn1Encodable obj);
+
+		public abstract Stream GetRawOutputStream();
+
+		public abstract void Close();
+    }
+}
diff --git a/Crypto/src/asn1/ASN1OctetStringParser.cs b/Crypto/src/asn1/ASN1OctetStringParser.cs
new file mode 100644
index 000000000..5815aa42f
--- /dev/null
+++ b/Crypto/src/asn1/ASN1OctetStringParser.cs
@@ -0,0 +1,10 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public interface Asn1OctetStringParser
+		: IAsn1Convertible
+	{
+		Stream GetOctetStream();
+	}
+}
diff --git a/Crypto/src/asn1/ASN1SequenceParser.cs b/Crypto/src/asn1/ASN1SequenceParser.cs
new file mode 100644
index 000000000..9e88ac788
--- /dev/null
+++ b/Crypto/src/asn1/ASN1SequenceParser.cs
@@ -0,0 +1,8 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public interface Asn1SequenceParser
+		: IAsn1Convertible
+	{
+		IAsn1Convertible ReadObject();
+	}
+}
diff --git a/Crypto/src/asn1/ASN1SetParser.cs b/Crypto/src/asn1/ASN1SetParser.cs
new file mode 100644
index 000000000..d1b9c64e2
--- /dev/null
+++ b/Crypto/src/asn1/ASN1SetParser.cs
@@ -0,0 +1,8 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public interface Asn1SetParser
+		: IAsn1Convertible
+	{
+		IAsn1Convertible ReadObject();
+	}
+}
diff --git a/Crypto/src/asn1/ASN1StreamParser.cs b/Crypto/src/asn1/ASN1StreamParser.cs
new file mode 100644
index 000000000..6c256db53
--- /dev/null
+++ b/Crypto/src/asn1/ASN1StreamParser.cs
@@ -0,0 +1,232 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class Asn1StreamParser
+	{
+		private readonly Stream _in;
+		private readonly int _limit;
+
+		public Asn1StreamParser(
+			Stream inStream)
+			: this(inStream, Asn1InputStream.FindLimit(inStream))
+		{
+		}
+
+		public Asn1StreamParser(
+			Stream	inStream,
+			int		limit)
+		{
+			if (!inStream.CanRead)
+				throw new ArgumentException("Expected stream to be readable", "inStream");
+
+			this._in = inStream;
+			this._limit = limit;
+		}
+
+		public Asn1StreamParser(
+			byte[] encoding)
+			: this(new MemoryStream(encoding, false), encoding.Length)
+		{
+		}
+
+		internal IAsn1Convertible ReadIndef(int tagValue)
+		{
+			// Note: INDEF => CONSTRUCTED
+
+			// TODO There are other tags that may be constructed (e.g. BIT_STRING)
+			switch (tagValue)
+			{
+				case Asn1Tags.External:
+					return new DerExternalParser(this);
+				case Asn1Tags.OctetString:
+					return new BerOctetStringParser(this);
+				case Asn1Tags.Sequence:
+					return new BerSequenceParser(this);
+				case Asn1Tags.Set:
+					return new BerSetParser(this);
+				default:
+					throw new Asn1Exception("unknown BER object encountered: 0x" + tagValue.ToString("X"));
+			}
+		}
+
+		internal IAsn1Convertible ReadImplicit(bool constructed, int tag)
+		{
+			if (_in is IndefiniteLengthInputStream)
+			{
+				if (!constructed)
+					throw new IOException("indefinite length primitive encoding encountered");
+
+				return ReadIndef(tag);
+			}
+
+			if (constructed)
+			{
+				switch (tag)
+				{
+					case Asn1Tags.Set:
+						return new DerSetParser(this);
+					case Asn1Tags.Sequence:
+						return new DerSequenceParser(this);
+					case Asn1Tags.OctetString:
+						return new BerOctetStringParser(this);
+				}
+			}
+			else
+			{
+				switch (tag)
+				{
+					case Asn1Tags.Set:
+						throw new Asn1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)");
+					case Asn1Tags.Sequence:
+						throw new Asn1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)");
+					case Asn1Tags.OctetString:
+						return new DerOctetStringParser((DefiniteLengthInputStream)_in);
+				}
+			}
+
+			throw new Asn1Exception("implicit tagging not implemented");
+		}
+
+		internal Asn1Object ReadTaggedObject(bool constructed, int tag)
+		{
+			if (!constructed)
+			{
+				// Note: !CONSTRUCTED => IMPLICIT
+				DefiniteLengthInputStream defIn = (DefiniteLengthInputStream)_in;
+				return new DerTaggedObject(false, tag, new DerOctetString(defIn.ToArray()));
+			}
+
+			Asn1EncodableVector v = ReadVector();
+
+			if (_in is IndefiniteLengthInputStream)
+			{
+				return v.Count == 1
+					?   new BerTaggedObject(true, tag, v[0])
+					:   new BerTaggedObject(false, tag, BerSequence.FromVector(v));
+			}
+
+			return v.Count == 1
+				?   new DerTaggedObject(true, tag, v[0])
+				:   new DerTaggedObject(false, tag, DerSequence.FromVector(v));
+		}
+
+		public virtual IAsn1Convertible ReadObject()
+		{
+			int tag = _in.ReadByte();
+			if (tag == -1)
+				return null;
+
+			// turn of looking for "00" while we resolve the tag
+			Set00Check(false);
+
+			//
+			// calculate tag number
+			//
+			int tagNo = Asn1InputStream.ReadTagNumber(_in, tag);
+
+			bool isConstructed = (tag & Asn1Tags.Constructed) != 0;
+
+			//
+			// calculate length
+			//
+			int length = Asn1InputStream.ReadLength(_in, _limit);
+
+			if (length < 0) // indefinite length method
+			{
+				if (!isConstructed)
+					throw new IOException("indefinite length primitive encoding encountered");
+
+				IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit);
+				Asn1StreamParser sp = new Asn1StreamParser(indIn, _limit);
+
+				if ((tag & Asn1Tags.Application) != 0)
+				{
+					return new BerApplicationSpecificParser(tagNo, sp);
+				}
+
+				if ((tag & Asn1Tags.Tagged) != 0)
+				{
+					return new BerTaggedObjectParser(true, tagNo, sp);
+				}
+
+				return sp.ReadIndef(tagNo);
+			}
+			else
+			{
+				DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length);
+
+				if ((tag & Asn1Tags.Application) != 0)
+				{
+					return new DerApplicationSpecific(isConstructed, tagNo, defIn.ToArray());
+				}
+
+				if ((tag & Asn1Tags.Tagged) != 0)
+				{
+					return new BerTaggedObjectParser(isConstructed, tagNo, new Asn1StreamParser(defIn));
+				}
+
+				if (isConstructed)
+				{
+					// TODO There are other tags that may be constructed (e.g. BitString)
+					switch (tagNo)
+					{
+						case Asn1Tags.OctetString:
+							//
+							// yes, people actually do this...
+							//
+							return new BerOctetStringParser(new Asn1StreamParser(defIn));
+						case Asn1Tags.Sequence:
+							return new DerSequenceParser(new Asn1StreamParser(defIn));
+						case Asn1Tags.Set:
+							return new DerSetParser(new Asn1StreamParser(defIn));
+						case Asn1Tags.External:
+							return new DerExternalParser(new Asn1StreamParser(defIn));
+						default:
+							// TODO Add DerUnknownTagParser class?
+							return new DerUnknownTag(true, tagNo, defIn.ToArray());
+					}
+				}
+
+				// Some primitive encodings can be handled by parsers too...
+				switch (tagNo)
+				{
+					case Asn1Tags.OctetString:
+						return new DerOctetStringParser(defIn);
+				}
+
+				try
+				{
+					return Asn1InputStream.CreatePrimitiveDerObject(tagNo, defIn.ToArray());
+				}
+				catch (ArgumentException e)
+				{
+					throw new Asn1Exception("corrupted stream detected", e);
+				}
+			}
+		}
+
+		private void Set00Check(
+			bool enabled)
+		{
+			if (_in is IndefiniteLengthInputStream)
+			{
+				((IndefiniteLengthInputStream) _in).SetEofOn00(enabled);
+			}
+		}
+
+		internal Asn1EncodableVector ReadVector()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			IAsn1Convertible obj;
+			while ((obj = ReadObject()) != null)
+			{
+				v.Add(obj.ToAsn1Object());
+			}
+
+			return v;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/ASN1TaggedObjectParser.cs b/Crypto/src/asn1/ASN1TaggedObjectParser.cs
new file mode 100644
index 000000000..32327a269
--- /dev/null
+++ b/Crypto/src/asn1/ASN1TaggedObjectParser.cs
@@ -0,0 +1,10 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public interface Asn1TaggedObjectParser
+		: IAsn1Convertible
+	{
+		int TagNo { get; }
+
+		IAsn1Convertible GetObjectParser(int tag, bool isExplicit);
+	}
+}
diff --git a/Crypto/src/asn1/Asn1Encodable.cs b/Crypto/src/asn1/Asn1Encodable.cs
new file mode 100644
index 000000000..e3dd9a14c
--- /dev/null
+++ b/Crypto/src/asn1/Asn1Encodable.cs
@@ -0,0 +1,78 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public abstract class Asn1Encodable
+		: IAsn1Convertible
+    {
+		public const string Der = "DER";
+		public const string Ber = "BER";
+
+		public byte[] GetEncoded()
+        {
+            MemoryStream bOut = new MemoryStream();
+            Asn1OutputStream aOut = new Asn1OutputStream(bOut);
+
+			aOut.WriteObject(this);
+
+			return bOut.ToArray();
+        }
+
+		public byte[] GetEncoded(
+			string encoding)
+		{
+			if (encoding.Equals(Der))
+			{
+				MemoryStream bOut = new MemoryStream();
+				DerOutputStream dOut = new DerOutputStream(bOut);
+
+				dOut.WriteObject(this);
+
+				return bOut.ToArray();
+			}
+
+			return GetEncoded();
+		}
+
+		/**
+		* Return the DER encoding of the object, null if the DER encoding can not be made.
+		*
+		* @return a DER byte array, null otherwise.
+		*/
+		public byte[] GetDerEncoded()
+		{
+			try
+			{
+				return GetEncoded(Der);
+			}
+			catch (IOException)
+			{
+				return null;
+			}
+		}
+
+		public sealed override int GetHashCode()
+		{
+			return ToAsn1Object().CallAsn1GetHashCode();
+		}
+
+		public sealed override bool Equals(
+			object obj)
+		{
+			if (obj == this)
+				return true;
+
+			IAsn1Convertible other = obj as IAsn1Convertible;
+
+			if (other == null)
+				return false;
+
+			Asn1Object o1 = ToAsn1Object();
+			Asn1Object o2 = other.ToAsn1Object();
+
+			return o1 == o2 || o1.CallAsn1Equals(o2);
+		}
+
+		public abstract Asn1Object ToAsn1Object();
+    }
+}
diff --git a/Crypto/src/asn1/Asn1EncodableVector.cs b/Crypto/src/asn1/Asn1EncodableVector.cs
new file mode 100644
index 000000000..49532fe57
--- /dev/null
+++ b/Crypto/src/asn1/Asn1EncodableVector.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public class Asn1EncodableVector
+		: IEnumerable
+    {
+        private IList v = Platform.CreateArrayList();
+
+		public static Asn1EncodableVector FromEnumerable(
+			IEnumerable e)
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+			foreach (Asn1Encodable obj in e)
+			{
+				v.Add(obj);
+			}
+			return v;
+		}
+
+//		public Asn1EncodableVector()
+//		{
+//		}
+
+		public Asn1EncodableVector(
+			params Asn1Encodable[] v)
+		{
+			Add(v);
+		}
+
+//		public void Add(
+//			Asn1Encodable obj)
+//		{
+//			v.Add(obj);
+//		}
+
+		public void Add(
+			params Asn1Encodable[] objs)
+		{
+			foreach (Asn1Encodable obj in objs)
+			{
+				v.Add(obj);
+			}
+		}
+
+		public void AddOptional(
+			params Asn1Encodable[] objs)
+		{
+			if (objs != null)
+			{
+				foreach (Asn1Encodable obj in objs)
+				{
+					if (obj != null)
+					{
+						v.Add(obj);
+					}
+				}
+			}
+		}
+
+		public Asn1Encodable this[
+			int index]
+		{
+			get { return (Asn1Encodable) v[index]; }
+		}
+
+		[Obsolete("Use 'object[index]' syntax instead")]
+		public Asn1Encodable Get(
+            int index)
+        {
+            return this[index];
+        }
+
+		[Obsolete("Use 'Count' property instead")]
+		public int Size
+		{
+			get { return v.Count; }
+		}
+
+		public int Count
+		{
+			get { return v.Count; }
+		}
+
+		public IEnumerator GetEnumerator()
+		{
+			return v.GetEnumerator();
+		}
+	}
+}
diff --git a/Crypto/src/asn1/Asn1Exception.cs b/Crypto/src/asn1/Asn1Exception.cs
new file mode 100644
index 000000000..dfc1641a4
--- /dev/null
+++ b/Crypto/src/asn1/Asn1Exception.cs
@@ -0,0 +1,27 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class Asn1Exception
+		: IOException
+	{
+		public Asn1Exception()
+			: base()
+		{
+		}
+
+		public Asn1Exception(
+			string message)
+			: base(message)
+		{
+		}
+
+		public Asn1Exception(
+			string		message,
+			Exception	exception)
+			: base(message, exception)
+		{
+		}
+	}
+}
diff --git a/Crypto/src/asn1/Asn1InputStream.cs b/Crypto/src/asn1/Asn1InputStream.cs
new file mode 100644
index 000000000..9a9761653
--- /dev/null
+++ b/Crypto/src/asn1/Asn1InputStream.cs
@@ -0,0 +1,339 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	/**
+	 * a general purpose ASN.1 decoder - note: this class differs from the
+	 * others in that it returns null after it has read the last object in
+	 * the stream. If an ASN.1 Null is encountered a Der/BER Null object is
+	 * returned.
+	 */
+	public class Asn1InputStream
+		: FilterStream
+	{
+		private readonly int limit;
+
+		internal static int FindLimit(Stream input)
+		{
+			if (input is LimitedInputStream)
+			{
+				return ((LimitedInputStream)input).GetRemaining();
+			}
+			else if (input is MemoryStream)
+			{
+				MemoryStream mem = (MemoryStream)input;
+				return (int)(mem.Length - mem.Position);
+			}
+
+			return int.MaxValue;
+		}
+
+		public Asn1InputStream(
+			Stream inputStream)
+			: this(inputStream, FindLimit(inputStream))
+		{
+		}
+
+		/**
+		 * Create an ASN1InputStream where no DER object will be longer than limit.
+		 *
+		 * @param input stream containing ASN.1 encoded data.
+		 * @param limit maximum size of a DER encoded object.
+		 */
+		public Asn1InputStream(
+			Stream	inputStream,
+			int		limit)
+			: base(inputStream)
+		{
+			this.limit = limit;
+		}
+
+		/**
+		 * Create an ASN1InputStream based on the input byte array. The length of DER objects in
+		 * the stream is automatically limited to the length of the input array.
+		 *
+		 * @param input array containing ASN.1 encoded data.
+		 */
+		public Asn1InputStream(
+			byte[] input)
+			: this(new MemoryStream(input, false), input.Length)
+		{
+		}
+
+		/**
+		* build an object given its tag and the number of bytes to construct it from.
+		*/
+		private Asn1Object BuildObject(
+			int	tag,
+			int	tagNo,
+			int	length)
+		{
+			bool isConstructed = (tag & Asn1Tags.Constructed) != 0;
+
+			DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this.s, length);
+
+			if ((tag & Asn1Tags.Application) != 0)
+			{
+				return new DerApplicationSpecific(isConstructed, tagNo, defIn.ToArray());
+			}
+
+			if ((tag & Asn1Tags.Tagged) != 0)
+			{
+				return new Asn1StreamParser(defIn).ReadTaggedObject(isConstructed, tagNo);
+			}
+
+			if (isConstructed)
+			{
+				// TODO There are other tags that may be constructed (e.g. BitString)
+				switch (tagNo)
+				{
+					case Asn1Tags.OctetString:
+						//
+						// yes, people actually do this...
+						//
+						return new BerOctetString(BuildDerEncodableVector(defIn));
+					case Asn1Tags.Sequence:
+						return CreateDerSequence(defIn);
+					case Asn1Tags.Set:
+						return CreateDerSet(defIn);
+					case Asn1Tags.External:
+						return new DerExternal(BuildDerEncodableVector(defIn));                
+					default:
+						return new DerUnknownTag(true, tagNo, defIn.ToArray());
+				}
+			}
+
+			return CreatePrimitiveDerObject(tagNo, defIn.ToArray());
+		}
+
+		internal Asn1EncodableVector BuildEncodableVector()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			Asn1Object o;
+			while ((o = ReadObject()) != null)
+			{
+				v.Add(o);
+			}
+
+			return v;
+		}
+
+		internal virtual Asn1EncodableVector BuildDerEncodableVector(
+			DefiniteLengthInputStream dIn)
+		{
+			return new Asn1InputStream(dIn).BuildEncodableVector();
+		}
+
+		internal virtual DerSequence CreateDerSequence(
+			DefiniteLengthInputStream dIn)
+		{
+			return DerSequence.FromVector(BuildDerEncodableVector(dIn));
+		}
+
+		internal virtual DerSet CreateDerSet(
+			DefiniteLengthInputStream dIn)
+		{
+			return DerSet.FromVector(BuildDerEncodableVector(dIn), false);
+		}
+
+		public Asn1Object ReadObject()
+		{
+			int tag = ReadByte();
+			if (tag <= 0)
+			{
+				if (tag == 0)
+					throw new IOException("unexpected end-of-contents marker");
+
+				return null;
+			}
+
+			//
+			// calculate tag number
+			//
+			int tagNo = ReadTagNumber(this.s, tag);
+
+			bool isConstructed = (tag & Asn1Tags.Constructed) != 0;
+
+			//
+			// calculate length
+			//
+			int length = ReadLength(this.s, limit);
+
+			if (length < 0) // indefinite length method
+			{
+				if (!isConstructed)
+					throw new IOException("indefinite length primitive encoding encountered");
+
+				IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this.s, limit);
+            	Asn1StreamParser sp = new Asn1StreamParser(indIn, limit);
+
+				if ((tag & Asn1Tags.Application) != 0)
+				{
+					return new BerApplicationSpecificParser(tagNo, sp).ToAsn1Object();
+				}
+
+				if ((tag & Asn1Tags.Tagged) != 0)
+				{
+					return new BerTaggedObjectParser(true, tagNo, sp).ToAsn1Object();
+				}
+
+				// TODO There are other tags that may be constructed (e.g. BitString)
+				switch (tagNo)
+				{
+					case Asn1Tags.OctetString:
+						return new BerOctetStringParser(sp).ToAsn1Object();
+					case Asn1Tags.Sequence:
+						return new BerSequenceParser(sp).ToAsn1Object();
+					case Asn1Tags.Set:
+						return new BerSetParser(sp).ToAsn1Object();
+					case Asn1Tags.External:
+						return new DerExternalParser(sp).ToAsn1Object();
+					default:
+						throw new IOException("unknown BER object encountered");
+				}
+			}
+			else
+			{
+				try
+				{
+					return BuildObject(tag, tagNo, length);
+				}
+				catch (ArgumentException e)
+				{
+					throw new Asn1Exception("corrupted stream detected", e);
+				}
+			}
+		}
+
+		internal static int ReadTagNumber(
+			Stream	s,
+			int		tag)
+		{
+			int tagNo = tag & 0x1f;
+
+			//
+			// with tagged object tag number is bottom 5 bits, or stored at the start of the content
+			//
+			if (tagNo == 0x1f)
+			{
+				tagNo = 0;
+
+				int b = s.ReadByte();
+
+				// X.690-0207 8.1.2.4.2
+				// "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
+				if ((b & 0x7f) == 0) // Note: -1 will pass
+				{
+					throw new IOException("Corrupted stream - invalid high tag number found");
+				}
+
+				while ((b >= 0) && ((b & 0x80) != 0))
+				{
+					tagNo |= (b & 0x7f);
+					tagNo <<= 7;
+					b = s.ReadByte();
+				}
+
+				if (b < 0)
+					throw new EndOfStreamException("EOF found inside tag value.");
+
+				tagNo |= (b & 0x7f);
+			}
+
+			return tagNo;
+		}
+
+		internal static int ReadLength(
+			Stream	s,
+			int		limit)
+		{
+			int length = s.ReadByte();
+			if (length < 0)
+				throw new EndOfStreamException("EOF found when length expected");
+
+			if (length == 0x80)
+				return -1;      // indefinite-length encoding
+
+			if (length > 127)
+			{
+				int size = length & 0x7f;
+
+				// Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
+				if (size > 4)
+					throw new IOException("DER length more than 4 bytes: " + size);
+
+				length = 0;
+				for (int i = 0; i < size; i++)
+				{
+					int next = s.ReadByte();
+
+					if (next < 0)
+						throw new EndOfStreamException("EOF found reading length");
+
+					length = (length << 8) + next;
+				}
+
+				if (length < 0)
+					throw new IOException("Corrupted stream - negative length found");
+
+				if (length >= limit)   // after all we must have read at least 1 byte
+					throw new IOException("Corrupted stream - out of bounds length found");
+			}
+
+			return length;
+		}
+
+		internal static Asn1Object CreatePrimitiveDerObject(
+			int		tagNo,
+			byte[]	bytes)
+		{
+			switch (tagNo)
+			{
+				case Asn1Tags.BitString:
+					return DerBitString.FromAsn1Octets(bytes);
+				case Asn1Tags.BmpString:
+					return new DerBmpString(bytes);
+				case Asn1Tags.Boolean:
+					return new DerBoolean(bytes);
+				case Asn1Tags.Enumerated:
+					return new DerEnumerated(bytes);
+				case Asn1Tags.GeneralizedTime:
+					return new DerGeneralizedTime(bytes);
+				case Asn1Tags.GeneralString:
+					return new DerGeneralString(bytes);
+				case Asn1Tags.IA5String:
+					return new DerIA5String(bytes);
+				case Asn1Tags.Integer:
+					return new DerInteger(bytes);
+				case Asn1Tags.Null:
+					return DerNull.Instance;   // actual content is ignored (enforce 0 length?)
+				case Asn1Tags.NumericString:
+					return new DerNumericString(bytes);
+				case Asn1Tags.ObjectIdentifier:
+					return new DerObjectIdentifier(bytes);
+				case Asn1Tags.OctetString:
+					return new DerOctetString(bytes);
+				case Asn1Tags.PrintableString:
+					return new DerPrintableString(bytes);
+				case Asn1Tags.T61String:
+					return new DerT61String(bytes);
+				case Asn1Tags.UniversalString:
+					return new DerUniversalString(bytes);
+				case Asn1Tags.UtcTime:
+					return new DerUtcTime(bytes);
+				case Asn1Tags.Utf8String:
+					return new DerUtf8String(bytes);
+				case Asn1Tags.VisibleString:
+					return new DerVisibleString(bytes);
+				default:
+					return new DerUnknownTag(false, tagNo, bytes);
+			}
+		}
+	}
+}
diff --git a/Crypto/src/asn1/Asn1Null.cs b/Crypto/src/asn1/Asn1Null.cs
new file mode 100644
index 000000000..d54019f67
--- /dev/null
+++ b/Crypto/src/asn1/Asn1Null.cs
@@ -0,0 +1,18 @@
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * A Null object.
+     */
+    public abstract class Asn1Null
+        : Asn1Object
+    {
+        internal Asn1Null()
+        {
+        }
+
+		public override string ToString()
+		{
+			return "NULL";
+		}
+    }
+}
diff --git a/Crypto/src/asn1/Asn1Object.cs b/Crypto/src/asn1/Asn1Object.cs
new file mode 100644
index 000000000..08bd599c1
--- /dev/null
+++ b/Crypto/src/asn1/Asn1Object.cs
@@ -0,0 +1,63 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public abstract class Asn1Object
+		: Asn1Encodable
+    {
+		/// <summary>Create a base ASN.1 object from a byte array.</summary>
+		/// <param name="data">The byte array to parse.</param>
+		/// <returns>The base ASN.1 object represented by the byte array.</returns>
+		/// <exception cref="IOException">If there is a problem parsing the data.</exception>
+		public static Asn1Object FromByteArray(
+			byte[] data)
+		{
+			try
+			{
+				return new Asn1InputStream(data).ReadObject();
+			}
+			catch (InvalidCastException)
+			{
+				throw new IOException("cannot recognise object in stream");    
+			}
+		}
+
+		/// <summary>Read a base ASN.1 object from a stream.</summary>
+		/// <param name="inStr">The stream to parse.</param>
+		/// <returns>The base ASN.1 object represented by the byte array.</returns>
+		/// <exception cref="IOException">If there is a problem parsing the data.</exception>
+		public static Asn1Object FromStream(
+			Stream inStr)
+		{
+			try
+			{
+				return new Asn1InputStream(inStr).ReadObject();
+			}
+			catch (InvalidCastException)
+			{
+				throw new IOException("cannot recognise object in stream");    
+			}
+		}
+
+		public sealed override Asn1Object ToAsn1Object()
+        {
+            return this;
+        }
+
+		internal abstract void Encode(DerOutputStream derOut);
+
+		protected abstract bool Asn1Equals(Asn1Object asn1Object);
+		protected abstract int Asn1GetHashCode();
+
+		internal bool CallAsn1Equals(Asn1Object obj)
+		{
+			return Asn1Equals(obj);
+		}
+
+		internal int CallAsn1GetHashCode()
+		{
+			return Asn1GetHashCode();
+		}
+	}
+}
diff --git a/Crypto/src/asn1/Asn1OctetString.cs b/Crypto/src/asn1/Asn1OctetString.cs
new file mode 100644
index 000000000..9c738a8f2
--- /dev/null
+++ b/Crypto/src/asn1/Asn1OctetString.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public abstract class Asn1OctetString
+        : Asn1Object, Asn1OctetStringParser
+    {
+        internal byte[] str;
+
+		/**
+         * return an Octet string from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *              be converted.
+         */
+		public static Asn1OctetString GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is Asn1OctetString)
+			{
+				return GetInstance(o);
+			}
+
+			return BerOctetString.FromSequence(Asn1Sequence.GetInstance(o));
+		}
+
+        /**
+         * return an Octet string from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+		public static Asn1OctetString GetInstance(object obj)
+		{
+			if (obj == null || obj is Asn1OctetString)
+			{
+				return (Asn1OctetString)obj;
+			}
+
+			// TODO: this needs to be deleted in V2
+			if (obj is Asn1TaggedObject)
+				return GetInstance(((Asn1TaggedObject)obj).GetObject());
+
+			throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+		}
+
+        /**
+         * @param string the octets making up the octet string.
+         */
+        internal Asn1OctetString(
+            byte[] str)
+        {
+			if (str == null)
+				throw new ArgumentNullException("str");
+
+			this.str = str;
+        }
+
+        internal Asn1OctetString(
+            Asn1Encodable obj)
+        {
+            try
+            {
+				this.str = obj.GetEncoded(Asn1Encodable.Der);
+            }
+            catch (IOException e)
+            {
+                throw new ArgumentException("Error processing object : " + e.ToString());
+            }
+        }
+
+		public Stream GetOctetStream()
+		{
+			return new MemoryStream(str, false);
+		}
+
+		public Asn1OctetStringParser Parser
+		{
+			get { return this; }
+		}
+
+		public virtual byte[] GetOctets()
+        {
+            return str;
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+			return Arrays.GetHashCode(GetOctets());
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerOctetString other = asn1Object as DerOctetString;
+
+			if (other == null)
+				return false;
+
+			return Arrays.AreEqual(GetOctets(), other.GetOctets());
+		}
+
+		public override string ToString()
+		{
+			return "#" + Hex.ToHexString(str);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/Asn1OutputStream.cs b/Crypto/src/asn1/Asn1OutputStream.cs
new file mode 100644
index 000000000..39c8b1e5e
--- /dev/null
+++ b/Crypto/src/asn1/Asn1OutputStream.cs
@@ -0,0 +1,35 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public class Asn1OutputStream
+        : DerOutputStream
+    {
+        public Asn1OutputStream(Stream os) : base(os)
+        {
+        }
+
+		[Obsolete("Use version taking an Asn1Encodable arg instead")]
+        public override void WriteObject(
+            object    obj)
+        {
+            if (obj == null)
+            {
+                WriteNull();
+            }
+            else if (obj is Asn1Object)
+            {
+                ((Asn1Object)obj).Encode(this);
+            }
+            else if (obj is Asn1Encodable)
+            {
+                ((Asn1Encodable)obj).ToAsn1Object().Encode(this);
+            }
+            else
+            {
+                throw new IOException("object not Asn1Encodable");
+            }
+        }
+    }
+}
diff --git a/Crypto/src/asn1/Asn1ParsingException.cs b/Crypto/src/asn1/Asn1ParsingException.cs
new file mode 100644
index 000000000..8827d8329
--- /dev/null
+++ b/Crypto/src/asn1/Asn1ParsingException.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class Asn1ParsingException
+		: InvalidOperationException
+	{
+		public Asn1ParsingException()
+			: base()
+		{
+		}
+
+		public Asn1ParsingException(
+			string message)
+			: base(message)
+		{
+		}
+
+		public Asn1ParsingException(
+			string		message,
+			Exception	exception)
+			: base(message, exception)
+		{
+		}
+	}
+}
diff --git a/Crypto/src/asn1/Asn1Sequence.cs b/Crypto/src/asn1/Asn1Sequence.cs
new file mode 100644
index 000000000..3131ead84
--- /dev/null
+++ b/Crypto/src/asn1/Asn1Sequence.cs
@@ -0,0 +1,255 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public abstract class Asn1Sequence
+		: Asn1Object, IEnumerable
+    {
+        private readonly IList seq;
+
+		/**
+         * return an Asn1Sequence from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static Asn1Sequence GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is Asn1Sequence)
+            {
+                return (Asn1Sequence)obj;
+            }
+			else if (obj is byte[])
+			{
+				try
+				{
+					return Asn1Sequence.GetInstance(Asn1Object.FromByteArray((byte[])obj));
+				}
+				catch (IOException e)
+				{
+					throw new ArgumentException("Failed to construct sequence from byte[]", e);
+				}
+			}
+
+			throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		/**
+         * Return an ASN1 sequence from a tagged object. There is a special
+         * case here, if an object appears to have been explicitly tagged on
+         * reading but we were expecting it to be implicitly tagged in the
+         * normal course of events it indicates that we lost the surrounding
+         * sequence - so we need to add it back (this will happen if the tagged
+         * object is a sequence that contains other sequences). If you are
+         * dealing with implicitly tagged sequences you really <b>should</b>
+         * be using this method.
+         *
+         * @param obj the tagged object.
+         * @param explicitly true if the object is meant to be explicitly tagged,
+         *          false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *          be converted.
+         */
+        public static Asn1Sequence GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+			Asn1Object inner = obj.GetObject();
+
+			if (explicitly)
+            {
+                if (!obj.IsExplicit())
+                    throw new ArgumentException("object implicit - explicit expected.");
+
+				return (Asn1Sequence) inner;
+            }
+
+			//
+            // constructed object which appears to be explicitly tagged
+            // when it should be implicit means we have to add the
+            // surrounding sequence.
+            //
+            if (obj.IsExplicit())
+            {
+                if (obj is BerTaggedObject)
+                {
+                    return new BerSequence(inner);
+                }
+
+				return new DerSequence(inner);
+            }
+
+			if (inner is Asn1Sequence)
+            {
+                return (Asn1Sequence) inner;
+            }
+
+			throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		protected internal Asn1Sequence(
+			int capacity)
+		{
+            seq = Platform.CreateArrayList(capacity);
+		}
+
+		public virtual IEnumerator GetEnumerator()
+		{
+			return seq.GetEnumerator();
+		}
+
+		[Obsolete("Use GetEnumerator() instead")]
+		public IEnumerator GetObjects()
+        {
+            return GetEnumerator();
+        }
+
+		private class Asn1SequenceParserImpl
+			: Asn1SequenceParser
+		{
+			private readonly Asn1Sequence outer;
+			private readonly int max;
+			private int index;
+
+			public Asn1SequenceParserImpl(
+				Asn1Sequence outer)
+			{
+				this.outer = outer;
+				this.max = outer.Count;
+			}
+
+			public IAsn1Convertible ReadObject()
+			{
+				if (index == max)
+					return null;
+
+				Asn1Encodable obj = outer[index++];
+
+				if (obj is Asn1Sequence)
+					return ((Asn1Sequence)obj).Parser;
+
+				if (obj is Asn1Set)
+					return ((Asn1Set)obj).Parser;
+
+				// NB: Asn1OctetString implements Asn1OctetStringParser directly
+//				if (obj is Asn1OctetString)
+//					return ((Asn1OctetString)obj).Parser;
+
+				return obj;
+			}
+
+			public Asn1Object ToAsn1Object()
+			{
+				return outer;
+			}
+		}
+
+		public virtual Asn1SequenceParser Parser
+		{
+			get { return new Asn1SequenceParserImpl(this); }
+		}
+
+        /**
+         * return the object at the sequence position indicated by index.
+         *
+         * @param index the sequence number (starting at zero) of the object
+         * @return the object at the sequence position indicated by index.
+         */
+		public virtual Asn1Encodable this[int index]
+		{
+			get { return (Asn1Encodable) seq[index]; }
+		}
+
+		[Obsolete("Use 'object[index]' syntax instead")]
+        public Asn1Encodable GetObjectAt(
+            int index)
+        {
+             return this[index];
+        }
+
+		[Obsolete("Use 'Count' property instead")]
+		public int Size
+        {
+			get { return Count; }
+        }
+
+		public virtual int Count
+		{
+			get { return seq.Count; }
+		}
+
+		protected override int Asn1GetHashCode()
+		{
+			int hc = Count;
+
+			foreach (object o in this)
+			{
+				hc *= 17;
+				if (o == null)
+				{
+					hc ^= DerNull.Instance.GetHashCode();
+				}
+				else
+                {
+					hc ^= o.GetHashCode();
+                }
+            }
+
+			return hc;
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			Asn1Sequence other = asn1Object as Asn1Sequence;
+
+			if (other == null)
+                return false;
+
+			if (Count != other.Count)
+                return false;
+
+			IEnumerator s1 = GetEnumerator();
+            IEnumerator s2 = other.GetEnumerator();
+
+			while (s1.MoveNext() && s2.MoveNext())
+			{
+				Asn1Object o1 = GetCurrent(s1).ToAsn1Object();
+				Asn1Object o2 = GetCurrent(s2).ToAsn1Object();
+
+				if (!o1.Equals(o2))
+					return false;
+			}
+
+			return true;
+        }
+
+		private Asn1Encodable GetCurrent(IEnumerator e)
+		{
+			Asn1Encodable encObj = (Asn1Encodable)e.Current;
+
+			// unfortunately null was allowed as a substitute for DER null
+			if (encObj == null)
+				return DerNull.Instance;
+
+			return encObj;
+		}
+
+		protected internal void AddObject(
+            Asn1Encodable obj)
+        {
+            seq.Add(obj);
+        }
+
+		public override string ToString()
+		{
+			return CollectionUtilities.ToString(seq);
+		}
+    }
+}
diff --git a/Crypto/src/asn1/Asn1Set.cs b/Crypto/src/asn1/Asn1Set.cs
new file mode 100644
index 000000000..f5b66495c
--- /dev/null
+++ b/Crypto/src/asn1/Asn1Set.cs
@@ -0,0 +1,326 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1
+{
+    abstract public class Asn1Set
+        : Asn1Object, IEnumerable
+    {
+        private readonly IList _set;
+
+		/**
+         * return an ASN1Set from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static Asn1Set GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is Asn1Set)
+            {
+                return (Asn1Set)obj;
+            }
+
+			throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+        }
+
+        /**
+         * Return an ASN1 set from a tagged object. There is a special
+         * case here, if an object appears to have been explicitly tagged on
+         * reading but we were expecting it to be implicitly tagged in the
+         * normal course of events it indicates that we lost the surrounding
+         * set - so we need to add it back (this will happen if the tagged
+         * object is a sequence that contains other sequences). If you are
+         * dealing with implicitly tagged sets you really <b>should</b>
+         * be using this method.
+         *
+         * @param obj the tagged object.
+         * @param explicitly true if the object is meant to be explicitly tagged
+         *          false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *          be converted.
+         */
+        public static Asn1Set GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+			Asn1Object inner = obj.GetObject();
+
+			if (explicitly)
+            {
+                if (!obj.IsExplicit())
+                    throw new ArgumentException("object implicit - explicit expected.");
+
+				return (Asn1Set) inner;
+            }
+
+			//
+            // constructed object which appears to be explicitly tagged
+            // and it's really implicit means we have to add the
+            // surrounding sequence.
+            //
+            if (obj.IsExplicit())
+            {
+                return new DerSet(inner);
+            }
+
+			if (inner is Asn1Set)
+            {
+                return (Asn1Set) inner;
+            }
+
+            //
+            // in this case the parser returns a sequence, convert it
+            // into a set.
+            //
+			if (inner is Asn1Sequence)
+            {
+				Asn1EncodableVector v = new Asn1EncodableVector();
+				Asn1Sequence s = (Asn1Sequence) inner;
+
+				foreach (Asn1Encodable ae in s)
+				{
+                    v.Add(ae);
+                }
+
+				// TODO Should be able to construct set directly from sequence?
+				return new DerSet(v, false);
+            }
+
+			throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		protected internal Asn1Set(
+			int capacity)
+        {
+			_set = Platform.CreateArrayList(capacity);
+        }
+
+		public virtual IEnumerator GetEnumerator()
+		{
+			return _set.GetEnumerator();
+		}
+
+		[Obsolete("Use GetEnumerator() instead")]
+        public IEnumerator GetObjects()
+        {
+            return GetEnumerator();
+        }
+
+		/**
+         * return the object at the set position indicated by index.
+         *
+         * @param index the set number (starting at zero) of the object
+         * @return the object at the set position indicated by index.
+         */
+		public virtual Asn1Encodable this[int index]
+		{
+			get { return (Asn1Encodable) _set[index]; }
+		}
+
+		[Obsolete("Use 'object[index]' syntax instead")]
+		public Asn1Encodable GetObjectAt(
+            int index)
+        {
+             return this[index];
+        }
+
+		[Obsolete("Use 'Count' property instead")]
+		public int Size
+        {
+			get { return Count; }
+        }
+
+		public virtual int Count
+		{
+			get { return _set.Count; }
+		}
+
+		public virtual Asn1Encodable[] ToArray()
+		{
+			Asn1Encodable[] values = new Asn1Encodable[this.Count];
+			for (int i = 0; i < this.Count; ++i)
+			{
+				values[i] = this[i];
+			}
+			return values;
+		}
+
+		private class Asn1SetParserImpl
+			: Asn1SetParser
+		{
+			private readonly Asn1Set outer;
+			private readonly int max;
+			private int index;
+
+			public Asn1SetParserImpl(
+				Asn1Set outer)
+			{
+				this.outer = outer;
+				this.max = outer.Count;
+			}
+
+			public IAsn1Convertible ReadObject()
+			{
+				if (index == max)
+					return null;
+
+				Asn1Encodable obj = outer[index++];
+				if (obj is Asn1Sequence)
+					return ((Asn1Sequence)obj).Parser;
+
+				if (obj is Asn1Set)
+					return ((Asn1Set)obj).Parser;
+
+				// NB: Asn1OctetString implements Asn1OctetStringParser directly
+//				if (obj is Asn1OctetString)
+//					return ((Asn1OctetString)obj).Parser;
+
+				return obj;
+			}
+
+			public virtual Asn1Object ToAsn1Object()
+			{
+				return outer;
+			}
+		}
+
+		public Asn1SetParser Parser
+		{
+			get { return new Asn1SetParserImpl(this); }
+		}
+
+		protected override int Asn1GetHashCode()
+		{
+            int hc = Count;
+
+			foreach (object o in this)
+			{
+				hc *= 17;
+				if (o == null)
+				{
+					hc ^= DerNull.Instance.GetHashCode();
+				}
+				else
+                {
+					hc ^= o.GetHashCode();
+                }
+            }
+
+			return hc;
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+        {
+			Asn1Set other = asn1Object as Asn1Set;
+
+			if (other == null)
+				return false;
+
+			if (Count != other.Count)
+            {
+                return false;
+            }
+
+			IEnumerator s1 = GetEnumerator();
+            IEnumerator s2 = other.GetEnumerator();
+
+			while (s1.MoveNext() && s2.MoveNext())
+			{
+				Asn1Object o1 = GetCurrent(s1).ToAsn1Object();
+				Asn1Object o2 = GetCurrent(s2).ToAsn1Object();
+
+				if (!o1.Equals(o2))
+					return false;
+			}
+
+			return true;
+        }
+
+		private Asn1Encodable GetCurrent(IEnumerator e)
+		{
+			Asn1Encodable encObj = (Asn1Encodable)e.Current;
+
+			// unfortunately null was allowed as a substitute for DER null
+			if (encObj == null)
+				return DerNull.Instance;
+
+			return encObj;
+		}
+
+		/**
+         * return true if a &lt;= b (arrays are assumed padded with zeros).
+         */
+        private bool LessThanOrEqual(
+             byte[] a,
+             byte[] b)
+        {
+			int len = System.Math.Min(a.Length, b.Length);
+			for (int i = 0; i != len; ++i)
+			{
+				if (a[i] != b[i])
+				{
+					return a[i] < b[i];
+				}
+			}
+			return len == a.Length;
+		}
+
+		protected internal void Sort()
+        {
+			if (_set.Count > 1)
+			{
+				bool swapped = true;
+				int lastSwap = _set.Count - 1;
+
+				while (swapped)
+				{
+					int index = 0;
+					int swapIndex = 0;
+					byte[] a = ((Asn1Encodable) _set[0]).GetEncoded();
+
+					swapped = false;
+
+					while (index != lastSwap)
+					{
+						byte[] b = ((Asn1Encodable) _set[index + 1]).GetEncoded();
+
+						if (LessThanOrEqual(a, b))
+						{
+							a = b;
+						}
+						else
+						{
+							object o = _set[index];
+							_set[index] = _set[index + 1];
+							_set[index + 1] = o;
+
+							swapped = true;
+							swapIndex = index;
+						}
+
+						index++;
+					}
+
+					lastSwap = swapIndex;
+				}
+			}
+        }
+
+		protected internal void AddObject(
+			Asn1Encodable obj)
+        {
+            _set.Add(obj);
+        }
+
+		public override string ToString()
+		{
+			return CollectionUtilities.ToString(_set);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/Asn1TaggedObject.cs b/Crypto/src/asn1/Asn1TaggedObject.cs
new file mode 100644
index 000000000..2e480738a
--- /dev/null
+++ b/Crypto/src/asn1/Asn1TaggedObject.cs
@@ -0,0 +1,178 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * ASN.1 TaggedObject - in ASN.1 notation this is any object preceded by
+     * a [n] where n is some number - these are assumed to follow the construction
+     * rules (as with sequences).
+     */
+    public abstract class Asn1TaggedObject
+		: Asn1Object, Asn1TaggedObjectParser
+    {
+        internal int            tagNo;
+//        internal bool           empty;
+        internal bool           explicitly = true;
+        internal Asn1Encodable  obj;
+
+		static public Asn1TaggedObject GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            if (explicitly)
+            {
+                return (Asn1TaggedObject) obj.GetObject();
+            }
+
+            throw new ArgumentException("implicitly tagged tagged object");
+        }
+
+		static public Asn1TaggedObject GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is Asn1TaggedObject)
+			{
+				return (Asn1TaggedObject) obj;
+			}
+
+			throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		/**
+         * @param tagNo the tag number for this object.
+         * @param obj the tagged object.
+         */
+        protected Asn1TaggedObject(
+            int             tagNo,
+            Asn1Encodable   obj)
+        {
+            this.explicitly = true;
+            this.tagNo = tagNo;
+            this.obj = obj;
+        }
+
+		/**
+         * @param explicitly true if the object is explicitly tagged.
+         * @param tagNo the tag number for this object.
+         * @param obj the tagged object.
+         */
+        protected Asn1TaggedObject(
+            bool            explicitly,
+            int             tagNo,
+            Asn1Encodable   obj)
+        {
+			// IAsn1Choice marker interface 'insists' on explicit tagging
+            this.explicitly = explicitly || (obj is IAsn1Choice);
+            this.tagNo = tagNo;
+            this.obj = obj;
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+        {
+			Asn1TaggedObject other = asn1Object as Asn1TaggedObject;
+
+			if (other == null)
+				return false;
+
+			return this.tagNo == other.tagNo
+//				&& this.empty == other.empty
+				&& this.explicitly == other.explicitly   // TODO Should this be part of equality?
+				&& Platform.Equals(GetObject(), other.GetObject());
+		}
+
+		protected override int Asn1GetHashCode()
+		{
+            int code = tagNo.GetHashCode();
+
+			// TODO: actually this is wrong - the problem is that a re-encoded
+			// object may end up with a different hashCode due to implicit
+			// tagging. As implicit tagging is ambiguous if a sequence is involved
+			// it seems the only correct method for both equals and hashCode is to
+			// compare the encodings...
+//			code ^= explicitly.GetHashCode();
+
+			if (obj != null)
+            {
+                code ^= obj.GetHashCode();
+            }
+
+			return code;
+        }
+
+		public int TagNo
+        {
+			get { return tagNo; }
+        }
+
+		/**
+         * return whether or not the object may be explicitly tagged.
+         * <p>
+         * Note: if the object has been read from an input stream, the only
+         * time you can be sure if isExplicit is returning the true state of
+         * affairs is if it returns false. An implicitly tagged object may appear
+         * to be explicitly tagged, so you need to understand the context under
+         * which the reading was done as well, see GetObject below.</p>
+         */
+        public bool IsExplicit()
+        {
+            return explicitly;
+        }
+
+        public bool IsEmpty()
+        {
+            return false; //empty;
+        }
+
+		/**
+         * return whatever was following the tag.
+         * <p>
+         * Note: tagged objects are generally context dependent if you're
+         * trying to extract a tagged object you should be going via the
+         * appropriate GetInstance method.</p>
+         */
+        public Asn1Object GetObject()
+        {
+            if (obj != null)
+            {
+                return obj.ToAsn1Object();
+            }
+
+			return null;
+        }
+
+		/**
+		* Return the object held in this tagged object as a parser assuming it has
+		* the type of the passed in tag. If the object doesn't have a parser
+		* associated with it, the base object is returned.
+		*/
+		public IAsn1Convertible GetObjectParser(
+			int		tag,
+			bool	isExplicit)
+		{
+			switch (tag)
+			{
+				case Asn1Tags.Set:
+					return Asn1Set.GetInstance(this, isExplicit).Parser;
+				case Asn1Tags.Sequence:
+					return Asn1Sequence.GetInstance(this, isExplicit).Parser;
+				case Asn1Tags.OctetString:
+					return Asn1OctetString.GetInstance(this, isExplicit).Parser;
+			}
+
+			if (isExplicit)
+			{
+				return GetObject();
+			}
+
+			throw Platform.CreateNotImplementedException("implicit tagging for tag: " + tag);
+		}
+
+		public override string ToString()
+		{
+			return "[" + tagNo + "]" + obj;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/Asn1Tags.cs b/Crypto/src/asn1/Asn1Tags.cs
new file mode 100644
index 000000000..32ac6bc6c
--- /dev/null
+++ b/Crypto/src/asn1/Asn1Tags.cs
@@ -0,0 +1,36 @@
+namespace Org.BouncyCastle.Asn1
+{
+    public class Asn1Tags
+    {
+        public const int Boolean = 0x01;
+        public const int Integer = 0x02;
+        public const int BitString = 0x03;
+        public const int OctetString = 0x04;
+        public const int Null = 0x05;
+        public const int ObjectIdentifier = 0x06;
+        public const int External = 0x08;
+        public const int Enumerated = 0x0a;
+        public const int Sequence = 0x10;
+        public const int SequenceOf = 0x10; // for completeness
+        public const int Set = 0x11;
+        public const int SetOf = 0x11; // for completeness
+
+        public const int NumericString = 0x12;
+        public const int PrintableString = 0x13;
+        public const int T61String = 0x14;
+        public const int VideotexString = 0x15;
+        public const int IA5String = 0x16;
+        public const int UtcTime = 0x17;
+        public const int GeneralizedTime = 0x18;
+        public const int GraphicString = 0x19;
+        public const int VisibleString = 0x1a;
+        public const int GeneralString = 0x1b;
+        public const int UniversalString = 0x1c;
+        public const int BmpString = 0x1e;
+        public const int Utf8String = 0x0c;
+
+        public const int Constructed = 0x20;
+        public const int Application = 0x40;
+        public const int Tagged = 0x80;
+    }
+}
diff --git a/Crypto/src/asn1/BERGenerator.cs b/Crypto/src/asn1/BERGenerator.cs
new file mode 100644
index 000000000..271572c02
--- /dev/null
+++ b/Crypto/src/asn1/BERGenerator.cs
@@ -0,0 +1,102 @@
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public class BerGenerator
+        : Asn1Generator
+    {
+        private bool      _tagged = false;
+        private bool      _isExplicit;
+        private int          _tagNo;
+
+        protected BerGenerator(
+            Stream outStream)
+            : base(outStream)
+        {
+        }
+
+        public BerGenerator(
+            Stream outStream,
+            int tagNo,
+            bool isExplicit)
+            : base(outStream)
+        {
+            _tagged = true;
+            _isExplicit = isExplicit;
+            _tagNo = tagNo;
+        }
+
+		public override void AddObject(
+			Asn1Encodable obj)
+		{
+			new BerOutputStream(Out).WriteObject(obj);
+		}
+
+		public override Stream GetRawOutputStream()
+        {
+            return Out;
+        }
+
+		public override void Close()
+		{
+			WriteBerEnd();
+		}
+
+        private void WriteHdr(
+            int tag)
+        {
+            Out.WriteByte((byte) tag);
+            Out.WriteByte(0x80);
+        }
+
+        protected void WriteBerHeader(
+            int tag)
+        {
+            if (_tagged)
+            {
+                int tagNum = _tagNo | Asn1Tags.Tagged;
+
+                if (_isExplicit)
+                {
+                    WriteHdr(tagNum | Asn1Tags.Constructed);
+                    WriteHdr(tag);
+                }
+                else
+                {
+                    if ((tag & Asn1Tags.Constructed) != 0)
+                    {
+                        WriteHdr(tagNum | Asn1Tags.Constructed);
+                    }
+                    else
+                    {
+                        WriteHdr(tagNum);
+                    }
+                }
+            }
+            else
+            {
+                WriteHdr(tag);
+            }
+        }
+
+		protected void WriteBerBody(
+            Stream contentStream)
+        {
+			Streams.PipeAll(contentStream, Out);
+        }
+
+		protected void WriteBerEnd()
+        {
+            Out.WriteByte(0x00);
+            Out.WriteByte(0x00);
+
+            if (_tagged && _isExplicit)  // write extra end for tag header
+            {
+                Out.WriteByte(0x00);
+                Out.WriteByte(0x00);
+            }
+        }
+    }
+}
diff --git a/Crypto/src/asn1/BEROctetStringGenerator.cs b/Crypto/src/asn1/BEROctetStringGenerator.cs
new file mode 100644
index 000000000..644060765
--- /dev/null
+++ b/Crypto/src/asn1/BEROctetStringGenerator.cs
@@ -0,0 +1,121 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerOctetStringGenerator
+		: BerGenerator
+	{
+		public BerOctetStringGenerator(Stream outStream)
+			: base(outStream)
+		{
+			WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.OctetString);
+		}
+
+		public BerOctetStringGenerator(
+			Stream	outStream,
+			int		tagNo,
+			bool	isExplicit)
+			: base(outStream, tagNo, isExplicit)
+		{
+			WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.OctetString);
+		}
+
+		public Stream GetOctetOutputStream()
+		{
+			return GetOctetOutputStream(new byte[1000]); // limit for CER encoding.
+		}
+
+		public Stream GetOctetOutputStream(
+			int bufSize)
+		{
+			return bufSize < 1
+				?	GetOctetOutputStream()
+				:	GetOctetOutputStream(new byte[bufSize]);
+		}
+
+		public Stream GetOctetOutputStream(
+			byte[] buf)
+		{
+			return new BufferedBerOctetStream(this, buf);
+		}
+
+        private class BufferedBerOctetStream
+            : BaseOutputStream
+        {
+            private byte[] _buf;
+            private int _off;
+            private readonly BerOctetStringGenerator _gen;
+            private readonly DerOutputStream _derOut;
+
+            internal BufferedBerOctetStream(
+                BerOctetStringGenerator gen,
+                byte[] buf)
+            {
+                _gen = gen;
+                _buf = buf;
+                _off = 0;
+                _derOut = new DerOutputStream(_gen.Out);
+            }
+
+            public override void WriteByte(
+                byte b)
+            {
+                _buf[_off++] = b;
+
+                if (_off == _buf.Length)
+                {
+                    DerOctetString.Encode(_derOut, _buf, 0, _off);
+                    _off = 0;
+                }
+            }
+
+            public override void Write(
+                byte[] buf,
+                int offset,
+                int len)
+            {
+                while (len > 0)
+                {
+                    int numToCopy = System.Math.Min(len, _buf.Length - _off);
+
+                    if (numToCopy == _buf.Length)
+                    {
+                        DerOctetString.Encode(_derOut, buf, offset, numToCopy);
+                    }
+                    else
+                    {
+                        Array.Copy(buf, offset, _buf, _off, numToCopy);
+
+                        _off += numToCopy;
+                        if (_off < _buf.Length)
+                            break;
+
+                        DerOctetString.Encode(_derOut, _buf, 0, _off);
+                        _off = 0;
+                    }
+
+                    offset += numToCopy;
+                    len -= numToCopy;
+                }
+            }
+
+            protected override void Dispose(bool disposing)
+            {
+                if (disposing)
+                {
+                    if (_off != 0)
+                    {
+                        DerOctetString.Encode(_derOut, _buf, 0, _off);
+                    }
+
+                    _gen.WriteBerEnd();
+                }
+
+                base.Dispose(disposing);
+            }
+        }
+	}
+}
diff --git a/Crypto/src/asn1/BEROctetStringParser.cs b/Crypto/src/asn1/BEROctetStringParser.cs
new file mode 100644
index 000000000..3bfd2a98d
--- /dev/null
+++ b/Crypto/src/asn1/BEROctetStringParser.cs
@@ -0,0 +1,36 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerOctetStringParser
+		: Asn1OctetStringParser
+	{
+		private readonly Asn1StreamParser _parser;
+
+		internal BerOctetStringParser(
+			Asn1StreamParser parser)
+		{
+			_parser = parser;
+		}
+
+		public Stream GetOctetStream()
+		{
+			return new ConstructedOctetStream(_parser);
+		}
+
+		public Asn1Object ToAsn1Object()
+		{
+			try
+			{
+				return new BerOctetString(Streams.ReadAll(GetOctetStream()));
+			}
+			catch (IOException e)
+			{
+				throw new Asn1ParsingException("IOException converting stream to byte array: " + e.Message, e);
+			}
+		}
+	}
+}
diff --git a/Crypto/src/asn1/BERSequenceGenerator.cs b/Crypto/src/asn1/BERSequenceGenerator.cs
new file mode 100644
index 000000000..5ea2c9b82
--- /dev/null
+++ b/Crypto/src/asn1/BERSequenceGenerator.cs
@@ -0,0 +1,24 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerSequenceGenerator
+		: BerGenerator
+	{
+		public BerSequenceGenerator(
+			Stream outStream)
+			: base(outStream)
+		{
+			WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Sequence);
+		}
+
+		public BerSequenceGenerator(
+			Stream	outStream,
+			int		tagNo,
+			bool	isExplicit)
+			: base(outStream, tagNo, isExplicit)
+		{
+			WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Sequence);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/BERSequenceParser.cs b/Crypto/src/asn1/BERSequenceParser.cs
new file mode 100644
index 000000000..8474b8d24
--- /dev/null
+++ b/Crypto/src/asn1/BERSequenceParser.cs
@@ -0,0 +1,24 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerSequenceParser
+		: Asn1SequenceParser
+	{
+		private readonly Asn1StreamParser _parser;
+
+		internal BerSequenceParser(
+			Asn1StreamParser parser)
+		{
+			this._parser = parser;
+		}
+
+		public IAsn1Convertible ReadObject()
+		{
+			return _parser.ReadObject();
+		}
+
+		public Asn1Object ToAsn1Object()
+		{
+			return new BerSequence(_parser.ReadVector());
+		}
+	}
+}
diff --git a/Crypto/src/asn1/BERSetGenerator.cs b/Crypto/src/asn1/BERSetGenerator.cs
new file mode 100644
index 000000000..72b1f903a
--- /dev/null
+++ b/Crypto/src/asn1/BERSetGenerator.cs
@@ -0,0 +1,24 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerSetGenerator
+		: BerGenerator
+	{
+		public BerSetGenerator(
+			Stream outStream)
+			: base(outStream)
+		{
+			WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Set);
+		}
+
+		public BerSetGenerator(
+			Stream	outStream,
+			int		tagNo,
+			bool	isExplicit)
+			: base(outStream, tagNo, isExplicit)
+		{
+			WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Set);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/BERSetParser.cs b/Crypto/src/asn1/BERSetParser.cs
new file mode 100644
index 000000000..aa9ccbc12
--- /dev/null
+++ b/Crypto/src/asn1/BERSetParser.cs
@@ -0,0 +1,24 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerSetParser
+		: Asn1SetParser
+	{
+		private readonly Asn1StreamParser _parser;
+
+		internal BerSetParser(
+			Asn1StreamParser parser)
+		{
+			this._parser = parser;
+		}
+
+		public IAsn1Convertible ReadObject()
+		{
+			return _parser.ReadObject();
+		}
+
+		public Asn1Object ToAsn1Object()
+		{
+			return new BerSet(_parser.ReadVector(), false);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/BERTaggedObjectParser.cs b/Crypto/src/asn1/BERTaggedObjectParser.cs
new file mode 100644
index 000000000..354437a6a
--- /dev/null
+++ b/Crypto/src/asn1/BERTaggedObjectParser.cs
@@ -0,0 +1,71 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerTaggedObjectParser
+		: Asn1TaggedObjectParser
+	{
+		private bool				_constructed;
+		private int					_tagNumber;
+		private Asn1StreamParser	_parser;
+
+		[Obsolete]
+		internal BerTaggedObjectParser(
+			int		baseTag,
+			int		tagNumber,
+			Stream	contentStream)
+			: this((baseTag & Asn1Tags.Constructed) != 0, tagNumber, new Asn1StreamParser(contentStream))
+		{
+		}
+
+		internal BerTaggedObjectParser(
+			bool				constructed,
+			int					tagNumber,
+			Asn1StreamParser	parser)
+		{
+			_constructed = constructed;
+			_tagNumber = tagNumber;
+			_parser = parser;
+		}
+
+		public bool IsConstructed
+		{
+			get { return _constructed; }
+		}
+
+		public int TagNo
+		{
+			get { return _tagNumber; }
+		}
+
+		public IAsn1Convertible GetObjectParser(
+			int		tag,
+			bool	isExplicit)
+		{
+			if (isExplicit)
+			{
+				if (!_constructed)
+					throw new IOException("Explicit tags must be constructed (see X.690 8.14.2)");
+
+				return _parser.ReadObject();
+			}
+
+			return _parser.ReadImplicit(_constructed, tag);
+		}
+
+		public Asn1Object ToAsn1Object()
+		{
+			try
+			{
+				return _parser.ReadTaggedObject(_constructed, _tagNumber);
+			}
+			catch (IOException e)
+			{
+				throw new Asn1ParsingException(e.Message);
+			}
+		}
+	}
+}
diff --git a/Crypto/src/asn1/BerApplicationSpecific.cs b/Crypto/src/asn1/BerApplicationSpecific.cs
new file mode 100644
index 000000000..65fbecbe1
--- /dev/null
+++ b/Crypto/src/asn1/BerApplicationSpecific.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerApplicationSpecific
+		: DerApplicationSpecific
+	{
+		public BerApplicationSpecific(
+			int					tagNo,
+			Asn1EncodableVector	vec)
+			: base(tagNo, vec)
+		{
+		}
+	}
+}
diff --git a/Crypto/src/asn1/BerApplicationSpecificParser.cs b/Crypto/src/asn1/BerApplicationSpecificParser.cs
new file mode 100644
index 000000000..7d2c4b3e8
--- /dev/null
+++ b/Crypto/src/asn1/BerApplicationSpecificParser.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerApplicationSpecificParser
+		: IAsn1ApplicationSpecificParser
+	{
+		private readonly int tag;
+		private readonly Asn1StreamParser parser;
+
+		internal BerApplicationSpecificParser(
+			int					tag,
+			Asn1StreamParser	parser)
+		{
+			this.tag = tag;
+			this.parser = parser;
+		}
+
+		public IAsn1Convertible ReadObject()
+		{
+			return parser.ReadObject();
+		}
+
+		public Asn1Object ToAsn1Object()
+		{
+			return new BerApplicationSpecific(tag, parser.ReadVector());
+		}
+	}
+}
diff --git a/Crypto/src/asn1/BerNull.cs b/Crypto/src/asn1/BerNull.cs
new file mode 100644
index 000000000..0751bbac3
--- /dev/null
+++ b/Crypto/src/asn1/BerNull.cs
@@ -0,0 +1,35 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+	/**
+	 * A BER Null object.
+	 */
+	public class BerNull
+		: DerNull
+	{
+		public static new readonly BerNull Instance = new BerNull(0);
+
+		[Obsolete("Use static Instance object")]
+		public BerNull()
+		{
+		}
+
+		private BerNull(int dummy) : base(dummy)
+		{
+		}
+
+		internal override void Encode(
+			DerOutputStream  derOut)
+		{
+			if (derOut is Asn1OutputStream || derOut is BerOutputStream)
+			{
+				derOut.WriteByte(Asn1Tags.Null);
+			}
+			else
+			{
+				base.Encode(derOut);
+			}
+		}
+	}
+}
diff --git a/Crypto/src/asn1/BerOctetString.cs b/Crypto/src/asn1/BerOctetString.cs
new file mode 100644
index 000000000..a7c8ad33e
--- /dev/null
+++ b/Crypto/src/asn1/BerOctetString.cs
@@ -0,0 +1,135 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public class BerOctetString
+        : DerOctetString, IEnumerable
+    {
+		public static BerOctetString FromSequence(Asn1Sequence seq)
+		{
+			IList v = Platform.CreateArrayList();
+
+			foreach (Asn1Encodable obj in seq)
+			{
+				v.Add(obj);
+			}
+
+			return new BerOctetString(v);
+		}
+
+		private const int MaxLength = 1000;
+
+		/**
+         * convert a vector of octet strings into a single byte string
+         */
+        private static byte[] ToBytes(
+            IEnumerable octs)
+        {
+            MemoryStream bOut = new MemoryStream();
+			foreach (DerOctetString o in octs)
+			{
+                byte[] octets = o.GetOctets();
+                bOut.Write(octets, 0, octets.Length);
+            }
+			return bOut.ToArray();
+        }
+
+		private readonly IEnumerable octs;
+
+		/// <param name="str">The octets making up the octet string.</param>
+		public BerOctetString(
+			byte[] str)
+			: base(str)
+		{
+		}
+
+		public BerOctetString(
+			IEnumerable octets)
+			: base(ToBytes(octets))
+        {
+            this.octs = octets;
+        }
+
+        public BerOctetString(
+			Asn1Object obj)
+			: base(obj)
+        {
+        }
+
+        public BerOctetString(
+			Asn1Encodable obj)
+			: base(obj.ToAsn1Object())
+        {
+        }
+
+        public override byte[] GetOctets()
+        {
+            return str;
+        }
+
+        /**
+         * return the DER octets that make up this string.
+         */
+		public IEnumerator GetEnumerator()
+		{
+			if (octs == null)
+			{
+				return GenerateOcts().GetEnumerator();
+			}
+
+			return octs.GetEnumerator();
+		}
+
+		[Obsolete("Use GetEnumerator() instead")]
+        public IEnumerator GetObjects()
+        {
+			return GetEnumerator();
+		}
+
+		private IList GenerateOcts()
+        {
+            IList vec = Platform.CreateArrayList();
+			for (int i = 0; i < str.Length; i += MaxLength)
+			{
+				int end = System.Math.Min(str.Length, i + MaxLength);
+
+				byte[] nStr = new byte[end - i];
+
+				Array.Copy(str, i, nStr, 0, nStr.Length);
+
+				vec.Add(new DerOctetString(nStr));
+			}
+			return vec;
+        }
+
+        internal override void Encode(
+            DerOutputStream derOut)
+        {
+            if (derOut is Asn1OutputStream || derOut is BerOutputStream)
+            {
+                derOut.WriteByte(Asn1Tags.Constructed | Asn1Tags.OctetString);
+
+                derOut.WriteByte(0x80);
+
+                //
+                // write out the octet array
+                //
+                foreach (DerOctetString oct in this)
+                {
+                    derOut.WriteObject(oct);
+                }
+
+				derOut.WriteByte(0x00);
+                derOut.WriteByte(0x00);
+            }
+            else
+            {
+                base.Encode(derOut);
+            }
+        }
+    }
+}
diff --git a/Crypto/src/asn1/BerOutputStream.cs b/Crypto/src/asn1/BerOutputStream.cs
new file mode 100644
index 000000000..b3ece10d3
--- /dev/null
+++ b/Crypto/src/asn1/BerOutputStream.cs
@@ -0,0 +1,36 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	// TODO Make Obsolete in favour of Asn1OutputStream?
+    public class BerOutputStream
+        : DerOutputStream
+    {
+        public BerOutputStream(Stream os) : base(os)
+        {
+        }
+
+		[Obsolete("Use version taking an Asn1Encodable arg instead")]
+        public override void WriteObject(
+            object    obj)
+        {
+            if (obj == null)
+            {
+                WriteNull();
+            }
+            else if (obj is Asn1Object)
+            {
+                ((Asn1Object)obj).Encode(this);
+            }
+            else if (obj is Asn1Encodable)
+            {
+                ((Asn1Encodable)obj).ToAsn1Object().Encode(this);
+            }
+            else
+            {
+                throw new IOException("object not BerEncodable");
+            }
+        }
+    }
+}
diff --git a/Crypto/src/asn1/BerSequence.cs b/Crypto/src/asn1/BerSequence.cs
new file mode 100644
index 000000000..70b43fc79
--- /dev/null
+++ b/Crypto/src/asn1/BerSequence.cs
@@ -0,0 +1,69 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerSequence
+		: DerSequence
+	{
+		public static new readonly BerSequence Empty = new BerSequence();
+
+		public static new BerSequence FromVector(
+			Asn1EncodableVector v)
+		{
+			return v.Count < 1 ? Empty : new BerSequence(v);
+		}
+
+		/**
+		 * create an empty sequence
+		 */
+		public BerSequence()
+		{
+		}
+
+		/**
+		 * create a sequence containing one object
+		 */
+		public BerSequence(
+			Asn1Encodable obj)
+			: base(obj)
+		{
+		}
+
+		public BerSequence(
+			params Asn1Encodable[] v)
+			: base(v)
+		{
+		}
+
+		/**
+		 * create a sequence containing a vector of objects.
+		 */
+		public BerSequence(
+			Asn1EncodableVector v)
+			: base(v)
+		{
+		}
+
+		/*
+		 */
+		internal override void Encode(
+			DerOutputStream derOut)
+		{
+			if (derOut is Asn1OutputStream || derOut is BerOutputStream)
+			{
+				derOut.WriteByte(Asn1Tags.Sequence | Asn1Tags.Constructed);
+				derOut.WriteByte(0x80);
+
+				foreach (Asn1Encodable o in this)
+				{
+					derOut.WriteObject(o);
+				}
+
+				derOut.WriteByte(0x00);
+				derOut.WriteByte(0x00);
+			}
+			else
+			{
+				base.Encode(derOut);
+			}
+		}
+	}
+}
diff --git a/Crypto/src/asn1/BerSet.cs b/Crypto/src/asn1/BerSet.cs
new file mode 100644
index 000000000..a181e172d
--- /dev/null
+++ b/Crypto/src/asn1/BerSet.cs
@@ -0,0 +1,70 @@
+namespace Org.BouncyCastle.Asn1
+{
+    public class BerSet
+        : DerSet
+    {
+		public static new readonly BerSet Empty = new BerSet();
+
+		public static new BerSet FromVector(
+			Asn1EncodableVector v)
+		{
+			return v.Count < 1 ? Empty : new BerSet(v);
+		}
+
+		internal static new BerSet FromVector(
+			Asn1EncodableVector v,
+			bool				needsSorting)
+		{
+			return v.Count < 1 ? Empty : new BerSet(v, needsSorting);
+		}
+
+		/**
+         * create an empty sequence
+         */
+        public BerSet()
+        {
+        }
+
+        /**
+         * create a set containing one object
+         */
+        public BerSet(Asn1Encodable obj) : base(obj)
+        {
+        }
+
+        /**
+         * create a set containing a vector of objects.
+         */
+        public BerSet(Asn1EncodableVector v) : base(v, false)
+        {
+        }
+
+        internal BerSet(Asn1EncodableVector v, bool needsSorting) : base(v, needsSorting)
+        {
+        }
+
+        /*
+         */
+        internal override void Encode(
+            DerOutputStream derOut)
+        {
+            if (derOut is Asn1OutputStream || derOut is BerOutputStream)
+            {
+                derOut.WriteByte(Asn1Tags.Set | Asn1Tags.Constructed);
+                derOut.WriteByte(0x80);
+
+                foreach (Asn1Encodable o in this)
+				{
+                    derOut.WriteObject(o);
+                }
+
+                derOut.WriteByte(0x00);
+                derOut.WriteByte(0x00);
+            }
+            else
+            {
+                base.Encode(derOut);
+            }
+        }
+    }
+}
diff --git a/Crypto/src/asn1/BerTaggedObject.cs b/Crypto/src/asn1/BerTaggedObject.cs
new file mode 100644
index 000000000..228b136cb
--- /dev/null
+++ b/Crypto/src/asn1/BerTaggedObject.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+	/**
+	 * BER TaggedObject - in ASN.1 notation this is any object preceded by
+	 * a [n] where n is some number - these are assumed to follow the construction
+	 * rules (as with sequences).
+	 */
+	public class BerTaggedObject
+		: DerTaggedObject
+	{
+		/**
+		 * @param tagNo the tag number for this object.
+		 * @param obj the tagged object.
+		 */
+		public BerTaggedObject(
+			int				tagNo,
+			Asn1Encodable	obj)
+			: base(tagNo, obj)
+		{
+		}
+
+		/**
+		 * @param explicitly true if an explicitly tagged object.
+		 * @param tagNo the tag number for this object.
+		 * @param obj the tagged object.
+		 */
+		public BerTaggedObject(
+			bool			explicitly,
+			int				tagNo,
+			Asn1Encodable	obj)
+			: base(explicitly, tagNo, obj)
+		{
+		}
+
+		/**
+		 * create an implicitly tagged object that contains a zero
+		 * length sequence.
+		 */
+		public BerTaggedObject(
+			int tagNo)
+			: base(false, tagNo, BerSequence.Empty)
+		{
+		}
+
+		internal override void Encode(
+			DerOutputStream derOut)
+		{
+			if (derOut is Asn1OutputStream || derOut is BerOutputStream)
+			{
+				derOut.WriteTag((byte)(Asn1Tags.Constructed | Asn1Tags.Tagged), tagNo);
+				derOut.WriteByte(0x80);
+
+				if (!IsEmpty())
+				{
+					if (!explicitly)
+					{
+						IEnumerable eObj;
+						if (obj is Asn1OctetString)
+						{
+							if (obj is BerOctetString)
+							{
+								eObj = (BerOctetString) obj;
+							}
+							else
+							{
+								Asn1OctetString octs = (Asn1OctetString)obj;
+								eObj = new BerOctetString(octs.GetOctets());
+							}
+						}
+						else if (obj is Asn1Sequence)
+						{
+							eObj = (Asn1Sequence) obj;
+						}
+						else if (obj is Asn1Set)
+						{
+							eObj = (Asn1Set) obj;
+						}
+						else
+						{
+							throw Platform.CreateNotImplementedException(obj.GetType().Name);
+						}
+
+						foreach (Asn1Encodable o in eObj)
+						{
+							derOut.WriteObject(o);
+						}
+					}
+					else
+					{
+						derOut.WriteObject(obj);
+					}
+				}
+
+				derOut.WriteByte(0x00);
+				derOut.WriteByte(0x00);
+			}
+			else
+			{
+				base.Encode(derOut);
+			}
+		}
+	}
+}
diff --git a/Crypto/src/asn1/ConstructedOctetStream.cs b/Crypto/src/asn1/ConstructedOctetStream.cs
new file mode 100644
index 000000000..1773b22cc
--- /dev/null
+++ b/Crypto/src/asn1/ConstructedOctetStream.cs
@@ -0,0 +1,102 @@
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	internal class ConstructedOctetStream
+		: BaseInputStream
+	{
+		private readonly Asn1StreamParser _parser;
+
+		private bool _first = true;
+		private Stream _currentStream;
+
+		internal ConstructedOctetStream(
+			Asn1StreamParser parser)
+		{
+			_parser = parser;
+		}
+
+		public override int Read(byte[] buffer, int offset, int count)
+		{
+			if (_currentStream == null)
+			{
+				if (!_first)
+					return 0;
+
+				Asn1OctetStringParser s = (Asn1OctetStringParser)_parser.ReadObject();
+
+				if (s == null)
+					return 0;
+
+				_first = false;
+				_currentStream = s.GetOctetStream();
+			}
+
+			int totalRead = 0;
+
+			for (;;)
+			{
+				int numRead = _currentStream.Read(buffer, offset + totalRead, count - totalRead);
+
+				if (numRead > 0)
+				{
+					totalRead += numRead;
+
+					if (totalRead == count)
+						return totalRead;
+				}
+				else
+				{
+					Asn1OctetStringParser aos = (Asn1OctetStringParser)_parser.ReadObject();
+
+					if (aos == null)
+					{
+						_currentStream = null;
+						return totalRead;
+					}
+
+					_currentStream = aos.GetOctetStream();
+				}
+			}
+		}
+
+		public override int ReadByte()
+		{
+			if (_currentStream == null)
+			{
+				if (!_first)
+					return 0;
+
+				Asn1OctetStringParser s = (Asn1OctetStringParser)_parser.ReadObject();
+
+				if (s == null)
+					return 0;
+
+				_first = false;
+				_currentStream = s.GetOctetStream();
+			}
+
+			for (;;)
+			{
+				int b = _currentStream.ReadByte();
+
+				if (b >= 0)
+				{
+					return b;
+				}
+
+				Asn1OctetStringParser aos = (Asn1OctetStringParser)_parser.ReadObject();
+
+				if (aos == null)
+				{
+					_currentStream = null;
+					return -1;
+				}
+
+				_currentStream = aos.GetOctetStream();
+			}
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DERExternal.cs b/Crypto/src/asn1/DERExternal.cs
new file mode 100644
index 000000000..a342d6520
--- /dev/null
+++ b/Crypto/src/asn1/DERExternal.cs
@@ -0,0 +1,207 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+	/**
+	* Class representing the DER-type External
+	*/
+	public class DerExternal
+		: Asn1Object
+	{
+		private DerObjectIdentifier	directReference;
+		private DerInteger			indirectReference;
+		private Asn1Object			dataValueDescriptor;
+		private int					encoding;
+		private Asn1Object			externalContent;
+
+		public DerExternal(
+			Asn1EncodableVector vector)
+		{
+			int offset = 0;
+			Asn1Object enc = GetObjFromVector(vector, offset);
+			if (enc is DerObjectIdentifier)
+			{
+				directReference = (DerObjectIdentifier)enc;
+				offset++;
+				enc = GetObjFromVector(vector, offset);
+			}
+			if (enc is DerInteger)
+			{
+				indirectReference = (DerInteger) enc;
+				offset++;
+				enc = GetObjFromVector(vector, offset);
+			}
+			if (!(enc is DerTaggedObject))
+			{
+				dataValueDescriptor = (Asn1Object) enc;
+				offset++;
+				enc = GetObjFromVector(vector, offset);
+			}
+			if (!(enc is DerTaggedObject))
+			{
+				throw new InvalidOperationException(
+					"No tagged object found in vector. Structure doesn't seem to be of type External");
+			}
+
+			if (vector.Count != offset + 1)
+				throw new ArgumentException("input vector too large", "vector");
+
+			if (!(enc is DerTaggedObject))
+				throw new ArgumentException("No tagged object found in vector. Structure doesn't seem to be of type External", "vector");
+
+			DerTaggedObject obj = (DerTaggedObject)enc;
+
+			// Use property accessor to include check on value
+			Encoding = obj.TagNo;
+
+			if (encoding < 0 || encoding > 2)
+				throw new InvalidOperationException("invalid encoding value");
+
+			externalContent = obj.GetObject();
+		}
+
+		/**
+		* Creates a new instance of DerExternal
+		* See X.690 for more informations about the meaning of these parameters
+		* @param directReference The direct reference or <code>null</code> if not set.
+		* @param indirectReference The indirect reference or <code>null</code> if not set.
+		* @param dataValueDescriptor The data value descriptor or <code>null</code> if not set.
+		* @param externalData The external data in its encoded form.
+		*/
+		public DerExternal(DerObjectIdentifier directReference, DerInteger indirectReference, Asn1Object dataValueDescriptor, DerTaggedObject externalData)
+			: this(directReference, indirectReference, dataValueDescriptor, externalData.TagNo, externalData.ToAsn1Object())
+		{
+		}
+
+		/**
+		* Creates a new instance of DerExternal.
+		* See X.690 for more informations about the meaning of these parameters
+		* @param directReference The direct reference or <code>null</code> if not set.
+		* @param indirectReference The indirect reference or <code>null</code> if not set.
+		* @param dataValueDescriptor The data value descriptor or <code>null</code> if not set.
+		* @param encoding The encoding to be used for the external data
+		* @param externalData The external data
+		*/
+		public DerExternal(DerObjectIdentifier directReference, DerInteger indirectReference, Asn1Object dataValueDescriptor, int encoding, Asn1Object externalData)
+		{
+			DirectReference = directReference;
+			IndirectReference = indirectReference;
+			DataValueDescriptor = dataValueDescriptor;
+			Encoding = encoding;
+			ExternalContent = externalData.ToAsn1Object();
+		}
+
+		internal override void Encode(DerOutputStream derOut)
+		{
+			MemoryStream ms = new MemoryStream();
+			WriteEncodable(ms, directReference);
+			WriteEncodable(ms, indirectReference);
+			WriteEncodable(ms, dataValueDescriptor);
+			WriteEncodable(ms, new DerTaggedObject(Asn1Tags.External, externalContent));
+
+			derOut.WriteEncoded(Asn1Tags.Constructed, Asn1Tags.External, ms.ToArray());
+		}
+
+		protected override int Asn1GetHashCode()
+		{
+			int ret = externalContent.GetHashCode();
+			if (directReference != null)
+			{
+				ret ^= directReference.GetHashCode();
+			}
+			if (indirectReference != null)
+			{
+				ret ^= indirectReference.GetHashCode();
+			}
+			if (dataValueDescriptor != null)
+			{
+				ret ^= dataValueDescriptor.GetHashCode();
+			}
+			return ret;
+		}
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			if (this == asn1Object)
+				return true;
+
+			DerExternal other = asn1Object as DerExternal;
+
+			if (other == null)
+				return false;
+
+			return Platform.Equals(directReference, other.directReference)
+				&& Platform.Equals(indirectReference, other.indirectReference)
+				&& Platform.Equals(dataValueDescriptor, other.dataValueDescriptor)
+				&& externalContent.Equals(other.externalContent);
+		}
+
+		public Asn1Object DataValueDescriptor
+		{
+			get { return dataValueDescriptor; }
+			set { this.dataValueDescriptor = value; }
+		}
+
+		public DerObjectIdentifier DirectReference
+		{
+			get { return directReference; }
+			set { this.directReference = value; }
+		}
+
+		/**
+		* The encoding of the content. Valid values are
+		* <ul>
+		* <li><code>0</code> single-ASN1-type</li>
+		* <li><code>1</code> OCTET STRING</li>
+		* <li><code>2</code> BIT STRING</li>
+		* </ul>
+		*/
+		public int Encoding
+		{
+			get
+			{
+				return encoding;
+			}
+			set
+			{
+				if (encoding < 0 || encoding > 2)
+					throw new InvalidOperationException("invalid encoding value: " + encoding);
+
+				this.encoding = value;
+			}
+		}
+
+		public Asn1Object ExternalContent
+		{
+			get { return externalContent; }
+			set { this.externalContent = value; }
+		}
+
+		public DerInteger IndirectReference
+		{
+			get { return indirectReference; }
+			set { this.indirectReference = value; }
+		}
+
+		private static Asn1Object GetObjFromVector(Asn1EncodableVector v, int index)
+		{
+			if (v.Count <= index)
+				throw new ArgumentException("too few objects in input vector", "v");
+
+			return v[index].ToAsn1Object();
+		}
+
+		private static void WriteEncodable(MemoryStream ms, Asn1Encodable e)
+		{
+			if (e != null)
+			{
+				byte[] bs = e.GetDerEncoded();
+				ms.Write(bs, 0, bs.Length);
+			}
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DERExternalParser.cs b/Crypto/src/asn1/DERExternalParser.cs
new file mode 100644
index 000000000..70e426fed
--- /dev/null
+++ b/Crypto/src/asn1/DERExternalParser.cs
@@ -0,0 +1,26 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class DerExternalParser
+		: Asn1Encodable
+	{
+		private readonly Asn1StreamParser _parser;
+
+		public DerExternalParser(Asn1StreamParser parser)
+		{
+			this._parser = parser;
+		}
+
+		public IAsn1Convertible ReadObject()
+		{
+			return _parser.ReadObject();
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerExternal(_parser.ReadVector());
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DERGenerator.cs b/Crypto/src/asn1/DERGenerator.cs
new file mode 100644
index 000000000..aab40fefa
--- /dev/null
+++ b/Crypto/src/asn1/DERGenerator.cs
@@ -0,0 +1,107 @@
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public abstract class DerGenerator
+        : Asn1Generator
+    {
+        private bool _tagged = false;
+        private bool _isExplicit;
+        private int _tagNo;
+
+		protected DerGenerator(
+            Stream outStream)
+            : base(outStream)
+		{
+        }
+
+        protected DerGenerator(
+            Stream outStream,
+            int tagNo,
+            bool isExplicit)
+            : base(outStream)
+        {
+            _tagged = true;
+            _isExplicit = isExplicit;
+            _tagNo = tagNo;
+        }
+
+		private static void WriteLength(
+            Stream	outStr,
+            int		length)
+        {
+            if (length > 127)
+            {
+                int size = 1;
+                int val = length;
+
+				while ((val >>= 8) != 0)
+                {
+                    size++;
+                }
+
+				outStr.WriteByte((byte)(size | 0x80));
+
+				for (int i = (size - 1) * 8; i >= 0; i -= 8)
+                {
+                    outStr.WriteByte((byte)(length >> i));
+                }
+            }
+            else
+            {
+                outStr.WriteByte((byte)length);
+            }
+        }
+
+		internal static void WriteDerEncoded(
+            Stream	outStream,
+            int		tag,
+            byte[]	bytes)
+        {
+            outStream.WriteByte((byte) tag);
+            WriteLength(outStream, bytes.Length);
+            outStream.Write(bytes, 0, bytes.Length);
+        }
+
+		internal void WriteDerEncoded(
+            int		tag,
+            byte[]	bytes)
+        {
+            if (_tagged)
+            {
+                int tagNum = _tagNo | Asn1Tags.Tagged;
+
+                if (_isExplicit)
+                {
+                    int newTag = _tagNo | Asn1Tags.Constructed | Asn1Tags.Tagged;
+					MemoryStream bOut = new MemoryStream();
+                    WriteDerEncoded(bOut, tag, bytes);
+                    WriteDerEncoded(Out, newTag, bOut.ToArray());
+                }
+                else
+                {
+					if ((tag & Asn1Tags.Constructed) != 0)
+					{
+						tagNum |= Asn1Tags.Constructed;
+					}
+
+					WriteDerEncoded(Out, tagNum, bytes);
+                }
+            }
+            else
+            {
+                WriteDerEncoded(Out, tag, bytes);
+            }
+        }
+
+		internal static void WriteDerEncoded(
+            Stream	outStr,
+            int		tag,
+            Stream	inStr)
+        {
+			WriteDerEncoded(outStr, tag, Streams.ReadAll(inStr));
+        }
+    }
+}
diff --git a/Crypto/src/asn1/DEROctetStringParser.cs b/Crypto/src/asn1/DEROctetStringParser.cs
new file mode 100644
index 000000000..b0d3ad8cf
--- /dev/null
+++ b/Crypto/src/asn1/DEROctetStringParser.cs
@@ -0,0 +1,36 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class DerOctetStringParser
+		: Asn1OctetStringParser
+	{
+		private readonly DefiniteLengthInputStream stream;
+
+		internal DerOctetStringParser(
+			DefiniteLengthInputStream stream)
+		{
+			this.stream = stream;
+		}
+
+		public Stream GetOctetStream()
+		{
+			return stream;
+		}
+
+		public Asn1Object ToAsn1Object()
+		{
+			try
+			{
+				return new DerOctetString(stream.ToArray());
+			}
+			catch (IOException e)
+			{
+				throw new InvalidOperationException("IOException converting stream to byte array: " + e.Message, e);
+			}
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DERSequenceGenerator.cs b/Crypto/src/asn1/DERSequenceGenerator.cs
new file mode 100644
index 000000000..4c2bfd012
--- /dev/null
+++ b/Crypto/src/asn1/DERSequenceGenerator.cs
@@ -0,0 +1,40 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class DerSequenceGenerator
+		: DerGenerator
+	{
+		private readonly MemoryStream _bOut = new MemoryStream();
+
+		public DerSequenceGenerator(
+			Stream outStream)
+			: base(outStream)
+		{
+		}
+
+		public DerSequenceGenerator(
+			Stream	outStream,
+			int		tagNo,
+			bool	isExplicit)
+			: base(outStream, tagNo, isExplicit)
+		{
+		}
+
+		public override void AddObject(
+			Asn1Encodable obj)
+		{
+			new DerOutputStream(_bOut).WriteObject(obj);
+		}
+
+		public override Stream GetRawOutputStream()
+		{
+			return _bOut;
+		}
+
+		public override void Close()
+		{
+			WriteDerEncoded(Asn1Tags.Constructed | Asn1Tags.Sequence, _bOut.ToArray());
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DERSequenceParser.cs b/Crypto/src/asn1/DERSequenceParser.cs
new file mode 100644
index 000000000..69c2b9b2d
--- /dev/null
+++ b/Crypto/src/asn1/DERSequenceParser.cs
@@ -0,0 +1,24 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public class DerSequenceParser
+		: Asn1SequenceParser
+	{
+		private readonly Asn1StreamParser _parser;
+
+		internal DerSequenceParser(
+			Asn1StreamParser parser)
+		{
+			this._parser = parser;
+		}
+
+		public IAsn1Convertible ReadObject()
+		{
+			return _parser.ReadObject();
+		}
+
+		public Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(_parser.ReadVector());
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DERSetGenerator.cs b/Crypto/src/asn1/DERSetGenerator.cs
new file mode 100644
index 000000000..455ca88ac
--- /dev/null
+++ b/Crypto/src/asn1/DERSetGenerator.cs
@@ -0,0 +1,40 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class DerSetGenerator
+		: DerGenerator
+	{
+		private readonly MemoryStream _bOut = new MemoryStream();
+
+		public DerSetGenerator(
+			Stream outStream)
+			: base(outStream)
+		{
+		}
+
+		public DerSetGenerator(
+			Stream	outStream,
+			int		tagNo,
+			bool	isExplicit)
+			: base(outStream, tagNo, isExplicit)
+		{
+		}
+
+		public override void AddObject(
+			Asn1Encodable obj)
+		{
+			new DerOutputStream(_bOut).WriteObject(obj);
+		}
+
+		public override Stream GetRawOutputStream()
+		{
+			return _bOut;
+		}
+
+		public override void Close()
+		{
+			WriteDerEncoded(Asn1Tags.Constructed | Asn1Tags.Set, _bOut.ToArray());
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DERSetParser.cs b/Crypto/src/asn1/DERSetParser.cs
new file mode 100644
index 000000000..d67f135be
--- /dev/null
+++ b/Crypto/src/asn1/DERSetParser.cs
@@ -0,0 +1,24 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public class DerSetParser
+		: Asn1SetParser
+	{
+		private readonly Asn1StreamParser _parser;
+
+		internal DerSetParser(
+			Asn1StreamParser parser)
+		{
+			this._parser = parser;
+		}
+
+		public IAsn1Convertible ReadObject()
+		{
+			return _parser.ReadObject();
+		}
+
+		public Asn1Object ToAsn1Object()
+		{
+			return new DerSet(_parser.ReadVector(), false);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DefiniteLengthInputStream.cs b/Crypto/src/asn1/DefiniteLengthInputStream.cs
new file mode 100644
index 000000000..cfea89f21
--- /dev/null
+++ b/Crypto/src/asn1/DefiniteLengthInputStream.cs
@@ -0,0 +1,90 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+    class DefiniteLengthInputStream
+        : LimitedInputStream
+    {
+		private static readonly byte[] EmptyBytes = new byte[0];
+
+		private readonly int _originalLength;
+		private int _remaining;
+
+        internal DefiniteLengthInputStream(
+            Stream	inStream,
+            int		length)
+            : base(inStream, length)
+        {
+			if (length < 0)
+				throw new ArgumentException("negative lengths not allowed", "length");
+
+			this._originalLength = length;
+			this._remaining = length;
+
+			if (length == 0)
+			{
+				SetParentEofDetect(true);
+			}
+        }
+
+		internal int Remaining
+		{
+			get { return _remaining; }
+		}
+
+		public override int ReadByte()
+        {
+			if (_remaining == 0)
+				return -1;
+
+			int b = _in.ReadByte();
+
+			if (b < 0)
+				throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining);
+
+			if (--_remaining == 0)
+			{
+				SetParentEofDetect(true);
+			}
+
+			return b;
+        }
+
+		public override int Read(
+			byte[]	buf,
+			int		off,
+			int		len)
+		{
+			if (_remaining == 0)
+				return 0;
+
+			int toRead = System.Math.Min(len, _remaining);
+			int numRead = _in.Read(buf, off, toRead);
+
+			if (numRead < 1)
+				throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining);
+
+			if ((_remaining -= numRead) == 0)
+			{
+				SetParentEofDetect(true);
+			}
+
+			return numRead;
+		}
+
+		internal byte[] ToArray()
+		{
+			if (_remaining == 0)
+				return EmptyBytes;
+
+			byte[] bytes = new byte[_remaining];
+			if ((_remaining -= Streams.ReadFully(_in, bytes)) != 0)
+				throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining);
+			SetParentEofDetect(true);
+			return bytes;
+		}
+    }
+}
diff --git a/Crypto/src/asn1/DerApplicationSpecific.cs b/Crypto/src/asn1/DerApplicationSpecific.cs
new file mode 100644
index 000000000..394c7431e
--- /dev/null
+++ b/Crypto/src/asn1/DerApplicationSpecific.cs
@@ -0,0 +1,237 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Base class for an application specific object
+     */
+    public class DerApplicationSpecific
+        : Asn1Object
+    {
+		private readonly bool	isConstructed;
+        private readonly int	tag;
+        private readonly byte[]	octets;
+
+		internal DerApplicationSpecific(
+			bool	isConstructed,
+			int		tag,
+			byte[]	octets)
+		{
+			this.isConstructed = isConstructed;
+			this.tag = tag;
+			this.octets = octets;
+		}
+
+		public DerApplicationSpecific(
+            int		tag,
+            byte[]	octets)
+			: this(false, tag, octets)
+        {
+        }
+
+		public DerApplicationSpecific(
+			int				tag, 
+			Asn1Encodable	obj) 
+			: this(true, tag, obj)
+		{
+		}
+
+		public DerApplicationSpecific(
+			bool			isExplicit,
+			int				tag,
+			Asn1Encodable	obj)
+		{
+            Asn1Object asn1Obj = obj.ToAsn1Object();
+
+            byte[] data = asn1Obj.GetDerEncoded();
+
+			this.isConstructed = isExplicit || asn1Obj is Asn1Set || asn1Obj is Asn1Sequence;
+			this.tag = tag;
+
+			if (isExplicit)
+			{
+				this.octets = data;
+			}
+			else
+			{
+				int lenBytes = GetLengthOfHeader(data);
+				byte[] tmp = new byte[data.Length - lenBytes];
+				Array.Copy(data, lenBytes, tmp, 0, tmp.Length);
+				this.octets = tmp;
+			}
+		}
+
+		public DerApplicationSpecific(
+			int					tagNo,
+			Asn1EncodableVector	vec)
+		{
+			this.tag = tagNo;
+			this.isConstructed = true;
+			MemoryStream bOut = new MemoryStream();
+
+			for (int i = 0; i != vec.Count; i++)
+			{
+				try
+				{
+					byte[] bs = vec[i].GetDerEncoded();
+					bOut.Write(bs, 0, bs.Length);
+                }
+				catch (IOException e)
+				{
+					throw new InvalidOperationException("malformed object", e);
+				}
+			}
+			this.octets = bOut.ToArray();
+		}
+
+		private int GetLengthOfHeader(
+			byte[] data)
+		{
+            int length = data[1]; // TODO: assumes 1 byte tag
+
+            if (length == 0x80)
+            {
+                return 2;      // indefinite-length encoding
+            }
+
+            if (length > 127)
+            {
+                int size = length & 0x7f;
+
+                // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
+                if (size > 4)
+                {
+                    throw new InvalidOperationException("DER length more than 4 bytes: " + size);
+                }
+
+                return size + 2;
+            }
+
+            return 2;
+        }
+
+		public bool IsConstructed()
+        {
+			return isConstructed;
+        }
+
+		public byte[] GetContents()
+        {
+            return octets;
+        }
+
+		public int ApplicationTag
+        {
+            get { return tag; }
+        }
+
+		/**
+		 * Return the enclosed object assuming explicit tagging.
+		 *
+		 * @return  the resulting object
+		 * @throws IOException if reconstruction fails.
+		 */
+		public Asn1Object GetObject()
+        {
+			return FromByteArray(GetContents());
+		}
+
+		/**
+		 * Return the enclosed object assuming implicit tagging.
+		 *
+		 * @param derTagNo the type tag that should be applied to the object's contents.
+		 * @return  the resulting object
+		 * @throws IOException if reconstruction fails.
+		 */
+		public Asn1Object GetObject(
+			int derTagNo)
+		{
+			if (derTagNo >= 0x1f)
+				throw new IOException("unsupported tag number");
+
+			byte[] orig = this.GetEncoded();
+			byte[] tmp = ReplaceTagNumber(derTagNo, orig);
+
+			if ((orig[0] & Asn1Tags.Constructed) != 0)
+			{
+				tmp[0] |= Asn1Tags.Constructed;
+			}
+
+			return FromByteArray(tmp);;
+		}
+
+		internal override void Encode(
+			DerOutputStream derOut)
+        {
+			int classBits = Asn1Tags.Application;
+			if (isConstructed)
+			{
+				classBits |= Asn1Tags.Constructed; 
+			}
+
+			derOut.WriteEncoded(classBits, tag, octets);
+		}
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+        {
+			DerApplicationSpecific other = asn1Object as DerApplicationSpecific;
+
+			if (other == null)
+				return false;
+
+			return this.isConstructed == other.isConstructed
+				&& this.tag == other.tag
+				&& Arrays.AreEqual(this.octets, other.octets);
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+			return isConstructed.GetHashCode() ^ tag.GetHashCode() ^ Arrays.GetHashCode(octets);
+        }
+
+		private byte[] ReplaceTagNumber(
+			int		newTag,
+			byte[]	input)
+		{
+			int tagNo = input[0] & 0x1f;
+			int index = 1;
+			//
+			// with tagged object tag number is bottom 5 bits, or stored at the start of the content
+			//
+			if (tagNo == 0x1f)
+			{
+				tagNo = 0;
+
+				int b = input[index++] & 0xff;
+
+				// X.690-0207 8.1.2.4.2
+				// "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
+				if ((b & 0x7f) == 0) // Note: -1 will pass
+				{
+					throw new InvalidOperationException("corrupted stream - invalid high tag number found");
+				}
+
+				while ((b >= 0) && ((b & 0x80) != 0))
+				{
+					tagNo |= (b & 0x7f);
+					tagNo <<= 7;
+					b = input[index++] & 0xff;
+				}
+
+				tagNo |= (b & 0x7f);
+			}
+
+			byte[] tmp = new byte[input.Length - index + 1];
+
+			Array.Copy(input, index, tmp, 1, tmp.Length - 1);
+
+			tmp[0] = (byte)newTag;
+
+			return tmp;
+		}
+    }
+}
diff --git a/Crypto/src/asn1/DerBMPString.cs b/Crypto/src/asn1/DerBMPString.cs
new file mode 100644
index 000000000..4f7e0a635
--- /dev/null
+++ b/Crypto/src/asn1/DerBMPString.cs
@@ -0,0 +1,115 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Der BMPString object.
+     */
+    public class DerBmpString
+		: DerStringBase
+    {
+        private readonly string str;
+
+		/**
+         * return a BMP string from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerBmpString GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerBmpString)
+            {
+                return (DerBmpString)obj;
+            }
+
+			throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return a BMP string from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *              be converted.
+         */
+        public static DerBmpString GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerBmpString)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerBmpString(Asn1OctetString.GetInstance(o).GetOctets());
+        }
+
+		/**
+         * basic constructor - byte encoded string.
+         */
+        public DerBmpString(
+            byte[] str)
+        {
+			if (str == null)
+				throw new ArgumentNullException("str");
+
+            char[] cs = new char[str.Length / 2];
+
+			for (int i = 0; i != cs.Length; i++)
+            {
+                cs[i] = (char)((str[2 * i] << 8) | (str[2 * i + 1] & 0xff));
+            }
+
+			this.str = new string(cs);
+        }
+
+        /**
+         * basic constructor
+         */
+        public DerBmpString(
+            string str)
+        {
+			if (str == null)
+				throw new ArgumentNullException("str");
+
+			this.str = str;
+        }
+
+        public override string GetString()
+        {
+            return str;
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+        {
+			DerBmpString other = asn1Object as DerBmpString;
+
+			if (other == null)
+				return false;
+
+			return this.str.Equals(other.str);
+        }
+
+		internal override void Encode(
+            DerOutputStream derOut)
+        {
+            char[] c = str.ToCharArray();
+            byte[] b = new byte[c.Length * 2];
+
+			for (int i = 0; i != c.Length; i++)
+            {
+                b[2 * i] = (byte)(c[i] >> 8);
+                b[2 * i + 1] = (byte)c[i];
+            }
+
+            derOut.WriteEncoded(Asn1Tags.BmpString, b);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/DerBitString.cs b/Crypto/src/asn1/DerBitString.cs
new file mode 100644
index 000000000..d5cb872bc
--- /dev/null
+++ b/Crypto/src/asn1/DerBitString.cs
@@ -0,0 +1,248 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class DerBitString
+		: DerStringBase
+	{
+		private static readonly char[] table
+			= { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+		private readonly byte[]	data;
+		private readonly int	padBits;
+
+		/**
+		 * return the correct number of pad bits for a bit string defined in
+		 * a 32 bit constant
+		 */
+		static internal int GetPadBits(
+			int bitString)
+		{
+			int val = 0;
+			for (int i = 3; i >= 0; i--)
+			{
+				//
+				// this may look a little odd, but if it isn't done like this pre jdk1.2
+				// JVM's break!
+				//
+				if (i != 0)
+				{
+					if ((bitString >> (i * 8)) != 0)
+					{
+						val = (bitString >> (i * 8)) & 0xFF;
+						break;
+					}
+				}
+				else
+				{
+					if (bitString != 0)
+					{
+						val = bitString & 0xFF;
+						break;
+					}
+				}
+			}
+
+			if (val == 0)
+			{
+				return 7;
+			}
+
+			int bits = 1;
+
+			while (((val <<= 1) & 0xFF) != 0)
+			{
+				bits++;
+			}
+
+			return 8 - bits;
+		}
+
+		/**
+		 * return the correct number of bytes for a bit string defined in
+		 * a 32 bit constant
+		 */
+		static internal byte[] GetBytes(
+			int bitString)
+		{
+			int bytes = 4;
+			for (int i = 3; i >= 1; i--)
+			{
+				if ((bitString & (0xFF << (i * 8))) != 0)
+				{
+					break;
+				}
+				bytes--;
+			}
+
+			byte[] result = new byte[bytes];
+			for (int i = 0; i < bytes; i++)
+			{
+				result[i] = (byte) ((bitString >> (i * 8)) & 0xFF);
+			}
+
+			return result;
+		}
+
+		/**
+		 * return a Bit string from the passed in object
+		 *
+		 * @exception ArgumentException if the object cannot be converted.
+		 */
+		public static DerBitString GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is DerBitString)
+			{
+				return (DerBitString) obj;
+			}
+
+			throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+		}
+
+		/**
+		 * return a Bit string from a tagged object.
+		 *
+		 * @param obj the tagged object holding the object we want
+		 * @param explicitly true if the object is meant to be explicitly
+		 *              tagged false otherwise.
+		 * @exception ArgumentException if the tagged object cannot
+		 *               be converted.
+		 */
+		public static DerBitString GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerBitString)
+			{
+				return GetInstance(o);
+			}
+
+			return FromAsn1Octets(((Asn1OctetString)o).GetOctets());
+		}
+
+		internal DerBitString(
+			byte	data,
+			int		padBits)
+		{
+			this.data = new byte[]{ data };
+			this.padBits = padBits;
+		}
+
+		/**
+		 * @param data the octets making up the bit string.
+		 * @param padBits the number of extra bits at the end of the string.
+		 */
+		public DerBitString(
+			byte[]	data,
+			int		padBits)
+		{
+			// TODO Deep copy?
+			this.data = data;
+			this.padBits = padBits;
+		}
+
+		public DerBitString(
+			byte[] data)
+		{
+			// TODO Deep copy?
+			this.data = data;
+		}
+
+		public DerBitString(
+			Asn1Encodable obj)
+		{
+			this.data = obj.GetDerEncoded();
+			//this.padBits = 0;
+		}
+
+		public byte[] GetBytes()
+		{
+			return data;
+		}
+
+		public int PadBits
+		{
+			get { return padBits; }
+		}
+
+		/**
+		 * @return the value of the bit string as an int (truncating if necessary)
+		 */
+		public int IntValue
+		{
+			get
+			{
+				int value = 0;
+
+				for (int i = 0; i != data.Length && i != 4; i++)
+				{
+					value |= (data[i] & 0xff) << (8 * i);
+				}
+
+				return value;
+			}
+		}
+
+		internal override void Encode(
+			DerOutputStream derOut)
+		{
+			byte[] bytes = new byte[GetBytes().Length + 1];
+
+			bytes[0] = (byte) PadBits;
+			Array.Copy(GetBytes(), 0, bytes, 1, bytes.Length - 1);
+
+			derOut.WriteEncoded(Asn1Tags.BitString, bytes);
+		}
+
+		protected override int Asn1GetHashCode()
+		{
+			return padBits.GetHashCode() ^ Arrays.GetHashCode(data);
+		}
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerBitString other = asn1Object as DerBitString;
+
+			if (other == null)
+				return false;
+
+			return this.padBits == other.padBits
+				&& Arrays.AreEqual(this.data, other.data);
+		}
+
+		public override string GetString()
+		{
+			StringBuilder buffer = new StringBuilder("#");
+
+			byte[] str = GetDerEncoded();
+
+			for (int i = 0; i != str.Length; i++)
+			{
+				uint ubyte = str[i];
+				buffer.Append(table[(ubyte >> 4) & 0xf]);
+				buffer.Append(table[str[i] & 0xf]);
+			}
+
+			return buffer.ToString();
+		}
+
+		internal static DerBitString FromAsn1Octets(byte[] octets)
+		{
+	        if (octets.Length < 1)
+	            throw new ArgumentException("truncated BIT STRING detected");
+
+			int padBits = octets[0];
+			byte[] data = new byte[octets.Length - 1];
+			Array.Copy(octets, 1, data, 0, data.Length);
+			return new DerBitString(data, padBits);
+		}
+	}
+}
+
diff --git a/Crypto/src/asn1/DerBoolean.cs b/Crypto/src/asn1/DerBoolean.cs
new file mode 100644
index 000000000..41ccae8a1
--- /dev/null
+++ b/Crypto/src/asn1/DerBoolean.cs
@@ -0,0 +1,110 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public class DerBoolean
+        : Asn1Object
+    {
+        private readonly byte value;
+
+		public static readonly DerBoolean False = new DerBoolean(false);
+        public static readonly DerBoolean True  = new DerBoolean(true);
+
+		/**
+         * return a bool from the passed in object.
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerBoolean GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerBoolean)
+            {
+                return (DerBoolean) obj;
+            }
+
+			throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+		/**
+         * return a DerBoolean from the passed in bool.
+         */
+        public static DerBoolean GetInstance(
+            bool value)
+        {
+            return value ? True : False;
+        }
+
+		/**
+         * return a Boolean from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerBoolean GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerBoolean)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerBoolean(((Asn1OctetString)o).GetOctets());
+        }
+
+		public DerBoolean(
+            byte[] val)
+        {
+			if (val.Length != 1)
+				throw new ArgumentException("byte value should have 1 byte in it", "val");
+
+			// TODO Are there any constraints on the possible byte values?
+            this.value = val[0];
+        }
+
+		private DerBoolean(
+            bool value)
+        {
+            this.value = value ? (byte)0xff : (byte)0;
+        }
+
+		public bool IsTrue
+		{
+			get { return value != 0; }
+		}
+
+		internal override void Encode(
+            DerOutputStream derOut)
+        {
+			// TODO Should we make sure the byte value is one of '0' or '0xff' here?
+			derOut.WriteEncoded(Asn1Tags.Boolean, new byte[]{ value });
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+        {
+			DerBoolean other = asn1Object as DerBoolean;
+
+			if (other == null)
+				return false;
+
+			return IsTrue == other.IsTrue;
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+			return IsTrue.GetHashCode();
+        }
+
+		public override string ToString()
+		{
+			return IsTrue ? "TRUE" : "FALSE";
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DerEnumerated.cs b/Crypto/src/asn1/DerEnumerated.cs
new file mode 100644
index 000000000..0e67e6dbe
--- /dev/null
+++ b/Crypto/src/asn1/DerEnumerated.cs
@@ -0,0 +1,100 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public class DerEnumerated
+        : Asn1Object
+    {
+        private readonly byte[] bytes;
+
+		/**
+         * return an integer from the passed in object
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerEnumerated GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerEnumerated)
+            {
+                return (DerEnumerated)obj;
+            }
+
+            throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return an Enumerated from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerEnumerated GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerEnumerated)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerEnumerated(((Asn1OctetString)o).GetOctets());
+        }
+
+        public DerEnumerated(
+            int val)
+        {
+            bytes = BigInteger.ValueOf(val).ToByteArray();
+        }
+
+        public DerEnumerated(
+            BigInteger val)
+        {
+            bytes = val.ToByteArray();
+        }
+
+        public DerEnumerated(
+            byte[]   bytes)
+        {
+            this.bytes = bytes;
+        }
+
+        public BigInteger Value
+        {
+            get
+            {
+                return new BigInteger(bytes);
+            }
+        }
+
+		internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.Enumerated, bytes);
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+        {
+			DerEnumerated other = asn1Object as DerEnumerated;
+
+			if (other == null)
+				return false;
+
+			return Arrays.AreEqual(this.bytes, other.bytes);
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+			return Arrays.GetHashCode(bytes);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/DerGeneralString.cs b/Crypto/src/asn1/DerGeneralString.cs
new file mode 100644
index 000000000..0e20b53bd
--- /dev/null
+++ b/Crypto/src/asn1/DerGeneralString.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public class DerGeneralString
+        : DerStringBase
+    {
+        private readonly string str;
+
+        public static DerGeneralString GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerGeneralString)
+            {
+                return (DerGeneralString) obj;
+            }
+
+			throw new ArgumentException("illegal object in GetInstance: "
+                    + obj.GetType().Name);
+        }
+
+        public static DerGeneralString GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerGeneralString)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerGeneralString(((Asn1OctetString)o).GetOctets());
+        }
+
+        public DerGeneralString(
+			byte[] str)
+			: this(Strings.FromAsciiByteArray(str))
+        {
+        }
+
+		public DerGeneralString(
+			string str)
+        {
+			if (str == null)
+				throw new ArgumentNullException("str");
+
+			this.str = str;
+        }
+
+        public override string GetString()
+        {
+            return str;
+        }
+
+		public byte[] GetOctets()
+        {
+            return Strings.ToAsciiByteArray(str);
+        }
+
+		internal override void Encode(
+			DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.GeneralString, GetOctets());
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+        {
+			DerGeneralString other = asn1Object as DerGeneralString;
+
+			if (other == null)
+				return false;
+
+			return this.str.Equals(other.str);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/DerGeneralizedTime.cs b/Crypto/src/asn1/DerGeneralizedTime.cs
new file mode 100644
index 000000000..0a0e6fd7c
--- /dev/null
+++ b/Crypto/src/asn1/DerGeneralizedTime.cs
@@ -0,0 +1,305 @@
+using System;
+using System.Globalization;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Generalized time object.
+     */
+    public class DerGeneralizedTime
+        : Asn1Object
+    {
+        private readonly string time;
+
+		/**
+         * return a generalized time from the passed in object
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerGeneralizedTime GetInstance(
+            object obj)
+        {
+			if (obj == null || obj is DerGeneralizedTime)
+            {
+                return (DerGeneralizedTime)obj;
+            }
+
+			throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name, "obj");
+        }
+
+		/**
+         * return a Generalized Time object from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerGeneralizedTime GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerGeneralizedTime)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerGeneralizedTime(((Asn1OctetString)o).GetOctets());
+        }
+
+		/**
+		 * The correct format for this is YYYYMMDDHHMMSS[.f]Z, or without the Z
+		 * for local time, or Z+-HHMM on the end, for difference between local
+		 * time and UTC time. The fractional second amount f must consist of at
+		 * least one number with trailing zeroes removed.
+		 *
+		 * @param time the time string.
+		 * @exception ArgumentException if string is an illegal format.
+		 */
+		public DerGeneralizedTime(
+			string time)
+		{
+			this.time = time;
+
+			try
+			{
+				ToDateTime();
+			}
+			catch (FormatException e)
+			{
+				throw new ArgumentException("invalid date string: " + e.Message);
+			}
+		}
+
+		/**
+         * base constructor from a local time object
+         */
+        public DerGeneralizedTime(
+            DateTime time)
+        {
+            this.time = time.ToString(@"yyyyMMddHHmmss\Z");
+        }
+
+		internal DerGeneralizedTime(
+            byte[] bytes)
+        {
+            //
+            // explicitly convert to characters
+            //
+            this.time = Strings.FromAsciiByteArray(bytes);
+        }
+
+		/**
+		 * Return the time.
+		 * @return The time string as it appeared in the encoded object.
+		 */
+		public string TimeString
+		{
+			get { return time; }
+		}
+
+		/**
+         * return the time - always in the form of
+         *  YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm).
+         * <p>
+         * Normally in a certificate we would expect "Z" rather than "GMT",
+         * however adding the "GMT" means we can just use:
+         * <pre>
+         *     dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
+         * </pre>
+         * To read in the time and Get a date which is compatible with our local
+         * time zone.</p>
+         */
+        public string GetTime()
+        {
+            //
+            // standardise the format.
+            //
+            if (time[time.Length - 1] == 'Z')
+            {
+                return time.Substring(0, time.Length - 1) + "GMT+00:00";
+            }
+            else
+            {
+                int signPos = time.Length - 5;
+                char sign = time[signPos];
+                if (sign == '-' || sign == '+')
+                {
+                    return time.Substring(0, signPos)
+                        + "GMT"
+                        + time.Substring(signPos, 3)
+                        + ":"
+                        + time.Substring(signPos + 3);
+                }
+                else
+                {
+                    signPos = time.Length - 3;
+                    sign = time[signPos];
+                    if (sign == '-' || sign == '+')
+                    {
+                        return time.Substring(0, signPos)
+                            + "GMT"
+                            + time.Substring(signPos)
+                            + ":00";
+                    }
+                }
+            }
+
+            return time + CalculateGmtOffset();
+        }
+
+		private string CalculateGmtOffset()
+		{
+			char sign = '+';
+            DateTime time = ToDateTime();
+
+#if (SILVERLIGHT || PORTABLE)
+            long offset = time.Ticks - time.ToUniversalTime().Ticks;
+			if (offset < 0)
+			{
+				sign = '-';
+				offset = -offset;
+			}
+			int hours = (int)(offset / TimeSpan.TicksPerHour);
+			int minutes = (int)(offset / TimeSpan.TicksPerMinute) % 60;
+#else
+            // Note: GetUtcOffset incorporates Daylight Savings offset
+			TimeSpan offset =  TimeZone.CurrentTimeZone.GetUtcOffset(time);
+			if (offset.CompareTo(TimeSpan.Zero) < 0)
+			{
+				sign = '-';
+				offset = offset.Duration();
+			}
+			int hours = offset.Hours;
+			int minutes = offset.Minutes;
+#endif
+
+			return "GMT" + sign + Convert(hours) + ":" + Convert(minutes);
+		}
+
+		private static string Convert(
+			int time)
+		{
+			if (time < 10)
+			{
+				return "0" + time;
+			}
+
+			return time.ToString();
+		}
+
+		public DateTime ToDateTime()
+		{
+			string formatStr;
+			string d = time;
+			bool makeUniversal = false;
+
+			if (d.EndsWith("Z"))
+			{
+				if (HasFractionalSeconds)
+				{
+					int fCount = d.Length - d.IndexOf('.') - 2;
+					formatStr = @"yyyyMMddHHmmss." + FString(fCount) + @"\Z";
+				}
+				else
+				{
+					formatStr = @"yyyyMMddHHmmss\Z";
+				}
+			}
+			else if (time.IndexOf('-') > 0 || time.IndexOf('+') > 0)
+			{
+				d = GetTime();
+				makeUniversal = true;
+
+				if (HasFractionalSeconds)
+				{
+					int fCount = d.IndexOf("GMT") - 1 - d.IndexOf('.');
+					formatStr = @"yyyyMMddHHmmss." + FString(fCount) + @"'GMT'zzz";
+				}
+				else
+				{
+					formatStr = @"yyyyMMddHHmmss'GMT'zzz";
+				}
+			}
+			else
+			{
+				if (HasFractionalSeconds)
+				{
+					int fCount = d.Length - 1 - d.IndexOf('.');
+					formatStr = @"yyyyMMddHHmmss." + FString(fCount);
+				}
+				else
+				{
+					formatStr = @"yyyyMMddHHmmss";
+				}
+
+				// TODO?
+//				dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID()));
+			}
+
+			return ParseDateString(d, formatStr, makeUniversal);
+		}
+
+		private string FString(
+			int count)
+		{
+			StringBuilder sb = new StringBuilder();
+			for (int i = 0; i < count; ++i)
+			{
+				sb.Append('f');
+			}
+			return sb.ToString();
+		}
+
+		private DateTime ParseDateString(
+			string	dateStr,
+			string	formatStr,
+			bool	makeUniversal)
+		{
+			DateTime dt = DateTime.ParseExact(
+				dateStr,
+				formatStr,
+				DateTimeFormatInfo.InvariantInfo);
+
+			return makeUniversal ? dt.ToUniversalTime() : dt;
+		}
+
+		private bool HasFractionalSeconds
+		{
+			get { return time.IndexOf('.') == 14; }
+		}
+
+		private byte[] GetOctets()
+        {
+            return Strings.ToAsciiByteArray(time);
+        }
+
+		internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.GeneralizedTime, GetOctets());
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+        {
+			DerGeneralizedTime other = asn1Object as DerGeneralizedTime;
+
+			if (other == null)
+				return false;
+
+			return this.time.Equals(other.time);
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+            return time.GetHashCode();
+        }
+    }
+}
diff --git a/Crypto/src/asn1/DerIA5String.cs b/Crypto/src/asn1/DerIA5String.cs
new file mode 100644
index 000000000..9fa2cba3c
--- /dev/null
+++ b/Crypto/src/asn1/DerIA5String.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Der IA5String object - this is an ascii string.
+     */
+    public class DerIA5String
+        : DerStringBase
+    {
+        private readonly string str;
+
+        /**
+         * return a IA5 string from the passed in object
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerIA5String GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerIA5String)
+            {
+                return (DerIA5String)obj;
+            }
+
+            throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return an IA5 string from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerIA5String GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerIA5String)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerIA5String(((Asn1OctetString)o).GetOctets());
+        }
+
+        /**
+         * basic constructor - with bytes.
+         */
+        public DerIA5String(
+            byte[] str)
+            : this(Strings.FromAsciiByteArray(str), false)
+        {
+        }
+
+		/**
+		* basic constructor - without validation.
+		*/
+		public DerIA5String(
+			string str)
+			: this(str, false)
+		{
+		}
+
+		/**
+		* Constructor with optional validation.
+		*
+		* @param string the base string to wrap.
+		* @param validate whether or not to check the string.
+		* @throws ArgumentException if validate is true and the string
+		* contains characters that should not be in an IA5String.
+		*/
+		public DerIA5String(
+			string	str,
+			bool	validate)
+		{
+			if (str == null)
+				throw new ArgumentNullException("str");
+			if (validate && !IsIA5String(str))
+				throw new ArgumentException("string contains illegal characters", "str");
+
+			this.str = str;
+		}
+
+		public override string GetString()
+        {
+            return str;
+        }
+
+		public byte[] GetOctets()
+        {
+            return Strings.ToAsciiByteArray(str);
+        }
+
+		internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.IA5String, GetOctets());
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+            return this.str.GetHashCode();
+        }
+
+		protected override bool Asn1Equals(
+            Asn1Object asn1Object)
+        {
+			DerIA5String other = asn1Object as DerIA5String;
+
+			if (other == null)
+				return false;
+
+			return this.str.Equals(other.str);
+        }
+
+		/**
+		 * return true if the passed in String can be represented without
+		 * loss as an IA5String, false otherwise.
+		 *
+		 * @return true if in printable set, false otherwise.
+		 */
+		public static bool IsIA5String(
+			string str)
+		{
+			foreach (char ch in str)
+			{
+				if (ch > 0x007f)
+				{
+					return false;
+				}
+			}
+
+			return true;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DerInteger.cs b/Crypto/src/asn1/DerInteger.cs
new file mode 100644
index 000000000..eb0614515
--- /dev/null
+++ b/Crypto/src/asn1/DerInteger.cs
@@ -0,0 +1,117 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public class DerInteger
+        : Asn1Object
+    {
+        private readonly byte[] bytes;
+
+        /**
+         * return an integer from the passed in object
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerInteger GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerInteger)
+            {
+                return (DerInteger)obj;
+            }
+
+			throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return an Integer from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param isExplicit true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerInteger GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+            if (obj == null)
+                throw new ArgumentNullException("obj");
+
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerInteger)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerInteger(Asn1OctetString.GetInstance(o).GetOctets());
+        }
+
+		public DerInteger(
+            int value)
+        {
+            bytes = BigInteger.ValueOf(value).ToByteArray();
+        }
+
+		public DerInteger(
+            BigInteger value)
+        {
+            if (value == null)
+                throw new ArgumentNullException("value");
+
+			bytes = value.ToByteArray();
+        }
+
+		public DerInteger(
+            byte[] bytes)
+        {
+            this.bytes = bytes;
+        }
+
+		public BigInteger Value
+        {
+            get { return new BigInteger(bytes); }
+        }
+
+		/**
+         * in some cases positive values Get crammed into a space,
+         * that's not quite big enough...
+         */
+        public BigInteger PositiveValue
+        {
+            get { return new BigInteger(1, bytes); }
+        }
+
+        internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.Integer, bytes);
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+			return Arrays.GetHashCode(bytes);
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerInteger other = asn1Object as DerInteger;
+
+			if (other == null)
+				return false;
+
+			return Arrays.AreEqual(this.bytes, other.bytes);
+        }
+
+		public override string ToString()
+		{
+			return Value.ToString();
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DerNull.cs b/Crypto/src/asn1/DerNull.cs
new file mode 100644
index 000000000..a802f6486
--- /dev/null
+++ b/Crypto/src/asn1/DerNull.cs
@@ -0,0 +1,41 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+	/**
+	 * A Null object.
+	 */
+	public class DerNull
+		: Asn1Null
+	{
+		public static readonly DerNull Instance = new DerNull(0);
+
+		byte[] zeroBytes = new byte[0];
+
+		[Obsolete("Use static Instance object")]
+		public DerNull()
+		{
+		}
+
+		protected internal DerNull(int dummy)
+		{
+		}
+
+		internal override void Encode(
+			DerOutputStream  derOut)
+		{
+			derOut.WriteEncoded(Asn1Tags.Null, zeroBytes);
+		}
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			return asn1Object is DerNull;
+		}
+
+		protected override int Asn1GetHashCode()
+		{
+			return -1;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DerNumericString.cs b/Crypto/src/asn1/DerNumericString.cs
new file mode 100644
index 000000000..6e2715a4d
--- /dev/null
+++ b/Crypto/src/asn1/DerNumericString.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Der NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }.
+     */
+    public class DerNumericString
+        : DerStringBase
+    {
+        private readonly string str;
+
+        /**
+         * return a Numeric string from the passed in object
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerNumericString GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerNumericString)
+            {
+                return (DerNumericString)obj;
+            }
+
+            throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return an Numeric string from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerNumericString GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerNumericString)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerNumericString(Asn1OctetString.GetInstance(o).GetOctets());
+        }
+
+		/**
+		 * basic constructor - with bytes.
+		 */
+		public DerNumericString(
+			byte[] str)
+            : this(Strings.FromAsciiByteArray(str), false)
+		{
+		}
+
+		/**
+		 * basic constructor -  without validation..
+		 */
+		public DerNumericString(
+			string str)
+			: this(str, false)
+		{
+		}
+
+		/**
+		* Constructor with optional validation.
+		*
+		* @param string the base string to wrap.
+		* @param validate whether or not to check the string.
+		* @throws ArgumentException if validate is true and the string
+		* contains characters that should not be in a NumericString.
+		*/
+		public DerNumericString(
+			string	str,
+			bool	validate)
+		{
+			if (str == null)
+				throw new ArgumentNullException("str");
+			if (validate && !IsNumericString(str))
+				throw new ArgumentException("string contains illegal characters", "str");
+
+			this.str = str;
+		}
+
+		public override string GetString()
+        {
+            return str;
+        }
+
+		public byte[] GetOctets()
+        {
+            return Strings.ToAsciiByteArray(str);
+        }
+
+		internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.NumericString, GetOctets());
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerNumericString other = asn1Object as DerNumericString;
+
+			if (other == null)
+				return false;
+
+			return this.str.Equals(other.str);
+        }
+
+		/**
+		 * Return true if the string can be represented as a NumericString ('0'..'9', ' ')
+		 *
+		 * @param str string to validate.
+		 * @return true if numeric, fale otherwise.
+		 */
+		public static bool IsNumericString(
+			string str)
+		{
+			foreach (char ch in str)
+			{
+				if (ch > 0x007f || (ch != ' ' && !char.IsDigit(ch)))
+					return false;
+			}
+
+			return true;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DerObjectIdentifier.cs b/Crypto/src/asn1/DerObjectIdentifier.cs
new file mode 100644
index 000000000..7dc963729
--- /dev/null
+++ b/Crypto/src/asn1/DerObjectIdentifier.cs
@@ -0,0 +1,242 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public class DerObjectIdentifier
+        : Asn1Object
+    {
+		private static readonly Regex OidRegex = new Regex(@"\A[0-2](\.[0-9]+)+\z");
+
+		private readonly string identifier;
+
+		/**
+         * return an Oid from the passed in object
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerObjectIdentifier GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerObjectIdentifier)
+            {
+                return (DerObjectIdentifier) obj;
+            }
+
+			throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name, "obj");
+        }
+
+		/**
+         * return an object Identifier from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerObjectIdentifier GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(obj.GetObject());
+        }
+
+		public DerObjectIdentifier(
+            string identifier)
+        {
+			if (identifier == null)
+				throw new ArgumentNullException("identifier");
+			if (!OidRegex.IsMatch(identifier))
+				throw new FormatException("string " + identifier + " not an OID");
+
+			this.identifier = identifier;
+        }
+
+		// TODO Change to ID?
+		public string Id
+        {
+            get { return identifier; }
+        }
+
+		public virtual DerObjectIdentifier Branch(string branchID)
+		{
+			return new DerObjectIdentifier(identifier + "." + branchID);
+		}
+
+        /**
+         * Return  true if this oid is an extension of the passed in branch, stem.
+         * @param stem the arc or branch that is a possible parent.
+         * @return  true if the branch is on the passed in stem, false otherwise.
+         */
+        public virtual bool On(DerObjectIdentifier stem)
+        {
+            string id = Id, stemId = stem.Id;
+            return id.Length > stemId.Length && id[stemId.Length] == '.' && id.StartsWith(stemId);
+        }
+
+        internal DerObjectIdentifier(
+            byte[] bytes)
+            : this(MakeOidStringFromBytes(bytes))
+        {
+        }
+
+		private void WriteField(
+            Stream	outputStream,
+            long	fieldValue)
+        {
+			byte[] result = new byte[9];
+			int pos = 8;
+			result[pos] = (byte)(fieldValue & 0x7f);
+			while (fieldValue >= (1L << 7))
+			{
+				fieldValue >>= 7;
+				result[--pos] = (byte)((fieldValue & 0x7f) | 0x80);
+			}
+			outputStream.Write(result, pos, 9 - pos);
+        }
+
+		private void WriteField(
+			Stream		outputStream,
+			BigInteger	fieldValue)
+		{
+			int byteCount = (fieldValue.BitLength + 6) / 7;
+			if (byteCount == 0)
+			{
+				outputStream.WriteByte(0);
+			}
+			else
+			{
+				BigInteger tmpValue = fieldValue;
+				byte[] tmp = new byte[byteCount];
+				for (int i = byteCount-1; i >= 0; i--)
+				{
+					tmp[i] = (byte) ((tmpValue.IntValue & 0x7f) | 0x80);
+					tmpValue = tmpValue.ShiftRight(7);
+				}
+				tmp[byteCount-1] &= 0x7f;
+				outputStream.Write(tmp, 0, tmp.Length);
+			}
+		}
+
+        internal override void Encode(
+            DerOutputStream derOut)
+        {
+            OidTokenizer tok = new OidTokenizer(identifier);
+            MemoryStream bOut = new MemoryStream();
+            DerOutputStream dOut = new DerOutputStream(bOut);
+
+			string token = tok.NextToken();
+            int first = int.Parse(token);
+
+			token = tok.NextToken();
+            int second = int.Parse(token);
+
+            WriteField(bOut, first * 40 + second);
+
+            while (tok.HasMoreTokens)
+            {
+				token = tok.NextToken();
+				if (token.Length < 18)
+				{
+					WriteField(bOut, Int64.Parse(token));
+				}
+				else
+				{
+					WriteField(bOut, new BigInteger(token));
+				}
+			}
+
+            dOut.Dispose();
+
+			derOut.WriteEncoded(Asn1Tags.ObjectIdentifier, bOut.ToArray());
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+            return identifier.GetHashCode();
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerObjectIdentifier other = asn1Object as DerObjectIdentifier;
+
+			if (other == null)
+				return false;
+
+			return this.identifier.Equals(other.identifier);
+        }
+
+		public override string ToString()
+		{
+			return identifier;
+		}
+
+		private static string MakeOidStringFromBytes(
+			byte[] bytes)
+		{
+			StringBuilder	objId = new StringBuilder();
+			long			value = 0;
+			BigInteger		bigValue = null;
+			bool			first = true;
+
+			for (int i = 0; i != bytes.Length; i++)
+			{
+				int b = bytes[i];
+
+				if (value < 0x80000000000000L)
+				{
+					value = value * 128 + (b & 0x7f);
+					if ((b & 0x80) == 0)             // end of number reached
+					{
+						if (first)
+						{
+							switch ((int)value / 40)
+							{
+								case 0:
+									objId.Append('0');
+									break;
+								case 1:
+									objId.Append('1');
+									value -= 40;
+									break;
+								default:
+									objId.Append('2');
+									value -= 80;
+									break;
+							}
+							first = false;
+						}
+
+						objId.Append('.');
+						objId.Append(value);
+						value = 0;
+					}
+				}
+				else
+				{
+					if (bigValue == null)
+					{
+						bigValue = BigInteger.ValueOf(value);
+					}
+					bigValue = bigValue.ShiftLeft(7);
+					bigValue = bigValue.Or(BigInteger.ValueOf(b & 0x7f));
+					if ((b & 0x80) == 0)
+					{
+						objId.Append('.');
+						objId.Append(bigValue);
+						bigValue = null;
+						value = 0;
+					}
+				}
+			}
+
+			return objId.ToString();
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DerOctetString.cs b/Crypto/src/asn1/DerOctetString.cs
new file mode 100644
index 000000000..c046c9402
--- /dev/null
+++ b/Crypto/src/asn1/DerOctetString.cs
@@ -0,0 +1,34 @@
+namespace Org.BouncyCastle.Asn1
+{
+    public class DerOctetString
+        : Asn1OctetString
+    {
+		/// <param name="str">The octets making up the octet string.</param>
+        public DerOctetString(
+			byte[] str)
+			: base(str)
+        {
+        }
+
+		public DerOctetString(
+			Asn1Encodable obj)
+			: base(obj)
+        {
+        }
+
+        internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.OctetString, str);
+        }
+
+		internal static void Encode(
+			DerOutputStream	derOut,
+			byte[]			bytes,
+			int				offset,
+			int				length)
+		{
+			derOut.WriteEncoded(Asn1Tags.OctetString, bytes, offset, length);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DerOutputStream.cs b/Crypto/src/asn1/DerOutputStream.cs
new file mode 100644
index 000000000..f95d123f9
--- /dev/null
+++ b/Crypto/src/asn1/DerOutputStream.cs
@@ -0,0 +1,160 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class DerOutputStream
+		: FilterStream
+	{
+		public DerOutputStream(Stream os)
+			: base(os)
+		{
+		}
+
+		private void WriteLength(
+			int length)
+		{
+			if (length > 127)
+			{
+				int size = 1;
+				uint val = (uint) length;
+
+				while ((val >>= 8) != 0)
+				{
+					size++;
+				}
+
+				WriteByte((byte)(size | 0x80));
+
+				for (int i = (size - 1) * 8; i >= 0; i -= 8)
+				{
+					WriteByte((byte)(length >> i));
+				}
+			}
+			else
+			{
+				WriteByte((byte)length);
+			}
+		}
+
+		internal void WriteEncoded(
+			int		tag,
+			byte[]	bytes)
+		{
+			WriteByte((byte) tag);
+			WriteLength(bytes.Length);
+			Write(bytes, 0, bytes.Length);
+		}
+
+		internal void WriteEncoded(
+			int		tag,
+			byte[]	bytes,
+			int		offset,
+			int		length)
+		{
+			WriteByte((byte) tag);
+			WriteLength(length);
+			Write(bytes, offset, length);
+		}
+
+		internal void WriteTag(
+			int	flags,
+			int	tagNo)
+		{
+			if (tagNo < 31)
+			{
+				WriteByte((byte)(flags | tagNo));
+			}
+			else
+			{
+				WriteByte((byte)(flags | 0x1f));
+				if (tagNo < 128)
+				{
+					WriteByte((byte)tagNo);
+				}
+				else
+				{
+					byte[] stack = new byte[5];
+					int pos = stack.Length;
+
+					stack[--pos] = (byte)(tagNo & 0x7F);
+
+					do
+					{
+						tagNo >>= 7;
+						stack[--pos] = (byte)(tagNo & 0x7F | 0x80);
+					}
+					while (tagNo > 127);
+
+					Write(stack, pos, stack.Length - pos);
+				}
+			}
+		}
+
+		internal void WriteEncoded(
+			int		flags,
+			int		tagNo,
+			byte[]	bytes)
+		{
+			WriteTag(flags, tagNo);
+			WriteLength(bytes.Length);
+			Write(bytes, 0, bytes.Length);
+		}
+
+		protected void WriteNull()
+		{
+			WriteByte(Asn1Tags.Null);
+			WriteByte(0x00);
+		}
+
+		[Obsolete("Use version taking an Asn1Encodable arg instead")]
+		public virtual void WriteObject(
+			object obj)
+		{
+			if (obj == null)
+			{
+				WriteNull();
+			}
+			else if (obj is Asn1Object)
+			{
+				((Asn1Object)obj).Encode(this);
+			}
+			else if (obj is Asn1Encodable)
+			{
+				((Asn1Encodable)obj).ToAsn1Object().Encode(this);
+			}
+			else
+			{
+				throw new IOException("object not Asn1Object");
+			}
+		}
+
+		public virtual void WriteObject(
+			Asn1Encodable obj)
+		{
+			if (obj == null)
+			{
+				WriteNull();
+			}
+			else
+			{
+				obj.ToAsn1Object().Encode(this);
+			}
+		}
+
+		public virtual void WriteObject(
+			Asn1Object obj)
+		{
+			if (obj == null)
+			{
+				WriteNull();
+			}
+			else
+			{
+				obj.Encode(this);
+			}
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DerPrintableString.cs b/Crypto/src/asn1/DerPrintableString.cs
new file mode 100644
index 000000000..cd2f46b48
--- /dev/null
+++ b/Crypto/src/asn1/DerPrintableString.cs
@@ -0,0 +1,163 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Der PrintableString object.
+     */
+    public class DerPrintableString
+        : DerStringBase
+    {
+        private readonly string str;
+
+		/**
+         * return a printable string from the passed in object.
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerPrintableString GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerPrintableString)
+            {
+                return (DerPrintableString)obj;
+            }
+
+            throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return a Printable string from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerPrintableString GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerPrintableString)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerPrintableString(Asn1OctetString.GetInstance(o).GetOctets());
+        }
+
+        /**
+         * basic constructor - byte encoded string.
+         */
+        public DerPrintableString(
+            byte[] str)
+            : this(Strings.FromAsciiByteArray(str), false)
+        {
+        }
+
+		/**
+		 * basic constructor - this does not validate the string
+		 */
+		public DerPrintableString(
+			string str)
+			: this(str, false)
+		{
+		}
+
+		/**
+		* Constructor with optional validation.
+		*
+		* @param string the base string to wrap.
+		* @param validate whether or not to check the string.
+		* @throws ArgumentException if validate is true and the string
+		* contains characters that should not be in a PrintableString.
+		*/
+		public DerPrintableString(
+			string	str,
+			bool	validate)
+		{
+			if (str == null)
+				throw new ArgumentNullException("str");
+			if (validate && !IsPrintableString(str))
+				throw new ArgumentException("string contains illegal characters", "str");
+
+			this.str = str;
+		}
+
+		public override string GetString()
+        {
+            return str;
+        }
+
+		public byte[] GetOctets()
+        {
+            return Strings.ToAsciiByteArray(str);
+        }
+
+		internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.PrintableString, GetOctets());
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerPrintableString other = asn1Object as DerPrintableString;
+
+			if (other == null)
+				return false;
+
+			return this.str.Equals(other.str);
+        }
+
+		/**
+		 * return true if the passed in String can be represented without
+		 * loss as a PrintableString, false otherwise.
+		 *
+		 * @return true if in printable set, false otherwise.
+		 */
+		public static bool IsPrintableString(
+			string str)
+		{
+			foreach (char ch in str)
+			{
+				if (ch > 0x007f)
+					return false;
+
+				if (char.IsLetterOrDigit(ch))
+					continue;
+
+//				if (char.IsPunctuation(ch))
+//					continue;
+
+				switch (ch)
+				{
+					case ' ':
+					case '\'':
+					case '(':
+					case ')':
+					case '+':
+					case '-':
+					case '.':
+					case ':':
+					case '=':
+					case '?':
+					case '/':
+					case ',':
+						continue;
+				}
+
+				return false;
+			}
+
+			return true;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DerSequence.cs b/Crypto/src/asn1/DerSequence.cs
new file mode 100644
index 000000000..dd67d2fed
--- /dev/null
+++ b/Crypto/src/asn1/DerSequence.cs
@@ -0,0 +1,85 @@
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class DerSequence
+		: Asn1Sequence
+	{
+		public static readonly DerSequence Empty = new DerSequence();
+
+		public static DerSequence FromVector(
+			Asn1EncodableVector v)
+		{
+			return v.Count < 1 ? Empty : new DerSequence(v);
+		}
+
+		/**
+		 * create an empty sequence
+		 */
+		public DerSequence()
+			: base(0)
+		{
+		}
+
+		/**
+		 * create a sequence containing one object
+		 */
+		public DerSequence(
+			Asn1Encodable obj)
+			: base(1)
+		{
+			AddObject(obj);
+		}
+
+		public DerSequence(
+			params Asn1Encodable[] v)
+			: base(v.Length)
+		{
+			foreach (Asn1Encodable ae in v)
+			{
+				AddObject(ae);
+			}
+		}
+
+		/**
+		 * create a sequence containing a vector of objects.
+		 */
+		public DerSequence(
+			Asn1EncodableVector v)
+			: base(v.Count)
+		{
+			foreach (Asn1Encodable ae in v)
+			{
+				AddObject(ae);
+			}
+		}
+
+		/*
+		 * A note on the implementation:
+		 * <p>
+		 * As Der requires the constructed, definite-length model to
+		 * be used for structured types, this varies slightly from the
+		 * ASN.1 descriptions given. Rather than just outputing Sequence,
+		 * we also have to specify Constructed, and the objects length.
+		 */
+		internal override void Encode(
+			DerOutputStream derOut)
+		{
+			// TODO Intermediate buffer could be avoided if we could calculate expected length
+			MemoryStream bOut = new MemoryStream();
+			DerOutputStream dOut = new DerOutputStream(bOut);
+
+			foreach (Asn1Encodable obj in this)
+			{
+				dOut.WriteObject(obj);
+			}
+
+			dOut.Dispose();
+
+			byte[] bytes = bOut.ToArray();
+
+			derOut.WriteEncoded(Asn1Tags.Sequence | Asn1Tags.Constructed, bytes);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DerSet.cs b/Crypto/src/asn1/DerSet.cs
new file mode 100644
index 000000000..6d3f438bd
--- /dev/null
+++ b/Crypto/src/asn1/DerSet.cs
@@ -0,0 +1,108 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	/**
+	 * A Der encoded set object
+	 */
+	public class DerSet
+		: Asn1Set
+	{
+		public static readonly DerSet Empty = new DerSet();
+
+		public static DerSet FromVector(
+			Asn1EncodableVector v)
+		{
+			return v.Count < 1 ? Empty : new DerSet(v);
+		}
+
+		internal static DerSet FromVector(
+			Asn1EncodableVector	v,
+			bool				needsSorting)
+		{
+			return v.Count < 1 ? Empty : new DerSet(v, needsSorting);
+		}
+
+		/**
+		 * create an empty set
+		 */
+		public DerSet()
+			: base(0)
+		{
+		}
+
+		/**
+		 * @param obj - a single object that makes up the set.
+		 */
+		public DerSet(
+			Asn1Encodable obj)
+			: base(1)
+		{
+			AddObject(obj);
+		}
+
+		public DerSet(
+			params Asn1Encodable[] v)
+			: base(v.Length)
+		{
+			foreach (Asn1Encodable o in v)
+			{
+				AddObject(o);
+			}
+
+			Sort();
+		}
+
+		/**
+		 * @param v - a vector of objects making up the set.
+		 */
+		public DerSet(
+			Asn1EncodableVector v)
+			: this(v, true)
+		{
+		}
+
+		internal DerSet(
+			Asn1EncodableVector	v,
+			bool				needsSorting)
+			: base(v.Count)
+		{
+			foreach (Asn1Encodable o in v)
+			{
+				AddObject(o);
+			}
+
+			if (needsSorting)
+			{
+				Sort();
+			}
+		}
+
+		/*
+		 * A note on the implementation:
+		 * <p>
+		 * As Der requires the constructed, definite-length model to
+		 * be used for structured types, this varies slightly from the
+		 * ASN.1 descriptions given. Rather than just outputing Set,
+		 * we also have to specify Constructed, and the objects length.
+		 */
+		internal override void Encode(
+			DerOutputStream derOut)
+		{
+			// TODO Intermediate buffer could be avoided if we could calculate expected length
+			MemoryStream bOut = new MemoryStream();
+			DerOutputStream dOut = new DerOutputStream(bOut);
+
+			foreach (Asn1Encodable obj in this)
+			{
+				dOut.WriteObject(obj);
+			}
+
+            dOut.Dispose();
+
+			byte[] bytes = bOut.ToArray();
+
+			derOut.WriteEncoded(Asn1Tags.Set | Asn1Tags.Constructed, bytes);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DerStringBase.cs b/Crypto/src/asn1/DerStringBase.cs
new file mode 100644
index 000000000..2a5fb041e
--- /dev/null
+++ b/Crypto/src/asn1/DerStringBase.cs
@@ -0,0 +1,22 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public abstract class DerStringBase
+		: Asn1Object, IAsn1String
+	{
+		protected DerStringBase()
+		{
+		}
+
+		public abstract string GetString();
+
+		public override string ToString()
+		{
+			return GetString();
+		}
+
+		protected override int Asn1GetHashCode()
+		{
+			return GetString().GetHashCode();
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DerT61String.cs b/Crypto/src/asn1/DerT61String.cs
new file mode 100644
index 000000000..4dee6f30c
--- /dev/null
+++ b/Crypto/src/asn1/DerT61String.cs
@@ -0,0 +1,102 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Der T61String (also the teletex string) - 8-bit characters
+     */
+    public class DerT61String
+        : DerStringBase
+    {
+		private readonly string str;
+
+		/**
+         * return a T61 string from the passed in object.
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerT61String GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerT61String)
+            {
+                return (DerT61String)obj;
+            }
+
+            throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return an T61 string from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerT61String GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerT61String)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerT61String(Asn1OctetString.GetInstance(o).GetOctets());
+        }
+
+        /**
+         * basic constructor - with bytes.
+         */
+        public DerT61String(
+            byte[] str)
+			: this(Strings.FromByteArray(str))
+		{
+        }
+
+		/**
+         * basic constructor - with string.
+         */
+        public DerT61String(
+            string str)
+        {
+			if (str == null)
+				throw new ArgumentNullException("str");
+
+			this.str = str;
+        }
+
+		public override string GetString()
+        {
+            return str;
+        }
+
+        internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.T61String, GetOctets());
+        }
+
+        public byte[] GetOctets()
+        {
+			return Strings.ToByteArray(str);
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerT61String other = asn1Object as DerT61String;
+
+			if (other == null)
+				return false;
+
+            return this.str.Equals(other.str);
+        }
+	}
+}
diff --git a/Crypto/src/asn1/DerTaggedObject.cs b/Crypto/src/asn1/DerTaggedObject.cs
new file mode 100644
index 000000000..717d724b6
--- /dev/null
+++ b/Crypto/src/asn1/DerTaggedObject.cs
@@ -0,0 +1,72 @@
+namespace Org.BouncyCastle.Asn1
+{
+	/**
+	 * DER TaggedObject - in ASN.1 notation this is any object preceded by
+	 * a [n] where n is some number - these are assumed to follow the construction
+	 * rules (as with sequences).
+	 */
+	public class DerTaggedObject
+		: Asn1TaggedObject
+	{
+		/**
+		 * @param tagNo the tag number for this object.
+		 * @param obj the tagged object.
+		 */
+		public DerTaggedObject(
+			int				tagNo,
+			Asn1Encodable	obj)
+			: base(tagNo, obj)
+		{
+		}
+
+		/**
+		 * @param explicitly true if an explicitly tagged object.
+		 * @param tagNo the tag number for this object.
+		 * @param obj the tagged object.
+		 */
+		public DerTaggedObject(
+			bool			explicitly,
+			int				tagNo,
+			Asn1Encodable	obj)
+			: base(explicitly, tagNo, obj)
+		{
+		}
+
+		/**
+		 * create an implicitly tagged object that contains a zero
+		 * length sequence.
+		 */
+		public DerTaggedObject(
+			int tagNo)
+			: base(false, tagNo, DerSequence.Empty)
+		{
+		}
+
+		internal override void Encode(
+			DerOutputStream derOut)
+		{
+			if (!IsEmpty())
+			{
+				byte[] bytes = obj.GetDerEncoded();
+
+				if (explicitly)
+				{
+					derOut.WriteEncoded(Asn1Tags.Constructed | Asn1Tags.Tagged, tagNo, bytes);
+				}
+				else
+				{
+					//
+					// need to mark constructed types... (preserve Constructed tag)
+					//
+					int flags = (bytes[0] & Asn1Tags.Constructed) | Asn1Tags.Tagged;
+					derOut.WriteTag(flags, tagNo);
+					derOut.Write(bytes, 1, bytes.Length - 1);
+				}
+			}
+			else
+			{
+				derOut.WriteEncoded(Asn1Tags.Constructed | Asn1Tags.Tagged, tagNo, new byte[0]);
+			}
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DerUTCTime.cs b/Crypto/src/asn1/DerUTCTime.cs
new file mode 100644
index 000000000..56fabeb47
--- /dev/null
+++ b/Crypto/src/asn1/DerUTCTime.cs
@@ -0,0 +1,263 @@
+using System;
+using System.Globalization;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * UTC time object.
+     */
+    public class DerUtcTime
+        : Asn1Object
+    {
+        private readonly string time;
+
+		/**
+         * return an UTC Time from the passed in object.
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerUtcTime GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerUtcTime)
+            {
+                return (DerUtcTime)obj;
+            }
+
+            throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return an UTC Time from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerUtcTime GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerUtcTime)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerUtcTime(((Asn1OctetString)o).GetOctets());
+        }
+
+        /**
+         * The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were
+         * never encoded. When you're creating one of these objects from scratch, that's
+         * what you want to use, otherwise we'll try to deal with whatever Gets read from
+         * the input stream... (this is why the input format is different from the GetTime()
+         * method output).
+         * <p>
+         * @param time the time string.</p>
+         */
+        public DerUtcTime(
+            string time)
+        {
+			if (time == null)
+				throw new ArgumentNullException("time");
+
+			this.time = time;
+
+			try
+			{
+				ToDateTime();
+			}
+			catch (FormatException e)
+			{
+				throw new ArgumentException("invalid date string: " + e.Message);
+			}
+        }
+
+		/**
+         * base constructor from a DateTime object
+         */
+        public DerUtcTime(
+            DateTime time)
+        {
+            this.time = time.ToString("yyMMddHHmmss") + "Z";
+        }
+
+		internal DerUtcTime(
+            byte[] bytes)
+        {
+            //
+            // explicitly convert to characters
+            //
+            this.time = Strings.FromAsciiByteArray(bytes);
+        }
+
+//		public DateTime ToDateTime()
+//		{
+//			string tm = this.AdjustedTimeString;
+//
+//			return new DateTime(
+//				Int16.Parse(tm.Substring(0, 4)),
+//				Int16.Parse(tm.Substring(4, 2)),
+//				Int16.Parse(tm.Substring(6, 2)),
+//				Int16.Parse(tm.Substring(8, 2)),
+//				Int16.Parse(tm.Substring(10, 2)),
+//				Int16.Parse(tm.Substring(12, 2)));
+//		}
+
+		/**
+		 * return the time as a date based on whatever a 2 digit year will return. For
+		 * standardised processing use ToAdjustedDateTime().
+		 *
+		 * @return the resulting date
+		 * @exception ParseException if the date string cannot be parsed.
+		 */
+		public DateTime ToDateTime()
+		{
+			return ParseDateString(TimeString, @"yyMMddHHmmss'GMT'zzz");
+		}
+
+		/**
+		* return the time as an adjusted date
+		* in the range of 1950 - 2049.
+		*
+		* @return a date in the range of 1950 to 2049.
+		* @exception ParseException if the date string cannot be parsed.
+		*/
+		public DateTime ToAdjustedDateTime()
+		{
+			return ParseDateString(AdjustedTimeString, @"yyyyMMddHHmmss'GMT'zzz");
+		}
+
+		private DateTime ParseDateString(
+			string	dateStr,
+			string	formatStr)
+		{
+			DateTime dt = DateTime.ParseExact(
+				dateStr,
+				formatStr,
+				DateTimeFormatInfo.InvariantInfo);
+
+			return dt.ToUniversalTime();
+		}
+
+		/**
+         * return the time - always in the form of
+         *  YYMMDDhhmmssGMT(+hh:mm|-hh:mm).
+         * <p>
+         * Normally in a certificate we would expect "Z" rather than "GMT",
+         * however adding the "GMT" means we can just use:
+         * <pre>
+         *     dateF = new SimpleDateFormat("yyMMddHHmmssz");
+         * </pre>
+         * To read in the time and Get a date which is compatible with our local
+         * time zone.</p>
+         * <p>
+         * <b>Note:</b> In some cases, due to the local date processing, this
+         * may lead to unexpected results. If you want to stick the normal
+         * convention of 1950 to 2049 use the GetAdjustedTime() method.</p>
+         */
+        public string TimeString
+        {
+			get
+			{
+				//
+				// standardise the format.
+				//
+				if (time.IndexOf('-') < 0 && time.IndexOf('+') < 0)
+				{
+					if (time.Length == 11)
+					{
+						return time.Substring(0, 10) + "00GMT+00:00";
+					}
+					else
+					{
+						return time.Substring(0, 12) + "GMT+00:00";
+					}
+				}
+				else
+				{
+					int index = time.IndexOf('-');
+					if (index < 0)
+					{
+						index = time.IndexOf('+');
+					}
+					string d = time;
+
+					if (index == time.Length - 3)
+					{
+						d += "00";
+					}
+
+					if (index == 10)
+					{
+						return d.Substring(0, 10) + "00GMT" + d.Substring(10, 3) + ":" + d.Substring(13, 2);
+					}
+					else
+					{
+						return d.Substring(0, 12) + "GMT" + d.Substring(12, 3) + ":" +  d.Substring(15, 2);
+					}
+				}
+			}
+        }
+
+		[Obsolete("Use 'AdjustedTimeString' property instead")]
+		public string AdjustedTime
+		{
+			get { return AdjustedTimeString; }
+		}
+
+		/// <summary>
+		/// Return a time string as an adjusted date with a 4 digit year.
+		/// This goes in the range of 1950 - 2049.
+		/// </summary>
+		public string AdjustedTimeString
+		{
+			get
+			{
+				string d = TimeString;
+				string c = d[0] < '5' ? "20" : "19";
+
+				return c + d;
+			}
+		}
+
+        private byte[] GetOctets()
+        {
+            return Strings.ToAsciiByteArray(time);
+        }
+
+		internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.UtcTime, GetOctets());
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerUtcTime other = asn1Object as DerUtcTime;
+
+			if (other == null)
+				return false;
+
+			return this.time.Equals(other.time);
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+            return time.GetHashCode();
+        }
+
+		public override string ToString()
+		{
+			return time;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DerUTF8String.cs b/Crypto/src/asn1/DerUTF8String.cs
new file mode 100644
index 000000000..92a50e824
--- /dev/null
+++ b/Crypto/src/asn1/DerUTF8String.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Der UTF8String object.
+     */
+    public class DerUtf8String
+        : DerStringBase
+    {
+        private readonly string str;
+
+		/**
+         * return an UTF8 string from the passed in object.
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerUtf8String GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerUtf8String)
+            {
+                return (DerUtf8String)obj;
+            }
+
+			throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return an UTF8 string from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerUtf8String GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerUtf8String)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerUtf8String(Asn1OctetString.GetInstance(o).GetOctets());
+        }
+
+        /**
+         * basic constructor - byte encoded string.
+         */
+        public DerUtf8String(
+            byte[] str)
+			: this(Encoding.UTF8.GetString(str, 0, str.Length))
+        {
+        }
+
+		/**
+         * basic constructor
+         */
+        public DerUtf8String(
+            string str)
+        {
+			if (str == null)
+				throw new ArgumentNullException("str");
+
+			this.str = str;
+        }
+
+		public override string GetString()
+        {
+            return str;
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerUtf8String other = asn1Object as DerUtf8String;
+
+			if (other == null)
+				return false;
+
+			return this.str.Equals(other.str);
+        }
+
+		internal override void Encode(
+			DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.Utf8String, Encoding.UTF8.GetBytes(str));
+        }
+    }
+}
diff --git a/Crypto/src/asn1/DerUniversalString.cs b/Crypto/src/asn1/DerUniversalString.cs
new file mode 100644
index 000000000..305102f2f
--- /dev/null
+++ b/Crypto/src/asn1/DerUniversalString.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Der UniversalString object.
+     */
+    public class DerUniversalString
+        : DerStringBase
+    {
+        private static readonly char[] table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+		private readonly byte[] str;
+
+		/**
+         * return a Universal string from the passed in object.
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerUniversalString GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerUniversalString)
+            {
+                return (DerUniversalString)obj;
+            }
+
+            throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return a Universal string from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerUniversalString GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerUniversalString)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerUniversalString(Asn1OctetString.GetInstance(o).GetOctets());
+        }
+
+        /**
+         * basic constructor - byte encoded string.
+         */
+        public DerUniversalString(
+            byte[] str)
+        {
+			if (str == null)
+				throw new ArgumentNullException("str");
+
+			this.str = str;
+        }
+
+        public override string GetString()
+        {
+			StringBuilder buffer = new StringBuilder("#");
+			byte[] enc = GetDerEncoded();
+
+			for (int i = 0; i != enc.Length; i++)
+			{
+				uint ubyte = enc[i];
+				buffer.Append(table[(ubyte >> 4) & 0xf]);
+				buffer.Append(table[enc[i] & 0xf]);
+			}
+
+            return buffer.ToString();
+        }
+
+		public byte[] GetOctets()
+        {
+            return (byte[]) str.Clone();
+        }
+
+		internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.UniversalString, this.str);
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerUniversalString other = asn1Object as DerUniversalString;
+
+			if (other == null)
+				return false;
+
+//			return this.GetString().Equals(other.GetString());
+			return Arrays.AreEqual(this.str, other.str);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/DerUnknownTag.cs b/Crypto/src/asn1/DerUnknownTag.cs
new file mode 100644
index 000000000..1e0e61495
--- /dev/null
+++ b/Crypto/src/asn1/DerUnknownTag.cs
@@ -0,0 +1,80 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * We insert one of these when we find a tag we don't recognise.
+     */
+    public class DerUnknownTag
+        : Asn1Object
+    {
+		private readonly bool	isConstructed;
+        private readonly int	tag;
+        private readonly byte[]	data;
+
+        /**
+         * @param tag the tag value.
+         * @param data the contents octets.
+         */
+        public DerUnknownTag(
+            int		tag,
+            byte[]	data)
+			: this(false, tag, data)
+        {
+        }
+
+		public DerUnknownTag(
+			bool	isConstructed,
+			int		tag,
+			byte[]	data)
+		{
+			if (data == null)
+				throw new ArgumentNullException("data");
+
+			this.isConstructed = isConstructed;
+			this.tag = tag;
+			this.data = data;
+		}
+
+		public bool IsConstructed
+		{
+			get { return isConstructed; }
+		}
+
+		public int Tag
+        {
+			get { return tag; }
+        }
+
+		public byte[] GetData()
+        {
+            return data;
+        }
+
+        internal override void Encode(
+            DerOutputStream derOut)
+        {
+			derOut.WriteEncoded(isConstructed ? Asn1Tags.Constructed : 0, tag, data);
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerUnknownTag other = asn1Object as DerUnknownTag;
+
+			if (other == null)
+				return false;
+
+			return this.isConstructed == other.isConstructed
+				&& this.tag == other.tag
+				&& Arrays.AreEqual(this.data, other.data);
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+			return isConstructed.GetHashCode() ^ tag.GetHashCode() ^ Arrays.GetHashCode(data);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/DerVisibleString.cs b/Crypto/src/asn1/DerVisibleString.cs
new file mode 100644
index 000000000..84c9caade
--- /dev/null
+++ b/Crypto/src/asn1/DerVisibleString.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Der VisibleString object.
+     */
+    public class DerVisibleString
+        : DerStringBase
+    {
+        private readonly string str;
+
+        /**
+         * return a Visible string from the passed in object.
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerVisibleString GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerVisibleString)
+            {
+                return (DerVisibleString)obj;
+            }
+
+            if (obj is Asn1OctetString)
+            {
+                return new DerVisibleString(((Asn1OctetString)obj).GetOctets());
+            }
+
+            if (obj is Asn1TaggedObject)
+            {
+                return GetInstance(((Asn1TaggedObject)obj).GetObject());
+            }
+
+            throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return a Visible string from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerVisibleString GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(obj.GetObject());
+        }
+
+        /**
+         * basic constructor - byte encoded string.
+         */
+        public DerVisibleString(
+            byte[] str)
+			: this(Strings.FromAsciiByteArray(str))
+        {
+        }
+
+		/**
+         * basic constructor
+         */
+        public DerVisibleString(
+            string str)
+        {
+			if (str == null)
+				throw new ArgumentNullException("str");
+
+			this.str = str;
+        }
+
+		public override string GetString()
+        {
+            return str;
+        }
+
+		public byte[] GetOctets()
+        {
+            return Strings.ToAsciiByteArray(str);
+        }
+
+		internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.VisibleString, GetOctets());
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerVisibleString other = asn1Object as DerVisibleString;
+
+			if (other == null)
+				return false;
+
+			return this.str.Equals(other.str);
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+            return this.str.GetHashCode();
+        }
+    }
+}
diff --git a/Crypto/src/asn1/IAsn1ApplicationSpecificParser.cs b/Crypto/src/asn1/IAsn1ApplicationSpecificParser.cs
new file mode 100644
index 000000000..89cf64c70
--- /dev/null
+++ b/Crypto/src/asn1/IAsn1ApplicationSpecificParser.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public interface IAsn1ApplicationSpecificParser
+    	: IAsn1Convertible
+	{
+    	IAsn1Convertible ReadObject();
+	}
+}
diff --git a/Crypto/src/asn1/IAsn1Choice.cs b/Crypto/src/asn1/IAsn1Choice.cs
new file mode 100644
index 000000000..ecd76e427
--- /dev/null
+++ b/Crypto/src/asn1/IAsn1Choice.cs
@@ -0,0 +1,17 @@
+
+namespace Org.BouncyCastle.Asn1
+{
+	/**
+	 * Marker interface for CHOICE objects - if you implement this in a roll-your-own
+	 * object, any attempt to tag the object implicitly will convert the tag to an
+	 * explicit one as the encoding rules require.
+	 * <p>
+	 * If you use this interface your class should also implement the getInstance
+	 * pattern which takes a tag object and the tagging mode used. 
+	 * </p>
+	 */
+	public interface IAsn1Choice
+	{
+		// marker interface
+	}
+}
diff --git a/Crypto/src/asn1/IAsn1Convertible.cs b/Crypto/src/asn1/IAsn1Convertible.cs
new file mode 100644
index 000000000..d3f83afc9
--- /dev/null
+++ b/Crypto/src/asn1/IAsn1Convertible.cs
@@ -0,0 +1,7 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public interface IAsn1Convertible
+	{
+		Asn1Object ToAsn1Object();
+	}
+}
diff --git a/Crypto/src/asn1/IAsn1String.cs b/Crypto/src/asn1/IAsn1String.cs
new file mode 100644
index 000000000..cbc2635ff
--- /dev/null
+++ b/Crypto/src/asn1/IAsn1String.cs
@@ -0,0 +1,10 @@
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * basic interface for Der string objects.
+     */
+    public interface IAsn1String
+    {
+        string GetString();
+    }
+}
diff --git a/Crypto/src/asn1/IndefiniteLengthInputStream.cs b/Crypto/src/asn1/IndefiniteLengthInputStream.cs
new file mode 100644
index 000000000..56c1bdfbc
--- /dev/null
+++ b/Crypto/src/asn1/IndefiniteLengthInputStream.cs
@@ -0,0 +1,166 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	class IndefiniteLengthInputStream
+		: LimitedInputStream
+	{
+        private int _lookAhead;
+        private bool _eofOn00 = true;
+
+		internal IndefiniteLengthInputStream(
+			Stream	inStream,
+			int		limit)
+			: base(inStream, limit)
+		{
+            _lookAhead = RequireByte();
+            CheckForEof();
+		}
+
+		internal void SetEofOn00(
+			bool eofOn00)
+		{
+			_eofOn00 = eofOn00;
+            CheckForEof();
+        }
+
+		private bool CheckForEof()
+		{
+            if (_lookAhead == 0x00 && _eofOn00)
+            {
+                int extra = RequireByte();
+                if (extra != 0)
+                {
+                    throw new IOException("malformed end-of-contents marker");
+                }
+
+                _lookAhead = -1;
+                SetParentEofDetect(true);
+            }
+            return _lookAhead < 0;
+        }
+
+		public override int Read(
+			byte[]	buffer,
+			int		offset,
+			int		count)
+		{
+			// Only use this optimisation if we aren't checking for 00
+			if (_eofOn00 || count <= 1)
+				return base.Read(buffer, offset, count);
+
+			if (_lookAhead < 0)
+				return 0;
+
+			int numRead = _in.Read(buffer, offset + 1, count - 1);
+
+			if (numRead <= 0)
+			{
+				// Corrupted stream
+				throw new EndOfStreamException();
+			}
+
+			buffer[offset] = (byte)_lookAhead;
+			_lookAhead = RequireByte();
+
+			return numRead + 1;
+		}
+
+		public override int ReadByte()
+		{
+			if (CheckForEof())
+				return -1;
+
+            int result = _lookAhead;
+            _lookAhead = RequireByte();
+            return result;
+		}
+
+        private int RequireByte()
+        {
+            int b = _in.ReadByte();
+            if (b < 0)
+            {
+                // Corrupted stream
+                throw new EndOfStreamException();
+            }
+            return b;
+        }
+	}
+}
+
+//using System;
+//using System.IO;
+
+//namespace Org.BouncyCastle.Asn1
+//{
+//    class IndefiniteLengthInputStream
+//        : LimitedInputStream
+//    {
+//        private bool _eofReached = false;
+//        private bool _eofOn00 = true;
+
+//        internal IndefiniteLengthInputStream(
+//            Stream	inStream,
+//            int		limit)
+//            : base(inStream, limit)
+//        {
+//        }
+
+//        internal void SetEofOn00(
+//            bool eofOn00)
+//        {
+//            _eofOn00 = eofOn00;
+//        }
+
+//        public override int Read(
+//            byte[]	buffer,
+//            int		offset,
+//            int		count)
+//        {
+//            if (_eofReached)
+//                return 0;
+
+//            if (_eofOn00)
+//                return base.Read(buffer, offset, count);
+
+//            int numRead = _in.Read(buffer, offset, count);
+
+//            if (numRead <= 0)
+//                throw new EndOfStreamException();
+
+//            return numRead;
+//        }
+
+//        public override int ReadByte()
+//        {
+//            if (_eofReached)
+//                return -1;
+
+//            int b1 = _in.ReadByte();
+
+//            if (b1 < 0)
+//                throw new EndOfStreamException();
+
+//            if (b1 == 0 && _eofOn00)
+//            {
+//                int b2 = _in.ReadByte();
+
+//                if (b2 < 0)
+//                    throw new EndOfStreamException();
+
+//                if (b2 == 0)
+//                {
+//                    _eofReached = true;
+//                    SetParentEofDetect(true);
+//                    return -1;
+//                }
+
+//                throw new InvalidDataException();
+//            }
+
+//            return b1;
+//        }
+//    }
+//}
diff --git a/Crypto/src/asn1/LazyASN1InputStream.cs b/Crypto/src/asn1/LazyASN1InputStream.cs
new file mode 100644
index 000000000..4cf2305fd
--- /dev/null
+++ b/Crypto/src/asn1/LazyASN1InputStream.cs
@@ -0,0 +1,33 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class LazyAsn1InputStream
+		: Asn1InputStream
+	{
+		public LazyAsn1InputStream(
+			byte[] input)
+			: base(input)
+		{
+		}
+
+		public LazyAsn1InputStream(
+			Stream inputStream)
+			: base(inputStream)
+		{
+		}
+
+		internal override DerSequence CreateDerSequence(
+			DefiniteLengthInputStream dIn)
+		{
+			return new LazyDerSequence(dIn.ToArray());
+		}
+
+		internal override DerSet CreateDerSet(
+			DefiniteLengthInputStream dIn)
+		{
+			return new LazyDerSet(dIn.ToArray());
+		}
+	}
+}
diff --git a/Crypto/src/asn1/LazyDERSequence.cs b/Crypto/src/asn1/LazyDERSequence.cs
new file mode 100644
index 000000000..5e3dd076e
--- /dev/null
+++ b/Crypto/src/asn1/LazyDERSequence.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+
+namespace Org.BouncyCastle.Asn1
+{
+	internal class LazyDerSequence
+		: DerSequence
+	{
+		private byte[]	encoded;
+		private bool	parsed = false;
+
+		internal LazyDerSequence(
+			byte[] encoded)
+		{
+			this.encoded = encoded;
+		}
+
+		private void Parse()
+		{
+			lock (this)
+			{
+				if (!parsed)
+				{
+					Asn1InputStream e = new LazyAsn1InputStream(encoded);
+
+					Asn1Object o;
+					while ((o = e.ReadObject()) != null)
+					{
+						AddObject(o);
+					}
+
+					encoded = null;
+					parsed = true;
+				}
+			}
+		}
+
+		public override Asn1Encodable this[int index]
+		{
+			get
+			{
+				Parse();
+
+				return base[index];
+			}
+		}
+
+		public override IEnumerator GetEnumerator()
+		{
+			Parse();
+
+			return base.GetEnumerator();
+		}
+
+		public override int Count
+		{
+			get
+			{
+				Parse();
+
+				return base.Count;
+			}
+		}
+
+		internal override void Encode(
+			DerOutputStream derOut)
+		{
+			lock (this)
+			{
+				if (parsed)
+				{
+					base.Encode(derOut);
+				}
+				else
+				{
+					derOut.WriteEncoded(Asn1Tags.Sequence | Asn1Tags.Constructed, encoded);
+				}
+			}
+		}
+	}
+}
diff --git a/Crypto/src/asn1/LazyDERSet.cs b/Crypto/src/asn1/LazyDERSet.cs
new file mode 100644
index 000000000..84fce4808
--- /dev/null
+++ b/Crypto/src/asn1/LazyDERSet.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+
+namespace Org.BouncyCastle.Asn1
+{
+	internal class LazyDerSet
+		: DerSet
+	{
+		private byte[]	encoded;
+		private bool	parsed = false;
+
+		internal LazyDerSet(
+			byte[] encoded)
+		{
+			this.encoded = encoded;
+		}
+
+		private void Parse()
+		{
+			lock (this)
+			{
+				if (!parsed)
+				{
+					Asn1InputStream e = new LazyAsn1InputStream(encoded);
+
+					Asn1Object o;
+					while ((o = e.ReadObject()) != null)
+					{
+						AddObject(o);
+					}
+
+					encoded = null;
+					parsed = true;
+				}
+			}
+		}
+
+		public override Asn1Encodable this[int index]
+		{
+			get
+			{
+				Parse();
+
+				return base[index];
+			}
+		}
+
+		public override IEnumerator GetEnumerator()
+		{
+			Parse();
+
+			return base.GetEnumerator();
+		}
+
+		public override int Count
+		{
+			get
+			{
+				Parse();
+
+				return base.Count;
+			}
+		}
+
+		internal override void Encode(
+			DerOutputStream derOut)
+		{
+			lock (this)
+			{
+				if (parsed)
+				{
+					base.Encode(derOut);
+				}
+				else
+				{
+					derOut.WriteEncoded(Asn1Tags.Set | Asn1Tags.Constructed, encoded);
+				}
+			}
+		}
+	}
+}
diff --git a/Crypto/src/asn1/LimitedInputStream.cs b/Crypto/src/asn1/LimitedInputStream.cs
new file mode 100644
index 000000000..62486aa77
--- /dev/null
+++ b/Crypto/src/asn1/LimitedInputStream.cs
@@ -0,0 +1,35 @@
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+    internal abstract class LimitedInputStream
+        : BaseInputStream
+    {
+        protected readonly Stream _in;
+		private int _limit;
+
+        internal LimitedInputStream(
+            Stream	inStream,
+			int		limit)
+        {
+            this._in = inStream;
+			this._limit = limit;
+        }
+
+	    internal virtual int GetRemaining()
+	    {
+	        // TODO: maybe one day this can become more accurate
+	        return _limit;
+	    }
+
+		protected virtual void SetParentEofDetect(bool on)
+        {
+            if (_in is IndefiniteLengthInputStream)
+            {
+                ((IndefiniteLengthInputStream)_in).SetEofOn00(on);
+            }
+        }
+    }
+}
diff --git a/Crypto/src/asn1/OidTokenizer.cs b/Crypto/src/asn1/OidTokenizer.cs
new file mode 100644
index 000000000..6e76e8c8b
--- /dev/null
+++ b/Crypto/src/asn1/OidTokenizer.cs
@@ -0,0 +1,45 @@
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * class for breaking up an Oid into it's component tokens, ala
+     * java.util.StringTokenizer. We need this class as some of the
+     * lightweight Java environment don't support classes like
+     * StringTokenizer.
+     */
+    public class OidTokenizer
+    {
+        private string  oid;
+        private int     index;
+
+		public OidTokenizer(
+            string oid)
+        {
+            this.oid = oid;
+        }
+
+		public bool HasMoreTokens
+        {
+			get { return index != -1; }
+        }
+
+		public string NextToken()
+        {
+            if (index == -1)
+            {
+                return null;
+            }
+
+            int end = oid.IndexOf('.', index);
+            if (end == -1)
+            {
+                string lastToken = oid.Substring(index);
+                index = -1;
+                return lastToken;
+            }
+
+            string nextToken = oid.Substring(index, end - index);
+			index = end + 1;
+            return nextToken;
+        }
+    }
+}
diff --git a/Crypto/src/asn1/bc/BCObjectIdentifiers.cs b/Crypto/src/asn1/bc/BCObjectIdentifiers.cs
new file mode 100644
index 000000000..075e5384c
--- /dev/null
+++ b/Crypto/src/asn1/bc/BCObjectIdentifiers.cs
@@ -0,0 +1,39 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.BC
+{
+	public abstract class BCObjectIdentifiers
+	{
+		// iso.org.dod.internet.private.enterprise.legion-of-the-bouncy-castle
+		// 1.3.6.1.4.1.22554
+		public static readonly DerObjectIdentifier bc = new DerObjectIdentifier("1.3.6.1.4.1.22554");
+
+		// pbe(1) algorithms
+		public static readonly DerObjectIdentifier bc_pbe = new DerObjectIdentifier(bc + ".1");
+
+		// SHA-1(1)
+		public static readonly DerObjectIdentifier bc_pbe_sha1 = new DerObjectIdentifier(bc_pbe + ".1");
+
+		// SHA-2(2) . (SHA-256(1)|SHA-384(2)|SHA-512(3)|SHA-224(4))
+		public static readonly DerObjectIdentifier bc_pbe_sha256 = new DerObjectIdentifier(bc_pbe + ".2.1");
+		public static readonly DerObjectIdentifier bc_pbe_sha384 = new DerObjectIdentifier(bc_pbe + ".2.2");
+		public static readonly DerObjectIdentifier bc_pbe_sha512 = new DerObjectIdentifier(bc_pbe + ".2.3");
+		public static readonly DerObjectIdentifier bc_pbe_sha224 = new DerObjectIdentifier(bc_pbe + ".2.4");
+		
+		// PKCS-5(1)|PKCS-12(2)
+		public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs5 = new DerObjectIdentifier(bc_pbe_sha1 + ".1");
+		public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12 = new DerObjectIdentifier(bc_pbe_sha1 + ".2");
+		
+		public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs5 = new DerObjectIdentifier(bc_pbe_sha256 + ".1");
+		public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12 = new DerObjectIdentifier(bc_pbe_sha256 + ".2");
+
+		// AES(1) . (CBC-128(2)|CBC-192(22)|CBC-256(42))
+		public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12_aes128_cbc = new DerObjectIdentifier(bc_pbe_sha1_pkcs12 + ".1.2");
+		public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12_aes192_cbc = new DerObjectIdentifier(bc_pbe_sha1_pkcs12 + ".1.22");
+		public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12_aes256_cbc = new DerObjectIdentifier(bc_pbe_sha1_pkcs12 + ".1.42");
+
+		public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12_aes128_cbc = new DerObjectIdentifier(bc_pbe_sha256_pkcs12 + ".1.2");
+		public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12_aes192_cbc = new DerObjectIdentifier(bc_pbe_sha256_pkcs12 + ".1.22");
+		public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12_aes256_cbc = new DerObjectIdentifier(bc_pbe_sha256_pkcs12 + ".1.42");
+	}
+}
\ No newline at end of file
diff --git a/Crypto/src/asn1/cmp/CAKeyUpdAnnContent.cs b/Crypto/src/asn1/cmp/CAKeyUpdAnnContent.cs
new file mode 100644
index 000000000..3cdb128a6
--- /dev/null
+++ b/Crypto/src/asn1/cmp/CAKeyUpdAnnContent.cs
@@ -0,0 +1,60 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class CAKeyUpdAnnContent
+		: Asn1Encodable
+	{
+		private readonly CmpCertificate oldWithNew;
+		private readonly CmpCertificate newWithOld;
+		private readonly CmpCertificate newWithNew;
+
+		private CAKeyUpdAnnContent(Asn1Sequence seq)
+		{
+			oldWithNew = CmpCertificate.GetInstance(seq[0]);
+			newWithOld = CmpCertificate.GetInstance(seq[1]);
+			newWithNew = CmpCertificate.GetInstance(seq[2]);
+		}
+
+		public static CAKeyUpdAnnContent GetInstance(object obj)
+		{
+			if (obj is CAKeyUpdAnnContent)
+				return (CAKeyUpdAnnContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new CAKeyUpdAnnContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual CmpCertificate OldWithNew
+		{
+			get { return oldWithNew; }
+		}
+		
+		public virtual CmpCertificate NewWithOld
+		{
+			get { return newWithOld; }
+		}
+
+		public virtual CmpCertificate NewWithNew
+		{
+			get { return newWithNew; }
+		}
+
+		/**
+		 * <pre>
+		 * CAKeyUpdAnnContent ::= SEQUENCE {
+		 *                             oldWithNew   CmpCertificate, -- old pub signed with new priv
+		 *                             newWithOld   CmpCertificate, -- new pub signed with old priv
+		 *                             newWithNew   CmpCertificate  -- new pub signed with new priv
+		 *  }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(oldWithNew, newWithOld, newWithNew);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/CertConfirmContent.cs b/Crypto/src/asn1/cmp/CertConfirmContent.cs
new file mode 100644
index 000000000..f4016d8d8
--- /dev/null
+++ b/Crypto/src/asn1/cmp/CertConfirmContent.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class CertConfirmContent
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence content;
+
+		private CertConfirmContent(Asn1Sequence seq)
+		{
+			content = seq;
+		}
+
+		public static CertConfirmContent GetInstance(object obj)
+		{
+			if (obj is CertConfirmContent)
+				return (CertConfirmContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new CertConfirmContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual CertStatus[] ToCertStatusArray()
+		{
+			CertStatus[] result = new CertStatus[content.Count];
+			for (int i = 0; i != result.Length; i++)
+			{
+				result[i] = CertStatus.GetInstance(content[i]);
+			}
+			return result;
+		}
+
+		/**
+		 * <pre>
+		 * CertConfirmContent ::= SEQUENCE OF CertStatus
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return content;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/CertOrEncCert.cs b/Crypto/src/asn1/cmp/CertOrEncCert.cs
new file mode 100644
index 000000000..4c049c180
--- /dev/null
+++ b/Crypto/src/asn1/cmp/CertOrEncCert.cs
@@ -0,0 +1,85 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class CertOrEncCert
+		: Asn1Encodable, IAsn1Choice
+	{
+		private readonly CmpCertificate certificate;
+		private readonly EncryptedValue encryptedCert;
+
+		private CertOrEncCert(Asn1TaggedObject tagged)
+		{
+			if (tagged.TagNo == 0)
+			{
+				certificate = CmpCertificate.GetInstance(tagged.GetObject());
+			}
+			else if (tagged.TagNo == 1)
+			{
+				encryptedCert = EncryptedValue.GetInstance(tagged.GetObject());
+			}
+			else
+			{
+				throw new ArgumentException("unknown tag: " + tagged.TagNo, "tagged");
+			}
+		}
+		
+		public static CertOrEncCert GetInstance(object obj)
+		{
+			if (obj is CertOrEncCert)
+				return (CertOrEncCert)obj;
+
+			if (obj is Asn1TaggedObject)
+				return new CertOrEncCert((Asn1TaggedObject)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public CertOrEncCert(CmpCertificate certificate)
+		{
+			if (certificate == null)
+				throw new ArgumentNullException("certificate");
+
+			this.certificate = certificate;
+		}
+
+		public CertOrEncCert(EncryptedValue encryptedCert)
+		{
+			if (encryptedCert == null)
+				throw new ArgumentNullException("encryptedCert");
+
+			this.encryptedCert = encryptedCert;
+		}
+
+		public virtual CmpCertificate Certificate
+		{
+			get { return certificate; }
+		}
+
+		public virtual EncryptedValue EncryptedCert
+		{
+			get { return encryptedCert; }
+		}
+
+		/**
+		 * <pre>
+		 * CertOrEncCert ::= CHOICE {
+		 *                      certificate     [0] CMPCertificate,
+		 *                      encryptedCert   [1] EncryptedValue
+		 *           }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			if (certificate != null)
+			{
+				return new DerTaggedObject(true, 0, certificate);
+			}
+
+			return new DerTaggedObject(true, 1, encryptedCert);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/CertRepMessage.cs b/Crypto/src/asn1/cmp/CertRepMessage.cs
new file mode 100644
index 000000000..c22b079c8
--- /dev/null
+++ b/Crypto/src/asn1/cmp/CertRepMessage.cs
@@ -0,0 +1,94 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class CertRepMessage
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence caPubs;
+		private readonly Asn1Sequence response;
+		
+		private CertRepMessage(Asn1Sequence seq)
+		{
+			int index = 0;
+
+			if (seq.Count > 1)
+			{
+				caPubs = Asn1Sequence.GetInstance((Asn1TaggedObject)seq[index++], true);
+			}
+
+			response = Asn1Sequence.GetInstance(seq[index]);
+		}
+
+		public static CertRepMessage GetInstance(object obj)
+		{
+			if (obj is CertRepMessage)
+				return (CertRepMessage)obj;
+
+			if (obj is Asn1Sequence)
+				return new CertRepMessage((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public CertRepMessage(CmpCertificate[] caPubs, CertResponse[] response)
+		{
+			if (response == null)
+				throw new ArgumentNullException("response");
+
+			if (caPubs != null)
+			{
+				this.caPubs = new DerSequence(caPubs);
+			}
+
+			this.response = new DerSequence(response);
+		}
+
+		public virtual CmpCertificate[] GetCAPubs()
+		{
+			if (caPubs == null)
+				return null;
+
+			CmpCertificate[] results = new CmpCertificate[caPubs.Count];
+			for (int i = 0; i != results.Length; ++i)
+			{
+				results[i] = CmpCertificate.GetInstance(caPubs[i]);
+			}
+			return results;
+		}
+
+		public virtual CertResponse[] GetResponse()
+		{
+			CertResponse[] results = new CertResponse[response.Count];
+			for (int i = 0; i != results.Length; ++i)
+			{
+				results[i] = CertResponse.GetInstance(response[i]);
+			}
+			return results;
+		}
+
+		/**
+		 * <pre>
+		 * CertRepMessage ::= SEQUENCE {
+		 *                          caPubs       [1] SEQUENCE SIZE (1..MAX) OF CMPCertificate
+		 *                                                                             OPTIONAL,
+		 *                          response         SEQUENCE OF CertResponse
+		 * }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (caPubs != null)
+			{
+				v.Add(new DerTaggedObject(true, 1, caPubs));
+			}
+
+			v.Add(response);
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/CertResponse.cs b/Crypto/src/asn1/cmp/CertResponse.cs
new file mode 100644
index 000000000..246b8ce70
--- /dev/null
+++ b/Crypto/src/asn1/cmp/CertResponse.cs
@@ -0,0 +1,115 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class CertResponse
+		: Asn1Encodable
+	{
+		private readonly DerInteger certReqId;
+		private readonly PkiStatusInfo status;
+		private readonly CertifiedKeyPair certifiedKeyPair;
+		private readonly Asn1OctetString rspInfo;
+
+		private CertResponse(Asn1Sequence seq)
+		{
+			certReqId = DerInteger.GetInstance(seq[0]);
+			status = PkiStatusInfo.GetInstance(seq[1]);
+
+			if (seq.Count >= 3)
+			{
+				if (seq.Count == 3)
+				{
+					Asn1Encodable o = seq[2];
+					if (o is Asn1OctetString)
+					{
+						rspInfo = Asn1OctetString.GetInstance(o);
+					}
+					else
+					{
+						certifiedKeyPair = CertifiedKeyPair.GetInstance(o);
+					}
+				}
+				else
+				{
+					certifiedKeyPair = CertifiedKeyPair.GetInstance(seq[2]);
+					rspInfo = Asn1OctetString.GetInstance(seq[3]);
+				}
+			}
+		}
+
+		public static CertResponse GetInstance(object obj)
+		{
+			if (obj is CertResponse)
+				return (CertResponse)obj;
+
+			if (obj is Asn1Sequence)
+				return new CertResponse((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public CertResponse(
+			DerInteger certReqId,
+			PkiStatusInfo status)
+			: this(certReqId, status, null, null)
+		{
+		}
+
+		public CertResponse(
+			DerInteger			certReqId,
+			PkiStatusInfo		status,
+			CertifiedKeyPair	certifiedKeyPair,
+			Asn1OctetString		rspInfo)
+		{
+			if (certReqId == null)
+				throw new ArgumentNullException("certReqId");
+
+			if (status == null)
+				throw new ArgumentNullException("status");
+
+			this.certReqId = certReqId;
+			this.status = status;
+			this.certifiedKeyPair = certifiedKeyPair;
+			this.rspInfo = rspInfo;
+		}
+
+		public virtual DerInteger CertReqID
+		{
+			get { return certReqId; }
+		}
+
+		public virtual PkiStatusInfo Status
+		{
+			get { return status; }
+		}
+
+		public virtual CertifiedKeyPair CertifiedKeyPair
+		{
+			get { return certifiedKeyPair; }
+		}
+
+		/**
+		 * <pre>
+		 * CertResponse ::= SEQUENCE {
+		 *                            certReqId           INTEGER,
+		 *                            -- to match this response with corresponding request (a value
+		 *                            -- of -1 is to be used if certReqId is not specified in the
+		 *                            -- corresponding request)
+		 *                            status              PKIStatusInfo,
+		 *                            certifiedKeyPair    CertifiedKeyPair    OPTIONAL,
+		 *                            rspInfo             OCTET STRING        OPTIONAL
+		 *                            -- analogous to the id-regInfo-utf8Pairs string defined
+		 *                            -- for regInfo in CertReqMsg [CRMF]
+		 *             }
+		 * </pre> 
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(certReqId, status);
+			v.AddOptional(certifiedKeyPair);
+			v.AddOptional(rspInfo);
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/CertStatus.cs b/Crypto/src/asn1/cmp/CertStatus.cs
new file mode 100644
index 000000000..52d5ac504
--- /dev/null
+++ b/Crypto/src/asn1/cmp/CertStatus.cs
@@ -0,0 +1,84 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class CertStatus
+		: Asn1Encodable
+	{
+		private readonly Asn1OctetString certHash;
+		private readonly DerInteger certReqId;
+		private readonly PkiStatusInfo statusInfo;
+
+		private CertStatus(Asn1Sequence seq)
+		{
+			certHash = Asn1OctetString.GetInstance(seq[0]);
+			certReqId = DerInteger.GetInstance(seq[1]);
+
+			if (seq.Count > 2)
+			{
+				statusInfo = PkiStatusInfo.GetInstance(seq[2]);
+			}
+		}
+
+		public CertStatus(byte[] certHash, BigInteger certReqId)
+		{
+			this.certHash = new DerOctetString(certHash);
+			this.certReqId = new DerInteger(certReqId);
+		}
+
+		public CertStatus(byte[] certHash, BigInteger certReqId, PkiStatusInfo statusInfo)
+		{
+			this.certHash = new DerOctetString(certHash);
+			this.certReqId = new DerInteger(certReqId);
+			this.statusInfo = statusInfo;
+		}
+
+		public static CertStatus GetInstance(object obj)
+		{
+			if (obj is CertStatus)
+				return (CertStatus)obj;
+
+			if (obj is Asn1Sequence)
+				return new CertStatus((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual Asn1OctetString CertHash
+		{
+			get { return certHash; }
+		}
+
+		public virtual DerInteger CertReqID
+		{
+			get { return certReqId; }
+		}
+
+		public virtual PkiStatusInfo StatusInfo
+		{
+			get { return statusInfo; }
+		}
+
+		/**
+		 * <pre>
+		 * CertStatus ::= SEQUENCE {
+		 *                   certHash    OCTET STRING,
+		 *                   -- the hash of the certificate, using the same hash algorithm
+		 *                   -- as is used to create and verify the certificate signature
+		 *                   certReqId   INTEGER,
+		 *                   -- to match this confirmation with the corresponding req/rep
+		 *                   statusInfo  PKIStatusInfo OPTIONAL
+		 * }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(certHash, certReqId);
+			v.AddOptional(statusInfo);
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/CertifiedKeyPair.cs b/Crypto/src/asn1/cmp/CertifiedKeyPair.cs
new file mode 100644
index 000000000..655dde0c5
--- /dev/null
+++ b/Crypto/src/asn1/cmp/CertifiedKeyPair.cs
@@ -0,0 +1,114 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class CertifiedKeyPair
+		: Asn1Encodable
+	{
+		private readonly CertOrEncCert certOrEncCert;
+		private readonly EncryptedValue privateKey;
+		private readonly PkiPublicationInfo publicationInfo;
+
+		private CertifiedKeyPair(Asn1Sequence seq)
+		{
+			certOrEncCert = CertOrEncCert.GetInstance(seq[0]);
+
+			if (seq.Count >= 2)
+			{
+				if (seq.Count == 2)
+				{
+					Asn1TaggedObject tagged = Asn1TaggedObject.GetInstance(seq[1]);
+					if (tagged.TagNo == 0)
+					{
+						privateKey = EncryptedValue.GetInstance(tagged.GetObject());
+					}
+					else
+					{
+						publicationInfo = PkiPublicationInfo.GetInstance(tagged.GetObject());
+					}
+				}
+				else
+				{
+					privateKey = EncryptedValue.GetInstance(Asn1TaggedObject.GetInstance(seq[1]));
+					publicationInfo = PkiPublicationInfo.GetInstance(Asn1TaggedObject.GetInstance(seq[2]));
+				}
+			}
+		}
+
+		public static CertifiedKeyPair GetInstance(object obj)
+		{
+			if (obj is CertifiedKeyPair)
+				return (CertifiedKeyPair)obj;
+
+			if (obj is Asn1Sequence)
+				return new CertifiedKeyPair((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public CertifiedKeyPair(
+			CertOrEncCert certOrEncCert)
+			: this(certOrEncCert, null, null)
+		{
+		}
+
+		public CertifiedKeyPair(
+			CertOrEncCert		certOrEncCert,
+			EncryptedValue		privateKey,
+			PkiPublicationInfo	publicationInfo
+		)
+		{
+			if (certOrEncCert == null)
+				throw new ArgumentNullException("certOrEncCert");
+
+			this.certOrEncCert = certOrEncCert;
+			this.privateKey = privateKey;
+			this.publicationInfo = publicationInfo;
+		}
+
+		public virtual CertOrEncCert CertOrEncCert
+		{
+			get { return certOrEncCert; }
+		}
+
+		public virtual EncryptedValue PrivateKey
+		{
+			get { return privateKey; }
+		}
+
+		public virtual PkiPublicationInfo PublicationInfo
+		{
+			get { return publicationInfo; }
+		}
+
+		/**
+		 * <pre>
+		 * CertifiedKeyPair ::= SEQUENCE {
+		 *                                  certOrEncCert       CertOrEncCert,
+		 *                                  privateKey      [0] EncryptedValue      OPTIONAL,
+		 *                                  -- see [CRMF] for comment on encoding
+		 *                                  publicationInfo [1] PKIPublicationInfo  OPTIONAL
+		 *       }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(certOrEncCert);
+
+			if (privateKey != null)
+			{
+				v.Add(new DerTaggedObject(true, 0, privateKey));
+			}
+
+			if (publicationInfo != null)
+			{
+				v.Add(new DerTaggedObject(true, 1, publicationInfo));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/Challenge.cs b/Crypto/src/asn1/cmp/Challenge.cs
new file mode 100644
index 000000000..bee5f96f5
--- /dev/null
+++ b/Crypto/src/asn1/cmp/Challenge.cs
@@ -0,0 +1,79 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class Challenge
+		: Asn1Encodable
+	{
+		private readonly AlgorithmIdentifier owf;
+		private readonly Asn1OctetString witness;
+		private readonly Asn1OctetString challenge;
+
+		private Challenge(Asn1Sequence seq)
+		{
+			int index = 0;
+
+			if (seq.Count == 3)
+			{
+				owf = AlgorithmIdentifier.GetInstance(seq[index++]);
+			}
+
+			witness = Asn1OctetString.GetInstance(seq[index++]);
+			challenge = Asn1OctetString.GetInstance(seq[index]);
+		}
+
+		public static Challenge GetInstance(object obj)
+		{
+			if (obj is Challenge)
+				return (Challenge)obj;
+
+			if (obj is Asn1Sequence)
+				return new Challenge((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual AlgorithmIdentifier Owf
+		{
+			get { return owf; }
+		}
+
+		/**
+		 * <pre>
+		 * Challenge ::= SEQUENCE {
+		 *                 owf                 AlgorithmIdentifier  OPTIONAL,
+		 *
+		 *                 -- MUST be present in the first Challenge; MAY be omitted in
+		 *                 -- any subsequent Challenge in POPODecKeyChallContent (if
+		 *                 -- omitted, then the owf used in the immediately preceding
+		 *                 -- Challenge is to be used).
+		 *
+		 *                 witness             OCTET STRING,
+		 *                 -- the result of applying the one-way function (owf) to a
+		 *                 -- randomly-generated INTEGER, A.  [Note that a different
+		 *                 -- INTEGER MUST be used for each Challenge.]
+		 *                 challenge           OCTET STRING
+		 *                 -- the encryption (under the public key for which the cert.
+		 *                 -- request is being made) of Rand, where Rand is specified as
+		 *                 --   Rand ::= SEQUENCE {
+		 *                 --      int      INTEGER,
+		 *                 --       - the randomly-generated INTEGER A (above)
+		 *                 --      sender   GeneralName
+		 *                 --       - the sender's name (as included in PKIHeader)
+		 *                 --   }
+		 *      }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+			v.AddOptional(owf);
+			v.Add(witness);
+			v.Add(challenge);
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/CmpCertificate.cs b/Crypto/src/asn1/cmp/CmpCertificate.cs
new file mode 100644
index 000000000..16ee30059
--- /dev/null
+++ b/Crypto/src/asn1/cmp/CmpCertificate.cs
@@ -0,0 +1,80 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    public class CmpCertificate
+        : Asn1Encodable, IAsn1Choice
+    {
+        private readonly X509CertificateStructure x509v3PKCert;
+        private readonly AttributeCertificate x509v2AttrCert;
+
+        /**
+         * Note: the addition of attribute certificates is a BC extension.
+         */
+        public CmpCertificate(AttributeCertificate x509v2AttrCert)
+        {
+            this.x509v2AttrCert = x509v2AttrCert;
+        }
+
+        public CmpCertificate(X509CertificateStructure x509v3PKCert)
+        {
+            if (x509v3PKCert.Version != 3)
+                throw new ArgumentException("only version 3 certificates allowed", "x509v3PKCert");
+
+            this.x509v3PKCert = x509v3PKCert;
+        }
+
+        public static CmpCertificate GetInstance(object obj)
+        {
+            if (obj is CmpCertificate)
+                return (CmpCertificate)obj;
+
+            if (obj is Asn1Sequence)
+                return new CmpCertificate(X509CertificateStructure.GetInstance(obj));
+
+            if (obj is Asn1TaggedObject)
+                return new CmpCertificate(AttributeCertificate.GetInstance(((Asn1TaggedObject)obj).GetObject()));
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public virtual bool IsX509v3PKCert
+        {
+            get { return x509v3PKCert != null; }
+        }
+
+        public virtual X509CertificateStructure X509v3PKCert
+        {
+            get { return x509v3PKCert; }
+        }
+
+        public virtual AttributeCertificate X509v2AttrCert
+        {
+            get { return x509v2AttrCert; }
+        }
+
+        /**
+         * <pre>
+         * CMPCertificate ::= CHOICE {
+         *            x509v3PKCert        Certificate
+         *            x509v2AttrCert      [1] AttributeCertificate
+         *  }
+         * </pre>
+         * Note: the addition of attribute certificates is a BC extension.
+         *
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            if (x509v2AttrCert != null)
+            {
+                // explicit following CMP conventions
+                return new DerTaggedObject(true, 1, x509v2AttrCert);
+            }
+
+            return x509v3PKCert.ToAsn1Object();
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cmp/CmpObjectIdentifiers.cs b/Crypto/src/asn1/cmp/CmpObjectIdentifiers.cs
new file mode 100644
index 000000000..7e8274175
--- /dev/null
+++ b/Crypto/src/asn1/cmp/CmpObjectIdentifiers.cs
@@ -0,0 +1,106 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public abstract class CmpObjectIdentifiers
+	{
+		// RFC 4210
+
+		// id-PasswordBasedMac OBJECT IDENTIFIER ::= {1 2 840 113533 7 66 13}
+		public static readonly DerObjectIdentifier passwordBasedMac = new DerObjectIdentifier("1.2.840.113533.7.66.13");
+
+		// id-DHBasedMac OBJECT IDENTIFIER ::= {1 2 840 113533 7 66 30}
+		public static readonly DerObjectIdentifier dhBasedMac = new DerObjectIdentifier("1.2.840.113533.7.66.30");
+
+		// Example InfoTypeAndValue contents include, but are not limited
+		// to, the following (un-comment in this ASN.1 module and use as
+		// appropriate for a given environment):
+		//
+		// id-it-caProtEncCert OBJECT IDENTIFIER ::= {id-it 1}
+		// CAProtEncCertValue ::= CMPCertificate
+		// id-it-signKeyPairTypes OBJECT IDENTIFIER ::= {id-it 2}
+		// SignKeyPairTypesValue ::= SEQUENCE OF AlgorithmIdentifier
+		// id-it-encKeyPairTypes OBJECT IDENTIFIER ::= {id-it 3}
+		// EncKeyPairTypesValue ::= SEQUENCE OF AlgorithmIdentifier
+		// id-it-preferredSymmAlg OBJECT IDENTIFIER ::= {id-it 4}
+		// PreferredSymmAlgValue ::= AlgorithmIdentifier
+		// id-it-caKeyUpdateInfo OBJECT IDENTIFIER ::= {id-it 5}
+		// CAKeyUpdateInfoValue ::= CAKeyUpdAnnContent
+		// id-it-currentCRL OBJECT IDENTIFIER ::= {id-it 6}
+		// CurrentCRLValue ::= CertificateList
+		// id-it-unsupportedOIDs OBJECT IDENTIFIER ::= {id-it 7}
+		// UnsupportedOIDsValue ::= SEQUENCE OF OBJECT IDENTIFIER
+		// id-it-keyPairParamReq OBJECT IDENTIFIER ::= {id-it 10}
+		// KeyPairParamReqValue ::= OBJECT IDENTIFIER
+		// id-it-keyPairParamRep OBJECT IDENTIFIER ::= {id-it 11}
+		// KeyPairParamRepValue ::= AlgorithmIdentifer
+		// id-it-revPassphrase OBJECT IDENTIFIER ::= {id-it 12}
+		// RevPassphraseValue ::= EncryptedValue
+		// id-it-implicitConfirm OBJECT IDENTIFIER ::= {id-it 13}
+		// ImplicitConfirmValue ::= NULL
+		// id-it-confirmWaitTime OBJECT IDENTIFIER ::= {id-it 14}
+		// ConfirmWaitTimeValue ::= GeneralizedTime
+		// id-it-origPKIMessage OBJECT IDENTIFIER ::= {id-it 15}
+		// OrigPKIMessageValue ::= PKIMessages
+		// id-it-suppLangTags OBJECT IDENTIFIER ::= {id-it 16}
+		// SuppLangTagsValue ::= SEQUENCE OF UTF8String
+		//
+		// where
+		//
+		// id-pkix OBJECT IDENTIFIER ::= {
+		// iso(1) identified-organization(3)
+		// dod(6) internet(1) security(5) mechanisms(5) pkix(7)}
+		// and
+		// id-it OBJECT IDENTIFIER ::= {id-pkix 4}
+		public static readonly DerObjectIdentifier it_caProtEncCert = new DerObjectIdentifier("1.3.6.1.5.5.7.4.1");
+		public static readonly DerObjectIdentifier it_signKeyPairTypes = new DerObjectIdentifier("1.3.6.1.5.5.7.4.2");
+		public static readonly DerObjectIdentifier it_encKeyPairTypes = new DerObjectIdentifier("1.3.6.1.5.5.7.4.3");
+		public static readonly DerObjectIdentifier it_preferredSymAlg = new DerObjectIdentifier("1.3.6.1.5.5.7.4.4");
+		public static readonly DerObjectIdentifier it_caKeyUpdateInfo = new DerObjectIdentifier("1.3.6.1.5.5.7.4.5");
+		public static readonly DerObjectIdentifier it_currentCRL = new DerObjectIdentifier("1.3.6.1.5.5.7.4.6");
+		public static readonly DerObjectIdentifier it_unsupportedOIDs = new DerObjectIdentifier("1.3.6.1.5.5.7.4.7");
+		public static readonly DerObjectIdentifier it_keyPairParamReq = new DerObjectIdentifier("1.3.6.1.5.5.7.4.10");
+		public static readonly DerObjectIdentifier it_keyPairParamRep = new DerObjectIdentifier("1.3.6.1.5.5.7.4.11");
+		public static readonly DerObjectIdentifier it_revPassphrase = new DerObjectIdentifier("1.3.6.1.5.5.7.4.12");
+		public static readonly DerObjectIdentifier it_implicitConfirm = new DerObjectIdentifier("1.3.6.1.5.5.7.4.13");
+		public static readonly DerObjectIdentifier it_confirmWaitTime = new DerObjectIdentifier("1.3.6.1.5.5.7.4.14");
+		public static readonly DerObjectIdentifier it_origPKIMessage = new DerObjectIdentifier("1.3.6.1.5.5.7.4.15");
+		public static readonly DerObjectIdentifier it_suppLangTags = new DerObjectIdentifier("1.3.6.1.5.5.7.4.16");
+
+		// RFC 4211
+
+		// id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
+		// dod(6) internet(1) security(5) mechanisms(5) pkix(7) }
+		//
+		// arc for Internet X.509 PKI protocols and their components
+		// id-pkip OBJECT IDENTIFIER :: { id-pkix pkip(5) }
+		//
+		// arc for Registration Controls in CRMF
+		// id-regCtrl OBJECT IDENTIFIER ::= { id-pkip regCtrl(1) }
+		//
+		// arc for Registration Info in CRMF
+		// id-regInfo OBJECT IDENTIFIER ::= { id-pkip id-regInfo(2) }
+
+		public static readonly DerObjectIdentifier regCtrl_regToken = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.1");
+		public static readonly DerObjectIdentifier regCtrl_authenticator = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.2");
+		public static readonly DerObjectIdentifier regCtrl_pkiPublicationInfo = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.3");
+		public static readonly DerObjectIdentifier regCtrl_pkiArchiveOptions = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.4");
+		public static readonly DerObjectIdentifier regCtrl_oldCertID = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.5");
+		public static readonly DerObjectIdentifier regCtrl_protocolEncrKey = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.6");
+
+		// From RFC4210:
+		// id-regCtrl-altCertTemplate OBJECT IDENTIFIER ::= {id-regCtrl 7}
+		public static readonly DerObjectIdentifier regCtrl_altCertTemplate = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.7");
+
+		public static readonly DerObjectIdentifier regInfo_utf8Pairs = new DerObjectIdentifier("1.3.6.1.5.5.7.5.2.1");
+		public static readonly DerObjectIdentifier regInfo_certReq = new DerObjectIdentifier("1.3.6.1.5.5.7.5.2.2");
+
+		// id-smime OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+		// us(840) rsadsi(113549) pkcs(1) pkcs9(9) 16 }
+		//
+		// id-ct OBJECT IDENTIFIER ::= { id-smime 1 } -- content types
+		//
+		// id-ct-encKeyWithID OBJECT IDENTIFIER ::= {id-ct 21}
+		public static readonly DerObjectIdentifier ct_encKeyWithID = new DerObjectIdentifier("1.2.840.113549.1.9.16.1.21");
+	}
+}
diff --git a/Crypto/src/asn1/cmp/CrlAnnContent.cs b/Crypto/src/asn1/cmp/CrlAnnContent.cs
new file mode 100644
index 000000000..3dc11d32c
--- /dev/null
+++ b/Crypto/src/asn1/cmp/CrlAnnContent.cs
@@ -0,0 +1,49 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class CrlAnnContent
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence content;
+
+		private CrlAnnContent(Asn1Sequence seq)
+		{
+			content = seq;
+		}
+
+		public static CrlAnnContent GetInstance(object obj)
+		{
+			if (obj is CrlAnnContent)
+				return (CrlAnnContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new CrlAnnContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual CertificateList[] ToCertificateListArray()
+		{
+			CertificateList[] result = new CertificateList[content.Count];
+			for (int i = 0; i != result.Length; ++ i)
+			{
+				result[i] = CertificateList.GetInstance(content[i]);
+			}
+			return result;
+		}
+
+		/**
+		 * <pre>
+		 * CrlAnnContent ::= SEQUENCE OF CertificateList
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return content;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/ErrorMsgContent.cs b/Crypto/src/asn1/cmp/ErrorMsgContent.cs
new file mode 100644
index 000000000..f4dc584ea
--- /dev/null
+++ b/Crypto/src/asn1/cmp/ErrorMsgContent.cs
@@ -0,0 +1,94 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class ErrorMsgContent
+		: Asn1Encodable
+	{
+		private readonly PkiStatusInfo pkiStatusInfo;
+		private readonly DerInteger errorCode;
+		private readonly PkiFreeText errorDetails;
+
+		private ErrorMsgContent(Asn1Sequence seq)
+		{
+			pkiStatusInfo = PkiStatusInfo.GetInstance(seq[0]);
+
+			for (int pos = 1; pos < seq.Count; ++pos)
+			{
+				Asn1Encodable ae = seq[pos];
+				if (ae is DerInteger)
+				{
+					errorCode = DerInteger.GetInstance(ae);
+				}
+				else
+				{
+					errorDetails = PkiFreeText.GetInstance(ae);
+				}
+			}
+		}
+
+		public static ErrorMsgContent GetInstance(object obj)
+		{
+			if (obj is ErrorMsgContent)
+				return (ErrorMsgContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new ErrorMsgContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public ErrorMsgContent(PkiStatusInfo pkiStatusInfo)
+			: this(pkiStatusInfo, null, null)
+		{
+		}
+
+		public ErrorMsgContent(
+			PkiStatusInfo	pkiStatusInfo,
+			DerInteger		errorCode,
+			PkiFreeText		errorDetails)
+		{
+			if (pkiStatusInfo == null)
+				throw new ArgumentNullException("pkiStatusInfo");
+
+			this.pkiStatusInfo = pkiStatusInfo;
+			this.errorCode = errorCode;
+			this.errorDetails = errorDetails;
+		}
+		
+		public virtual PkiStatusInfo PkiStatusInfo
+		{
+			get { return pkiStatusInfo; }
+		}
+
+		public virtual DerInteger ErrorCode
+		{
+			get { return errorCode; }
+		}
+
+		public virtual PkiFreeText ErrorDetails
+		{
+			get { return errorDetails; }
+		}
+
+		/**
+		 * <pre>
+		 * ErrorMsgContent ::= SEQUENCE {
+		 *                        pKIStatusInfo          PKIStatusInfo,
+		 *                        errorCode              INTEGER           OPTIONAL,
+		 *                        -- implementation-specific error codes
+		 *                        errorDetails           PKIFreeText       OPTIONAL
+		 *                        -- implementation-specific error details
+		 * }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(pkiStatusInfo);
+			v.AddOptional(errorCode);
+			v.AddOptional(errorDetails);
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/GenMsgContent.cs b/Crypto/src/asn1/cmp/GenMsgContent.cs
new file mode 100644
index 000000000..9f042491c
--- /dev/null
+++ b/Crypto/src/asn1/cmp/GenMsgContent.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class GenMsgContent
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence content;
+
+		private GenMsgContent(Asn1Sequence seq)
+		{
+			content = seq;
+		}
+
+		public static GenMsgContent GetInstance(object obj)
+		{
+			if (obj is GenMsgContent)
+				return (GenMsgContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new GenMsgContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public GenMsgContent(params InfoTypeAndValue[] itv)
+		{
+			content = new DerSequence(itv);
+		}
+
+		public virtual InfoTypeAndValue[] ToInfoTypeAndValueArray()
+		{
+			InfoTypeAndValue[] result = new InfoTypeAndValue[content.Count];
+			for (int i = 0; i != result.Length; ++i)
+			{
+				result[i] = InfoTypeAndValue.GetInstance(content[i]);
+			}
+			return result;
+		}
+
+		/**
+		 * <pre>
+		 * GenMsgContent ::= SEQUENCE OF InfoTypeAndValue
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return content;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/GenRepContent.cs b/Crypto/src/asn1/cmp/GenRepContent.cs
new file mode 100644
index 000000000..5bdc5550a
--- /dev/null
+++ b/Crypto/src/asn1/cmp/GenRepContent.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class GenRepContent
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence content;
+
+		private GenRepContent(Asn1Sequence seq)
+		{
+			content = seq;
+		}
+
+		public static GenRepContent GetInstance(object obj)
+		{
+			if (obj is GenRepContent)
+				return (GenRepContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new GenRepContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public GenRepContent(params InfoTypeAndValue[] itv)
+		{
+			content = new DerSequence(itv);
+		}
+
+		public virtual InfoTypeAndValue[] ToInfoTypeAndValueArray()
+		{
+			InfoTypeAndValue[] result = new InfoTypeAndValue[content.Count];
+			for (int i = 0; i != result.Length; ++i)
+			{
+				result[i] = InfoTypeAndValue.GetInstance(content[i]);
+			}
+			return result;
+		}
+
+		/**
+		 * <pre>
+		 * GenRepContent ::= SEQUENCE OF InfoTypeAndValue
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return content;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/InfoTypeAndValue.cs b/Crypto/src/asn1/cmp/InfoTypeAndValue.cs
new file mode 100644
index 000000000..9b51dba02
--- /dev/null
+++ b/Crypto/src/asn1/cmp/InfoTypeAndValue.cs
@@ -0,0 +1,121 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    /**
+     * Example InfoTypeAndValue contents include, but are not limited
+     * to, the following (un-comment in this ASN.1 module and use as
+     * appropriate for a given environment):
+     * <pre>
+     *   id-it-caProtEncCert    OBJECT IDENTIFIER ::= {id-it 1}
+     *      CAProtEncCertValue      ::= CMPCertificate
+     *   id-it-signKeyPairTypes OBJECT IDENTIFIER ::= {id-it 2}
+     *     SignKeyPairTypesValue   ::= SEQUENCE OF AlgorithmIdentifier
+     *   id-it-encKeyPairTypes  OBJECT IDENTIFIER ::= {id-it 3}
+     *     EncKeyPairTypesValue    ::= SEQUENCE OF AlgorithmIdentifier
+     *   id-it-preferredSymmAlg OBJECT IDENTIFIER ::= {id-it 4}
+     *      PreferredSymmAlgValue   ::= AlgorithmIdentifier
+     *   id-it-caKeyUpdateInfo  OBJECT IDENTIFIER ::= {id-it 5}
+     *      CAKeyUpdateInfoValue    ::= CAKeyUpdAnnContent
+     *   id-it-currentCRL       OBJECT IDENTIFIER ::= {id-it 6}
+     *      CurrentCRLValue         ::= CertificateList
+     *   id-it-unsupportedOIDs  OBJECT IDENTIFIER ::= {id-it 7}
+     *      UnsupportedOIDsValue    ::= SEQUENCE OF OBJECT IDENTIFIER
+     *   id-it-keyPairParamReq  OBJECT IDENTIFIER ::= {id-it 10}
+     *      KeyPairParamReqValue    ::= OBJECT IDENTIFIER
+     *   id-it-keyPairParamRep  OBJECT IDENTIFIER ::= {id-it 11}
+     *      KeyPairParamRepValue    ::= AlgorithmIdentifer
+     *   id-it-revPassphrase    OBJECT IDENTIFIER ::= {id-it 12}
+     *      RevPassphraseValue      ::= EncryptedValue
+     *   id-it-implicitConfirm  OBJECT IDENTIFIER ::= {id-it 13}
+     *      ImplicitConfirmValue    ::= NULL
+     *   id-it-confirmWaitTime  OBJECT IDENTIFIER ::= {id-it 14}
+     *      ConfirmWaitTimeValue    ::= GeneralizedTime
+     *   id-it-origPKIMessage   OBJECT IDENTIFIER ::= {id-it 15}
+     *      OrigPKIMessageValue     ::= PKIMessages
+     *   id-it-suppLangTags     OBJECT IDENTIFIER ::= {id-it 16}
+     *      SuppLangTagsValue       ::= SEQUENCE OF UTF8String
+     *
+     * where
+     *
+     *   id-pkix OBJECT IDENTIFIER ::= {
+     *      iso(1) identified-organization(3)
+     *      dod(6) internet(1) security(5) mechanisms(5) pkix(7)}
+     * and
+     *      id-it   OBJECT IDENTIFIER ::= {id-pkix 4}
+     * </pre>
+     */
+    public class InfoTypeAndValue
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier infoType;
+        private readonly Asn1Encodable infoValue;
+
+        private InfoTypeAndValue(Asn1Sequence seq)
+        {
+            infoType = DerObjectIdentifier.GetInstance(seq[0]);
+
+            if (seq.Count > 1)
+            {
+                infoValue = (Asn1Encodable)seq[1];
+            }
+        }
+
+        public static InfoTypeAndValue GetInstance(object obj)
+        {
+            if (obj is InfoTypeAndValue)
+                return (InfoTypeAndValue)obj;
+
+            if (obj is Asn1Sequence)
+                return new InfoTypeAndValue((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public InfoTypeAndValue(
+            DerObjectIdentifier infoType)
+        {
+            this.infoType = infoType;
+            this.infoValue = null;
+        }
+
+        public InfoTypeAndValue(
+            DerObjectIdentifier infoType,
+            Asn1Encodable       optionalValue)
+        {
+            this.infoType = infoType;
+            this.infoValue = optionalValue;
+        }
+
+        public virtual DerObjectIdentifier InfoType
+        {
+            get { return infoType; }
+        }
+
+        public virtual Asn1Encodable InfoValue
+        {
+            get { return infoValue; }
+        }
+
+        /**
+         * <pre>
+         * InfoTypeAndValue ::= SEQUENCE {
+         *                         infoType               OBJECT IDENTIFIER,
+         *                         infoValue              ANY DEFINED BY infoType  OPTIONAL
+         * }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(infoType);
+
+            if (infoValue != null)
+            {
+                v.Add(infoValue);
+            }
+
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cmp/KeyRecRepContent.cs b/Crypto/src/asn1/cmp/KeyRecRepContent.cs
new file mode 100644
index 000000000..b0352f048
--- /dev/null
+++ b/Crypto/src/asn1/cmp/KeyRecRepContent.cs
@@ -0,0 +1,115 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class KeyRecRepContent
+		: Asn1Encodable
+	{
+		private readonly PkiStatusInfo status;
+		private readonly CmpCertificate newSigCert;
+		private readonly Asn1Sequence caCerts;
+		private readonly Asn1Sequence keyPairHist;
+
+		private KeyRecRepContent(Asn1Sequence seq)
+		{
+			status = PkiStatusInfo.GetInstance(seq[0]);
+
+			for (int pos = 1; pos < seq.Count; ++pos)
+			{
+				Asn1TaggedObject tObj = Asn1TaggedObject.GetInstance(seq[pos]);
+
+				switch (tObj.TagNo)
+				{
+					case 0:
+						newSigCert = CmpCertificate.GetInstance(tObj.GetObject());
+						break;
+					case 1:
+						caCerts = Asn1Sequence.GetInstance(tObj.GetObject());
+						break;
+					case 2:
+						keyPairHist = Asn1Sequence.GetInstance(tObj.GetObject());
+						break;
+					default:
+						throw new ArgumentException("unknown tag number: " + tObj.TagNo, "seq");
+				}
+			}
+		}
+
+		public static KeyRecRepContent GetInstance(object obj)
+		{
+			if (obj is KeyRecRepContent)
+				return (KeyRecRepContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new KeyRecRepContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual PkiStatusInfo Status
+		{
+			get { return status; }
+		}
+
+		public virtual CmpCertificate NewSigCert
+		{
+			get { return newSigCert; }
+		}
+
+		public virtual CmpCertificate[] GetCACerts()
+		{
+			if (caCerts == null)
+				return null;
+
+			CmpCertificate[] results = new CmpCertificate[caCerts.Count];
+			for (int i = 0; i != results.Length; ++i)
+			{
+				results[i] = CmpCertificate.GetInstance(caCerts[i]);
+			}
+			return results;
+		}
+
+		public virtual CertifiedKeyPair[] GetKeyPairHist()
+		{
+			if (keyPairHist == null)
+				return null;
+
+			CertifiedKeyPair[] results = new CertifiedKeyPair[keyPairHist.Count];
+			for (int i = 0; i != results.Length; ++i)
+			{
+				results[i] = CertifiedKeyPair.GetInstance(keyPairHist[i]);
+			}
+			return results;
+		}
+
+		/**
+		 * <pre>
+		 * KeyRecRepContent ::= SEQUENCE {
+		 *                         status                  PKIStatusInfo,
+		 *                         newSigCert          [0] CMPCertificate OPTIONAL,
+		 *                         caCerts             [1] SEQUENCE SIZE (1..MAX) OF
+		 *                                                           CMPCertificate OPTIONAL,
+		 *                         keyPairHist         [2] SEQUENCE SIZE (1..MAX) OF
+		 *                                                           CertifiedKeyPair OPTIONAL
+		 *              }
+		 * </pre> 
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(status);
+			AddOptional(v, 0, newSigCert);
+			AddOptional(v, 1, caCerts);
+			AddOptional(v, 2, keyPairHist);
+			return new DerSequence(v);
+		}
+
+		private void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+		{
+			if (obj != null)
+			{
+				v.Add(new DerTaggedObject(true, tagNo, obj));
+			}
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/OobCertHash.cs b/Crypto/src/asn1/cmp/OobCertHash.cs
new file mode 100644
index 000000000..63ddff7c4
--- /dev/null
+++ b/Crypto/src/asn1/cmp/OobCertHash.cs
@@ -0,0 +1,87 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class OobCertHash
+		: Asn1Encodable
+	{
+		private readonly AlgorithmIdentifier hashAlg;
+		private readonly CertId certId;
+		private readonly DerBitString  hashVal;
+
+		private OobCertHash(Asn1Sequence seq)
+		{
+			int index = seq.Count - 1;
+
+			hashVal = DerBitString.GetInstance(seq[index--]);
+
+			for (int i = index; i >= 0; i--)
+			{
+				Asn1TaggedObject tObj = (Asn1TaggedObject)seq[i];
+
+				if (tObj.TagNo == 0)
+				{
+					hashAlg = AlgorithmIdentifier.GetInstance(tObj, true);
+				}
+				else
+				{
+					certId = CertId.GetInstance(tObj, true);
+				}
+			}
+		}
+
+		public static OobCertHash GetInstance(object obj)
+		{
+			if (obj is OobCertHash)
+				return (OobCertHash)obj;
+
+			if (obj is Asn1Sequence)
+				return new OobCertHash((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+		
+		public virtual AlgorithmIdentifier HashAlg
+		{
+			get { return hashAlg; }
+		}
+		
+		public virtual CertId CertID
+		{
+			get { return certId; }
+		}
+		
+		/**
+		 * <pre>
+		 * OobCertHash ::= SEQUENCE {
+		 *                      hashAlg     [0] AlgorithmIdentifier     OPTIONAL,
+		 *                      certId      [1] CertId                  OPTIONAL,
+		 *                      hashVal         BIT STRING
+		 *                      -- hashVal is calculated over the Der encoding of the
+		 *                      -- self-signed certificate with the identifier certID.
+		 *       }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+			AddOptional(v, 0, hashAlg);
+			AddOptional(v, 1, certId);
+			v.Add(hashVal);
+			return new DerSequence(v);
+		}
+
+		private void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+		{
+			if (obj != null)
+			{
+				v.Add(new DerTaggedObject(true, tagNo, obj));
+			}
+		}
+	}
+}
+
diff --git a/Crypto/src/asn1/cmp/PKIBody.cs b/Crypto/src/asn1/cmp/PKIBody.cs
new file mode 100644
index 000000000..3205a907e
--- /dev/null
+++ b/Crypto/src/asn1/cmp/PKIBody.cs
@@ -0,0 +1,186 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    public class PkiBody
+        : Asn1Encodable, IAsn1Choice
+    {
+        public const int TYPE_INIT_REQ = 0;
+        public const int TYPE_INIT_REP = 1;
+        public const int TYPE_CERT_REQ = 2;
+        public const int TYPE_CERT_REP = 3;
+        public const int TYPE_P10_CERT_REQ = 4;
+        public const int TYPE_POPO_CHALL = 5;
+        public const int TYPE_POPO_REP = 6;
+        public const int TYPE_KEY_UPDATE_REQ = 7;
+        public const int TYPE_KEY_UPDATE_REP = 8;
+        public const int TYPE_KEY_RECOVERY_REQ = 9;
+        public const int TYPE_KEY_RECOVERY_REP = 10;
+        public const int TYPE_REVOCATION_REQ = 11;
+        public const int TYPE_REVOCATION_REP = 12;
+        public const int TYPE_CROSS_CERT_REQ = 13;
+        public const int TYPE_CROSS_CERT_REP = 14;
+        public const int TYPE_CA_KEY_UPDATE_ANN = 15;
+        public const int TYPE_CERT_ANN = 16;
+        public const int TYPE_REVOCATION_ANN = 17;
+        public const int TYPE_CRL_ANN = 18;
+        public const int TYPE_CONFIRM = 19;
+        public const int TYPE_NESTED = 20;
+        public const int TYPE_GEN_MSG = 21;
+        public const int TYPE_GEN_REP = 22;
+        public const int TYPE_ERROR = 23;
+        public const int TYPE_CERT_CONFIRM = 24;
+        public const int TYPE_POLL_REQ = 25;
+        public const int TYPE_POLL_REP = 26;
+
+        private int tagNo;
+        private Asn1Encodable body;
+
+        public static PkiBody GetInstance(object obj)
+        {
+            if (obj is PkiBody)
+                return (PkiBody)obj;
+
+            if (obj is Asn1TaggedObject)
+                return new PkiBody((Asn1TaggedObject)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        private PkiBody(Asn1TaggedObject tagged)
+        {
+            tagNo = tagged.TagNo;
+            body = GetBodyForType(tagNo, tagged.GetObject());
+        }
+
+        /**
+         * Creates a new PkiBody.
+         * @param type one of the TYPE_* constants
+         * @param content message content
+         */
+        public PkiBody(
+            int type,
+            Asn1Encodable content)
+        {
+            tagNo = type;
+            body = GetBodyForType(type, content);
+        }
+
+        private static Asn1Encodable GetBodyForType(
+            int type,
+            Asn1Encodable o)
+        {
+            switch (type)
+            {
+                case TYPE_INIT_REQ:
+                    return CertReqMessages.GetInstance(o);
+	            case TYPE_INIT_REP:
+	                return CertRepMessage.GetInstance(o);
+                case TYPE_CERT_REQ:
+                    return CertReqMessages.GetInstance(o);
+	            case TYPE_CERT_REP:
+	                return CertRepMessage.GetInstance(o);
+	            case TYPE_P10_CERT_REQ:
+	                return CertificationRequest.GetInstance(o);
+	            case TYPE_POPO_CHALL:
+	                return PopoDecKeyChallContent.GetInstance(o);
+	            case TYPE_POPO_REP:
+	                return PopoDecKeyRespContent.GetInstance(o);
+                case TYPE_KEY_UPDATE_REQ:
+                    return CertReqMessages.GetInstance(o);
+	            case TYPE_KEY_UPDATE_REP:
+	                return CertRepMessage.GetInstance(o);
+                case TYPE_KEY_RECOVERY_REQ:
+                    return CertReqMessages.GetInstance(o);
+	            case TYPE_KEY_RECOVERY_REP:
+	                return KeyRecRepContent.GetInstance(o);
+	            case TYPE_REVOCATION_REQ:
+	                return RevReqContent.GetInstance(o);
+	            case TYPE_REVOCATION_REP:
+	                return RevRepContent.GetInstance(o);
+                case TYPE_CROSS_CERT_REQ:
+                    return CertReqMessages.GetInstance(o);
+	            case TYPE_CROSS_CERT_REP:
+	                return CertRepMessage.GetInstance(o);
+	            case TYPE_CA_KEY_UPDATE_ANN:
+	                return CAKeyUpdAnnContent.GetInstance(o);
+	            case TYPE_CERT_ANN:
+	                return CmpCertificate.GetInstance(o);
+	            case TYPE_REVOCATION_ANN:
+	                return RevAnnContent.GetInstance(o);
+	            case TYPE_CRL_ANN:
+	                return CrlAnnContent.GetInstance(o);
+	            case TYPE_CONFIRM:
+	                return PkiConfirmContent.GetInstance(o);
+                case TYPE_NESTED:
+                    return PkiMessages.GetInstance(o);
+	            case TYPE_GEN_MSG:
+	                return GenMsgContent.GetInstance(o);
+	            case TYPE_GEN_REP:
+	                return GenRepContent.GetInstance(o);
+	            case TYPE_ERROR:
+	                return ErrorMsgContent.GetInstance(o);
+	            case TYPE_CERT_CONFIRM:
+	                return CertConfirmContent.GetInstance(o);
+	            case TYPE_POLL_REQ:
+	                return PollReqContent.GetInstance(o);
+	            case TYPE_POLL_REP:
+	                return PollRepContent.GetInstance(o);
+	            default:
+	                throw new ArgumentException("unknown tag number: " + type, "type");
+            }
+        }
+
+        public virtual int Type
+        {
+            get { return tagNo; }
+        }
+
+        public virtual Asn1Encodable Content
+        {
+            get { return body; }
+        }
+
+        /**
+         * <pre>
+         * PkiBody ::= CHOICE {       -- message-specific body elements
+         *        ir       [0]  CertReqMessages,        --Initialization Request
+         *        ip       [1]  CertRepMessage,         --Initialization Response
+         *        cr       [2]  CertReqMessages,        --Certification Request
+         *        cp       [3]  CertRepMessage,         --Certification Response
+         *        p10cr    [4]  CertificationRequest,   --imported from [PKCS10]
+         *        popdecc  [5]  POPODecKeyChallContent, --pop Challenge
+         *        popdecr  [6]  POPODecKeyRespContent,  --pop Response
+         *        kur      [7]  CertReqMessages,        --Key Update Request
+         *        kup      [8]  CertRepMessage,         --Key Update Response
+         *        krr      [9]  CertReqMessages,        --Key Recovery Request
+         *        krp      [10] KeyRecRepContent,       --Key Recovery Response
+         *        rr       [11] RevReqContent,          --Revocation Request
+         *        rp       [12] RevRepContent,          --Revocation Response
+         *        ccr      [13] CertReqMessages,        --Cross-Cert. Request
+         *        ccp      [14] CertRepMessage,         --Cross-Cert. Response
+         *        ckuann   [15] CAKeyUpdAnnContent,     --CA Key Update Ann.
+         *        cann     [16] CertAnnContent,         --Certificate Ann.
+         *        rann     [17] RevAnnContent,          --Revocation Ann.
+         *        crlann   [18] CRLAnnContent,          --CRL Announcement
+         *        pkiconf  [19] PKIConfirmContent,      --Confirmation
+         *        nested   [20] NestedMessageContent,   --Nested Message
+         *        genm     [21] GenMsgContent,          --General Message
+         *        genp     [22] GenRepContent,          --General Response
+         *        error    [23] ErrorMsgContent,        --Error Message
+         *        certConf [24] CertConfirmContent,     --Certificate confirm
+         *        pollReq  [25] PollReqContent,         --Polling request
+         *        pollRep  [26] PollRepContent          --Polling response
+         * }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerTaggedObject(true, tagNo, body);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cmp/PKIConfirmContent.cs b/Crypto/src/asn1/cmp/PKIConfirmContent.cs
new file mode 100644
index 000000000..98645766a
--- /dev/null
+++ b/Crypto/src/asn1/cmp/PKIConfirmContent.cs
@@ -0,0 +1,34 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class PkiConfirmContent
+		: Asn1Encodable
+	{
+		public static PkiConfirmContent GetInstance(object obj)
+		{
+			if (obj is PkiConfirmContent)
+				return (PkiConfirmContent)obj;
+
+			if (obj is Asn1Null)
+				return new PkiConfirmContent();
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public PkiConfirmContent()
+		{
+		}
+
+		/**
+		 * <pre>
+		 * PkiConfirmContent ::= NULL
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return DerNull.Instance;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/PKIFailureInfo.cs b/Crypto/src/asn1/cmp/PKIFailureInfo.cs
new file mode 100644
index 000000000..1df0e0693
--- /dev/null
+++ b/Crypto/src/asn1/cmp/PKIFailureInfo.cs
@@ -0,0 +1,73 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	/**
+	 * <pre>
+	 * PKIFailureInfo ::= BIT STRING {
+	 * badAlg               (0),
+	 *   -- unrecognized or unsupported Algorithm Identifier
+	 * badMessageCheck      (1), -- integrity check failed (e.g., signature did not verify)
+	 * badRequest           (2),
+	 *   -- transaction not permitted or supported
+	 * badTime              (3), -- messageTime was not sufficiently close to the system time, as defined by local policy
+	 * badCertId            (4), -- no certificate could be found matching the provided criteria
+	 * badDataFormat        (5),
+	 *   -- the data submitted has the wrong format
+	 * wrongAuthority       (6), -- the authority indicated in the request is different from the one creating the response token
+	 * incorrectData        (7), -- the requester's data is incorrect (for notary services)
+	 * missingTimeStamp     (8), -- when the timestamp is missing but should be there (by policy)
+	 * badPOP               (9)  -- the proof-of-possession failed
+	 * timeNotAvailable    (14),
+	 *   -- the TSA's time source is not available
+	 * unacceptedPolicy    (15),
+	 *   -- the requested TSA policy is not supported by the TSA
+	 * unacceptedExtension (16),
+	 *   -- the requested extension is not supported by the TSA
+	 *  addInfoNotAvailable (17)
+	 *    -- the additional information requested could not be understood
+	 *    -- or is not available
+	 *  systemFailure       (25)
+	 *    -- the request cannot be handled due to system failure
+	 * </pre>
+	 */
+	public class PkiFailureInfo
+		: DerBitString
+	{
+		public const int BadAlg               = (1 << 7); // unrecognized or unsupported Algorithm Identifier
+		public const int BadMessageCheck      = (1 << 6); // integrity check failed (e.g., signature did not verify)
+		public const int BadRequest           = (1 << 5);
+		public const int BadTime              = (1 << 4); // -- messageTime was not sufficiently close to the system time, as defined by local policy
+		public const int BadCertId            = (1 << 3); // no certificate could be found matching the provided criteria
+		public const int BadDataFormat        = (1 << 2);
+		public const int WrongAuthority       = (1 << 1); // the authority indicated in the request is different from the one creating the response token
+		public const int IncorrectData        = 1;        // the requester's data is incorrect (for notary services)
+		public const int MissingTimeStamp     = (1 << 15); // when the timestamp is missing but should be there (by policy)
+		public const int BadPop               = (1 << 14); // the proof-of-possession failed
+		public const int TimeNotAvailable     = (1 << 9); // the TSA's time source is not available
+		public const int UnacceptedPolicy     = (1 << 8); // the requested TSA policy is not supported by the TSA
+		public const int UnacceptedExtension  = (1 << 23); //the requested extension is not supported by the TSA
+		public const int AddInfoNotAvailable  = (1 << 22); //the additional information requested could not be understood or is not available
+		public const int SystemFailure        = (1 << 30); //the request cannot be handled due to system failure
+
+		/**
+		 * Basic constructor.
+		 */
+		public PkiFailureInfo(
+			int info)
+			:	base(GetBytes(info), GetPadBits(info))
+		{
+		}
+
+		public PkiFailureInfo(
+			DerBitString info)
+			:	base(info.GetBytes(), info.PadBits)
+		{
+		}
+
+		public override string ToString()
+		{
+			return "PkiFailureInfo: 0x" + this.IntValue.ToString("X");
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/PKIFreeText.cs b/Crypto/src/asn1/cmp/PKIFreeText.cs
new file mode 100644
index 000000000..571c8d93a
--- /dev/null
+++ b/Crypto/src/asn1/cmp/PKIFreeText.cs
@@ -0,0 +1,97 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class PkiFreeText
+		: Asn1Encodable
+	{
+		internal Asn1Sequence strings;
+
+		public static PkiFreeText GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+
+		public static PkiFreeText GetInstance(
+			object obj)
+		{
+			if (obj is PkiFreeText)
+			{
+				return (PkiFreeText)obj;
+			}
+			else if (obj is Asn1Sequence)
+			{
+				return new PkiFreeText((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public PkiFreeText(
+			Asn1Sequence seq)
+		{
+			foreach (object o in seq)
+			{
+				if (!(o is DerUtf8String))
+				{
+					throw new ArgumentException("attempt to insert non UTF8 STRING into PkiFreeText");
+				}
+			}
+
+			this.strings = seq;
+		}
+
+		public PkiFreeText(
+			DerUtf8String p)
+		{
+			strings = new DerSequence(p);
+		}
+
+		/**
+		 * Return the number of string elements present.
+		 *
+		 * @return number of elements present.
+		 */
+		[Obsolete("Use 'Count' property instead")]
+		public int Size
+		{
+			get { return strings.Count; }
+		}
+
+		public int Count
+		{
+			get { return strings.Count; }
+		}
+
+		/**
+		 * Return the UTF8STRING at index.
+		 *
+		 * @param index index of the string of interest
+		 * @return the string at index.
+		 */
+		public DerUtf8String this[int index]
+		{
+			get { return (DerUtf8String) strings[index]; }
+		}
+
+		[Obsolete("Use 'object[index]' syntax instead")]
+		public DerUtf8String GetStringAt(
+			int index)
+		{
+			return this[index];
+		}
+
+		/**
+		 * <pre>
+		 * PkiFreeText ::= SEQUENCE SIZE (1..MAX) OF UTF8String
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return strings;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/PKIHeader.cs b/Crypto/src/asn1/cmp/PKIHeader.cs
new file mode 100644
index 000000000..e758e9f16
--- /dev/null
+++ b/Crypto/src/asn1/cmp/PKIHeader.cs
@@ -0,0 +1,237 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    public class PkiHeader
+        : Asn1Encodable
+    {
+        /**
+         * Value for a "null" recipient or sender.
+         */
+        public static readonly GeneralName NULL_NAME = new GeneralName(X509Name.GetInstance(new DerSequence()));
+
+        public static readonly int CMP_1999 = 1;
+        public static readonly int CMP_2000 = 2;
+
+        private readonly DerInteger pvno;
+        private readonly GeneralName sender;
+        private readonly GeneralName recipient;
+        private readonly DerGeneralizedTime messageTime;
+        private readonly AlgorithmIdentifier protectionAlg;
+        private readonly Asn1OctetString senderKID;       // KeyIdentifier
+        private readonly Asn1OctetString recipKID;        // KeyIdentifier
+        private readonly Asn1OctetString transactionID;
+        private readonly Asn1OctetString senderNonce;
+        private readonly Asn1OctetString recipNonce;
+        private readonly PkiFreeText freeText;
+        private readonly Asn1Sequence generalInfo;
+
+        private PkiHeader(Asn1Sequence seq)
+        {
+            pvno = DerInteger.GetInstance(seq[0]);
+            sender = GeneralName.GetInstance(seq[1]);
+            recipient = GeneralName.GetInstance(seq[2]);
+
+            for (int pos = 3; pos < seq.Count; ++pos)
+            {
+                Asn1TaggedObject tObj = (Asn1TaggedObject)seq[pos];
+
+                switch (tObj.TagNo)
+                {
+                    case 0:
+                        messageTime = DerGeneralizedTime.GetInstance(tObj, true);
+                        break;
+                    case 1:
+                        protectionAlg = AlgorithmIdentifier.GetInstance(tObj, true);
+                        break;
+                    case 2:
+                        senderKID = Asn1OctetString.GetInstance(tObj, true);
+                        break;
+                    case 3:
+                        recipKID = Asn1OctetString.GetInstance(tObj, true);
+                        break;
+                    case 4:
+                        transactionID = Asn1OctetString.GetInstance(tObj, true);
+                        break;
+                    case 5:
+                        senderNonce = Asn1OctetString.GetInstance(tObj, true);
+                        break;
+                    case 6:
+                        recipNonce = Asn1OctetString.GetInstance(tObj, true);
+                        break;
+                    case 7:
+                        freeText = PkiFreeText.GetInstance(tObj, true);
+                        break;
+                    case 8:
+                        generalInfo = Asn1Sequence.GetInstance(tObj, true);
+                        break;
+                    default:
+                        throw new ArgumentException("unknown tag number: " + tObj.TagNo, "seq");
+                }
+            }
+        }
+
+        public static PkiHeader GetInstance(object obj)
+        {
+            if (obj is PkiHeader)
+                return (PkiHeader)obj;
+
+            if (obj is Asn1Sequence)
+                return new PkiHeader((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public PkiHeader(
+            int pvno,
+            GeneralName sender,
+            GeneralName recipient)
+            : this(new DerInteger(pvno), sender, recipient)
+        {
+        }
+
+        private PkiHeader(
+            DerInteger pvno,
+            GeneralName sender,
+            GeneralName recipient)
+        {
+            this.pvno = pvno;
+            this.sender = sender;
+            this.recipient = recipient;
+        }
+
+        public virtual DerInteger Pvno
+        {
+            get { return pvno; }
+        }
+
+        public virtual GeneralName Sender
+        {
+            get { return sender; }
+        }
+
+        public virtual GeneralName Recipient
+        {
+            get { return recipient; }
+        }
+
+        public virtual DerGeneralizedTime MessageTime
+        {
+            get { return messageTime; }
+        }
+
+        public virtual AlgorithmIdentifier ProtectionAlg
+        {
+            get { return protectionAlg; }
+        }
+
+        public virtual Asn1OctetString SenderKID
+        {   
+            get { return senderKID; }
+        }
+
+        public virtual Asn1OctetString RecipKID
+        {   
+            get { return recipKID; }
+        }
+
+        public virtual Asn1OctetString TransactionID
+        {   
+            get { return transactionID; }
+        }
+
+        public virtual Asn1OctetString SenderNonce
+        {   
+            get { return senderNonce; }
+        }
+
+        public virtual Asn1OctetString RecipNonce
+        {   
+            get { return recipNonce; }
+        }
+
+        public virtual PkiFreeText FreeText
+        {
+            get { return freeText; }
+        }
+
+        public virtual InfoTypeAndValue[] GetGeneralInfo()
+        {
+            if (generalInfo == null)
+            {
+                return null;
+            }
+            InfoTypeAndValue[] results = new InfoTypeAndValue[generalInfo.Count];
+            for (int i = 0; i < results.Length; i++)
+            {
+                results[i] = InfoTypeAndValue.GetInstance(generalInfo[i]);
+            }
+            return results;
+        }
+
+        /**
+         * <pre>
+         *  PkiHeader ::= SEQUENCE {
+         *            pvno                INTEGER     { cmp1999(1), cmp2000(2) },
+         *            sender              GeneralName,
+         *            -- identifies the sender
+         *            recipient           GeneralName,
+         *            -- identifies the intended recipient
+         *            messageTime     [0] GeneralizedTime         OPTIONAL,
+         *            -- time of production of this message (used when sender
+         *            -- believes that the transport will be "suitable"; i.e.,
+         *            -- that the time will still be meaningful upon receipt)
+         *            protectionAlg   [1] AlgorithmIdentifier     OPTIONAL,
+         *            -- algorithm used for calculation of protection bits
+         *            senderKID       [2] KeyIdentifier           OPTIONAL,
+         *            recipKID        [3] KeyIdentifier           OPTIONAL,
+         *            -- to identify specific keys used for protection
+         *            transactionID   [4] OCTET STRING            OPTIONAL,
+         *            -- identifies the transaction; i.e., this will be the same in
+         *            -- corresponding request, response, certConf, and PKIConf
+         *            -- messages
+         *            senderNonce     [5] OCTET STRING            OPTIONAL,
+         *            recipNonce      [6] OCTET STRING            OPTIONAL,
+         *            -- nonces used to provide replay protection, senderNonce
+         *            -- is inserted by the creator of this message; recipNonce
+         *            -- is a nonce previously inserted in a related message by
+         *            -- the intended recipient of this message
+         *            freeText        [7] PKIFreeText             OPTIONAL,
+         *            -- this may be used to indicate context-specific instructions
+         *            -- (this field is intended for human consumption)
+         *            generalInfo     [8] SEQUENCE SIZE (1..MAX) OF
+         *                                 InfoTypeAndValue     OPTIONAL
+         *            -- this may be used to convey context-specific information
+         *            -- (this field not primarily intended for human consumption)
+         * }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(pvno, sender, recipient);
+
+            AddOptional(v, 0, messageTime);
+            AddOptional(v, 1, protectionAlg);
+            AddOptional(v, 2, senderKID);
+            AddOptional(v, 3, recipKID);
+            AddOptional(v, 4, transactionID);
+            AddOptional(v, 5, senderNonce);
+            AddOptional(v, 6, recipNonce);
+            AddOptional(v, 7, freeText);
+            AddOptional(v, 8, generalInfo);
+
+            return new DerSequence(v);
+        }
+
+        private static void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+        {
+            if (obj != null)
+            {
+                v.Add(new DerTaggedObject(true, tagNo, obj));
+            }
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cmp/PKIHeaderBuilder.cs b/Crypto/src/asn1/cmp/PKIHeaderBuilder.cs
new file mode 100644
index 000000000..00073c062
--- /dev/null
+++ b/Crypto/src/asn1/cmp/PKIHeaderBuilder.cs
@@ -0,0 +1,223 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class PkiHeaderBuilder
+	{
+		private DerInteger pvno;
+		private GeneralName sender;
+		private GeneralName recipient;
+		private DerGeneralizedTime messageTime;
+		private AlgorithmIdentifier protectionAlg;
+		private Asn1OctetString senderKID;       // KeyIdentifier
+		private Asn1OctetString recipKID;        // KeyIdentifier
+		private Asn1OctetString transactionID;
+		private Asn1OctetString senderNonce;
+		private Asn1OctetString recipNonce;
+		private PkiFreeText     freeText;
+		private Asn1Sequence    generalInfo;
+
+		public PkiHeaderBuilder(
+			int			pvno,
+			GeneralName	sender,
+			GeneralName	recipient)
+			: this(new DerInteger(pvno), sender, recipient)
+		{
+		}
+
+		private PkiHeaderBuilder(
+			DerInteger	pvno,
+			GeneralName	sender,
+			GeneralName	recipient)
+		{
+			this.pvno = pvno;
+			this.sender = sender;
+			this.recipient = recipient;
+		}
+
+		public virtual PkiHeaderBuilder SetMessageTime(DerGeneralizedTime time)
+		{
+			messageTime = time;
+			return this;
+		}
+
+		public virtual PkiHeaderBuilder SetProtectionAlg(AlgorithmIdentifier aid)
+		{
+			protectionAlg = aid;
+			return this;
+		}
+
+		public virtual PkiHeaderBuilder SetSenderKID(byte[] kid)
+		{
+            return SetSenderKID(kid == null ? null : new DerOctetString(kid));
+		}
+
+		public virtual PkiHeaderBuilder SetSenderKID(Asn1OctetString kid)
+		{
+			senderKID = kid;
+			return this;
+		}
+
+		public virtual PkiHeaderBuilder SetRecipKID(byte[] kid)
+		{
+            return SetRecipKID(kid == null ? null : new DerOctetString(kid));
+		}
+		
+		public virtual PkiHeaderBuilder SetRecipKID(DerOctetString kid)
+		{
+			recipKID = kid;
+			return this;
+		}
+
+		public virtual PkiHeaderBuilder SetTransactionID(byte[] tid)
+		{
+			return SetTransactionID(tid == null ? null : new DerOctetString(tid));
+		}
+
+		public virtual PkiHeaderBuilder SetTransactionID(Asn1OctetString tid)
+		{
+			transactionID = tid;
+			return this;
+		}
+		
+		public virtual PkiHeaderBuilder SetSenderNonce(byte[] nonce)
+		{
+            return SetSenderNonce(nonce == null ? null : new DerOctetString(nonce));
+		}
+
+		public virtual PkiHeaderBuilder SetSenderNonce(Asn1OctetString nonce)
+		{
+			senderNonce = nonce;
+			return this;
+		}
+
+		public virtual PkiHeaderBuilder SetRecipNonce(byte[] nonce)
+		{
+            return SetRecipNonce(nonce == null ? null : new DerOctetString(nonce));
+		}
+
+		public virtual PkiHeaderBuilder SetRecipNonce(Asn1OctetString nonce)
+		{
+			recipNonce = nonce;
+			return this;
+		}
+
+		public virtual PkiHeaderBuilder SetFreeText(PkiFreeText text)
+		{
+			freeText = text;
+			return this;
+		}
+		
+		public virtual PkiHeaderBuilder SetGeneralInfo(InfoTypeAndValue genInfo)
+		{
+			return SetGeneralInfo(MakeGeneralInfoSeq(genInfo));
+		}
+		
+		public virtual PkiHeaderBuilder SetGeneralInfo(InfoTypeAndValue[] genInfos)
+		{
+			return SetGeneralInfo(MakeGeneralInfoSeq(genInfos));
+		}
+		
+		public virtual PkiHeaderBuilder SetGeneralInfo(Asn1Sequence seqOfInfoTypeAndValue)
+		{
+			generalInfo = seqOfInfoTypeAndValue;
+			return this;
+		}
+
+		private static Asn1Sequence MakeGeneralInfoSeq(
+			InfoTypeAndValue generalInfo)
+		{
+			return new DerSequence(generalInfo);
+		}
+		
+		private static Asn1Sequence MakeGeneralInfoSeq(
+			InfoTypeAndValue[] generalInfos)
+		{
+			Asn1Sequence genInfoSeq = null;
+			if (generalInfos != null)
+			{
+				Asn1EncodableVector v = new Asn1EncodableVector();
+				for (int i = 0; i < generalInfos.Length; ++i)
+				{
+					v.Add(generalInfos[i]);
+				}
+				genInfoSeq = new DerSequence(v);
+			}
+			return genInfoSeq;
+		}
+
+		/**
+		 * <pre>
+		 *  PKIHeader ::= SEQUENCE {
+		 *            pvno                INTEGER     { cmp1999(1), cmp2000(2) },
+		 *            sender              GeneralName,
+		 *            -- identifies the sender
+		 *            recipient           GeneralName,
+		 *            -- identifies the intended recipient
+		 *            messageTime     [0] GeneralizedTime         OPTIONAL,
+		 *            -- time of production of this message (used when sender
+		 *            -- believes that the transport will be "suitable"; i.e.,
+		 *            -- that the time will still be meaningful upon receipt)
+		 *            protectionAlg   [1] AlgorithmIdentifier     OPTIONAL,
+		 *            -- algorithm used for calculation of protection bits
+		 *            senderKID       [2] KeyIdentifier           OPTIONAL,
+		 *            recipKID        [3] KeyIdentifier           OPTIONAL,
+		 *            -- to identify specific keys used for protection
+		 *            transactionID   [4] OCTET STRING            OPTIONAL,
+		 *            -- identifies the transaction; i.e., this will be the same in
+		 *            -- corresponding request, response, certConf, and PKIConf
+		 *            -- messages
+		 *            senderNonce     [5] OCTET STRING            OPTIONAL,
+		 *            recipNonce      [6] OCTET STRING            OPTIONAL,
+		 *            -- nonces used to provide replay protection, senderNonce
+		 *            -- is inserted by the creator of this message; recipNonce
+		 *            -- is a nonce previously inserted in a related message by
+		 *            -- the intended recipient of this message
+		 *            freeText        [7] PKIFreeText             OPTIONAL,
+		 *            -- this may be used to indicate context-specific instructions
+		 *            -- (this field is intended for human consumption)
+		 *            generalInfo     [8] SEQUENCE SIZE (1..MAX) OF
+		 *                                 InfoTypeAndValue     OPTIONAL
+		 *            -- this may be used to convey context-specific information
+		 *            -- (this field not primarily intended for human consumption)
+		 * }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public virtual PkiHeader Build()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(pvno, sender, recipient);
+			AddOptional(v, 0, messageTime);
+			AddOptional(v, 1, protectionAlg);
+			AddOptional(v, 2, senderKID);
+			AddOptional(v, 3, recipKID);
+			AddOptional(v, 4, transactionID);
+			AddOptional(v, 5, senderNonce);
+			AddOptional(v, 6, recipNonce);
+			AddOptional(v, 7, freeText);
+			AddOptional(v, 8, generalInfo);
+
+			messageTime = null;
+			protectionAlg = null;
+			senderKID = null;
+			recipKID = null;
+			transactionID = null;
+			senderNonce = null;
+			recipNonce = null;
+			freeText = null;
+			generalInfo = null;
+
+			return PkiHeader.GetInstance(new DerSequence(v));
+		}
+
+		private void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+		{
+			if (obj != null)
+			{
+				v.Add(new DerTaggedObject(true, tagNo, obj));
+			}
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/PKIMessage.cs b/Crypto/src/asn1/cmp/PKIMessage.cs
new file mode 100644
index 000000000..086a2d938
--- /dev/null
+++ b/Crypto/src/asn1/cmp/PKIMessage.cs
@@ -0,0 +1,140 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    public class PkiMessage
+        : Asn1Encodable
+    {
+        private readonly PkiHeader header;
+        private readonly PkiBody body;
+        private readonly DerBitString protection;
+        private readonly Asn1Sequence extraCerts;
+
+        private PkiMessage(Asn1Sequence seq)
+        {
+            header = PkiHeader.GetInstance(seq[0]);
+            body = PkiBody.GetInstance(seq[1]);
+
+            for (int pos = 2; pos < seq.Count; ++pos)
+            {
+                Asn1TaggedObject tObj = (Asn1TaggedObject)seq[pos].ToAsn1Object();
+
+                if (tObj.TagNo == 0)
+                {
+                    protection = DerBitString.GetInstance(tObj, true);
+                }
+                else
+                {
+                    extraCerts = Asn1Sequence.GetInstance(tObj, true);
+                }
+            }
+        }
+
+        public static PkiMessage GetInstance(object obj)
+        {
+            if (obj is PkiMessage)
+                return (PkiMessage)obj;
+
+            if (obj != null)
+                return new PkiMessage(Asn1Sequence.GetInstance(obj));
+
+            return null;
+        }
+
+        /**
+         * Creates a new PkiMessage.
+         *
+         * @param header message header
+         * @param body message body
+         * @param protection message protection (may be null)
+         * @param extraCerts extra certificates (may be null)
+         */
+        public PkiMessage(
+            PkiHeader header,
+            PkiBody body,
+            DerBitString protection,
+            CmpCertificate[] extraCerts)
+        {
+            this.header = header;
+            this.body = body;
+            this.protection = protection;
+            if (extraCerts != null)
+            {
+                this.extraCerts = new DerSequence(extraCerts);
+            }
+        }
+
+        public PkiMessage(
+            PkiHeader header,
+            PkiBody body,
+            DerBitString protection)
+            : this(header, body, protection, null)
+        {
+        }
+
+        public PkiMessage(
+            PkiHeader header,
+            PkiBody body)
+            : this(header, body, null, null)
+        {
+        }
+
+        public virtual PkiHeader Header
+        {
+            get { return header; }
+        }
+
+        public virtual PkiBody Body
+        {
+            get { return body; }
+        }
+
+        public virtual DerBitString Protection
+        {
+            get { return protection; }
+        }
+
+        public virtual CmpCertificate[] GetExtraCerts()
+        {
+            if (extraCerts == null)
+                return null;
+
+            CmpCertificate[] results = new CmpCertificate[extraCerts.Count];
+            for (int i = 0; i < results.Length; ++i)
+            {
+                results[i] = CmpCertificate.GetInstance(extraCerts[i]);
+            }
+            return results;
+        }
+
+        /**
+         * <pre>
+         * PkiMessage ::= SEQUENCE {
+         *                  header           PKIHeader,
+         *                  body             PKIBody,
+         *                  protection   [0] PKIProtection OPTIONAL,
+         *                  extraCerts   [1] SEQUENCE SIZE (1..MAX) OF CMPCertificate
+         *                                                                     OPTIONAL
+         * }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(header, body);
+
+            AddOptional(v, 0, protection);
+            AddOptional(v, 1, extraCerts);
+
+            return new DerSequence(v);
+        }
+
+        private static void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+        {
+            if (obj != null)
+            {
+                v.Add(new DerTaggedObject(true, tagNo, obj));
+            }
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cmp/PKIMessages.cs b/Crypto/src/asn1/cmp/PKIMessages.cs
new file mode 100644
index 000000000..ddabdf4ae
--- /dev/null
+++ b/Crypto/src/asn1/cmp/PKIMessages.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    public class PkiMessages
+        : Asn1Encodable
+    {
+        private Asn1Sequence content;
+
+        private PkiMessages(Asn1Sequence seq)
+        {
+            content = seq;
+        }
+
+        public static PkiMessages GetInstance(object obj)
+        {
+            if (obj is PkiMessages)
+                return (PkiMessages)obj;
+
+            if (obj is Asn1Sequence)
+                return new PkiMessages((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+		public PkiMessages(params PkiMessage[] msgs)
+        {
+            content = new DerSequence(msgs);
+        }
+
+        public virtual PkiMessage[] ToPkiMessageArray()
+        {
+            PkiMessage[] result = new PkiMessage[content.Count];
+            for (int i = 0; i != result.Length; ++i)
+            {
+                result[i] = PkiMessage.GetInstance(content[i]);
+            }
+            return result;
+        }
+
+        /**
+         * <pre>
+         * PkiMessages ::= SEQUENCE SIZE (1..MAX) OF PkiMessage
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return content;
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cmp/PKIStatus.cs b/Crypto/src/asn1/cmp/PKIStatus.cs
new file mode 100644
index 000000000..b03dd3d62
--- /dev/null
+++ b/Crypto/src/asn1/cmp/PKIStatus.cs
@@ -0,0 +1,62 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public enum PkiStatus
+	{
+		Granted					= 0,
+		GrantedWithMods			= 1,
+		Rejection				= 2,
+		Waiting					= 3,
+		RevocationWarning		= 4,
+		RevocationNotification	= 5,
+    	KeyUpdateWarning		= 6,
+	}
+
+	public class PkiStatusEncodable
+		: Asn1Encodable
+	{
+		public static readonly PkiStatusEncodable granted = new PkiStatusEncodable(PkiStatus.Granted);
+		public static readonly PkiStatusEncodable grantedWithMods = new PkiStatusEncodable(PkiStatus.GrantedWithMods);
+		public static readonly PkiStatusEncodable rejection = new PkiStatusEncodable(PkiStatus.Rejection);
+		public static readonly PkiStatusEncodable waiting = new PkiStatusEncodable(PkiStatus.Waiting);
+		public static readonly PkiStatusEncodable revocationWarning = new PkiStatusEncodable(PkiStatus.RevocationWarning);
+		public static readonly PkiStatusEncodable revocationNotification = new PkiStatusEncodable(PkiStatus.RevocationNotification);
+		public static readonly PkiStatusEncodable keyUpdateWaiting = new PkiStatusEncodable(PkiStatus.KeyUpdateWarning);
+
+		private readonly DerInteger status;
+
+		private PkiStatusEncodable(PkiStatus status)
+			: this(new DerInteger((int)status))
+		{
+		}
+
+		private PkiStatusEncodable(DerInteger status)
+		{
+			this.status = status;
+		}
+
+		public static PkiStatusEncodable GetInstance(object obj)
+		{
+			if (obj is PkiStatusEncodable)
+				return (PkiStatusEncodable)obj;
+
+			if (obj is DerInteger)
+				return new PkiStatusEncodable((DerInteger)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual BigInteger Value
+		{
+			get { return status.Value; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return status;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/PKIStatusInfo.cs b/Crypto/src/asn1/cmp/PKIStatusInfo.cs
new file mode 100644
index 000000000..2463e0081
--- /dev/null
+++ b/Crypto/src/asn1/cmp/PKIStatusInfo.cs
@@ -0,0 +1,165 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class PkiStatusInfo
+		: Asn1Encodable
+	{
+		DerInteger      status;
+		PkiFreeText     statusString;
+		DerBitString    failInfo;
+
+		public static PkiStatusInfo GetInstance(
+			Asn1TaggedObject obj,
+			bool isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+
+		public static PkiStatusInfo GetInstance(
+			object obj)
+		{
+			if (obj is PkiStatusInfo)
+			{
+				return (PkiStatusInfo)obj;
+			}
+			else if (obj is Asn1Sequence)
+			{
+				return new PkiStatusInfo((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public PkiStatusInfo(
+			Asn1Sequence seq)
+		{
+			this.status = DerInteger.GetInstance(seq[0]);
+
+			this.statusString = null;
+			this.failInfo = null;
+
+			if (seq.Count > 2)
+			{
+				this.statusString = PkiFreeText.GetInstance(seq[1]);
+				this.failInfo = DerBitString.GetInstance(seq[2]);
+			}
+			else if (seq.Count > 1)
+			{
+				object obj = seq[1];
+				if (obj is DerBitString)
+				{
+					this.failInfo = DerBitString.GetInstance(obj);
+				}
+				else
+				{
+					this.statusString = PkiFreeText.GetInstance(obj);
+				}
+			}
+		}
+
+		/**
+		 * @param status
+		 */
+		public PkiStatusInfo(int status)
+		{
+			this.status = new DerInteger(status);
+		}
+
+		/**
+		 * @param status
+		 * @param statusString
+		 */
+		public PkiStatusInfo(
+			int			status,
+			PkiFreeText	statusString)
+		{
+			this.status = new DerInteger(status);
+			this.statusString = statusString;
+		}
+
+		public PkiStatusInfo(
+			int				status,
+			PkiFreeText		statusString,
+			PkiFailureInfo	failInfo)
+		{
+			this.status = new DerInteger(status);
+			this.statusString = statusString;
+			this.failInfo = failInfo;
+		}
+
+		public BigInteger Status
+		{
+			get
+			{
+				return status.Value;
+			}
+		}
+
+		public PkiFreeText StatusString
+		{
+			get
+			{
+				return statusString;
+			}
+		}
+
+		public DerBitString FailInfo
+		{
+			get
+			{
+				return failInfo;
+			}
+		}
+
+		/**
+		 * <pre>
+		 * PkiStatusInfo ::= SEQUENCE {
+		 *     status        PKIStatus,                (INTEGER)
+		 *     statusString  PkiFreeText     OPTIONAL,
+		 *     failInfo      PkiFailureInfo  OPTIONAL  (BIT STRING)
+		 * }
+		 *
+		 * PKIStatus:
+		 *   granted                (0), -- you got exactly what you asked for
+		 *   grantedWithMods        (1), -- you got something like what you asked for
+		 *   rejection              (2), -- you don't get it, more information elsewhere in the message
+		 *   waiting                (3), -- the request body part has not yet been processed, expect to hear more later
+		 *   revocationWarning      (4), -- this message contains a warning that a revocation is imminent
+		 *   revocationNotification (5), -- notification that a revocation has occurred
+		 *   keyUpdateWarning       (6)  -- update already done for the oldCertId specified in CertReqMsg
+		 *
+		 * PkiFailureInfo:
+		 *   badAlg           (0), -- unrecognized or unsupported Algorithm Identifier
+		 *   badMessageCheck  (1), -- integrity check failed (e.g., signature did not verify)
+		 *   badRequest       (2), -- transaction not permitted or supported
+		 *   badTime          (3), -- messageTime was not sufficiently close to the system time, as defined by local policy
+		 *   badCertId        (4), -- no certificate could be found matching the provided criteria
+		 *   badDataFormat    (5), -- the data submitted has the wrong format
+		 *   wrongAuthority   (6), -- the authority indicated in the request is different from the one creating the response token
+		 *   incorrectData    (7), -- the requester's data is incorrect (for notary services)
+		 *   missingTimeStamp (8), -- when the timestamp is missing but should be there (by policy)
+		 *   badPOP           (9)  -- the proof-of-possession failed
+		 *
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(status);
+
+			if (statusString != null)
+			{
+				v.Add(statusString);
+			}
+
+			if (failInfo!= null)
+			{
+				v.Add(failInfo);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/PbmParameter.cs b/Crypto/src/asn1/cmp/PbmParameter.cs
new file mode 100644
index 000000000..59b1bd7bb
--- /dev/null
+++ b/Crypto/src/asn1/cmp/PbmParameter.cs
@@ -0,0 +1,100 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    public class PbmParameter
+        : Asn1Encodable
+    {
+        private Asn1OctetString salt;
+        private AlgorithmIdentifier owf;
+        private DerInteger iterationCount;
+        private AlgorithmIdentifier mac;
+
+        private PbmParameter(Asn1Sequence seq)
+        {
+            salt = Asn1OctetString.GetInstance(seq[0]);
+            owf = AlgorithmIdentifier.GetInstance(seq[1]);
+            iterationCount = DerInteger.GetInstance(seq[2]);
+            mac = AlgorithmIdentifier.GetInstance(seq[3]);
+        }
+
+        public static PbmParameter GetInstance(object obj)
+        {
+            if (obj is PbmParameter)
+                return (PbmParameter)obj;
+
+            if (obj is Asn1Sequence)
+                return new PbmParameter((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public PbmParameter(
+            byte[] salt,
+            AlgorithmIdentifier owf,
+            int iterationCount,
+            AlgorithmIdentifier mac)
+            : this(new DerOctetString(salt), owf, new DerInteger(iterationCount), mac)
+        {
+        }
+
+        public PbmParameter(
+            Asn1OctetString salt,
+            AlgorithmIdentifier owf,
+            DerInteger iterationCount,
+            AlgorithmIdentifier mac)
+        {
+            this.salt = salt;
+            this.owf = owf;
+            this.iterationCount = iterationCount;
+            this.mac = mac;
+        }
+
+        public virtual Asn1OctetString Salt
+        {
+            get { return salt; }
+        }
+
+        public virtual AlgorithmIdentifier Owf
+        {
+            get { return owf; }
+        }
+
+        public virtual DerInteger IterationCount
+        {
+            get { return iterationCount; }
+        }
+
+        public virtual AlgorithmIdentifier Mac
+        {
+            get { return mac; }
+        }
+
+        /**
+         * <pre>
+         *  PbmParameter ::= SEQUENCE {
+         *                        salt                OCTET STRING,
+         *                        -- note:  implementations MAY wish to limit acceptable sizes
+         *                        -- of this string to values appropriate for their environment
+         *                        -- in order to reduce the risk of denial-of-service attacks
+         *                        owf                 AlgorithmIdentifier,
+         *                        -- AlgId for a One-Way Function (SHA-1 recommended)
+         *                        iterationCount      INTEGER,
+         *                        -- number of times the OWF is applied
+         *                        -- note:  implementations MAY wish to limit acceptable sizes
+         *                        -- of this integer to values appropriate for their environment
+         *                        -- in order to reduce the risk of denial-of-service attacks
+         *                        mac                 AlgorithmIdentifier
+         *                        -- the MAC AlgId (e.g., DES-MAC, Triple-DES-MAC [PKCS11],
+         *    }   -- or HMAC [RFC2104, RFC2202])
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(salt, owf, iterationCount, mac);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cmp/PollRepContent.cs b/Crypto/src/asn1/cmp/PollRepContent.cs
new file mode 100644
index 000000000..4045ac7ed
--- /dev/null
+++ b/Crypto/src/asn1/cmp/PollRepContent.cs
@@ -0,0 +1,66 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class PollRepContent
+		: Asn1Encodable
+	{
+		private readonly DerInteger certReqId;
+		private readonly DerInteger checkAfter;
+		private readonly PkiFreeText reason;
+
+		private PollRepContent(Asn1Sequence seq)
+		{
+			certReqId = DerInteger.GetInstance(seq[0]);
+			checkAfter = DerInteger.GetInstance(seq[1]);
+
+			if (seq.Count > 2)
+			{
+				reason = PkiFreeText.GetInstance(seq[2]);
+			}
+		}
+
+		public static PollRepContent GetInstance(object obj)
+		{
+			if (obj is PollRepContent)
+				return (PollRepContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new PollRepContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual DerInteger CertReqID
+		{
+			get { return certReqId; }
+		}
+
+		public virtual DerInteger CheckAfter
+		{
+			get { return checkAfter; }
+		}
+
+		public virtual PkiFreeText Reason
+		{
+			get { return reason; }
+		}
+
+		/**
+		 * <pre>
+		 * PollRepContent ::= SEQUENCE OF SEQUENCE {
+		 *         certReqId              INTEGER,
+		 *         checkAfter             INTEGER,  -- time in seconds
+		 *         reason                 PKIFreeText OPTIONAL
+		 *     }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(certReqId, checkAfter);
+			v.AddOptional(reason);
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/PollReqContent.cs b/Crypto/src/asn1/cmp/PollReqContent.cs
new file mode 100644
index 000000000..ca2164151
--- /dev/null
+++ b/Crypto/src/asn1/cmp/PollReqContent.cs
@@ -0,0 +1,59 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class PollReqContent
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence content;
+
+		private PollReqContent(Asn1Sequence seq)
+		{
+			content = seq;
+		}
+
+		public static PollReqContent GetInstance(object obj)
+		{
+			if (obj is PollReqContent)
+				return (PollReqContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new PollReqContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual DerInteger[][] GetCertReqIDs()
+		{
+			DerInteger[][] result = new DerInteger[content.Count][];
+			for (int i = 0; i != result.Length; ++i)
+			{
+				result[i] = SequenceToDerIntegerArray((Asn1Sequence)content[i]);
+			}
+			return result;
+		}
+
+		private static DerInteger[] SequenceToDerIntegerArray(Asn1Sequence seq)
+		{
+			DerInteger[] result = new DerInteger[seq.Count];
+			for (int i = 0; i != result.Length; ++i)
+			{
+				result[i] = DerInteger.GetInstance(seq[i]);
+			}
+			return result;
+		}
+
+		/**
+		 * <pre>
+		 * PollReqContent ::= SEQUENCE OF SEQUENCE {
+		 *                        certReqId              INTEGER
+		 * }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return content;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/PopoDecKeyChallContent.cs b/Crypto/src/asn1/cmp/PopoDecKeyChallContent.cs
new file mode 100644
index 000000000..20b173b85
--- /dev/null
+++ b/Crypto/src/asn1/cmp/PopoDecKeyChallContent.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class PopoDecKeyChallContent
+	    : Asn1Encodable
+	{
+	    private readonly Asn1Sequence content;
+
+	    private PopoDecKeyChallContent(Asn1Sequence seq)
+	    {
+	        content = seq;
+	    }
+
+	    public static PopoDecKeyChallContent GetInstance(object obj)
+	    {
+	        if (obj is PopoDecKeyChallContent)
+	            return (PopoDecKeyChallContent)obj;
+
+			if (obj is Asn1Sequence)
+	            return new PopoDecKeyChallContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+	    }
+
+	    public virtual Challenge[] ToChallengeArray()
+	    {
+	        Challenge[] result = new Challenge[content.Count];
+	        for (int i = 0; i != result.Length; ++i)
+	        {
+	            result[i] = Challenge.GetInstance(content[i]);
+	        }
+	        return result;
+	    }
+
+	    /**
+	     * <pre>
+	     * PopoDecKeyChallContent ::= SEQUENCE OF Challenge
+	     * </pre>
+	     * @return a basic ASN.1 object representation.
+	     */
+	    public override Asn1Object ToAsn1Object()
+	    {
+	        return content;
+	    }
+	}
+}
diff --git a/Crypto/src/asn1/cmp/PopoDecKeyRespContent.cs b/Crypto/src/asn1/cmp/PopoDecKeyRespContent.cs
new file mode 100644
index 000000000..8c322e4ec
--- /dev/null
+++ b/Crypto/src/asn1/cmp/PopoDecKeyRespContent.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class PopoDecKeyRespContent
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence content;
+
+		private PopoDecKeyRespContent(Asn1Sequence seq)
+		{
+			content = seq;
+		}
+
+		public static PopoDecKeyRespContent GetInstance(object obj)
+		{
+			if (obj is PopoDecKeyRespContent)
+				return (PopoDecKeyRespContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new PopoDecKeyRespContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual DerInteger[] ToDerIntegerArray()
+		{
+			DerInteger[] result = new DerInteger[content.Count];
+			for (int i = 0; i != result.Length; ++i)
+			{
+				result[i] = DerInteger.GetInstance(content[i]);
+			}
+			return result;
+		}
+
+		/**
+		 * <pre>
+		 * PopoDecKeyRespContent ::= SEQUENCE OF INTEGER
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return content;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/ProtectedPart.cs b/Crypto/src/asn1/cmp/ProtectedPart.cs
new file mode 100644
index 000000000..db6798fee
--- /dev/null
+++ b/Crypto/src/asn1/cmp/ProtectedPart.cs
@@ -0,0 +1,58 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class ProtectedPart
+		: Asn1Encodable
+	{
+		private readonly PkiHeader header;
+		private readonly PkiBody body;
+		
+		private ProtectedPart(Asn1Sequence seq)
+		{
+			header = PkiHeader.GetInstance(seq[0]);
+			body = PkiBody.GetInstance(seq[1]);
+		}
+
+		public static ProtectedPart GetInstance(object obj)
+		{
+			if (obj is ProtectedPart)
+				return (ProtectedPart)obj;
+
+			if (obj is Asn1Sequence)
+				return new ProtectedPart((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public ProtectedPart(PkiHeader header, PkiBody body)
+		{
+			this.header = header;
+			this.body = body;
+		}
+
+		public virtual PkiHeader Header
+		{
+			get { return header; }
+		}
+
+		public virtual PkiBody Body
+		{
+			get { return body; }
+		}
+
+		/**
+		 * <pre>
+		 * ProtectedPart ::= SEQUENCE {
+		 *                    header    PKIHeader,
+		 *                    body      PKIBody
+		 * }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(header, body);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/RevAnnContent.cs b/Crypto/src/asn1/cmp/RevAnnContent.cs
new file mode 100644
index 000000000..2c3bd5f77
--- /dev/null
+++ b/Crypto/src/asn1/cmp/RevAnnContent.cs
@@ -0,0 +1,86 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class RevAnnContent
+		: Asn1Encodable
+	{
+		private readonly PkiStatusEncodable status;
+		private readonly CertId certId;
+		private readonly DerGeneralizedTime willBeRevokedAt;
+		private readonly DerGeneralizedTime badSinceDate;
+		private readonly X509Extensions crlDetails;
+
+		private RevAnnContent(Asn1Sequence seq)
+		{
+			status = PkiStatusEncodable.GetInstance(seq[0]);
+			certId = CertId.GetInstance(seq[1]);
+			willBeRevokedAt = DerGeneralizedTime.GetInstance(seq[2]);
+			badSinceDate = DerGeneralizedTime.GetInstance(seq[3]);
+
+			if (seq.Count > 4)
+			{
+				crlDetails = X509Extensions.GetInstance(seq[4]);
+			}
+		}
+
+		public static RevAnnContent GetInstance(object obj)
+		{
+			if (obj is RevAnnContent)
+				return (RevAnnContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new RevAnnContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual PkiStatusEncodable Status
+		{
+			get { return status; }
+		}
+
+		public virtual CertId CertID
+		{
+			get { return certId; }
+		}
+
+		public virtual DerGeneralizedTime WillBeRevokedAt
+		{
+			get { return willBeRevokedAt; }
+		}
+
+		public virtual DerGeneralizedTime BadSinceDate
+		{
+			get { return badSinceDate; }
+		}
+
+		public virtual X509Extensions CrlDetails
+		{
+			get { return crlDetails; }
+		}
+
+		/**
+		 * <pre>
+		 * RevAnnContent ::= SEQUENCE {
+		 *       status              PKIStatus,
+		 *       certId              CertId,
+		 *       willBeRevokedAt     GeneralizedTime,
+		 *       badSinceDate        GeneralizedTime,
+		 *       crlDetails          Extensions  OPTIONAL
+		 *        -- extra CRL details (e.g., crl number, reason, location, etc.)
+		 * }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(status, certId, willBeRevokedAt, badSinceDate);
+			v.AddOptional(crlDetails);
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/RevDetails.cs b/Crypto/src/asn1/cmp/RevDetails.cs
new file mode 100644
index 000000000..1bd95f1db
--- /dev/null
+++ b/Crypto/src/asn1/cmp/RevDetails.cs
@@ -0,0 +1,75 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class RevDetails
+		: Asn1Encodable
+	{
+		private readonly CertTemplate certDetails;
+		private readonly X509Extensions crlEntryDetails;
+
+		private RevDetails(Asn1Sequence seq)
+		{
+			certDetails = CertTemplate.GetInstance(seq[0]);
+
+			if  (seq.Count > 1)
+			{
+				crlEntryDetails = X509Extensions.GetInstance(seq[1]);
+			}
+		}
+
+		public static RevDetails GetInstance(object obj)
+		{
+			if (obj is RevDetails)
+				return (RevDetails)obj;
+
+			if (obj is Asn1Sequence)
+				return new RevDetails((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public RevDetails(CertTemplate certDetails)
+		{
+			this.certDetails = certDetails;
+		}
+		
+		public RevDetails(CertTemplate certDetails, X509Extensions crlEntryDetails)
+		{
+			this.crlEntryDetails = crlEntryDetails;
+		}
+
+		public virtual CertTemplate CertDetails
+		{
+			get { return certDetails; }
+		}
+
+		public virtual X509Extensions CrlEntryDetails
+		{
+			get { return crlEntryDetails; }
+		}
+
+		/**
+		* <pre>
+		* RevDetails ::= SEQUENCE {
+		*                  certDetails         CertTemplate,
+		*                   -- allows requester to specify as much as they can about
+		*                   -- the cert. for which revocation is requested
+		*                   -- (e.g., for cases in which serialNumber is not available)
+		*                   crlEntryDetails     Extensions       OPTIONAL
+		*                   -- requested crlEntryExtensions
+		*             }
+		* </pre>
+		* @return a basic ASN.1 object representation.
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(certDetails);
+			v.AddOptional(crlEntryDetails);
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/RevRepContent.cs b/Crypto/src/asn1/cmp/RevRepContent.cs
new file mode 100644
index 000000000..47987265a
--- /dev/null
+++ b/Crypto/src/asn1/cmp/RevRepContent.cs
@@ -0,0 +1,112 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class RevRepContent
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence status;
+		private readonly Asn1Sequence revCerts;
+		private readonly Asn1Sequence crls;
+
+		private RevRepContent(Asn1Sequence seq)
+		{
+			status = Asn1Sequence.GetInstance(seq[0]);
+
+			for (int pos = 1; pos < seq.Count; ++pos)
+			{
+				Asn1TaggedObject tObj = Asn1TaggedObject.GetInstance(seq[pos]);
+
+				if (tObj.TagNo == 0)
+				{
+					revCerts = Asn1Sequence.GetInstance(tObj, true);
+				}
+				else
+				{
+					crls = Asn1Sequence.GetInstance(tObj, true);
+				}
+			}
+		}
+
+		public static RevRepContent GetInstance(object obj)
+		{
+			if (obj is RevRepContent)
+				return (RevRepContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new RevRepContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+		
+		public virtual PkiStatusInfo[] GetStatus()
+		{
+			PkiStatusInfo[] results = new PkiStatusInfo[status.Count];
+			for (int i = 0; i != results.Length; ++i)
+			{
+				results[i] = PkiStatusInfo.GetInstance(status[i]);
+			}
+			return results;
+		}
+
+		public virtual CertId[] GetRevCerts()
+		{
+			if (revCerts == null)
+				return null;
+
+			CertId[] results = new CertId[revCerts.Count];
+			for (int i = 0; i != results.Length; ++i)
+			{
+				results[i] = CertId.GetInstance(revCerts[i]);
+			}
+			return results;
+		}
+
+		public virtual CertificateList[] GetCrls()
+		{
+			if (crls == null)
+				return null;
+
+			CertificateList[] results = new CertificateList[crls.Count];
+			for (int i = 0; i != results.Length; ++i)
+			{
+				results[i] = CertificateList.GetInstance(crls[i]);
+			}
+			return results;
+		}
+
+		/**
+		 * <pre>
+		 * RevRepContent ::= SEQUENCE {
+		 *        status       SEQUENCE SIZE (1..MAX) OF PKIStatusInfo,
+		 *        -- in same order as was sent in RevReqContent
+		 *        revCerts [0] SEQUENCE SIZE (1..MAX) OF CertId OPTIONAL,
+		 *        -- IDs for which revocation was requested
+		 *        -- (same order as status)
+		 *        crls     [1] SEQUENCE SIZE (1..MAX) OF CertificateList OPTIONAL
+		 *        -- the resulting CRLs (there may be more than one)
+		 *   }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(status);
+			AddOptional(v, 0, revCerts);
+			AddOptional(v, 1, crls);
+			return new DerSequence(v);
+		}
+
+		private void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+		{
+			if (obj != null)
+			{
+				v.Add(new DerTaggedObject(true, tagNo, obj));
+			}
+		}
+	}
+}
+
diff --git a/Crypto/src/asn1/cmp/RevRepContentBuilder.cs b/Crypto/src/asn1/cmp/RevRepContentBuilder.cs
new file mode 100644
index 000000000..cc17d1d4c
--- /dev/null
+++ b/Crypto/src/asn1/cmp/RevRepContentBuilder.cs
@@ -0,0 +1,55 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class RevRepContentBuilder
+	{
+		private readonly Asn1EncodableVector status = new Asn1EncodableVector();
+		private readonly Asn1EncodableVector revCerts = new Asn1EncodableVector();
+		private readonly Asn1EncodableVector crls = new Asn1EncodableVector();
+
+		public virtual RevRepContentBuilder Add(PkiStatusInfo status)
+		{
+			this.status.Add(status);
+			return this;
+		}
+
+		public virtual RevRepContentBuilder Add(PkiStatusInfo status, CertId certId)
+		{
+			if (this.status.Count != this.revCerts.Count)
+				throw new InvalidOperationException("status and revCerts sequence must be in common order");
+
+			this.status.Add(status);
+			this.revCerts.Add(certId);
+			return this;
+		}
+
+		public virtual RevRepContentBuilder AddCrl(CertificateList crl)
+		{
+			this.crls.Add(crl);
+			return this;
+		}
+
+		public virtual RevRepContent Build()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			v.Add(new DerSequence(status));
+
+			if (revCerts.Count != 0)
+			{
+				v.Add(new DerTaggedObject(true, 0, new DerSequence(revCerts)));
+			}
+
+			if (crls.Count != 0)
+			{
+				v.Add(new DerTaggedObject(true, 1, new DerSequence(crls)));
+			}
+
+			return RevRepContent.GetInstance(new DerSequence(v));
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cmp/RevReqContent.cs b/Crypto/src/asn1/cmp/RevReqContent.cs
new file mode 100644
index 000000000..fbf869203
--- /dev/null
+++ b/Crypto/src/asn1/cmp/RevReqContent.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class RevReqContent
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence content;
+		
+		private RevReqContent(Asn1Sequence seq)
+		{
+			content = seq;
+		}
+
+		public static RevReqContent GetInstance(object obj)
+		{
+			if (obj is RevReqContent)
+				return (RevReqContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new RevReqContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public RevReqContent(params RevDetails[] revDetails)
+		{
+			this.content = new DerSequence(revDetails);
+		}
+
+		public virtual RevDetails[] ToRevDetailsArray()
+		{
+			RevDetails[] result = new RevDetails[content.Count];
+			for (int i = 0; i != result.Length; ++i)
+			{
+				result[i] = RevDetails.GetInstance(content[i]);
+			}
+			return result;
+		}
+
+		/**
+		 * <pre>
+		 * RevReqContent ::= SEQUENCE OF RevDetails
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return content;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/Attribute.cs b/Crypto/src/asn1/cms/Attribute.cs
new file mode 100644
index 000000000..c4a104a3f
--- /dev/null
+++ b/Crypto/src/asn1/cms/Attribute.cs
@@ -0,0 +1,70 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class Attribute
+        : Asn1Encodable
+    {
+        private DerObjectIdentifier	attrType;
+        private Asn1Set				attrValues;
+
+		/**
+        * return an Attribute object from the given object.
+        *
+        * @param o the object we want converted.
+        * @exception ArgumentException if the object cannot be converted.
+        */
+        public static Attribute GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is Attribute)
+				return (Attribute) obj;
+
+			if (obj is Asn1Sequence)
+                return new Attribute((Asn1Sequence) obj);
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        }
+
+		public Attribute(
+            Asn1Sequence seq)
+        {
+            attrType = (DerObjectIdentifier)seq[0];
+            attrValues = (Asn1Set)seq[1];
+        }
+
+		public Attribute(
+            DerObjectIdentifier attrType,
+            Asn1Set             attrValues)
+        {
+            this.attrType = attrType;
+            this.attrValues = attrValues;
+        }
+
+        public DerObjectIdentifier AttrType
+		{
+			get { return attrType; }
+		}
+
+		public Asn1Set AttrValues
+		{
+			get { return attrValues; }
+		}
+
+		/**
+        * Produce an object suitable for an Asn1OutputStream.
+        * <pre>
+        * Attribute ::= SEQUENCE {
+        *     attrType OBJECT IDENTIFIER,
+        *     attrValues SET OF AttributeValue
+        * }
+        * </pre>
+        */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(attrType, attrValues);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/AttributeTable.cs b/Crypto/src/asn1/cms/AttributeTable.cs
new file mode 100644
index 000000000..3c0164ce8
--- /dev/null
+++ b/Crypto/src/asn1/cms/AttributeTable.cs
@@ -0,0 +1,231 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class AttributeTable
+    {
+        private readonly IDictionary attributes;
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete]
+        public AttributeTable(
+            Hashtable attrs)
+        {
+            this.attributes = Platform.CreateHashtable(attrs);
+        }
+#endif
+
+        public AttributeTable(
+            IDictionary attrs)
+        {
+            this.attributes = Platform.CreateHashtable(attrs);
+        }
+
+        public AttributeTable(
+            Asn1EncodableVector v)
+        {
+            this.attributes = Platform.CreateHashtable(v.Count);
+
+			foreach (Asn1Encodable o in v)
+            {
+                Attribute a = Attribute.GetInstance(o);
+
+				AddAttribute(a);
+            }
+        }
+
+        public AttributeTable(
+            Asn1Set s)
+        {
+            this.attributes = Platform.CreateHashtable(s.Count);
+
+			for (int i = 0; i != s.Count; i++)
+            {
+                Attribute a = Attribute.GetInstance(s[i]);
+
+                AddAttribute(a);
+            }
+        }
+
+		public AttributeTable(
+			Attributes attrs)
+			: this(Asn1Set.GetInstance(attrs.ToAsn1Object()))
+		{
+		}
+
+		private void AddAttribute(
+            Attribute a)
+        {
+			DerObjectIdentifier oid = a.AttrType;
+            object obj = attributes[oid];
+
+            if (obj == null)
+            {
+                attributes[oid] = a;
+            }
+            else
+            {
+                IList v;
+
+                if (obj is Attribute)
+                {
+                    v = Platform.CreateArrayList();
+
+                    v.Add(obj);
+                    v.Add(a);
+                }
+                else
+                {
+                    v = (IList) obj;
+
+                    v.Add(a);
+                }
+
+                attributes[oid] = v;
+            }
+        }
+
+		/// <summary>Return the first attribute matching the given OBJECT IDENTIFIER</summary>
+		public Attribute this[DerObjectIdentifier oid]
+		{
+			get
+			{
+				object obj = attributes[oid];
+
+				if (obj is IList)
+				{
+					return (Attribute)((IList)obj)[0];
+				}
+
+				return (Attribute) obj;
+			}
+		}
+
+		[Obsolete("Use 'object[oid]' syntax instead")]
+        public Attribute Get(
+            DerObjectIdentifier oid)
+        {
+			return this[oid];
+        }
+
+		/**
+        * Return all the attributes matching the OBJECT IDENTIFIER oid. The vector will be
+        * empty if there are no attributes of the required type present.
+        *
+        * @param oid type of attribute required.
+        * @return a vector of all the attributes found of type oid.
+        */
+        public Asn1EncodableVector GetAll(
+            DerObjectIdentifier oid)
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            object obj = attributes[oid];
+
+			if (obj is IList)
+            {
+                foreach (Attribute a in (IList)obj)
+                {
+                    v.Add(a);
+                }
+            }
+            else if (obj != null)
+            {
+                v.Add((Attribute) obj);
+            }
+
+			return v;
+        }
+
+		public int Count
+		{
+			get
+			{
+				int total = 0;
+
+				foreach (object o in attributes.Values)
+				{
+					if (o is IList)
+					{
+						total += ((IList)o).Count;
+					}
+					else
+					{
+						++total;
+					}
+				}
+
+				return total;
+			}
+		}
+
+        public IDictionary ToDictionary()
+        {
+            return Platform.CreateHashtable(attributes);
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete("Use 'ToDictionary' instead")]
+		public Hashtable ToHashtable()
+        {
+            return new Hashtable(attributes);
+        }
+#endif
+
+        public Asn1EncodableVector ToAsn1EncodableVector()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			foreach (object obj in attributes.Values)
+            {
+                if (obj is IList)
+                {
+                    foreach (object el in (IList)obj)
+                    {
+                        v.Add(Attribute.GetInstance(el));
+                    }
+                }
+                else
+                {
+                    v.Add(Attribute.GetInstance(obj));
+                }
+            }
+
+			return v;
+        }
+
+		public Attributes ToAttributes()
+		{
+			return new Attributes(this.ToAsn1EncodableVector());
+		}
+
+		/**
+		 * Return a new table with the passed in attribute added.
+		 *
+		 * @param attrType
+		 * @param attrValue
+		 * @return
+		 */
+		public AttributeTable Add(DerObjectIdentifier attrType, Asn1Encodable attrValue)
+		{
+			AttributeTable newTable = new AttributeTable(attributes);
+
+			newTable.AddAttribute(new Attribute(attrType, new DerSet(attrValue)));
+
+			return newTable;
+		}
+
+		public AttributeTable Remove(DerObjectIdentifier attrType)
+		{
+			AttributeTable newTable = new AttributeTable(attributes);
+
+			newTable.attributes.Remove(attrType);
+
+			return newTable;
+		}
+    }
+}
diff --git a/Crypto/src/asn1/cms/Attributes.cs b/Crypto/src/asn1/cms/Attributes.cs
new file mode 100644
index 000000000..47cb66bdb
--- /dev/null
+++ b/Crypto/src/asn1/cms/Attributes.cs
@@ -0,0 +1,43 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class Attributes
+		: Asn1Encodable
+	{
+		private readonly Asn1Set attributes;
+
+		private Attributes(Asn1Set attributes)
+		{
+			this.attributes = attributes;
+		}
+
+		public Attributes(Asn1EncodableVector v)
+		{
+			attributes = new BerSet(v);
+		}
+
+		public static Attributes GetInstance(object obj)
+		{
+			if (obj is Attributes)
+				return (Attributes)obj;
+
+			if (obj != null)
+				return new Attributes(Asn1Set.GetInstance(obj));
+
+			return null;
+		}
+
+		/**
+		 * <pre>
+		 * Attributes ::=
+		 *   SET SIZE(1..MAX) OF Attribute -- according to RFC 5652
+		 * </pre>
+		 * @return
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return attributes;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/AuthEnvelopedData.cs b/Crypto/src/asn1/cms/AuthEnvelopedData.cs
new file mode 100644
index 000000000..4260d80f9
--- /dev/null
+++ b/Crypto/src/asn1/cms/AuthEnvelopedData.cs
@@ -0,0 +1,203 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class AuthEnvelopedData
+		: Asn1Encodable
+	{
+		private DerInteger				version;
+		private OriginatorInfo			originatorInfo;
+		private Asn1Set					recipientInfos;
+		private EncryptedContentInfo	authEncryptedContentInfo;
+		private Asn1Set					authAttrs;
+		private Asn1OctetString			mac;
+		private Asn1Set					unauthAttrs;
+
+		public AuthEnvelopedData(
+			OriginatorInfo			originatorInfo,
+			Asn1Set					recipientInfos,
+			EncryptedContentInfo	authEncryptedContentInfo,
+			Asn1Set					authAttrs,
+			Asn1OctetString			mac,
+			Asn1Set					unauthAttrs)
+		{
+			// "It MUST be set to 0."
+			this.version = new DerInteger(0);
+
+			this.originatorInfo = originatorInfo;
+
+			// TODO
+			// "There MUST be at least one element in the collection."
+			this.recipientInfos = recipientInfos;
+
+			this.authEncryptedContentInfo = authEncryptedContentInfo;
+
+			// TODO
+			// "The authAttrs MUST be present if the content type carried in
+			// EncryptedContentInfo is not id-data."
+			this.authAttrs = authAttrs;
+
+			this.mac = mac;
+
+			this.unauthAttrs = unauthAttrs;
+	    }
+
+		private AuthEnvelopedData(
+			Asn1Sequence	seq)
+		{
+			int index = 0;
+
+			// TODO
+			// "It MUST be set to 0."
+			Asn1Object tmp = seq[index++].ToAsn1Object();
+			version = (DerInteger)tmp;
+
+			tmp = seq[index++].ToAsn1Object();
+			if (tmp is Asn1TaggedObject)
+			{
+				originatorInfo = OriginatorInfo.GetInstance((Asn1TaggedObject)tmp, false);
+				tmp = seq[index++].ToAsn1Object();
+			}
+
+			// TODO
+			// "There MUST be at least one element in the collection."
+			recipientInfos = Asn1Set.GetInstance(tmp);
+
+			tmp = seq[index++].ToAsn1Object();
+			authEncryptedContentInfo = EncryptedContentInfo.GetInstance(tmp);
+
+			tmp = seq[index++].ToAsn1Object();
+			if (tmp is Asn1TaggedObject)
+			{
+				authAttrs = Asn1Set.GetInstance((Asn1TaggedObject)tmp, false);
+				tmp = seq[index++].ToAsn1Object();
+			}
+			else
+			{
+				// TODO
+				// "The authAttrs MUST be present if the content type carried in
+				// EncryptedContentInfo is not id-data."
+			}
+
+			mac = Asn1OctetString.GetInstance(tmp);
+
+			if (seq.Count > index)
+			{
+				tmp = seq[index++].ToAsn1Object();
+				unauthAttrs = Asn1Set.GetInstance((Asn1TaggedObject)tmp, false);
+			}
+		}
+
+		/**
+		 * return an AuthEnvelopedData object from a tagged object.
+		 *
+		 * @param obj      the tagged object holding the object we want.
+		 * @param isExplicit true if the object is meant to be explicitly
+		 *                 tagged false otherwise.
+		 * @throws ArgumentException if the object held by the
+		 *                                  tagged object cannot be converted.
+		 */
+		public static AuthEnvelopedData GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+
+		/**
+		 * return an AuthEnvelopedData object from the given object.
+		 *
+		 * @param obj the object we want converted.
+		 * @throws ArgumentException if the object cannot be converted.
+		 */
+		public static AuthEnvelopedData GetInstance(
+			object	obj)
+		{
+			if (obj == null || obj is AuthEnvelopedData)
+				return (AuthEnvelopedData)obj;
+
+			if (obj is Asn1Sequence)
+				return new AuthEnvelopedData((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid AuthEnvelopedData: " + obj.GetType().Name);
+		}
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public OriginatorInfo OriginatorInfo
+		{
+			get { return originatorInfo; }
+		}
+
+		public Asn1Set RecipientInfos
+		{
+			get { return recipientInfos; }
+		}
+
+		public EncryptedContentInfo AuthEncryptedContentInfo
+		{
+			get { return authEncryptedContentInfo; }
+		}
+
+		public Asn1Set AuthAttrs
+		{
+			get { return authAttrs; }
+		}
+
+		public Asn1OctetString Mac
+		{
+			get { return mac; }
+		}
+
+		public Asn1Set UnauthAttrs
+		{
+			get { return unauthAttrs; }
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * <pre>
+		 * AuthEnvelopedData ::= SEQUENCE {
+		 *   version CMSVersion,
+		 *   originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+		 *   recipientInfos RecipientInfos,
+		 *   authEncryptedContentInfo EncryptedContentInfo,
+		 *   authAttrs [1] IMPLICIT AuthAttributes OPTIONAL,
+		 *   mac MessageAuthenticationCode,
+		 *   unauthAttrs [2] IMPLICIT UnauthAttributes OPTIONAL }
+		 * </pre>
+		 */
+	    public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(version);
+
+			if (originatorInfo != null)
+			{
+				v.Add(new DerTaggedObject(false, 0, originatorInfo));
+			}
+
+			v.Add(recipientInfos, authEncryptedContentInfo);
+
+			// "authAttrs optionally contains the authenticated attributes."
+			if (authAttrs != null)
+			{
+				// "AuthAttributes MUST be DER encoded, even if the rest of the
+				// AuthEnvelopedData structure is BER encoded."
+				v.Add(new DerTaggedObject(false, 1, authAttrs));
+			}
+
+			v.Add(mac);
+
+			// "unauthAttrs optionally contains the unauthenticated attributes."
+			if (unauthAttrs != null)
+			{
+				v.Add(new DerTaggedObject(false, 2, unauthAttrs));
+			}
+
+			return new BerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/AuthEnvelopedDataParser.cs b/Crypto/src/asn1/cms/AuthEnvelopedDataParser.cs
new file mode 100644
index 000000000..35cb3bfcc
--- /dev/null
+++ b/Crypto/src/asn1/cms/AuthEnvelopedDataParser.cs
@@ -0,0 +1,145 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	/**
+	 * Produce an object suitable for an Asn1OutputStream.
+	 * 
+	 * <pre>
+	 * AuthEnvelopedData ::= SEQUENCE {
+	 *   version CMSVersion,
+	 *   originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+	 *   recipientInfos RecipientInfos,
+	 *   authEncryptedContentInfo EncryptedContentInfo,
+	 *   authAttrs [1] IMPLICIT AuthAttributes OPTIONAL,
+	 *   mac MessageAuthenticationCode,
+	 *   unauthAttrs [2] IMPLICIT UnauthAttributes OPTIONAL }
+	 * </pre>
+	*/
+	public class AuthEnvelopedDataParser
+	{
+		private Asn1SequenceParser	seq;
+		private DerInteger			version;
+		private IAsn1Convertible	nextObject;
+		private bool				originatorInfoCalled;
+
+		public AuthEnvelopedDataParser(
+			Asn1SequenceParser	seq)
+		{
+			this.seq = seq;
+
+			// TODO
+			// "It MUST be set to 0."
+			this.version = (DerInteger)seq.ReadObject();
+		}
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public OriginatorInfo GetOriginatorInfo()
+		{
+			originatorInfoCalled = true;
+
+			if (nextObject == null)
+			{
+				nextObject = seq.ReadObject();
+			}
+
+			if (nextObject is Asn1TaggedObjectParser && ((Asn1TaggedObjectParser)nextObject).TagNo == 0)
+			{
+				Asn1SequenceParser originatorInfo = (Asn1SequenceParser) ((Asn1TaggedObjectParser)nextObject).GetObjectParser(Asn1Tags.Sequence, false);
+				nextObject = null;
+				return OriginatorInfo.GetInstance(originatorInfo.ToAsn1Object());
+			}
+
+			return null;
+		}
+
+		public Asn1SetParser GetRecipientInfos()
+		{
+			if (!originatorInfoCalled)
+			{
+				GetOriginatorInfo();
+			}
+
+			if (nextObject == null)
+			{
+				nextObject = seq.ReadObject();
+			}
+
+			Asn1SetParser recipientInfos = (Asn1SetParser)nextObject;
+			nextObject = null;
+			return recipientInfos;
+		}
+
+		public EncryptedContentInfoParser GetAuthEncryptedContentInfo() 
+		{
+			if (nextObject == null)
+			{
+				nextObject = seq.ReadObject();
+			}
+
+			if (nextObject != null)
+			{
+				Asn1SequenceParser o = (Asn1SequenceParser) nextObject;
+				nextObject = null;
+				return new EncryptedContentInfoParser(o);
+			}
+
+			return null;
+		}
+		
+		public Asn1SetParser GetAuthAttrs()
+		{
+			if (nextObject == null)
+			{
+				nextObject = seq.ReadObject();
+			}
+
+			if (nextObject is Asn1TaggedObjectParser)
+			{
+				IAsn1Convertible o = nextObject;
+				nextObject = null;
+				return (Asn1SetParser)((Asn1TaggedObjectParser)o).GetObjectParser(Asn1Tags.Set, false);
+			}
+
+			// TODO
+			// "The authAttrs MUST be present if the content type carried in
+			// EncryptedContentInfo is not id-data."
+
+			return null;
+		}
+		
+		public Asn1OctetString GetMac()
+		{
+			if (nextObject == null)
+			{
+				nextObject = seq.ReadObject();
+			}
+
+			IAsn1Convertible o = nextObject;
+			nextObject = null;
+
+			return Asn1OctetString.GetInstance(o.ToAsn1Object());
+		}
+		
+		public Asn1SetParser GetUnauthAttrs()
+		{
+			if (nextObject == null)
+			{
+				nextObject = seq.ReadObject();
+			}
+
+			if (nextObject != null)
+			{
+				IAsn1Convertible o = nextObject;
+				nextObject = null;
+				return (Asn1SetParser)((Asn1TaggedObjectParser)o).GetObjectParser(Asn1Tags.Set, false);
+			}
+
+			return null;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/AuthenticatedData.cs b/Crypto/src/asn1/cms/AuthenticatedData.cs
new file mode 100644
index 000000000..15286d1aa
--- /dev/null
+++ b/Crypto/src/asn1/cms/AuthenticatedData.cs
@@ -0,0 +1,270 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class AuthenticatedData
+		: Asn1Encodable
+	{
+		private DerInteger version;
+		private OriginatorInfo originatorInfo;
+		private Asn1Set recipientInfos;
+		private AlgorithmIdentifier macAlgorithm;
+		private AlgorithmIdentifier digestAlgorithm;
+		private ContentInfo encapsulatedContentInfo;
+		private Asn1Set authAttrs;
+		private Asn1OctetString mac;
+		private Asn1Set unauthAttrs;
+
+		public AuthenticatedData(
+			OriginatorInfo		originatorInfo,
+			Asn1Set				recipientInfos,
+			AlgorithmIdentifier	macAlgorithm,
+			AlgorithmIdentifier	digestAlgorithm,
+			ContentInfo			encapsulatedContent,
+			Asn1Set				authAttrs,
+			Asn1OctetString		mac,
+			Asn1Set				unauthAttrs)
+		{
+			if (digestAlgorithm != null || authAttrs != null)
+			{
+				if (digestAlgorithm == null || authAttrs == null)
+				{
+					throw new ArgumentException("digestAlgorithm and authAttrs must be set together");
+				}
+			}
+
+			version = new DerInteger(CalculateVersion(originatorInfo));
+
+			this.originatorInfo = originatorInfo;
+			this.macAlgorithm = macAlgorithm;
+			this.digestAlgorithm = digestAlgorithm;
+			this.recipientInfos = recipientInfos;
+			this.encapsulatedContentInfo = encapsulatedContent;
+			this.authAttrs = authAttrs;
+			this.mac = mac;
+			this.unauthAttrs = unauthAttrs;
+		}
+
+		private AuthenticatedData(
+			Asn1Sequence	seq)
+		{
+			int index = 0;
+
+			version = (DerInteger)seq[index++];
+
+			Asn1Encodable tmp = seq[index++];
+			if (tmp is Asn1TaggedObject)
+			{
+				originatorInfo = OriginatorInfo.GetInstance((Asn1TaggedObject)tmp, false);
+				tmp = seq[index++];
+			}
+
+			recipientInfos = Asn1Set.GetInstance(tmp);
+			macAlgorithm = AlgorithmIdentifier.GetInstance(seq[index++]);
+
+			tmp = seq[index++];
+			if (tmp is Asn1TaggedObject)
+			{
+				digestAlgorithm = AlgorithmIdentifier.GetInstance((Asn1TaggedObject)tmp, false);
+				tmp = seq[index++];
+			}
+
+			encapsulatedContentInfo = ContentInfo.GetInstance(tmp);
+
+			tmp = seq[index++];
+			if (tmp is Asn1TaggedObject)
+			{
+				authAttrs = Asn1Set.GetInstance((Asn1TaggedObject)tmp, false);
+				tmp = seq[index++];
+			}
+
+			mac = Asn1OctetString.GetInstance(tmp);
+
+			if (seq.Count > index)
+			{
+				unauthAttrs = Asn1Set.GetInstance((Asn1TaggedObject)seq[index], false);
+			}
+		}
+
+		/**
+		 * return an AuthenticatedData object from a tagged object.
+		 *
+		 * @param obj      the tagged object holding the object we want.
+		 * @param isExplicit true if the object is meant to be explicitly
+		 *                 tagged false otherwise.
+		 * @throws ArgumentException if the object held by the
+		 *                                  tagged object cannot be converted.
+		 */
+		public static AuthenticatedData GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+
+		/**
+		 * return an AuthenticatedData object from the given object.
+		 *
+		 * @param obj the object we want converted.
+		 * @throws ArgumentException if the object cannot be converted.
+		 */
+		public static AuthenticatedData GetInstance(
+			object	obj)
+		{
+			if (obj == null || obj is AuthenticatedData)
+			{
+				return (AuthenticatedData)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new AuthenticatedData((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("Invalid AuthenticatedData: " + obj.GetType().Name);
+		}
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public OriginatorInfo OriginatorInfo
+		{
+			get { return originatorInfo; }
+		}
+
+		public Asn1Set RecipientInfos
+		{
+			get { return recipientInfos; }
+		}
+
+		public AlgorithmIdentifier MacAlgorithm
+		{
+			get { return macAlgorithm; }
+		}
+
+        public AlgorithmIdentifier DigestAlgorithm
+        {
+            get { return digestAlgorithm; }
+        }
+
+		public ContentInfo EncapsulatedContentInfo
+		{
+			get { return encapsulatedContentInfo; }
+		}
+
+		public Asn1Set AuthAttrs
+		{
+			get { return authAttrs; }
+		}
+
+		public Asn1OctetString Mac
+		{
+			get { return mac; }
+		}
+
+		public Asn1Set UnauthAttrs
+		{
+			get { return unauthAttrs; }
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * <pre>
+		 * AuthenticatedData ::= SEQUENCE {
+		 *       version CMSVersion,
+		 *       originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+		 *       recipientInfos RecipientInfos,
+		 *       macAlgorithm MessageAuthenticationCodeAlgorithm,
+		 *       digestAlgorithm [1] DigestAlgorithmIdentifier OPTIONAL,
+		 *       encapContentInfo EncapsulatedContentInfo,
+		 *       authAttrs [2] IMPLICIT AuthAttributes OPTIONAL,
+		 *       mac MessageAuthenticationCode,
+		 *       unauthAttrs [3] IMPLICIT UnauthAttributes OPTIONAL }
+		 *
+		 * AuthAttributes ::= SET SIZE (1..MAX) OF Attribute
+		 *
+		 * UnauthAttributes ::= SET SIZE (1..MAX) OF Attribute
+		 *
+		 * MessageAuthenticationCode ::= OCTET STRING
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(version);
+
+			if (originatorInfo != null)
+			{
+				v.Add(new DerTaggedObject(false, 0, originatorInfo));
+			}
+
+			v.Add(recipientInfos, macAlgorithm);
+
+			if (digestAlgorithm != null)
+			{
+				v.Add(new DerTaggedObject(false, 1, digestAlgorithm));
+			}
+
+			v.Add(encapsulatedContentInfo);
+
+			if (authAttrs != null)
+			{
+				v.Add(new DerTaggedObject(false, 2, authAttrs));
+			}
+
+			v.Add(mac);
+
+			if (unauthAttrs != null)
+			{
+				v.Add(new DerTaggedObject(false, 3, unauthAttrs));
+			}
+
+			return new BerSequence(v);
+		}
+
+		public static int CalculateVersion(OriginatorInfo origInfo)
+		{
+			if (origInfo == null)
+				return 0;
+
+			int ver = 0;
+
+			foreach (object obj in origInfo.Certificates)
+			{
+				if (obj is Asn1TaggedObject)
+				{
+					Asn1TaggedObject tag = (Asn1TaggedObject)obj;
+
+					if (tag.TagNo == 2)
+					{
+						ver = 1;
+					}
+					else if (tag.TagNo == 3)
+					{
+						ver = 3;
+						break;
+					}
+				}
+			}
+
+			foreach (object obj in origInfo.Crls)
+			{
+				if (obj is Asn1TaggedObject)
+				{
+					Asn1TaggedObject tag = (Asn1TaggedObject)obj;
+
+					if (tag.TagNo == 1)
+					{
+						ver = 3;
+						break;
+					}
+				}
+			}
+
+			return ver;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/AuthenticatedDataParser.cs b/Crypto/src/asn1/cms/AuthenticatedDataParser.cs
new file mode 100644
index 000000000..4b80d1b02
--- /dev/null
+++ b/Crypto/src/asn1/cms/AuthenticatedDataParser.cs
@@ -0,0 +1,182 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	/**
+	 * Produce an object suitable for an Asn1OutputStream.
+	 * <pre>
+	 * AuthenticatedData ::= SEQUENCE {
+	 *       version CMSVersion,
+	 *       originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+	 *       recipientInfos RecipientInfos,
+	 *       macAlgorithm MessageAuthenticationCodeAlgorithm,
+	 *       digestAlgorithm [1] DigestAlgorithmIdentifier OPTIONAL,
+	 *       encapContentInfo EncapsulatedContentInfo,
+	 *       authAttrs [2] IMPLICIT AuthAttributes OPTIONAL,
+	 *       mac MessageAuthenticationCode,
+	 *       unauthAttrs [3] IMPLICIT UnauthAttributes OPTIONAL }
+	 *
+	 * AuthAttributes ::= SET SIZE (1..MAX) OF Attribute
+	 *
+	 * UnauthAttributes ::= SET SIZE (1..MAX) OF Attribute
+	 *
+	 * MessageAuthenticationCode ::= OCTET STRING
+	 * </pre>
+	 */
+	public class AuthenticatedDataParser
+	{
+	    private Asn1SequenceParser	seq;
+	    private DerInteger			version;
+	    private IAsn1Convertible	nextObject;
+	    private bool				originatorInfoCalled;
+
+	    public AuthenticatedDataParser(
+	        Asn1SequenceParser	seq)
+	    {
+	        this.seq = seq;
+	        this.version = (DerInteger)seq.ReadObject();
+	    }
+
+	    public DerInteger Version
+	    {
+	        get { return version; }
+	    }
+
+	    public OriginatorInfo GetOriginatorInfo()
+	    {
+	        originatorInfoCalled = true;
+
+	        if (nextObject == null)
+	        {
+	            nextObject = seq.ReadObject();
+	        }
+
+	        if (nextObject is Asn1TaggedObjectParser && ((Asn1TaggedObjectParser)nextObject).TagNo == 0)
+	        {
+	            Asn1SequenceParser originatorInfo = (Asn1SequenceParser) ((Asn1TaggedObjectParser)nextObject).GetObjectParser(Asn1Tags.Sequence, false);
+	            nextObject = null;
+	            return OriginatorInfo.GetInstance(originatorInfo.ToAsn1Object());
+	        }
+
+	        return null;
+	    }
+
+	    public Asn1SetParser GetRecipientInfos()
+	    {
+	        if (!originatorInfoCalled)
+	        {
+	            GetOriginatorInfo();
+	        }
+
+	        if (nextObject == null)
+	        {
+	            nextObject = seq.ReadObject();
+	        }
+
+	        Asn1SetParser recipientInfos = (Asn1SetParser)nextObject;
+	        nextObject = null;
+	        return recipientInfos;
+	    }
+
+	    public AlgorithmIdentifier GetMacAlgorithm()
+	    {
+	        if (nextObject == null)
+	        {
+	            nextObject = seq.ReadObject();
+	        }
+
+	        if (nextObject != null)
+	        {
+	            Asn1SequenceParser o = (Asn1SequenceParser)nextObject;
+	            nextObject = null;
+	            return AlgorithmIdentifier.GetInstance(o.ToAsn1Object());
+	        }
+
+	        return null;
+	    }
+
+		public AlgorithmIdentifier GetDigestAlgorithm()
+		{
+			if (nextObject == null)
+			{
+				nextObject = seq.ReadObject();
+			}
+
+			if (nextObject is Asn1TaggedObjectParser)
+			{
+				AlgorithmIdentifier obj = AlgorithmIdentifier.GetInstance(
+					(Asn1TaggedObject)nextObject.ToAsn1Object(), false);
+				nextObject = null;
+				return obj;
+			}
+
+			return null;
+		}
+
+	    public ContentInfoParser GetEnapsulatedContentInfo()
+	    {
+	        if (nextObject == null)
+	        {
+	            nextObject = seq.ReadObject();
+	        }
+
+	        if (nextObject != null)
+	        {
+	            Asn1SequenceParser o = (Asn1SequenceParser)nextObject;
+	            nextObject = null;
+	            return new ContentInfoParser(o);
+	        }
+
+	        return null;
+	    }
+
+	    public Asn1SetParser GetAuthAttrs()
+	    {
+	        if (nextObject == null)
+	        {
+	            nextObject = seq.ReadObject();
+	        }
+
+	        if (nextObject is Asn1TaggedObjectParser)
+	        {
+	            IAsn1Convertible o = nextObject;
+	            nextObject = null;
+	            return (Asn1SetParser)((Asn1TaggedObjectParser)o).GetObjectParser(Asn1Tags.Set, false);
+	        }
+
+	        return null;
+	    }
+
+	    public Asn1OctetString GetMac()
+	    {
+	        if (nextObject == null)
+	        {
+	            nextObject = seq.ReadObject();
+	        }
+
+	        IAsn1Convertible o = nextObject;
+	        nextObject = null;
+
+	        return Asn1OctetString.GetInstance(o.ToAsn1Object());
+	    }
+
+	    public Asn1SetParser GetUnauthAttrs()
+	    {
+	        if (nextObject == null)
+	        {
+	            nextObject = seq.ReadObject();
+	        }
+
+	        if (nextObject != null)
+	        {
+	            IAsn1Convertible o = nextObject;
+	            nextObject = null;
+	            return (Asn1SetParser)((Asn1TaggedObjectParser)o).GetObjectParser(Asn1Tags.Set, false);
+	        }
+
+	        return null;
+	    }
+	}
+}
diff --git a/Crypto/src/asn1/cms/CMSAttributes.cs b/Crypto/src/asn1/cms/CMSAttributes.cs
new file mode 100644
index 000000000..fca2b6738
--- /dev/null
+++ b/Crypto/src/asn1/cms/CMSAttributes.cs
@@ -0,0 +1,14 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public abstract class CmsAttributes
+    {
+        public static readonly DerObjectIdentifier ContentType		= PkcsObjectIdentifiers.Pkcs9AtContentType;
+        public static readonly DerObjectIdentifier MessageDigest	= PkcsObjectIdentifiers.Pkcs9AtMessageDigest;
+        public static readonly DerObjectIdentifier SigningTime		= PkcsObjectIdentifiers.Pkcs9AtSigningTime;
+		public static readonly DerObjectIdentifier CounterSignature = PkcsObjectIdentifiers.Pkcs9AtCounterSignature;
+		public static readonly DerObjectIdentifier ContentHint		= PkcsObjectIdentifiers.IdAAContentHint;
+	}
+}
diff --git a/Crypto/src/asn1/cms/CMSObjectIdentifiers.cs b/Crypto/src/asn1/cms/CMSObjectIdentifiers.cs
new file mode 100644
index 000000000..59009bda7
--- /dev/null
+++ b/Crypto/src/asn1/cms/CMSObjectIdentifiers.cs
@@ -0,0 +1,18 @@
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public abstract class CmsObjectIdentifiers
+    {
+        public static readonly DerObjectIdentifier Data = PkcsObjectIdentifiers.Data;
+        public static readonly DerObjectIdentifier SignedData = PkcsObjectIdentifiers.SignedData;
+        public static readonly DerObjectIdentifier EnvelopedData = PkcsObjectIdentifiers.EnvelopedData;
+        public static readonly DerObjectIdentifier SignedAndEnvelopedData = PkcsObjectIdentifiers.SignedAndEnvelopedData;
+        public static readonly DerObjectIdentifier DigestedData = PkcsObjectIdentifiers.DigestedData;
+        public static readonly DerObjectIdentifier EncryptedData = PkcsObjectIdentifiers.EncryptedData;
+		public static readonly DerObjectIdentifier AuthenticatedData = PkcsObjectIdentifiers.IdCTAuthData;
+        public static readonly DerObjectIdentifier CompressedData = PkcsObjectIdentifiers.IdCTCompressedData;
+		public static readonly DerObjectIdentifier AuthEnvelopedData = PkcsObjectIdentifiers.IdCTAuthEnvelopedData;
+		public static readonly DerObjectIdentifier timestampedData = PkcsObjectIdentifiers.IdCTTimestampedData;
+    }
+}
diff --git a/Crypto/src/asn1/cms/CompressedData.cs b/Crypto/src/asn1/cms/CompressedData.cs
new file mode 100644
index 000000000..5a2869b8c
--- /dev/null
+++ b/Crypto/src/asn1/cms/CompressedData.cs
@@ -0,0 +1,96 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    /**
+     * RFC 3274 - CMS Compressed Data.
+     * <pre>
+     * CompressedData ::= Sequence {
+     *  version CMSVersion,
+     *  compressionAlgorithm CompressionAlgorithmIdentifier,
+     *  encapContentInfo EncapsulatedContentInfo
+     * }
+     * </pre>
+     */
+    public class CompressedData
+        : Asn1Encodable
+    {
+        private DerInteger			version;
+        private AlgorithmIdentifier	compressionAlgorithm;
+        private ContentInfo			encapContentInfo;
+
+		public CompressedData(
+            AlgorithmIdentifier	compressionAlgorithm,
+            ContentInfo			encapContentInfo)
+        {
+            this.version = new DerInteger(0);
+            this.compressionAlgorithm = compressionAlgorithm;
+            this.encapContentInfo = encapContentInfo;
+        }
+
+		public CompressedData(
+            Asn1Sequence seq)
+        {
+            this.version = (DerInteger) seq[0];
+            this.compressionAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+            this.encapContentInfo = ContentInfo.GetInstance(seq[2]);
+        }
+
+		/**
+         * return a CompressedData object from a tagged object.
+         *
+         * @param ato the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static CompressedData GetInstance(
+            Asn1TaggedObject ato,
+            bool explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(ato, explicitly));
+        }
+
+        /**
+         * return a CompressedData object from the given object.
+         *
+         * @param _obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static CompressedData GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is CompressedData)
+                return (CompressedData)obj;
+
+			if (obj is Asn1Sequence)
+                return new CompressedData((Asn1Sequence) obj);
+
+			throw new ArgumentException("Invalid CompressedData: " + obj.GetType().Name);
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public AlgorithmIdentifier CompressionAlgorithmIdentifier
+		{
+			get { return compressionAlgorithm; }
+		}
+
+		public ContentInfo EncapContentInfo
+		{
+			get { return encapContentInfo; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new BerSequence(version, compressionAlgorithm, encapContentInfo);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/CompressedDataParser.cs b/Crypto/src/asn1/cms/CompressedDataParser.cs
new file mode 100644
index 000000000..7c53453df
--- /dev/null
+++ b/Crypto/src/asn1/cms/CompressedDataParser.cs
@@ -0,0 +1,47 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	/**
+	* RFC 3274 - CMS Compressed Data.
+	* <pre>
+	* CompressedData ::= SEQUENCE {
+	*  version CMSVersion,
+	*  compressionAlgorithm CompressionAlgorithmIdentifier,
+	*  encapContentInfo EncapsulatedContentInfo
+	* }
+	* </pre>
+	*/
+	public class CompressedDataParser
+	{
+		private DerInteger			_version;
+		private AlgorithmIdentifier	_compressionAlgorithm;
+		private ContentInfoParser	_encapContentInfo;
+
+		public CompressedDataParser(
+			Asn1SequenceParser seq)
+		{
+			this._version = (DerInteger)seq.ReadObject();
+			this._compressionAlgorithm = AlgorithmIdentifier.GetInstance(seq.ReadObject().ToAsn1Object());
+			this._encapContentInfo = new ContentInfoParser((Asn1SequenceParser)seq.ReadObject());
+		}
+
+		public DerInteger Version
+		{
+			get { return _version; }
+		}
+
+		public AlgorithmIdentifier CompressionAlgorithmIdentifier
+		{
+			get { return _compressionAlgorithm; }
+		}
+
+		public ContentInfoParser GetEncapContentInfo()
+		{
+			return _encapContentInfo;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/ContentInfo.cs b/Crypto/src/asn1/cms/ContentInfo.cs
new file mode 100644
index 000000000..61a277535
--- /dev/null
+++ b/Crypto/src/asn1/cms/ContentInfo.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class ContentInfo
+		: Asn1Encodable
+	{
+		private readonly DerObjectIdentifier	contentType;
+		private readonly Asn1Encodable			content;
+
+		public static ContentInfo GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is ContentInfo)
+				return (ContentInfo) obj;
+
+			if (obj is Asn1Sequence)
+				return new ContentInfo((Asn1Sequence) obj);
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name);
+		}
+
+		private ContentInfo(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1 || seq.Count > 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			contentType = (DerObjectIdentifier) seq[0];
+
+			if (seq.Count > 1)
+			{
+				Asn1TaggedObject tagged = (Asn1TaggedObject) seq[1];
+				if (!tagged.IsExplicit() || tagged.TagNo != 0)
+					throw new ArgumentException("Bad tag for 'content'", "seq");
+
+				content = tagged.GetObject();
+			}
+		}
+
+		public ContentInfo(
+			DerObjectIdentifier	contentType,
+			Asn1Encodable		content)
+		{
+			this.contentType = contentType;
+			this.content = content;
+		}
+
+		public DerObjectIdentifier ContentType
+		{
+			get { return contentType; }
+		}
+
+		public Asn1Encodable Content
+		{
+			get { return content; }
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * <pre>
+		 * ContentInfo ::= Sequence {
+		 *          contentType ContentType,
+		 *          content
+		 *          [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(contentType);
+
+			if (content != null)
+			{
+				v.Add(new BerTaggedObject(0, content));
+			}
+
+			return new BerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/ContentInfoParser.cs b/Crypto/src/asn1/cms/ContentInfoParser.cs
new file mode 100644
index 000000000..541cc0f59
--- /dev/null
+++ b/Crypto/src/asn1/cms/ContentInfoParser.cs
@@ -0,0 +1,40 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	/**
+	* Produce an object suitable for an Asn1OutputStream.
+	* <pre>
+	* ContentInfo ::= SEQUENCE {
+	*          contentType ContentType,
+	*          content
+	*          [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+	* </pre>
+	*/
+	public class ContentInfoParser
+	{
+		private DerObjectIdentifier		contentType;
+		private Asn1TaggedObjectParser	content;
+
+		public ContentInfoParser(
+			Asn1SequenceParser seq)
+		{
+			contentType = (DerObjectIdentifier)seq.ReadObject();
+			content = (Asn1TaggedObjectParser)seq.ReadObject();
+		}
+
+		public DerObjectIdentifier ContentType
+		{
+			get { return contentType; }
+		}
+
+		public IAsn1Convertible GetContent(
+			int tag)
+		{
+			if (content == null)
+				return null;
+
+			return content.GetObjectParser(tag, true);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/EncryptedContentInfo.cs b/Crypto/src/asn1/cms/EncryptedContentInfo.cs
new file mode 100644
index 000000000..4fdc47138
--- /dev/null
+++ b/Crypto/src/asn1/cms/EncryptedContentInfo.cs
@@ -0,0 +1,94 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class EncryptedContentInfo
+        : Asn1Encodable
+    {
+        private DerObjectIdentifier	contentType;
+        private AlgorithmIdentifier	contentEncryptionAlgorithm;
+        private Asn1OctetString		encryptedContent;
+
+		public EncryptedContentInfo(
+            DerObjectIdentifier	contentType,
+            AlgorithmIdentifier	contentEncryptionAlgorithm,
+            Asn1OctetString		encryptedContent)
+        {
+            this.contentType = contentType;
+            this.contentEncryptionAlgorithm = contentEncryptionAlgorithm;
+            this.encryptedContent = encryptedContent;
+        }
+
+		public EncryptedContentInfo(
+            Asn1Sequence seq)
+        {
+            contentType = (DerObjectIdentifier) seq[0];
+            contentEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+
+			if (seq.Count > 2)
+            {
+                encryptedContent = Asn1OctetString.GetInstance(
+					(Asn1TaggedObject) seq[2], false);
+            }
+        }
+
+		/**
+         * return an EncryptedContentInfo object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static EncryptedContentInfo GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is EncryptedContentInfo)
+                return (EncryptedContentInfo)obj;
+
+			if (obj is Asn1Sequence)
+                return new EncryptedContentInfo((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid EncryptedContentInfo: " + obj.GetType().Name);
+        }
+
+        public DerObjectIdentifier ContentType
+        {
+            get { return contentType; }
+        }
+
+		public AlgorithmIdentifier ContentEncryptionAlgorithm
+        {
+			get { return contentEncryptionAlgorithm; }
+        }
+
+		public Asn1OctetString EncryptedContent
+        {
+			get { return encryptedContent; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * EncryptedContentInfo ::= Sequence {
+         *     contentType ContentType,
+         *     contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+         *     encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				contentType, contentEncryptionAlgorithm);
+
+			if (encryptedContent != null)
+            {
+                v.Add(new BerTaggedObject(false, 0, encryptedContent));
+            }
+
+			return new BerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/EncryptedContentInfoParser.cs b/Crypto/src/asn1/cms/EncryptedContentInfoParser.cs
new file mode 100644
index 000000000..af748b1b3
--- /dev/null
+++ b/Crypto/src/asn1/cms/EncryptedContentInfoParser.cs
@@ -0,0 +1,46 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	/**
+	* <pre>
+	* EncryptedContentInfo ::= SEQUENCE {
+	*     contentType ContentType,
+	*     contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+	*     encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+	* }
+	* </pre>
+	*/
+	public class EncryptedContentInfoParser
+	{
+		private DerObjectIdentifier		_contentType;
+		private AlgorithmIdentifier		_contentEncryptionAlgorithm;
+		private Asn1TaggedObjectParser	_encryptedContent;
+
+		public EncryptedContentInfoParser(
+			Asn1SequenceParser seq)
+		{
+			_contentType = (DerObjectIdentifier)seq.ReadObject();
+			_contentEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq.ReadObject().ToAsn1Object());
+			_encryptedContent = (Asn1TaggedObjectParser)seq.ReadObject();
+		}
+
+		public DerObjectIdentifier ContentType
+		{
+			get { return _contentType; }
+		}
+
+		public AlgorithmIdentifier ContentEncryptionAlgorithm
+		{
+			get { return _contentEncryptionAlgorithm; }
+		}
+
+		public IAsn1Convertible GetEncryptedContent(
+			int tag)
+		{
+			return _encryptedContent.GetObjectParser(tag, false);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/EncryptedData.cs b/Crypto/src/asn1/cms/EncryptedData.cs
new file mode 100644
index 000000000..5b8378282
--- /dev/null
+++ b/Crypto/src/asn1/cms/EncryptedData.cs
@@ -0,0 +1,95 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class EncryptedData
+		: Asn1Encodable
+	{
+		private readonly DerInteger				version;
+		private readonly EncryptedContentInfo	encryptedContentInfo;
+		private readonly Asn1Set				unprotectedAttrs;
+
+		public static EncryptedData GetInstance(
+			object obj)
+		{
+			if (obj is EncryptedData)
+				return (EncryptedData) obj;
+
+			if (obj is Asn1Sequence)
+				return new EncryptedData((Asn1Sequence) obj);
+
+			throw new ArgumentException("Invalid EncryptedData: " + obj.GetType().Name);
+		}
+
+		public EncryptedData(
+			EncryptedContentInfo encInfo)
+			: this(encInfo, null)
+		{
+		}
+
+		public EncryptedData(
+			EncryptedContentInfo	encInfo,
+			Asn1Set					unprotectedAttrs)
+		{
+			if (encInfo == null)
+				throw new ArgumentNullException("encInfo");
+
+			this.version = new DerInteger((unprotectedAttrs == null) ? 0 : 2);
+			this.encryptedContentInfo = encInfo;
+			this.unprotectedAttrs = unprotectedAttrs;
+		}
+
+		private EncryptedData(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count < 2 || seq.Count > 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.version = DerInteger.GetInstance(seq[0]);
+			this.encryptedContentInfo = EncryptedContentInfo.GetInstance(seq[1]);
+
+			if (seq.Count > 2)
+			{
+				this.unprotectedAttrs = Asn1Set.GetInstance(seq[2]);
+			}
+		}
+
+		public virtual DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public virtual EncryptedContentInfo EncryptedContentInfo
+		{
+			get { return encryptedContentInfo; }
+		}
+
+		public virtual Asn1Set UnprotectedAttrs
+		{
+			get { return unprotectedAttrs; }
+		}
+
+		/**
+		* <pre>
+		*       EncryptedData ::= SEQUENCE {
+		*                     version CMSVersion,
+		*                     encryptedContentInfo EncryptedContentInfo,
+		*                     unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL }
+		* </pre>
+		* @return a basic ASN.1 object representation.
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(version, encryptedContentInfo);
+
+			if (unprotectedAttrs != null)
+			{
+				v.Add(new BerTaggedObject(false, 1, unprotectedAttrs));
+			}
+
+			return new BerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/EnvelopedData.cs b/Crypto/src/asn1/cms/EnvelopedData.cs
new file mode 100644
index 000000000..47cd4a9f5
--- /dev/null
+++ b/Crypto/src/asn1/cms/EnvelopedData.cs
@@ -0,0 +1,167 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class EnvelopedData
+        : Asn1Encodable
+    {
+        private DerInteger				version;
+        private OriginatorInfo			originatorInfo;
+        private Asn1Set					recipientInfos;
+        private EncryptedContentInfo	encryptedContentInfo;
+        private Asn1Set					unprotectedAttrs;
+
+		public EnvelopedData(
+            OriginatorInfo			originatorInfo,
+            Asn1Set					recipientInfos,
+            EncryptedContentInfo	encryptedContentInfo,
+            Asn1Set					unprotectedAttrs)
+        {
+            if (originatorInfo != null || unprotectedAttrs != null)
+            {
+                version = new DerInteger(2);
+            }
+            else
+            {
+                version = new DerInteger(0);
+
+				foreach (object o in recipientInfos)
+				{
+                    RecipientInfo ri = RecipientInfo.GetInstance(o);
+
+					if (!ri.Version.Equals(version))
+                    {
+                        version = new DerInteger(2);
+                        break;
+                    }
+                }
+            }
+
+			this.originatorInfo = originatorInfo;
+            this.recipientInfos = recipientInfos;
+            this.encryptedContentInfo = encryptedContentInfo;
+            this.unprotectedAttrs = unprotectedAttrs;
+        }
+
+		public EnvelopedData(
+            Asn1Sequence seq)
+        {
+            int index = 0;
+
+			version = (DerInteger) seq[index++];
+
+			object tmp = seq[index++];
+
+			if (tmp is Asn1TaggedObject)
+            {
+                originatorInfo = OriginatorInfo.GetInstance((Asn1TaggedObject) tmp, false);
+                tmp = seq[index++];
+            }
+
+			recipientInfos = Asn1Set.GetInstance(tmp);
+            encryptedContentInfo = EncryptedContentInfo.GetInstance(seq[index++]);
+
+			if (seq.Count > index)
+            {
+				unprotectedAttrs = Asn1Set.GetInstance((Asn1TaggedObject) seq[index], false);
+            }
+        }
+
+		/**
+         * return an EnvelopedData object from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static EnvelopedData GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		/**
+         * return an EnvelopedData object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static EnvelopedData GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is EnvelopedData)
+            {
+                return (EnvelopedData)obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new EnvelopedData((Asn1Sequence)obj);
+            }
+
+			throw new ArgumentException("Invalid EnvelopedData: " + obj.GetType().Name);
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public OriginatorInfo OriginatorInfo
+		{
+			get { return originatorInfo; }
+		}
+
+		public Asn1Set RecipientInfos
+		{
+			get { return recipientInfos; }
+		}
+
+		public EncryptedContentInfo EncryptedContentInfo
+		{
+			get { return encryptedContentInfo; }
+		}
+
+		public Asn1Set UnprotectedAttrs
+		{
+			get { return unprotectedAttrs; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * EnvelopedData ::= Sequence {
+         *     version CMSVersion,
+         *     originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+         *     recipientInfos RecipientInfos,
+         *     encryptedContentInfo EncryptedContentInfo,
+         *     unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(version);
+
+			if (originatorInfo != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, originatorInfo));
+            }
+
+			v.Add(recipientInfos, encryptedContentInfo);
+
+			if (unprotectedAttrs != null)
+            {
+                v.Add(new DerTaggedObject(false, 1, unprotectedAttrs));
+            }
+
+			return new BerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/EnvelopedDataParser.cs b/Crypto/src/asn1/cms/EnvelopedDataParser.cs
new file mode 100644
index 000000000..599353791
--- /dev/null
+++ b/Crypto/src/asn1/cms/EnvelopedDataParser.cs
@@ -0,0 +1,107 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	/**
+	* Produce an object suitable for an Asn1OutputStream.
+	* <pre>
+	* EnvelopedData ::= SEQUENCE {
+	*     version CMSVersion,
+	*     originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+	*     recipientInfos RecipientInfos,
+	*     encryptedContentInfo EncryptedContentInfo,
+	*     unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL
+	* }
+	* </pre>
+	*/
+	public class EnvelopedDataParser
+	{
+		private Asn1SequenceParser	_seq;
+		private DerInteger			_version;
+		private IAsn1Convertible	_nextObject;
+		private bool				_originatorInfoCalled;
+
+		public EnvelopedDataParser(
+			Asn1SequenceParser seq)
+		{
+			this._seq = seq;
+			this._version = (DerInteger)seq.ReadObject();
+		}
+
+		public DerInteger Version
+		{
+			get { return _version; }
+		}
+
+		public OriginatorInfo GetOriginatorInfo() 
+		{
+			_originatorInfoCalled = true; 
+
+			if (_nextObject == null)
+			{
+				_nextObject = _seq.ReadObject();
+			}
+
+			if (_nextObject is Asn1TaggedObjectParser && ((Asn1TaggedObjectParser)_nextObject).TagNo == 0)
+			{
+				Asn1SequenceParser originatorInfo = (Asn1SequenceParser)
+					((Asn1TaggedObjectParser)_nextObject).GetObjectParser(Asn1Tags.Sequence, false);
+				_nextObject = null;
+				return OriginatorInfo.GetInstance(originatorInfo.ToAsn1Object());
+			}
+
+			return null;
+		}
+
+		public Asn1SetParser GetRecipientInfos()
+		{
+			if (!_originatorInfoCalled)
+			{
+				GetOriginatorInfo();
+			}
+
+			if (_nextObject == null)
+			{
+				_nextObject = _seq.ReadObject();
+			}
+
+			Asn1SetParser recipientInfos = (Asn1SetParser)_nextObject;
+			_nextObject = null;
+			return recipientInfos;
+		}
+
+		public EncryptedContentInfoParser GetEncryptedContentInfo()
+		{
+			if (_nextObject == null)
+			{
+				_nextObject = _seq.ReadObject();
+			}
+
+			if (_nextObject != null)
+			{
+				Asn1SequenceParser o = (Asn1SequenceParser) _nextObject;
+				_nextObject = null;
+				return new EncryptedContentInfoParser(o);
+			}
+
+			return null;
+		}
+
+		public Asn1SetParser GetUnprotectedAttrs()
+		{
+			if (_nextObject == null)
+			{
+				_nextObject = _seq.ReadObject();
+			}
+
+			if (_nextObject != null)
+			{
+				IAsn1Convertible o = _nextObject;
+				_nextObject = null;
+				return (Asn1SetParser)((Asn1TaggedObjectParser)o).GetObjectParser(Asn1Tags.Set, false);
+			}
+        
+			return null;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/Evidence.cs b/Crypto/src/asn1/cms/Evidence.cs
new file mode 100644
index 000000000..4745e565b
--- /dev/null
+++ b/Crypto/src/asn1/cms/Evidence.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class Evidence
+		: Asn1Encodable, IAsn1Choice
+	{
+		private TimeStampTokenEvidence tstEvidence;
+
+		public Evidence(TimeStampTokenEvidence tstEvidence)
+		{
+			this.tstEvidence = tstEvidence;
+		}
+
+		private Evidence(Asn1TaggedObject tagged)
+		{
+			if (tagged.TagNo == 0)
+			{
+				this.tstEvidence = TimeStampTokenEvidence.GetInstance(tagged, false);
+			}
+		}
+
+		public static Evidence GetInstance(object obj)
+		{
+			if (obj is Evidence)
+				return (Evidence)obj;
+
+			if (obj is Asn1TaggedObject)
+				return new Evidence(Asn1TaggedObject.GetInstance(obj));
+
+			throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		public virtual TimeStampTokenEvidence TstEvidence
+		{
+			get { return tstEvidence; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			if (tstEvidence != null)
+				return new DerTaggedObject(false, 0, tstEvidence);
+
+			return null;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/IssuerAndSerialNumber.cs b/Crypto/src/asn1/cms/IssuerAndSerialNumber.cs
new file mode 100644
index 000000000..ac1af961f
--- /dev/null
+++ b/Crypto/src/asn1/cms/IssuerAndSerialNumber.cs
@@ -0,0 +1,66 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class IssuerAndSerialNumber
+        : Asn1Encodable
+    {
+        private X509Name	name;
+        private DerInteger	serialNumber;
+
+        public static IssuerAndSerialNumber GetInstance(
+            object obj)
+        {
+            if (obj is IssuerAndSerialNumber)
+                return (IssuerAndSerialNumber)obj;
+
+			if (obj is Asn1Sequence)
+                return new IssuerAndSerialNumber((Asn1Sequence)obj);
+
+			throw new ArgumentException(
+                "Illegal object in IssuerAndSerialNumber: " + obj.GetType().Name);
+        }
+
+        public IssuerAndSerialNumber(
+            Asn1Sequence seq)
+        {
+            this.name = X509Name.GetInstance(seq[0]);
+            this.serialNumber = (DerInteger) seq[1];
+        }
+
+		public IssuerAndSerialNumber(
+            X509Name	name,
+            BigInteger	serialNumber)
+        {
+            this.name = name;
+            this.serialNumber = new DerInteger(serialNumber);
+        }
+
+        public IssuerAndSerialNumber(
+            X509Name	name,
+            DerInteger	serialNumber)
+        {
+            this.name = name;
+            this.serialNumber = serialNumber;
+        }
+
+		public X509Name Name
+		{
+			get { return name; }
+		}
+
+		public DerInteger SerialNumber
+		{
+			get { return serialNumber; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(name, serialNumber);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/KEKIdentifier.cs b/Crypto/src/asn1/cms/KEKIdentifier.cs
new file mode 100644
index 000000000..e5d1d9090
--- /dev/null
+++ b/Crypto/src/asn1/cms/KEKIdentifier.cs
@@ -0,0 +1,119 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class KekIdentifier
+        : Asn1Encodable
+    {
+        private Asn1OctetString		keyIdentifier;
+        private DerGeneralizedTime	date;
+        private OtherKeyAttribute	other;
+
+		public KekIdentifier(
+            byte[]              keyIdentifier,
+            DerGeneralizedTime  date,
+            OtherKeyAttribute   other)
+        {
+            this.keyIdentifier = new DerOctetString(keyIdentifier);
+            this.date = date;
+            this.other = other;
+        }
+
+		public KekIdentifier(
+            Asn1Sequence seq)
+        {
+            keyIdentifier = (Asn1OctetString) seq[0];
+
+			switch (seq.Count)
+            {
+            case 1:
+				break;
+            case 2:
+				if (seq[1] is DerGeneralizedTime)
+				{
+					date = (DerGeneralizedTime) seq[1];
+				}
+				else
+				{
+					other = OtherKeyAttribute.GetInstance(seq[2]);
+				}
+				break;
+            case 3:
+				date  = (DerGeneralizedTime) seq[1];
+				other = OtherKeyAttribute.GetInstance(seq[2]);
+				break;
+            default:
+				throw new ArgumentException("Invalid KekIdentifier");
+            }
+        }
+
+		/**
+         * return a KekIdentifier object from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static KekIdentifier GetInstance(
+            Asn1TaggedObject obj,
+            bool explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+        /**
+         * return a KekIdentifier object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static KekIdentifier GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is KekIdentifier)
+                return (KekIdentifier)obj;
+
+			if (obj is Asn1Sequence)
+                return new KekIdentifier((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid KekIdentifier: " + obj.GetType().Name);
+        }
+
+		public Asn1OctetString KeyIdentifier
+		{
+			get { return keyIdentifier; }
+		}
+
+		public DerGeneralizedTime Date
+		{
+			get { return date; }
+		}
+
+		public OtherKeyAttribute Other
+		{
+			get { return other; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * KekIdentifier ::= Sequence {
+         *     keyIdentifier OCTET STRING,
+         *     date GeneralizedTime OPTIONAL,
+         *     other OtherKeyAttribute OPTIONAL
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(keyIdentifier);
+			v.AddOptional(date, other);
+			return new DerSequence(v);
+        }
+    }
+}
+
diff --git a/Crypto/src/asn1/cms/KEKRecipientInfo.cs b/Crypto/src/asn1/cms/KEKRecipientInfo.cs
new file mode 100644
index 000000000..d847b50cc
--- /dev/null
+++ b/Crypto/src/asn1/cms/KEKRecipientInfo.cs
@@ -0,0 +1,106 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class KekRecipientInfo
+        : Asn1Encodable
+    {
+        private DerInteger			version;
+        private KekIdentifier       kekID;
+        private AlgorithmIdentifier keyEncryptionAlgorithm;
+        private Asn1OctetString     encryptedKey;
+
+		public KekRecipientInfo(
+            KekIdentifier       kekID,
+            AlgorithmIdentifier keyEncryptionAlgorithm,
+            Asn1OctetString     encryptedKey)
+        {
+            this.version = new DerInteger(4);
+            this.kekID = kekID;
+            this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+            this.encryptedKey = encryptedKey;
+        }
+
+		public KekRecipientInfo(
+            Asn1Sequence seq)
+        {
+            version = (DerInteger) seq[0];
+            kekID = KekIdentifier.GetInstance(seq[1]);
+            keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[2]);
+            encryptedKey = (Asn1OctetString) seq[3];
+        }
+
+		/**
+         * return a KekRecipientInfo object from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static KekRecipientInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+        /**
+         * return a KekRecipientInfo object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static KekRecipientInfo GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is KekRecipientInfo)
+                return (KekRecipientInfo)obj;
+
+			if(obj is Asn1Sequence)
+                return new KekRecipientInfo((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid KekRecipientInfo: " + obj.GetType().Name);
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public KekIdentifier KekID
+		{
+			get { return kekID; }
+		}
+
+		public AlgorithmIdentifier KeyEncryptionAlgorithm
+		{
+			get { return keyEncryptionAlgorithm; }
+		}
+
+		public Asn1OctetString EncryptedKey
+		{
+			get { return encryptedKey; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * KekRecipientInfo ::= Sequence {
+         *     version CMSVersion,  -- always set to 4
+         *     kekID KekIdentifier,
+         *     keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+         *     encryptedKey EncryptedKey
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(version, kekID, keyEncryptionAlgorithm, encryptedKey);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/KeyAgreeRecipientIdentifier.cs b/Crypto/src/asn1/cms/KeyAgreeRecipientIdentifier.cs
new file mode 100644
index 000000000..fa6fdb0f3
--- /dev/null
+++ b/Crypto/src/asn1/cms/KeyAgreeRecipientIdentifier.cs
@@ -0,0 +1,92 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class KeyAgreeRecipientIdentifier
+		: Asn1Encodable, IAsn1Choice
+	{
+		/**
+		 * return an KeyAgreeRecipientIdentifier object from a tagged object.
+		 *
+		 * @param obj the tagged object holding the object we want.
+		 * @param isExplicit true if the object is meant to be explicitly
+		 *              tagged false otherwise.
+		 * @exception ArgumentException if the object held by the
+		 *          tagged object cannot be converted.
+		 */
+		public static KeyAgreeRecipientIdentifier GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+    
+		/**
+		 * return an KeyAgreeRecipientIdentifier object from the given object.
+		 *
+		 * @param obj the object we want converted.
+		 * @exception ArgumentException if the object cannot be converted.
+		 */
+		public static KeyAgreeRecipientIdentifier GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is KeyAgreeRecipientIdentifier)
+				return (KeyAgreeRecipientIdentifier)obj;
+
+			if (obj is Asn1Sequence)
+				return new KeyAgreeRecipientIdentifier(IssuerAndSerialNumber.GetInstance(obj));
+
+			if (obj is Asn1TaggedObject && ((Asn1TaggedObject)obj).TagNo == 0)
+			{
+				return new KeyAgreeRecipientIdentifier(RecipientKeyIdentifier.GetInstance(
+					(Asn1TaggedObject)obj, false));
+			}
+
+			throw new ArgumentException("Invalid KeyAgreeRecipientIdentifier: " + obj.GetType().FullName, "obj");
+		} 
+
+		private readonly IssuerAndSerialNumber issuerSerial;
+		private readonly RecipientKeyIdentifier rKeyID;
+
+		public KeyAgreeRecipientIdentifier(
+			IssuerAndSerialNumber issuerSerial)
+		{
+			this.issuerSerial = issuerSerial;
+		}
+
+		public KeyAgreeRecipientIdentifier(
+			RecipientKeyIdentifier rKeyID)
+		{
+			this.rKeyID = rKeyID;
+		}
+
+		public IssuerAndSerialNumber IssuerAndSerialNumber
+		{
+			get { return issuerSerial; }
+		}
+
+		public RecipientKeyIdentifier RKeyID
+		{
+			get { return rKeyID; }
+		}
+
+		/** 
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * <pre>
+		 * KeyAgreeRecipientIdentifier ::= CHOICE {
+		 *     issuerAndSerialNumber IssuerAndSerialNumber,
+		 *     rKeyId [0] IMPLICIT RecipientKeyIdentifier
+		 * }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			if (issuerSerial != null)
+			{
+				return issuerSerial.ToAsn1Object();
+			}
+
+			return new DerTaggedObject(false, 0, rKeyID);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/KeyAgreeRecipientInfo.cs b/Crypto/src/asn1/cms/KeyAgreeRecipientInfo.cs
new file mode 100644
index 000000000..aafb008d4
--- /dev/null
+++ b/Crypto/src/asn1/cms/KeyAgreeRecipientInfo.cs
@@ -0,0 +1,141 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class KeyAgreeRecipientInfo
+        : Asn1Encodable
+    {
+        private DerInteger                  version;
+        private OriginatorIdentifierOrKey   originator;
+        private Asn1OctetString             ukm;
+        private AlgorithmIdentifier         keyEncryptionAlgorithm;
+        private Asn1Sequence                recipientEncryptedKeys;
+
+		public KeyAgreeRecipientInfo(
+            OriginatorIdentifierOrKey   originator,
+            Asn1OctetString             ukm,
+            AlgorithmIdentifier         keyEncryptionAlgorithm,
+            Asn1Sequence                recipientEncryptedKeys)
+        {
+            this.version = new DerInteger(3);
+            this.originator = originator;
+            this.ukm = ukm;
+            this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+            this.recipientEncryptedKeys = recipientEncryptedKeys;
+        }
+
+		public KeyAgreeRecipientInfo(
+            Asn1Sequence seq)
+        {
+            int index = 0;
+
+            version = (DerInteger) seq[index++];
+            originator = OriginatorIdentifierOrKey.GetInstance(
+				(Asn1TaggedObject) seq[index++], true);
+
+			if (seq[index] is Asn1TaggedObject)
+            {
+                ukm = Asn1OctetString.GetInstance(
+					(Asn1TaggedObject) seq[index++], true);
+            }
+
+			keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(
+				seq[index++]);
+
+			recipientEncryptedKeys = (Asn1Sequence) seq[index++];
+        }
+
+		/**
+         * return a KeyAgreeRecipientInfo object from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static KeyAgreeRecipientInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		/**
+         * return a KeyAgreeRecipientInfo object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static KeyAgreeRecipientInfo GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is KeyAgreeRecipientInfo)
+                return (KeyAgreeRecipientInfo)obj;
+
+			if (obj is Asn1Sequence)
+                return new KeyAgreeRecipientInfo((Asn1Sequence)obj);
+
+			throw new ArgumentException(
+                "Illegal object in KeyAgreeRecipientInfo: " + obj.GetType().Name);
+
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public OriginatorIdentifierOrKey Originator
+		{
+			get { return originator; }
+		}
+
+		public Asn1OctetString UserKeyingMaterial
+		{
+			get { return ukm; }
+		}
+
+		public AlgorithmIdentifier KeyEncryptionAlgorithm
+		{
+			get { return keyEncryptionAlgorithm; }
+		}
+
+		public Asn1Sequence RecipientEncryptedKeys
+		{
+			get { return recipientEncryptedKeys; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * KeyAgreeRecipientInfo ::= Sequence {
+         *     version CMSVersion,  -- always set to 3
+         *     originator [0] EXPLICIT OriginatorIdentifierOrKey,
+         *     ukm [1] EXPLICIT UserKeyingMaterial OPTIONAL,
+         *     keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+         *     recipientEncryptedKeys RecipientEncryptedKeys
+         * }
+		 *
+		 * UserKeyingMaterial ::= OCTET STRING
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				version, new DerTaggedObject(true, 0, originator));
+
+			if (ukm != null)
+            {
+                v.Add(new DerTaggedObject(true, 1, ukm));
+            }
+
+			v.Add(keyEncryptionAlgorithm, recipientEncryptedKeys);
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/KeyTransRecipientInfo.cs b/Crypto/src/asn1/cms/KeyTransRecipientInfo.cs
new file mode 100644
index 000000000..aae18c59d
--- /dev/null
+++ b/Crypto/src/asn1/cms/KeyTransRecipientInfo.cs
@@ -0,0 +1,99 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class KeyTransRecipientInfo
+        : Asn1Encodable
+    {
+        private DerInteger          version;
+        private RecipientIdentifier rid;
+        private AlgorithmIdentifier keyEncryptionAlgorithm;
+        private Asn1OctetString     encryptedKey;
+
+		public KeyTransRecipientInfo(
+            RecipientIdentifier rid,
+            AlgorithmIdentifier keyEncryptionAlgorithm,
+            Asn1OctetString     encryptedKey)
+        {
+            if (rid.ToAsn1Object() is Asn1TaggedObject)
+            {
+                this.version = new DerInteger(2);
+            }
+            else
+            {
+                this.version = new DerInteger(0);
+            }
+
+			this.rid = rid;
+            this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+            this.encryptedKey = encryptedKey;
+        }
+
+		public KeyTransRecipientInfo(
+            Asn1Sequence seq)
+        {
+            this.version = (DerInteger) seq[0];
+            this.rid = RecipientIdentifier.GetInstance(seq[1]);
+            this.keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[2]);
+            this.encryptedKey = (Asn1OctetString) seq[3];
+        }
+
+		/**
+         * return a KeyTransRecipientInfo object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static KeyTransRecipientInfo GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is KeyTransRecipientInfo)
+                return (KeyTransRecipientInfo) obj;
+
+			if(obj is Asn1Sequence)
+                return new KeyTransRecipientInfo((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Illegal object in KeyTransRecipientInfo: " + obj.GetType().Name);
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public RecipientIdentifier RecipientIdentifier
+		{
+			get { return rid; }
+		}
+
+		public AlgorithmIdentifier KeyEncryptionAlgorithm
+		{
+			get { return keyEncryptionAlgorithm; }
+		}
+
+		public Asn1OctetString EncryptedKey
+		{
+			get { return encryptedKey; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * KeyTransRecipientInfo ::= Sequence {
+         *     version CMSVersion,  -- always set to 0 or 2
+         *     rid RecipientIdentifier,
+         *     keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+         *     encryptedKey EncryptedKey
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(version, rid, keyEncryptionAlgorithm, encryptedKey);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/MetaData.cs b/Crypto/src/asn1/cms/MetaData.cs
new file mode 100644
index 000000000..ad2b5c426
--- /dev/null
+++ b/Crypto/src/asn1/cms/MetaData.cs
@@ -0,0 +1,94 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class MetaData
+		: Asn1Encodable
+	{
+		private DerBoolean hashProtected;
+		private DerUtf8String fileName;
+		private DerIA5String  mediaType;
+		private Attributes otherMetaData;
+
+		public MetaData(
+			DerBoolean		hashProtected,
+			DerUtf8String	fileName,
+			DerIA5String	mediaType,
+			Attributes		otherMetaData)
+		{
+			this.hashProtected = hashProtected;
+			this.fileName = fileName;
+			this.mediaType = mediaType;
+			this.otherMetaData = otherMetaData;
+		}
+
+		private MetaData(Asn1Sequence seq)
+		{
+			this.hashProtected = DerBoolean.GetInstance(seq[0]);
+
+			int index = 1;
+
+			if (index < seq.Count && seq[index] is DerUtf8String)
+			{
+				this.fileName = DerUtf8String.GetInstance(seq[index++]);
+			}
+			if (index < seq.Count && seq[index] is DerIA5String)
+			{
+				this.mediaType = DerIA5String.GetInstance(seq[index++]);
+			}
+			if (index < seq.Count)
+			{
+				this.otherMetaData = Attributes.GetInstance(seq[index++]);
+			}
+		}
+
+		public static MetaData GetInstance(object obj)
+		{
+			if (obj is MetaData)
+				return (MetaData)obj;
+
+			if (obj != null)
+				return new MetaData(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		/**
+		 * <pre>
+		 * MetaData ::= SEQUENCE {
+		 *   hashProtected        BOOLEAN,
+		 *   fileName             UTF8String OPTIONAL,
+		 *   mediaType            IA5String OPTIONAL,
+		 *   otherMetaData        Attributes OPTIONAL
+		 * }
+		 * </pre>
+		 * @return
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(hashProtected);
+			v.AddOptional(fileName, mediaType, otherMetaData);
+			return new DerSequence(v);
+		}
+
+		public virtual bool IsHashProtected
+		{
+			get { return hashProtected.IsTrue; }
+		}
+
+		public virtual DerUtf8String FileName
+		{
+			get { return fileName; }
+		}
+
+		public virtual DerIA5String MediaType
+		{
+			get { return mediaType; }
+		}
+
+		public virtual Attributes OtherMetaData
+		{
+			get { return otherMetaData; }
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/OriginatorIdentifierOrKey.cs b/Crypto/src/asn1/cms/OriginatorIdentifierOrKey.cs
new file mode 100644
index 000000000..d33a11725
--- /dev/null
+++ b/Crypto/src/asn1/cms/OriginatorIdentifierOrKey.cs
@@ -0,0 +1,168 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class OriginatorIdentifierOrKey
+        : Asn1Encodable, IAsn1Choice
+    {
+        private Asn1Encodable id;
+
+        public OriginatorIdentifierOrKey(
+            IssuerAndSerialNumber id)
+        {
+            this.id = id;
+        }
+
+		[Obsolete("Use version taking a 'SubjectKeyIdentifier'")]
+        public OriginatorIdentifierOrKey(
+            Asn1OctetString id)
+			: this(new SubjectKeyIdentifier(id))
+        {
+        }
+
+        public OriginatorIdentifierOrKey(
+            SubjectKeyIdentifier id)
+        {
+            this.id = new DerTaggedObject(false, 0, id);
+        }
+
+        public OriginatorIdentifierOrKey(
+            OriginatorPublicKey id)
+        {
+            this.id = new DerTaggedObject(false, 1, id);
+        }
+
+		[Obsolete("Use more specific version")]
+        public OriginatorIdentifierOrKey(
+            Asn1Object id)
+        {
+            this.id = id;
+        }
+
+		private OriginatorIdentifierOrKey(
+			Asn1TaggedObject id)
+		{
+			// TODO Add validation
+			this.id = id;
+		}
+
+		/**
+         * return an OriginatorIdentifierOrKey object from a tagged object.
+         *
+         * @param o the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static OriginatorIdentifierOrKey GetInstance(
+            Asn1TaggedObject	o,
+            bool				explicitly)
+        {
+            if (!explicitly)
+            {
+                throw new ArgumentException(
+                        "Can't implicitly tag OriginatorIdentifierOrKey");
+            }
+
+			return GetInstance(o.GetObject());
+        }
+
+        /**
+         * return an OriginatorIdentifierOrKey object from the given object.
+         *
+         * @param o the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static OriginatorIdentifierOrKey GetInstance(
+            object o)
+        {
+            if (o == null || o is OriginatorIdentifierOrKey)
+                return (OriginatorIdentifierOrKey)o;
+
+			if (o is IssuerAndSerialNumber)
+				return new OriginatorIdentifierOrKey((IssuerAndSerialNumber)o);
+
+			if (o is SubjectKeyIdentifier)
+				return new OriginatorIdentifierOrKey((SubjectKeyIdentifier)o);
+
+			if (o is OriginatorPublicKey)
+				return new OriginatorIdentifierOrKey((OriginatorPublicKey)o);
+
+			if (o is Asn1TaggedObject)
+				return new OriginatorIdentifierOrKey((Asn1TaggedObject)o);
+
+			throw new ArgumentException("Invalid OriginatorIdentifierOrKey: " + o.GetType().Name);
+        }
+
+		public Asn1Encodable ID
+		{
+			get { return id; }
+		}
+
+		public IssuerAndSerialNumber IssuerAndSerialNumber
+		{
+			get
+			{
+				if (id is IssuerAndSerialNumber)
+				{
+					return (IssuerAndSerialNumber)id;
+				}
+
+				return null;
+			}
+		}
+
+		public SubjectKeyIdentifier SubjectKeyIdentifier
+		{
+			get
+			{
+				if (id is Asn1TaggedObject && ((Asn1TaggedObject)id).TagNo == 0)
+				{
+					return SubjectKeyIdentifier.GetInstance((Asn1TaggedObject)id, false);
+				}
+
+				return null;
+			}
+		}
+
+		[Obsolete("Use 'OriginatorPublicKey' property")]
+		public OriginatorPublicKey OriginatorKey
+		{
+			get { return OriginatorPublicKey; }
+		}
+
+		public OriginatorPublicKey OriginatorPublicKey
+		{
+			get
+			{
+				if (id is Asn1TaggedObject && ((Asn1TaggedObject)id).TagNo == 1)
+				{
+					return OriginatorPublicKey.GetInstance((Asn1TaggedObject)id, false);
+				}
+
+				return null;
+			}
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * OriginatorIdentifierOrKey ::= CHOICE {
+         *     issuerAndSerialNumber IssuerAndSerialNumber,
+         *     subjectKeyIdentifier [0] SubjectKeyIdentifier,
+         *     originatorKey [1] OriginatorPublicKey
+         * }
+         *
+         * SubjectKeyIdentifier ::= OCTET STRING
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return id.ToAsn1Object();
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/OriginatorInfo.cs b/Crypto/src/asn1/cms/OriginatorInfo.cs
new file mode 100644
index 000000000..b4549bc36
--- /dev/null
+++ b/Crypto/src/asn1/cms/OriginatorInfo.cs
@@ -0,0 +1,121 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class OriginatorInfo
+        : Asn1Encodable
+    {
+        private Asn1Set certs;
+        private Asn1Set crls;
+
+        public OriginatorInfo(
+            Asn1Set certs,
+            Asn1Set crls)
+        {
+            this.certs = certs;
+            this.crls = crls;
+        }
+
+		public OriginatorInfo(
+            Asn1Sequence seq)
+        {
+            switch (seq.Count)
+            {
+            case 0:     // empty
+                break;
+            case 1:
+                Asn1TaggedObject o = (Asn1TaggedObject) seq[0];
+                switch (o.TagNo)
+                {
+                case 0 :
+                    certs = Asn1Set.GetInstance(o, false);
+                    break;
+                case 1 :
+                    crls = Asn1Set.GetInstance(o, false);
+                    break;
+                default:
+                    throw new ArgumentException("Bad tag in OriginatorInfo: " + o.TagNo);
+                }
+                break;
+            case 2:
+                certs = Asn1Set.GetInstance((Asn1TaggedObject) seq[0], false);
+                crls  = Asn1Set.GetInstance((Asn1TaggedObject) seq[1], false);
+                break;
+            default:
+                throw new ArgumentException("OriginatorInfo too big");
+            }
+        }
+
+		/**
+         * return an OriginatorInfo object from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static OriginatorInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		/**
+         * return an OriginatorInfo object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static OriginatorInfo GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is OriginatorInfo)
+                return (OriginatorInfo)obj;
+
+			if (obj is Asn1Sequence)
+                return new OriginatorInfo((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid OriginatorInfo: " + obj.GetType().Name);
+        }
+
+		public Asn1Set Certificates
+		{
+			get { return certs; }
+		}
+
+		public Asn1Set Crls
+		{
+			get { return crls; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * OriginatorInfo ::= Sequence {
+         *     certs [0] IMPLICIT CertificateSet OPTIONAL,
+         *     crls [1] IMPLICIT CertificateRevocationLists OPTIONAL
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (certs != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, certs));
+            }
+
+			if (crls != null)
+            {
+                v.Add(new DerTaggedObject(false, 1, crls));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/OriginatorPublicKey.cs b/Crypto/src/asn1/cms/OriginatorPublicKey.cs
new file mode 100644
index 000000000..aabaf4386
--- /dev/null
+++ b/Crypto/src/asn1/cms/OriginatorPublicKey.cs
@@ -0,0 +1,87 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class OriginatorPublicKey
+        : Asn1Encodable
+    {
+        private AlgorithmIdentifier algorithm;
+        private DerBitString        publicKey;
+
+		public OriginatorPublicKey(
+            AlgorithmIdentifier algorithm,
+            byte[]              publicKey)
+        {
+            this.algorithm = algorithm;
+            this.publicKey = new DerBitString(publicKey);
+        }
+
+		public OriginatorPublicKey(
+            Asn1Sequence seq)
+        {
+            algorithm = AlgorithmIdentifier.GetInstance(seq[0]);
+            publicKey = (DerBitString) seq[1];
+        }
+
+		/**
+         * return an OriginatorPublicKey object from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static OriginatorPublicKey GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		/**
+         * return an OriginatorPublicKey object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static OriginatorPublicKey GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is OriginatorPublicKey)
+                return (OriginatorPublicKey)obj;
+
+			if (obj is Asn1Sequence)
+                return new OriginatorPublicKey((Asn1Sequence) obj);
+
+			throw new ArgumentException("Invalid OriginatorPublicKey: " + obj.GetType().Name);
+        }
+
+		public AlgorithmIdentifier Algorithm
+		{
+			get { return algorithm; }
+		}
+
+		public DerBitString PublicKey
+		{
+			get { return publicKey; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * OriginatorPublicKey ::= Sequence {
+         *     algorithm AlgorithmIdentifier,
+         *     publicKey BIT STRING
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(algorithm, publicKey);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/OtherKeyAttribute.cs b/Crypto/src/asn1/cms/OtherKeyAttribute.cs
new file mode 100644
index 000000000..271059175
--- /dev/null
+++ b/Crypto/src/asn1/cms/OtherKeyAttribute.cs
@@ -0,0 +1,70 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class OtherKeyAttribute
+        : Asn1Encodable
+    {
+        private DerObjectIdentifier	keyAttrId;
+        private Asn1Encodable		keyAttr;
+
+		/**
+         * return an OtherKeyAttribute object from the given object.
+         *
+         * @param o the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static OtherKeyAttribute GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is OtherKeyAttribute)
+                return (OtherKeyAttribute) obj;
+
+			if (obj is Asn1Sequence)
+                return new OtherKeyAttribute((Asn1Sequence) obj);
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        }
+
+		public OtherKeyAttribute(
+            Asn1Sequence seq)
+        {
+            keyAttrId = (DerObjectIdentifier) seq[0];
+            keyAttr = seq[1];
+        }
+
+		public OtherKeyAttribute(
+            DerObjectIdentifier	keyAttrId,
+            Asn1Encodable		keyAttr)
+        {
+            this.keyAttrId = keyAttrId;
+            this.keyAttr = keyAttr;
+        }
+
+		public DerObjectIdentifier KeyAttrId
+		{
+			get { return keyAttrId; }
+		}
+
+		public Asn1Encodable KeyAttr
+		{
+			get { return keyAttr; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * OtherKeyAttribute ::= Sequence {
+         *     keyAttrId OBJECT IDENTIFIER,
+         *     keyAttr ANY DEFINED BY keyAttrId OPTIONAL
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(keyAttrId, keyAttr);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/OtherRecipientInfo.cs b/Crypto/src/asn1/cms/OtherRecipientInfo.cs
new file mode 100644
index 000000000..8b06b1946
--- /dev/null
+++ b/Crypto/src/asn1/cms/OtherRecipientInfo.cs
@@ -0,0 +1,85 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class OtherRecipientInfo
+        : Asn1Encodable
+    {
+        private DerObjectIdentifier	oriType;
+        private Asn1Encodable		oriValue;
+
+		public OtherRecipientInfo(
+            DerObjectIdentifier	oriType,
+            Asn1Encodable		oriValue)
+        {
+            this.oriType = oriType;
+            this.oriValue = oriValue;
+        }
+
+		public OtherRecipientInfo(
+            Asn1Sequence seq)
+        {
+            oriType = DerObjectIdentifier.GetInstance(seq[0]);
+            oriValue = seq[1];
+		}
+
+		/**
+         * return a OtherRecipientInfo object from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static OtherRecipientInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		/**
+         * return a OtherRecipientInfo object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static OtherRecipientInfo GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is OtherRecipientInfo)
+                return (OtherRecipientInfo)obj;
+
+			if (obj is Asn1Sequence)
+                return new OtherRecipientInfo((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid OtherRecipientInfo: " + obj.GetType().Name);
+        }
+
+		public DerObjectIdentifier OriType
+		{
+			get { return oriType; }
+		}
+
+		public Asn1Encodable OriValue
+		{
+			get { return oriValue; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * OtherRecipientInfo ::= Sequence {
+         *    oriType OBJECT IDENTIFIER,
+         *    oriValue ANY DEFINED BY oriType }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(oriType, oriValue);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/PasswordRecipientInfo.cs b/Crypto/src/asn1/cms/PasswordRecipientInfo.cs
new file mode 100644
index 000000000..800b57951
--- /dev/null
+++ b/Crypto/src/asn1/cms/PasswordRecipientInfo.cs
@@ -0,0 +1,133 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class PasswordRecipientInfo
+        : Asn1Encodable
+    {
+        private readonly DerInteger				version;
+        private readonly AlgorithmIdentifier	keyDerivationAlgorithm;
+        private readonly AlgorithmIdentifier	keyEncryptionAlgorithm;
+        private readonly Asn1OctetString		encryptedKey;
+
+		public PasswordRecipientInfo(
+            AlgorithmIdentifier	keyEncryptionAlgorithm,
+            Asn1OctetString		encryptedKey)
+        {
+            this.version = new DerInteger(0);
+            this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+            this.encryptedKey = encryptedKey;
+        }
+
+		public PasswordRecipientInfo(
+			AlgorithmIdentifier	keyDerivationAlgorithm,
+			AlgorithmIdentifier	keyEncryptionAlgorithm,
+			Asn1OctetString		encryptedKey)
+		{
+			this.version = new DerInteger(0);
+			this.keyDerivationAlgorithm = keyDerivationAlgorithm;
+			this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+			this.encryptedKey = encryptedKey;
+		}
+
+		public PasswordRecipientInfo(
+            Asn1Sequence seq)
+        {
+            version = (DerInteger) seq[0];
+
+			if (seq[1] is Asn1TaggedObject)
+            {
+                keyDerivationAlgorithm = AlgorithmIdentifier.GetInstance((Asn1TaggedObject) seq[1], false);
+                keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[2]);
+                encryptedKey = (Asn1OctetString) seq[3];
+            }
+            else
+            {
+                keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+                encryptedKey = (Asn1OctetString) seq[2];
+            }
+        }
+
+		/**
+         * return a PasswordRecipientInfo object from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static PasswordRecipientInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		/**
+         * return a PasswordRecipientInfo object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static PasswordRecipientInfo GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is PasswordRecipientInfo)
+                return (PasswordRecipientInfo) obj;
+
+			if (obj is Asn1Sequence)
+                return new PasswordRecipientInfo((Asn1Sequence) obj);
+
+			throw new ArgumentException("Invalid PasswordRecipientInfo: " + obj.GetType().Name);
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public AlgorithmIdentifier KeyDerivationAlgorithm
+		{
+			get { return keyDerivationAlgorithm; }
+		}
+
+		public AlgorithmIdentifier KeyEncryptionAlgorithm
+		{
+			get { return keyEncryptionAlgorithm; }
+		}
+
+		public Asn1OctetString EncryptedKey
+		{
+			get { return encryptedKey; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * PasswordRecipientInfo ::= Sequence {
+         *   version CMSVersion,   -- Always set to 0
+         *   keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier
+         *                             OPTIONAL,
+         *  keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+         *  encryptedKey EncryptedKey }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(version);
+
+			if (keyDerivationAlgorithm != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, keyDerivationAlgorithm));
+            }
+
+			v.Add(keyEncryptionAlgorithm, encryptedKey);
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/RecipientEncryptedKey.cs b/Crypto/src/asn1/cms/RecipientEncryptedKey.cs
new file mode 100644
index 000000000..5ba25a742
--- /dev/null
+++ b/Crypto/src/asn1/cms/RecipientEncryptedKey.cs
@@ -0,0 +1,88 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class RecipientEncryptedKey
+		: Asn1Encodable
+	{
+		private readonly KeyAgreeRecipientIdentifier identifier;
+		private readonly Asn1OctetString encryptedKey;
+
+		private RecipientEncryptedKey(
+			Asn1Sequence seq)
+		{
+			identifier = KeyAgreeRecipientIdentifier.GetInstance(seq[0]);
+			encryptedKey = (Asn1OctetString) seq[1];
+		}
+
+		/**
+		 * return an RecipientEncryptedKey object from a tagged object.
+		 *
+		 * @param obj the tagged object holding the object we want.
+		 * @param isExplicit true if the object is meant to be explicitly
+		 *              tagged false otherwise.
+		 * @exception ArgumentException if the object held by the
+		 *          tagged object cannot be converted.
+		 */
+		public static RecipientEncryptedKey GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+
+		/**
+		 * return a RecipientEncryptedKey object from the given object.
+		 *
+		 * @param obj the object we want converted.
+		 * @exception ArgumentException if the object cannot be converted.
+		 */
+		public static RecipientEncryptedKey GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is RecipientEncryptedKey)
+			{
+				return (RecipientEncryptedKey) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new RecipientEncryptedKey((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("Invalid RecipientEncryptedKey: " + obj.GetType().FullName, "obj");
+		}
+
+		public RecipientEncryptedKey(
+			KeyAgreeRecipientIdentifier	id,
+			Asn1OctetString				encryptedKey)
+		{
+			this.identifier = id;
+			this.encryptedKey = encryptedKey;
+		}
+
+		public KeyAgreeRecipientIdentifier Identifier
+		{
+			get { return identifier; }
+		}
+
+		public Asn1OctetString EncryptedKey
+		{
+			get { return encryptedKey; }
+		}
+
+		/** 
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * <pre>
+		 * RecipientEncryptedKey ::= SEQUENCE {
+		 *     rid KeyAgreeRecipientIdentifier,
+		 *     encryptedKey EncryptedKey
+		 * }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(identifier, encryptedKey);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/RecipientIdentifier.cs b/Crypto/src/asn1/cms/RecipientIdentifier.cs
new file mode 100644
index 000000000..4982bc16a
--- /dev/null
+++ b/Crypto/src/asn1/cms/RecipientIdentifier.cs
@@ -0,0 +1,89 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class RecipientIdentifier
+        : Asn1Encodable, IAsn1Choice
+    {
+        private Asn1Encodable id;
+
+		public RecipientIdentifier(
+            IssuerAndSerialNumber id)
+        {
+            this.id = id;
+        }
+
+		public RecipientIdentifier(
+            Asn1OctetString id)
+        {
+            this.id = new DerTaggedObject(false, 0, id);
+        }
+
+		public RecipientIdentifier(
+            Asn1Object id)
+        {
+            this.id = id;
+        }
+
+		/**
+         * return a RecipientIdentifier object from the given object.
+         *
+         * @param o the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static RecipientIdentifier GetInstance(
+            object o)
+        {
+            if (o == null || o is RecipientIdentifier)
+                return (RecipientIdentifier)o;
+
+			if (o is IssuerAndSerialNumber)
+                return new RecipientIdentifier((IssuerAndSerialNumber) o);
+
+			if (o is Asn1OctetString)
+                return new RecipientIdentifier((Asn1OctetString) o);
+
+			if (o is Asn1Object)
+                return new RecipientIdentifier((Asn1Object) o);
+
+			throw new ArgumentException(
+              "Illegal object in RecipientIdentifier: " + o.GetType().Name);
+        }
+
+		public bool IsTagged
+		{
+			get { return (id is Asn1TaggedObject); }
+		}
+
+		public Asn1Encodable ID
+        {
+            get
+            {
+                if (id is Asn1TaggedObject)
+                {
+                    return Asn1OctetString.GetInstance((Asn1TaggedObject) id, false);
+                }
+
+				return IssuerAndSerialNumber.GetInstance(id);
+            }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * RecipientIdentifier ::= CHOICE {
+         *     issuerAndSerialNumber IssuerAndSerialNumber,
+         *     subjectKeyIdentifier [0] SubjectKeyIdentifier
+         * }
+         *
+         * SubjectKeyIdentifier ::= OCTET STRING
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return id.ToAsn1Object();
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/RecipientInfo.cs b/Crypto/src/asn1/cms/RecipientInfo.cs
new file mode 100644
index 000000000..daaf5a5e4
--- /dev/null
+++ b/Crypto/src/asn1/cms/RecipientInfo.cs
@@ -0,0 +1,145 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class RecipientInfo
+        : Asn1Encodable, IAsn1Choice
+    {
+        internal Asn1Encodable info;
+
+		public RecipientInfo(
+            KeyTransRecipientInfo info)
+        {
+            this.info = info;
+        }
+
+		public RecipientInfo(
+            KeyAgreeRecipientInfo info)
+        {
+            this.info = new DerTaggedObject(false, 1, info);
+        }
+
+		public RecipientInfo(
+            KekRecipientInfo info)
+        {
+            this.info = new DerTaggedObject(false, 2, info);
+        }
+
+		public RecipientInfo(
+            PasswordRecipientInfo info)
+        {
+            this.info = new DerTaggedObject(false, 3, info);
+        }
+
+		public RecipientInfo(
+            OtherRecipientInfo info)
+        {
+            this.info = new DerTaggedObject(false, 4, info);
+        }
+
+		public RecipientInfo(
+            Asn1Object   info)
+        {
+            this.info = info;
+        }
+
+		public static RecipientInfo GetInstance(
+            object o)
+        {
+            if (o == null || o is RecipientInfo)
+                return (RecipientInfo) o;
+
+			if (o is Asn1Sequence)
+                return new RecipientInfo((Asn1Sequence) o);
+
+			if (o is Asn1TaggedObject)
+                return new RecipientInfo((Asn1TaggedObject) o);
+
+			throw new ArgumentException("unknown object in factory: " + o.GetType().Name);
+        }
+
+		public DerInteger Version
+        {
+			get
+			{
+				if (info is Asn1TaggedObject)
+				{
+					Asn1TaggedObject o = (Asn1TaggedObject) info;
+
+					switch (o.TagNo)
+					{
+						case 1:
+							return KeyAgreeRecipientInfo.GetInstance(o, false).Version;
+						case 2:
+							return GetKekInfo(o).Version;
+						case 3:
+							return PasswordRecipientInfo.GetInstance(o, false).Version;
+						case 4:
+							return new DerInteger(0);    // no syntax version for OtherRecipientInfo
+						default:
+							throw new InvalidOperationException("unknown tag");
+					}
+				}
+
+				return KeyTransRecipientInfo.GetInstance(info).Version;
+			}
+        }
+
+		public bool IsTagged
+		{
+			get { return info is Asn1TaggedObject; }
+		}
+
+		public Asn1Encodable Info
+        {
+			get
+			{
+				if (info is Asn1TaggedObject)
+				{
+					Asn1TaggedObject o = (Asn1TaggedObject) info;
+
+					switch (o.TagNo)
+					{
+						case 1:
+							return KeyAgreeRecipientInfo.GetInstance(o, false);
+						case 2:
+							return GetKekInfo(o);
+						case 3:
+							return PasswordRecipientInfo.GetInstance(o, false);
+						case 4:
+							return OtherRecipientInfo.GetInstance(o, false);
+						default:
+							throw new InvalidOperationException("unknown tag");
+					}
+				}
+
+				return KeyTransRecipientInfo.GetInstance(info);
+			}
+        }
+
+		private KekRecipientInfo GetKekInfo(
+			Asn1TaggedObject o)
+		{
+			// For compatibility with erroneous version, we don't always pass 'false' here
+			return KekRecipientInfo.GetInstance(o, o.IsExplicit());
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * RecipientInfo ::= CHOICE {
+         *     ktri KeyTransRecipientInfo,
+         *     kari [1] KeyAgreeRecipientInfo,
+         *     kekri [2] KekRecipientInfo,
+         *     pwri [3] PasswordRecipientInfo,
+         *     ori [4] OtherRecipientInfo }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return info.ToAsn1Object();
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/RecipientKeyIdentifier.cs b/Crypto/src/asn1/cms/RecipientKeyIdentifier.cs
new file mode 100644
index 000000000..f3e45644b
--- /dev/null
+++ b/Crypto/src/asn1/cms/RecipientKeyIdentifier.cs
@@ -0,0 +1,137 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class RecipientKeyIdentifier
+        : Asn1Encodable
+    {
+        private Asn1OctetString      subjectKeyIdentifier;
+        private DerGeneralizedTime   date;
+        private OtherKeyAttribute    other;
+
+		public RecipientKeyIdentifier(
+            Asn1OctetString         subjectKeyIdentifier,
+            DerGeneralizedTime      date,
+            OtherKeyAttribute       other)
+        {
+            this.subjectKeyIdentifier = subjectKeyIdentifier;
+            this.date = date;
+            this.other = other;
+        }
+		
+		public RecipientKeyIdentifier(
+			byte[] subjectKeyIdentifier)
+			: this(subjectKeyIdentifier, null, null)
+		{
+		}
+
+		public RecipientKeyIdentifier(
+			byte[]				subjectKeyIdentifier,
+			DerGeneralizedTime	date,
+			OtherKeyAttribute	other)
+		{
+			this.subjectKeyIdentifier = new DerOctetString(subjectKeyIdentifier);
+			this.date = date;
+			this.other = other;
+		}
+
+		public RecipientKeyIdentifier(
+            Asn1Sequence seq)
+        {
+            subjectKeyIdentifier = Asn1OctetString.GetInstance(
+				seq[0]);
+
+			switch(seq.Count)
+            {
+				case 1:
+					break;
+				case 2:
+					if (seq[1] is DerGeneralizedTime)
+					{
+						date = (DerGeneralizedTime) seq[1];
+					}
+					else
+					{
+						other = OtherKeyAttribute.GetInstance(seq[2]);
+					}
+					break;
+				case 3:
+					date  = (DerGeneralizedTime) seq[1];
+					other = OtherKeyAttribute.GetInstance(seq[2]);
+					break;
+				default:
+					throw new ArgumentException("Invalid RecipientKeyIdentifier");
+            }
+        }
+
+		/**
+         * return a RecipientKeyIdentifier object from a tagged object.
+         *
+         * @param _ato the tagged object holding the object we want.
+         * @param _explicit true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static RecipientKeyIdentifier GetInstance(
+			Asn1TaggedObject	ato,
+			bool				explicitly)
+		{
+            return GetInstance(Asn1Sequence.GetInstance(ato, explicitly));
+        }
+
+		/**
+         * return a RecipientKeyIdentifier object from the given object.
+         *
+         * @param _obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static RecipientKeyIdentifier GetInstance(
+			object obj)
+		{
+            if (obj == null || obj is RecipientKeyIdentifier)
+                return (RecipientKeyIdentifier) obj;
+
+			if (obj is Asn1Sequence)
+				return new RecipientKeyIdentifier((Asn1Sequence) obj);
+
+			throw new ArgumentException("Invalid RecipientKeyIdentifier: " + obj.GetType().Name);
+        }
+
+		public Asn1OctetString SubjectKeyIdentifier
+		{
+			get { return subjectKeyIdentifier; }
+		}
+
+		public DerGeneralizedTime Date
+		{
+			get { return date; }
+		}
+
+		public OtherKeyAttribute OtherKeyAttribute
+		{
+			get { return other; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * RecipientKeyIdentifier ::= Sequence {
+         *     subjectKeyIdentifier SubjectKeyIdentifier,
+         *     date GeneralizedTime OPTIONAL,
+         *     other OtherKeyAttribute OPTIONAL
+         * }
+         *
+         * SubjectKeyIdentifier ::= OCTET STRING
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(subjectKeyIdentifier);
+			v.AddOptional(date, other);
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/SignedData.cs b/Crypto/src/asn1/cms/SignedData.cs
new file mode 100644
index 000000000..40ed09f32
--- /dev/null
+++ b/Crypto/src/asn1/cms/SignedData.cs
@@ -0,0 +1,282 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    /**
+     * a signed data object.
+     */
+    public class SignedData
+        : Asn1Encodable
+    {
+        private readonly DerInteger		version;
+        private readonly Asn1Set		digestAlgorithms;
+        private readonly ContentInfo	contentInfo;
+        private readonly Asn1Set		certificates;
+        private readonly Asn1Set		crls;
+        private readonly Asn1Set		signerInfos;
+        private readonly bool			certsBer;
+        private readonly bool		    crlsBer;
+
+		public static SignedData GetInstance(
+            object obj)
+        {
+            if (obj is SignedData)
+                return (SignedData) obj;
+
+			if (obj is Asn1Sequence)
+                return new SignedData((Asn1Sequence) obj);
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		public SignedData(
+			Asn1Set     digestAlgorithms,
+			ContentInfo contentInfo,
+			Asn1Set     certificates,
+			Asn1Set     crls,
+			Asn1Set     signerInfos)
+		{
+			this.version = CalculateVersion(contentInfo.ContentType, certificates, crls, signerInfos);
+			this.digestAlgorithms = digestAlgorithms;
+			this.contentInfo = contentInfo;
+			this.certificates = certificates;
+			this.crls = crls;
+			this.signerInfos = signerInfos;
+			this.crlsBer = crls is BerSet;
+			this.certsBer = certificates is BerSet;
+		}
+
+		// 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 DerInteger CalculateVersion(
+			DerObjectIdentifier	contentOid,
+			Asn1Set				certs,
+			Asn1Set				crls,
+			Asn1Set				signerInfs)
+		{
+			bool otherCert = false;
+			bool otherCrl = false;
+			bool attrCertV1Found = false;
+			bool attrCertV2Found = false;
+
+			if (certs != null)
+			{
+				foreach (object obj in certs)
+				{
+					if (obj is Asn1TaggedObject)
+					{
+						Asn1TaggedObject tagged = (Asn1TaggedObject)obj;
+
+						if (tagged.TagNo == 1)
+						{
+							attrCertV1Found = true;
+						}
+						else if (tagged.TagNo == 2)
+						{
+							attrCertV2Found = true;
+						}
+						else if (tagged.TagNo == 3)
+						{
+							otherCert = true;
+							break;
+						}
+					}
+				}
+			}
+
+			if (otherCert)
+			{
+				return new DerInteger(5);
+			}
+
+			if (crls != null)
+			{
+				foreach (object obj in crls)
+				{
+					if (obj is Asn1TaggedObject)
+					{
+						otherCrl = true;
+						break;
+					}
+				}
+			}
+
+			if (otherCrl)
+			{
+				return new DerInteger(5);
+			}
+
+			if (attrCertV2Found)
+			{
+				return new DerInteger(4);
+			}
+
+			if (attrCertV1Found || !CmsObjectIdentifiers.Data.Equals(contentOid) || CheckForVersion3(signerInfs))
+			{
+				return new DerInteger(3);
+			}
+
+            return new DerInteger(1);
+		}
+
+		private bool CheckForVersion3(
+			Asn1Set signerInfs)
+		{
+			foreach (object obj in signerInfs)
+			{
+				SignerInfo s = SignerInfo.GetInstance(obj);
+
+				if (s.Version.Value.IntValue == 3)
+				{
+					return true;
+				}
+			}
+
+			return false;
+		}
+
+		private SignedData(
+            Asn1Sequence seq)
+        {
+            IEnumerator e = seq.GetEnumerator();
+
+			e.MoveNext();
+            version = (DerInteger)e.Current;
+
+			e.MoveNext();
+            digestAlgorithms = ((Asn1Set)e.Current);
+
+			e.MoveNext();
+            contentInfo = ContentInfo.GetInstance(e.Current);
+
+			while (e.MoveNext())
+            {
+                Asn1Object o = (Asn1Object)e.Current;
+
+				//
+                // an interesting feature of SignedData is that there appear
+                // to be varying implementations...
+                // for the moment we ignore anything which doesn't fit.
+                //
+                if (o is Asn1TaggedObject)
+                {
+                    Asn1TaggedObject tagged = (Asn1TaggedObject)o;
+
+                    switch (tagged.TagNo)
+                    {
+						case 0:
+							certsBer = tagged is BerTaggedObject;
+							certificates = Asn1Set.GetInstance(tagged, false);
+							break;
+						case 1:
+							crlsBer = tagged is BerTaggedObject;
+							crls = Asn1Set.GetInstance(tagged, false);
+							break;
+						default:
+							throw new ArgumentException("unknown tag value " + tagged.TagNo);
+                    }
+                }
+                else
+                {
+                    signerInfos = (Asn1Set) o;
+                }
+            }
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public Asn1Set DigestAlgorithms
+		{
+			get { return digestAlgorithms; }
+		}
+
+		public ContentInfo EncapContentInfo
+		{
+			get { return contentInfo; }
+		}
+
+		public Asn1Set Certificates
+		{
+			get { return certificates; }
+		}
+
+		public Asn1Set CRLs
+		{
+			get { return crls; }
+		}
+
+		public Asn1Set SignerInfos
+		{
+			get { return signerInfos; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * SignedData ::= Sequence {
+         *     version CMSVersion,
+         *     digestAlgorithms DigestAlgorithmIdentifiers,
+         *     encapContentInfo EncapsulatedContentInfo,
+         *     certificates [0] IMPLICIT CertificateSet OPTIONAL,
+         *     crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+         *     signerInfos SignerInfos
+         *   }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				version, digestAlgorithms, contentInfo);
+
+			if (certificates != null)
+            {
+                if (certsBer)
+                {
+                    v.Add(new BerTaggedObject(false, 0, certificates));
+                }
+                else
+                {
+                    v.Add(new DerTaggedObject(false, 0, certificates));
+                }
+            }
+
+			if (crls != null)
+            {
+                if (crlsBer)
+                {
+                    v.Add(new BerTaggedObject(false, 1, crls));
+                }
+                else
+                {
+                    v.Add(new DerTaggedObject(false, 1, crls));
+                }
+            }
+
+			v.Add(signerInfos);
+
+			return new BerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/SignedDataParser.cs b/Crypto/src/asn1/cms/SignedDataParser.cs
new file mode 100644
index 000000000..341309263
--- /dev/null
+++ b/Crypto/src/asn1/cms/SignedDataParser.cs
@@ -0,0 +1,112 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	/**
+	* <pre>
+	* SignedData ::= SEQUENCE {
+	*     version CMSVersion,
+	*     digestAlgorithms DigestAlgorithmIdentifiers,
+	*     encapContentInfo EncapsulatedContentInfo,
+	*     certificates [0] IMPLICIT CertificateSet OPTIONAL,
+	*     crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+	*     signerInfos SignerInfos
+	*   }
+	* </pre>
+	*/
+	public class SignedDataParser
+	{
+		private Asn1SequenceParser	_seq;
+		private DerInteger			_version;
+		private object				_nextObject;
+		private bool				_certsCalled;
+		private bool				_crlsCalled;
+
+		public static SignedDataParser GetInstance(
+			object o)
+		{
+			if (o is Asn1Sequence)
+				return new SignedDataParser(((Asn1Sequence)o).Parser);
+
+			if (o is Asn1SequenceParser)
+				return new SignedDataParser((Asn1SequenceParser)o);
+
+			throw new IOException("unknown object encountered: " + o.GetType().Name);
+		}
+
+		public SignedDataParser(
+			Asn1SequenceParser seq)
+		{
+			this._seq = seq;
+			this._version = (DerInteger)seq.ReadObject();
+		}
+
+		public DerInteger Version
+		{
+			get { return _version; }
+		}
+
+		public Asn1SetParser GetDigestAlgorithms()
+		{
+			return (Asn1SetParser)_seq.ReadObject();
+		}
+
+		public ContentInfoParser GetEncapContentInfo()
+		{
+			return new ContentInfoParser((Asn1SequenceParser)_seq.ReadObject());
+		}
+
+		public Asn1SetParser GetCertificates()
+		{
+			_certsCalled = true;
+			_nextObject = _seq.ReadObject();
+
+			if (_nextObject is Asn1TaggedObjectParser && ((Asn1TaggedObjectParser)_nextObject).TagNo == 0)
+			{
+				Asn1SetParser certs = (Asn1SetParser)((Asn1TaggedObjectParser)_nextObject).GetObjectParser(Asn1Tags.Set, false);
+				_nextObject = null;
+
+				return certs;
+			}
+
+			return null;
+		}
+
+		public Asn1SetParser GetCrls()
+		{
+			if (!_certsCalled)
+				throw new IOException("GetCerts() has not been called.");
+
+			_crlsCalled = true;
+
+			if (_nextObject == null)
+			{
+				_nextObject = _seq.ReadObject();
+			}
+
+			if (_nextObject is Asn1TaggedObjectParser && ((Asn1TaggedObjectParser)_nextObject).TagNo == 1)
+			{
+				Asn1SetParser crls = (Asn1SetParser)((Asn1TaggedObjectParser)_nextObject).GetObjectParser(Asn1Tags.Set, false);
+				_nextObject = null;
+
+				return crls;
+			}
+
+			return null;
+		}
+
+		public Asn1SetParser GetSignerInfos()
+		{
+			if (!_certsCalled || !_crlsCalled)
+				throw new IOException("GetCerts() and/or GetCrls() has not been called.");
+
+			if (_nextObject == null)
+			{
+				_nextObject = _seq.ReadObject();
+			}
+
+			return (Asn1SetParser)_nextObject;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/SignerIdentifier.cs b/Crypto/src/asn1/cms/SignerIdentifier.cs
new file mode 100644
index 000000000..5742cee75
--- /dev/null
+++ b/Crypto/src/asn1/cms/SignerIdentifier.cs
@@ -0,0 +1,89 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class SignerIdentifier
+        : Asn1Encodable, IAsn1Choice
+    {
+        private Asn1Encodable id;
+
+		public SignerIdentifier(
+            IssuerAndSerialNumber id)
+        {
+            this.id = id;
+        }
+
+		public SignerIdentifier(
+            Asn1OctetString id)
+        {
+            this.id = new DerTaggedObject(false, 0, id);
+        }
+
+		public SignerIdentifier(
+            Asn1Object id)
+        {
+            this.id = id;
+        }
+
+		/**
+         * return a SignerIdentifier object from the given object.
+         *
+         * @param o the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static SignerIdentifier GetInstance(
+            object o)
+        {
+            if (o == null || o is SignerIdentifier)
+                return (SignerIdentifier) o;
+
+			if (o is IssuerAndSerialNumber)
+                return new SignerIdentifier((IssuerAndSerialNumber) o);
+
+			if (o is Asn1OctetString)
+                return new SignerIdentifier((Asn1OctetString) o);
+
+			if (o is Asn1Object)
+                return new SignerIdentifier((Asn1Object) o);
+
+			throw new ArgumentException(
+				"Illegal object in SignerIdentifier: " + o.GetType().Name);
+        }
+
+		public bool IsTagged
+		{
+			get { return (id is Asn1TaggedObject); }
+		}
+
+		public Asn1Encodable ID
+        {
+            get
+            {
+                if (id is Asn1TaggedObject)
+                {
+                    return Asn1OctetString.GetInstance((Asn1TaggedObject)id, false);
+                }
+
+				return id;
+            }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * SignerIdentifier ::= CHOICE {
+         *     issuerAndSerialNumber IssuerAndSerialNumber,
+         *     subjectKeyIdentifier [0] SubjectKeyIdentifier
+         * }
+         *
+         * SubjectKeyIdentifier ::= OCTET STRING
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return id.ToAsn1Object();
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/SignerInfo.cs b/Crypto/src/asn1/cms/SignerInfo.cs
new file mode 100644
index 000000000..ef71ddfc4
--- /dev/null
+++ b/Crypto/src/asn1/cms/SignerInfo.cs
@@ -0,0 +1,175 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class SignerInfo
+        : Asn1Encodable
+    {
+        private DerInteger              version;
+        private SignerIdentifier        sid;
+        private AlgorithmIdentifier     digAlgorithm;
+        private Asn1Set                 authenticatedAttributes;
+        private AlgorithmIdentifier     digEncryptionAlgorithm;
+        private Asn1OctetString         encryptedDigest;
+        private Asn1Set                 unauthenticatedAttributes;
+
+        public static SignerInfo GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is SignerInfo)
+                return (SignerInfo) obj;
+
+			if (obj is Asn1Sequence)
+                return new SignerInfo((Asn1Sequence) obj);
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		public SignerInfo(
+            SignerIdentifier        sid,
+            AlgorithmIdentifier     digAlgorithm,
+            Asn1Set                 authenticatedAttributes,
+            AlgorithmIdentifier     digEncryptionAlgorithm,
+            Asn1OctetString         encryptedDigest,
+            Asn1Set                 unauthenticatedAttributes)
+        {
+            if (sid.IsTagged)
+            {
+                this.version = new DerInteger(3);
+            }
+            else
+            {
+                this.version = new DerInteger(1);
+            }
+
+			this.sid = sid;
+            this.digAlgorithm = digAlgorithm;
+            this.authenticatedAttributes = authenticatedAttributes;
+            this.digEncryptionAlgorithm = digEncryptionAlgorithm;
+            this.encryptedDigest = encryptedDigest;
+            this.unauthenticatedAttributes = unauthenticatedAttributes;
+        }
+
+		public SignerInfo(
+            Asn1Sequence seq)
+        {
+            IEnumerator e = seq.GetEnumerator();
+
+            e.MoveNext();
+            version = (DerInteger) e.Current;
+
+			e.MoveNext();
+            sid = SignerIdentifier.GetInstance(e.Current);
+
+			e.MoveNext();
+            digAlgorithm = AlgorithmIdentifier.GetInstance(e.Current);
+
+			e.MoveNext();
+            object obj = e.Current;
+
+			if (obj is Asn1TaggedObject)
+            {
+                authenticatedAttributes = Asn1Set.GetInstance((Asn1TaggedObject) obj, false);
+
+				e.MoveNext();
+                digEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(e.Current);
+            }
+            else
+            {
+                authenticatedAttributes = null;
+                digEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(obj);
+            }
+
+			e.MoveNext();
+            encryptedDigest = DerOctetString.GetInstance(e.Current);
+
+			if (e.MoveNext())
+            {
+                unauthenticatedAttributes = Asn1Set.GetInstance((Asn1TaggedObject) e.Current, false);
+            }
+            else
+            {
+                unauthenticatedAttributes = null;
+            }
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public SignerIdentifier SignerID
+		{
+			get { return sid; }
+		}
+
+		public Asn1Set AuthenticatedAttributes
+		{
+			get { return authenticatedAttributes; }
+		}
+
+		public AlgorithmIdentifier DigestAlgorithm
+		{
+			get { return digAlgorithm; }
+		}
+
+		public Asn1OctetString EncryptedDigest
+		{
+			get { return encryptedDigest; }
+		}
+
+		public AlgorithmIdentifier DigestEncryptionAlgorithm
+		{
+			get { return digEncryptionAlgorithm; }
+		}
+
+		public Asn1Set UnauthenticatedAttributes
+		{
+			get { return unauthenticatedAttributes; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  SignerInfo ::= Sequence {
+         *      version Version,
+         *      SignerIdentifier sid,
+         *      digestAlgorithm DigestAlgorithmIdentifier,
+         *      authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
+         *      digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
+         *      encryptedDigest EncryptedDigest,
+         *      unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
+         *  }
+         *
+         *  EncryptedDigest ::= OCTET STRING
+         *
+         *  DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+         *
+         *  DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				version, sid, digAlgorithm);
+
+			if (authenticatedAttributes != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, authenticatedAttributes));
+            }
+
+			v.Add(digEncryptionAlgorithm, encryptedDigest);
+
+			if (unauthenticatedAttributes != null)
+            {
+                v.Add(new DerTaggedObject(false, 1, unauthenticatedAttributes));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/Time.cs b/Crypto/src/asn1/cms/Time.cs
new file mode 100644
index 000000000..d113bfa2e
--- /dev/null
+++ b/Crypto/src/asn1/cms/Time.cs
@@ -0,0 +1,118 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class Time
+        : Asn1Encodable, IAsn1Choice
+    {
+        private readonly Asn1Object time;
+
+		public static Time GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(obj.GetObject());
+        }
+
+		public Time(
+            Asn1Object time)
+        {
+            if (!(time is DerUtcTime)
+                && !(time is DerGeneralizedTime))
+            {
+                throw new ArgumentException("unknown object passed to Time");
+            }
+
+			this.time = time;
+        }
+
+		/**
+         * creates a time object from a given date - if the date is between 1950
+         * and 2049 a UTCTime object is Generated, otherwise a GeneralizedTime
+         * is used.
+         */
+        public Time(
+            DateTime date)
+        {
+            string d = date.ToString("yyyyMMddHHmmss") + "Z";
+
+			int year = int.Parse(d.Substring(0, 4));
+
+			if (year < 1950 || year > 2049)
+            {
+                time = new DerGeneralizedTime(d);
+            }
+            else
+            {
+                time = new DerUtcTime(d.Substring(2));
+            }
+        }
+
+		public static Time GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is Time)
+                return (Time)obj;
+
+			if (obj is DerUtcTime)
+                return new Time((DerUtcTime)obj);
+
+			if (obj is DerGeneralizedTime)
+                return new Time((DerGeneralizedTime)obj);
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        }
+
+		public string TimeString
+        {
+			get
+			{
+				if (time is DerUtcTime)
+				{
+					return ((DerUtcTime)time).AdjustedTimeString;
+				}
+				else
+				{
+					return ((DerGeneralizedTime)time).GetTime();
+				}
+			}
+        }
+
+		public DateTime Date
+        {
+			get
+			{
+				try
+				{
+					if (time is DerUtcTime)
+					{
+						return ((DerUtcTime)time).ToAdjustedDateTime();
+					}
+
+					return ((DerGeneralizedTime)time).ToDateTime();
+				}
+				catch (FormatException e)
+				{
+					// this should never happen
+					throw new InvalidOperationException("invalid date string: " + e.Message);
+				}
+			}
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * Time ::= CHOICE {
+         *             utcTime        UTCTime,
+         *             generalTime    GeneralizedTime }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return time;
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cms/TimeStampAndCRL.cs b/Crypto/src/asn1/cms/TimeStampAndCRL.cs
new file mode 100644
index 000000000..4cb5f2a52
--- /dev/null
+++ b/Crypto/src/asn1/cms/TimeStampAndCRL.cs
@@ -0,0 +1,62 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class TimeStampAndCrl
+		: Asn1Encodable
+	{
+		private ContentInfo timeStamp;
+		private X509.CertificateList crl;
+
+		public TimeStampAndCrl(ContentInfo timeStamp)
+		{
+			this.timeStamp = timeStamp;
+		}
+
+		private TimeStampAndCrl(Asn1Sequence seq)
+		{
+			this.timeStamp = ContentInfo.GetInstance(seq[0]);
+			if (seq.Count == 2)
+			{
+				this.crl = X509.CertificateList.GetInstance(seq[1]);
+			}
+		}
+
+		public static TimeStampAndCrl GetInstance(object obj)
+		{
+			if (obj is TimeStampAndCrl)
+				return (TimeStampAndCrl)obj;
+
+			if (obj != null)
+				return new TimeStampAndCrl(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		public virtual ContentInfo TimeStampToken
+		{
+			get { return this.timeStamp; }
+		}
+
+		public virtual X509.CertificateList Crl
+		{
+			get { return this.crl; }
+		}
+
+		/**
+		 * <pre>
+		 * TimeStampAndCRL ::= SEQUENCE {
+		 *     timeStamp   TimeStampToken,          -- according to RFC 3161
+		 *     crl         CertificateList OPTIONAL -- according to RFC 5280
+		 *  }
+		 * </pre>
+		 * @return
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(timeStamp);
+			v.AddOptional(crl);
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/TimeStampTokenEvidence.cs b/Crypto/src/asn1/cms/TimeStampTokenEvidence.cs
new file mode 100644
index 000000000..8625d058e
--- /dev/null
+++ b/Crypto/src/asn1/cms/TimeStampTokenEvidence.cs
@@ -0,0 +1,65 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class TimeStampTokenEvidence
+		: Asn1Encodable
+	{
+		private TimeStampAndCrl[] timeStampAndCrls;
+
+		public TimeStampTokenEvidence(TimeStampAndCrl[] timeStampAndCrls)
+		{
+			this.timeStampAndCrls = timeStampAndCrls;
+		}
+
+		public TimeStampTokenEvidence(TimeStampAndCrl timeStampAndCrl)
+		{
+			this.timeStampAndCrls = new TimeStampAndCrl[]{ timeStampAndCrl };
+		}
+
+		private TimeStampTokenEvidence(Asn1Sequence seq)
+		{
+			this.timeStampAndCrls = new TimeStampAndCrl[seq.Count];
+
+			int count = 0;
+
+			foreach (Asn1Encodable ae in seq)
+			{
+				this.timeStampAndCrls[count++] = TimeStampAndCrl.GetInstance(ae.ToAsn1Object());
+			}
+		}
+
+		public static TimeStampTokenEvidence GetInstance(Asn1TaggedObject tagged, bool isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(tagged, isExplicit));
+		}
+
+		public static TimeStampTokenEvidence GetInstance(object obj)
+		{
+			if (obj is TimeStampTokenEvidence)
+				return (TimeStampTokenEvidence)obj;
+
+			if (obj != null)
+				return new TimeStampTokenEvidence(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		public virtual TimeStampAndCrl[] ToTimeStampAndCrlArray()
+		{
+			return (TimeStampAndCrl[])timeStampAndCrls.Clone();
+		}
+
+		/**
+		 * <pre>
+		 * TimeStampTokenEvidence ::=
+		 *    SEQUENCE SIZE(1..MAX) OF TimeStampAndCrl
+		 * </pre>
+		 * @return
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(timeStampAndCrls);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/TimeStampedData.cs b/Crypto/src/asn1/cms/TimeStampedData.cs
new file mode 100644
index 000000000..15448a923
--- /dev/null
+++ b/Crypto/src/asn1/cms/TimeStampedData.cs
@@ -0,0 +1,95 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class TimeStampedData
+		: Asn1Encodable
+	{
+		private DerInteger version;
+		private DerIA5String dataUri;
+		private MetaData metaData;
+		private Asn1OctetString content;
+		private Evidence temporalEvidence;
+
+		public TimeStampedData(DerIA5String dataUri, MetaData metaData, Asn1OctetString content,
+			Evidence temporalEvidence)
+		{
+			this.version = new DerInteger(1);
+			this.dataUri = dataUri;
+			this.metaData = metaData;
+			this.content = content;
+			this.temporalEvidence = temporalEvidence;
+		}
+
+		private TimeStampedData(Asn1Sequence seq)
+		{
+			this.version = DerInteger.GetInstance(seq[0]);
+			
+			int index = 1;
+			if (seq[index] is DerIA5String)
+			{
+				this.dataUri = DerIA5String.GetInstance(seq[index++]);
+			}
+			if (seq[index] is MetaData || seq[index] is Asn1Sequence)
+			{
+				this.metaData = MetaData.GetInstance(seq[index++]);
+			}
+			if (seq[index] is Asn1OctetString)
+			{
+				this.content = Asn1OctetString.GetInstance(seq[index++]);
+			}
+			this.temporalEvidence = Evidence.GetInstance(seq[index]);
+		}
+
+		public static TimeStampedData GetInstance(object obj)
+		{
+			if (obj is TimeStampedData)
+				return (TimeStampedData)obj;
+
+			if (obj != null)
+				return new TimeStampedData(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		public virtual DerIA5String DataUri
+		{
+			get { return dataUri; }
+		}
+
+		public MetaData MetaData
+		{
+			get { return metaData; }
+		}
+
+		public Asn1OctetString Content
+		{
+			get { return content; }
+		}
+
+		public Evidence TemporalEvidence
+		{
+			get { return temporalEvidence; }
+		}
+
+		/**
+		 * <pre>
+		 * TimeStampedData ::= SEQUENCE {
+		 *   version              INTEGER { v1(1) },
+		 *   dataUri              IA5String OPTIONAL,
+		 *   metaData             MetaData OPTIONAL,
+		 *   content              OCTET STRING OPTIONAL,
+		 *   temporalEvidence     Evidence
+		 * }
+		 * </pre>
+		 * @return
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(version);
+			v.AddOptional(dataUri, metaData, content);
+			v.Add(temporalEvidence);
+			return new BerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/TimeStampedDataParser.cs b/Crypto/src/asn1/cms/TimeStampedDataParser.cs
new file mode 100644
index 000000000..90307bff9
--- /dev/null
+++ b/Crypto/src/asn1/cms/TimeStampedDataParser.cs
@@ -0,0 +1,76 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class TimeStampedDataParser
+	{
+		private DerInteger version;
+		private DerIA5String dataUri;
+		private MetaData metaData;
+		private Asn1OctetStringParser content;
+		private Evidence temporalEvidence;
+		private Asn1SequenceParser parser;
+		
+		private TimeStampedDataParser(Asn1SequenceParser parser)
+		{
+			this.parser = parser;
+			this.version = DerInteger.GetInstance(parser.ReadObject());
+
+			Asn1Object obj = parser.ReadObject().ToAsn1Object();
+
+			if (obj is DerIA5String)
+			{
+				this.dataUri = DerIA5String.GetInstance(obj);
+				obj = parser.ReadObject().ToAsn1Object();
+			}
+
+            if (//obj is MetaData ||
+                obj is Asn1SequenceParser)
+			{
+				this.metaData = MetaData.GetInstance(obj.ToAsn1Object());
+				obj = parser.ReadObject().ToAsn1Object();
+			}
+
+			if (obj is Asn1OctetStringParser)
+			{
+				this.content = (Asn1OctetStringParser)obj;
+			}
+		}
+
+		public static TimeStampedDataParser GetInstance(object obj)
+		{
+			if (obj is Asn1Sequence)
+				return new TimeStampedDataParser(((Asn1Sequence)obj).Parser);
+
+			if (obj is Asn1SequenceParser)
+				return new TimeStampedDataParser((Asn1SequenceParser)obj);
+
+			return null;
+		}
+		
+		public virtual DerIA5String DataUri
+		{
+			get { return dataUri; }
+		}
+
+		public virtual MetaData MetaData
+		{
+			get { return metaData; }
+		}
+
+		public virtual Asn1OctetStringParser Content
+		{
+			get { return content; }
+		}
+
+		public virtual Evidence GetTemporalEvidence()
+		{
+			if (temporalEvidence == null)
+			{
+				temporalEvidence = Evidence.GetInstance(parser.ReadObject().ToAsn1Object());
+			}
+
+			return temporalEvidence;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/cms/ecc/MQVuserKeyingMaterial.cs b/Crypto/src/asn1/cms/ecc/MQVuserKeyingMaterial.cs
new file mode 100644
index 000000000..53c5c706b
--- /dev/null
+++ b/Crypto/src/asn1/cms/ecc/MQVuserKeyingMaterial.cs
@@ -0,0 +1,103 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms.Ecc
+{
+	public class MQVuserKeyingMaterial
+		: Asn1Encodable
+	{
+		private OriginatorPublicKey	ephemeralPublicKey;
+		private Asn1OctetString		addedukm;
+
+		public MQVuserKeyingMaterial(
+			OriginatorPublicKey	ephemeralPublicKey,
+			Asn1OctetString		addedukm)
+		{
+			// TODO Check ephemeralPublicKey not null
+
+			this.ephemeralPublicKey = ephemeralPublicKey;
+			this.addedukm = addedukm;
+		}
+
+		private MQVuserKeyingMaterial(
+			Asn1Sequence seq)
+		{
+			// TODO Check seq has either 1 or 2 elements
+
+			this.ephemeralPublicKey = OriginatorPublicKey.GetInstance(seq[0]);
+
+			if (seq.Count > 1)
+			{
+				this.addedukm = Asn1OctetString.GetInstance(
+					(Asn1TaggedObject)seq[1], true);
+			}
+		}
+
+		/**
+		 * return an AuthEnvelopedData object from a tagged object.
+		 *
+		 * @param obj      the tagged object holding the object we want.
+		 * @param isExplicit true if the object is meant to be explicitly
+		 *                 tagged false otherwise.
+		 * @throws ArgumentException if the object held by the
+		 *                                  tagged object cannot be converted.
+		 */
+		public static MQVuserKeyingMaterial GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+
+		/**
+		 * return an AuthEnvelopedData object from the given object.
+		 *
+		 * @param obj the object we want converted.
+		 * @throws ArgumentException if the object cannot be converted.
+		 */
+		public static MQVuserKeyingMaterial GetInstance(
+			object	obj)
+		{
+			if (obj == null || obj is MQVuserKeyingMaterial)
+			{
+				return (MQVuserKeyingMaterial)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new MQVuserKeyingMaterial((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("Invalid MQVuserKeyingMaterial: " + obj.GetType().Name);
+		}
+		
+		public OriginatorPublicKey EphemeralPublicKey
+		{
+			get { return ephemeralPublicKey; }
+		}
+
+		public Asn1OctetString AddedUkm
+		{
+			get { return addedukm; }
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <pre>
+		* MQVuserKeyingMaterial ::= SEQUENCE {
+		*   ephemeralPublicKey OriginatorPublicKey,
+		*   addedukm [0] EXPLICIT UserKeyingMaterial OPTIONAL  }
+		* </pre>
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(ephemeralPublicKey);
+
+			if (addedukm != null)
+			{
+				v.Add(new DerTaggedObject(true, 0, addedukm));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/crmf/AttributeTypeAndValue.cs b/Crypto/src/asn1/crmf/AttributeTypeAndValue.cs
new file mode 100644
index 000000000..823668992
--- /dev/null
+++ b/Crypto/src/asn1/crmf/AttributeTypeAndValue.cs
@@ -0,0 +1,66 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class AttributeTypeAndValue
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier type;
+        private readonly Asn1Encodable value;
+
+        private AttributeTypeAndValue(Asn1Sequence seq)
+        {
+            type = (DerObjectIdentifier)seq[0];
+            value = (Asn1Encodable)seq[1];
+        }
+
+        public static AttributeTypeAndValue GetInstance(object obj)
+        {
+            if (obj is AttributeTypeAndValue)
+                return (AttributeTypeAndValue)obj;
+
+            if (obj is Asn1Sequence)
+                return new AttributeTypeAndValue((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public AttributeTypeAndValue(
+            String oid,
+            Asn1Encodable value)
+            : this(new DerObjectIdentifier(oid), value)
+        {
+        }
+
+        public AttributeTypeAndValue(
+            DerObjectIdentifier type,
+            Asn1Encodable value)
+        {
+            this.type = type;
+            this.value = value;
+        }
+
+        public virtual DerObjectIdentifier Type
+        {
+            get { return type; }
+        }
+
+        public virtual Asn1Encodable Value
+        {
+            get { return value; }
+        }
+
+        /**
+         * <pre>
+         * AttributeTypeAndValue ::= SEQUENCE {
+         *           type         OBJECT IDENTIFIER,
+         *           value        ANY DEFINED BY type }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(type, value);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/CertId.cs b/Crypto/src/asn1/crmf/CertId.cs
new file mode 100644
index 000000000..10c2cc8b4
--- /dev/null
+++ b/Crypto/src/asn1/crmf/CertId.cs
@@ -0,0 +1,58 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertId
+        : Asn1Encodable
+    {
+        private readonly GeneralName issuer;
+        private readonly DerInteger serialNumber;
+
+        private CertId(Asn1Sequence seq)
+        {
+            issuer = GeneralName.GetInstance(seq[0]);
+            serialNumber = DerInteger.GetInstance(seq[1]);
+        }
+
+        public static CertId GetInstance(object obj)
+        {
+            if (obj is CertId)
+                return (CertId)obj;
+
+            if (obj is Asn1Sequence)
+                return new CertId((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public static CertId GetInstance(Asn1TaggedObject obj, bool isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+        public virtual GeneralName Issuer
+        {
+            get { return issuer; }
+        }
+
+        public virtual DerInteger SerialNumber
+        {
+            get { return serialNumber; }
+        }
+
+        /**
+         * <pre>
+         * CertId ::= SEQUENCE {
+         *                 issuer           GeneralName,
+         *                 serialNumber     INTEGER }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(issuer, serialNumber);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/CertReqMessages.cs b/Crypto/src/asn1/crmf/CertReqMessages.cs
new file mode 100644
index 000000000..9247281e8
--- /dev/null
+++ b/Crypto/src/asn1/crmf/CertReqMessages.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertReqMessages
+        : Asn1Encodable
+    {
+        private readonly Asn1Sequence content;
+
+        private CertReqMessages(Asn1Sequence seq)
+        {
+            content = seq;
+        }
+
+        public static CertReqMessages GetInstance(object obj)
+        {
+            if (obj is CertReqMessages)
+                return (CertReqMessages)obj;
+
+            if (obj is Asn1Sequence)
+                return new CertReqMessages((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+		public CertReqMessages(params CertReqMsg[] msgs)
+        {
+            content = new DerSequence(msgs);
+        }
+
+        public virtual CertReqMsg[] ToCertReqMsgArray()
+        {
+            CertReqMsg[] result = new CertReqMsg[content.Count];
+            for (int i = 0; i != result.Length; ++i)
+            {
+                result[i] = CertReqMsg.GetInstance(content[i]);
+            }
+            return result;
+        }
+
+        /**
+         * <pre>
+         * CertReqMessages ::= SEQUENCE SIZE (1..MAX) OF CertReqMsg
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return content;
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/CertReqMsg.cs b/Crypto/src/asn1/crmf/CertReqMsg.cs
new file mode 100644
index 000000000..2ca319a57
--- /dev/null
+++ b/Crypto/src/asn1/crmf/CertReqMsg.cs
@@ -0,0 +1,106 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertReqMsg
+        : Asn1Encodable
+    {
+        private readonly CertRequest certReq;
+        private readonly ProofOfPossession popo;
+        private readonly Asn1Sequence regInfo;
+
+        private CertReqMsg(Asn1Sequence seq)
+        {
+            certReq = CertRequest.GetInstance(seq[0]);
+
+            for (int pos = 1; pos < seq.Count; ++pos)
+            {
+                object o = seq[pos];
+
+                if (o is Asn1TaggedObject || o is ProofOfPossession)
+                {
+                    popo = ProofOfPossession.GetInstance(o);
+                }
+                else
+                {
+                    regInfo = Asn1Sequence.GetInstance(o);
+                }
+            }
+        }
+
+        public static CertReqMsg GetInstance(object obj)
+        {
+            if (obj is CertReqMsg)
+                return (CertReqMsg)obj;
+
+            if (obj != null)
+                return new CertReqMsg(Asn1Sequence.GetInstance(obj));
+
+            return null;
+        }
+
+        /**
+         * Creates a new CertReqMsg.
+         * @param certReq CertRequest
+         * @param popo may be null
+         * @param regInfo may be null
+         */
+        public CertReqMsg(
+            CertRequest				certReq,
+            ProofOfPossession		popo,
+            AttributeTypeAndValue[]	regInfo)
+        {
+            if (certReq == null)
+                throw new ArgumentNullException("certReq");
+
+            this.certReq = certReq;
+            this.popo = popo;
+
+            if (regInfo != null)
+            {
+                this.regInfo = new DerSequence(regInfo);
+            }
+        }
+
+        public virtual CertRequest CertReq
+        {
+            get { return certReq; }
+        }
+
+        public virtual ProofOfPossession Popo
+        {
+            get { return popo; }
+        }
+
+        public virtual AttributeTypeAndValue[] GetRegInfo()
+        {
+            if (regInfo == null)
+                return null;
+
+            AttributeTypeAndValue[] results = new AttributeTypeAndValue[regInfo.Count];
+            for (int i = 0; i != results.Length; ++i)
+            {
+                results[i] = AttributeTypeAndValue.GetInstance(regInfo[i]);
+            }
+            return results;
+        }
+
+        /**
+         * <pre>
+         * CertReqMsg ::= SEQUENCE {
+         *                    certReq   CertRequest,
+         *                    pop       ProofOfPossession  OPTIONAL,
+         *                    -- content depends upon key type
+         *                    regInfo   SEQUENCE SIZE(1..MAX) OF AttributeTypeAndValue OPTIONAL }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(certReq);
+            v.AddOptional(popo);
+            v.AddOptional(regInfo);
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/CertRequest.cs b/Crypto/src/asn1/crmf/CertRequest.cs
new file mode 100644
index 000000000..625a9b519
--- /dev/null
+++ b/Crypto/src/asn1/crmf/CertRequest.cs
@@ -0,0 +1,82 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertRequest
+        : Asn1Encodable
+    {
+        private readonly DerInteger certReqId;
+        private readonly CertTemplate certTemplate;
+        private readonly Controls controls;
+
+        private CertRequest(Asn1Sequence seq)
+        {
+            certReqId = DerInteger.GetInstance(seq[0]);
+            certTemplate = CertTemplate.GetInstance(seq[1]);
+            if (seq.Count > 2)
+            {
+                controls = Controls.GetInstance(seq[2]);
+            }
+        }
+
+        public static CertRequest GetInstance(object obj)
+        {
+            if (obj is CertRequest)
+                return (CertRequest)obj;
+
+            if (obj != null)
+                return new CertRequest(Asn1Sequence.GetInstance(obj));
+
+            return null;
+        }
+
+        public CertRequest(
+            int certReqId,
+            CertTemplate certTemplate,
+            Controls controls)
+            : this(new DerInteger(certReqId), certTemplate, controls)
+        {
+        }
+
+        public CertRequest(
+            DerInteger certReqId,
+            CertTemplate certTemplate,
+            Controls controls)
+        {
+            this.certReqId = certReqId;
+            this.certTemplate = certTemplate;
+            this.controls = controls;
+        }
+
+        public virtual DerInteger CertReqID
+        {
+            get { return certReqId; }
+        }
+
+        public virtual CertTemplate CertTemplate
+        {
+            get { return certTemplate; }
+        }
+
+        public virtual Controls Controls
+        {
+            get { return controls; }
+        }
+
+        /**
+         * <pre>
+         * CertRequest ::= SEQUENCE {
+         *                      certReqId     INTEGER,          -- ID for matching request and reply
+         *                      certTemplate  CertTemplate,  -- Selected fields of cert to be issued
+         *                      controls      Controls OPTIONAL }   -- Attributes affecting issuance
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(certReqId, certTemplate);
+            v.AddOptional(controls);
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/CertTemplate.cs b/Crypto/src/asn1/crmf/CertTemplate.cs
new file mode 100644
index 000000000..3de9f1d5a
--- /dev/null
+++ b/Crypto/src/asn1/crmf/CertTemplate.cs
@@ -0,0 +1,149 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertTemplate
+        : Asn1Encodable
+    {
+        private readonly Asn1Sequence seq;
+
+        private readonly DerInteger version;
+        private readonly DerInteger serialNumber;
+        private readonly AlgorithmIdentifier signingAlg;
+        private readonly X509Name issuer;
+        private readonly OptionalValidity validity;
+        private readonly X509Name subject;
+        private readonly SubjectPublicKeyInfo publicKey;
+        private readonly DerBitString issuerUID;
+        private readonly DerBitString subjectUID;
+        private readonly X509Extensions extensions;
+
+        private CertTemplate(Asn1Sequence seq)
+        {
+            this.seq = seq;
+
+            foreach (Asn1TaggedObject tObj in seq)
+            {
+                switch (tObj.TagNo)
+                {
+                case 0:
+                    version = DerInteger.GetInstance(tObj, false);
+                    break;
+                case 1:
+                    serialNumber = DerInteger.GetInstance(tObj, false);
+                    break;
+                case 2:
+                    signingAlg = AlgorithmIdentifier.GetInstance(tObj, false);
+                    break;
+                case 3:
+                    issuer = X509Name.GetInstance(tObj, true); // CHOICE
+                    break;
+                case 4:
+                    validity = OptionalValidity.GetInstance(Asn1Sequence.GetInstance(tObj, false));
+                    break;
+                case 5:
+                    subject = X509Name.GetInstance(tObj, true); // CHOICE
+                    break;
+                case 6:
+                    publicKey = SubjectPublicKeyInfo.GetInstance(tObj, false);
+                    break;
+                case 7:
+                    issuerUID = DerBitString.GetInstance(tObj, false);
+                    break;
+                case 8:
+                    subjectUID = DerBitString.GetInstance(tObj, false);
+                    break;
+                case 9:
+                    extensions = X509Extensions.GetInstance(tObj, false);
+                    break;
+                default:
+                    throw new ArgumentException("unknown tag: " + tObj.TagNo, "seq");
+                }
+            }
+        }
+
+        public static CertTemplate GetInstance(object obj)
+        {
+            if (obj is CertTemplate)
+                return (CertTemplate)obj;
+
+            if (obj != null)
+                return new CertTemplate(Asn1Sequence.GetInstance(obj));
+
+            return null;
+        }
+
+        public virtual int Version
+        {
+            get { return version.Value.IntValue; }
+        }
+
+        public virtual DerInteger SerialNumber
+        {
+            get { return serialNumber; }
+        }
+
+        public virtual AlgorithmIdentifier SigningAlg
+        {
+            get { return signingAlg; }
+        }
+
+        public virtual X509Name Issuer
+        {
+            get { return issuer; }
+        }
+
+        public virtual OptionalValidity Validity
+        {
+            get { return validity; }
+        }
+
+        public virtual X509Name Subject
+        {
+            get { return subject; }
+        }
+
+        public virtual SubjectPublicKeyInfo PublicKey
+        {
+            get { return publicKey; }
+        }
+
+        public virtual DerBitString IssuerUID
+        {
+            get { return issuerUID; }
+        }
+
+        public virtual DerBitString SubjectUID
+        {
+            get { return subjectUID; }
+        }
+
+        public virtual X509Extensions Extensions
+        {
+            get { return extensions; }
+        }
+
+        /**
+         * <pre>
+         *  CertTemplate ::= SEQUENCE {
+         *      version      [0] Version               OPTIONAL,
+         *      serialNumber [1] INTEGER               OPTIONAL,
+         *      signingAlg   [2] AlgorithmIdentifier   OPTIONAL,
+         *      issuer       [3] Name                  OPTIONAL,
+         *      validity     [4] OptionalValidity      OPTIONAL,
+         *      subject      [5] Name                  OPTIONAL,
+         *      publicKey    [6] SubjectPublicKeyInfo  OPTIONAL,
+         *      issuerUID    [7] UniqueIdentifier      OPTIONAL,
+         *      subjectUID   [8] UniqueIdentifier      OPTIONAL,
+         *      extensions   [9] Extensions            OPTIONAL }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return seq;
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/CertTemplateBuilder.cs b/Crypto/src/asn1/crmf/CertTemplateBuilder.cs
new file mode 100644
index 000000000..51c73c4e1
--- /dev/null
+++ b/Crypto/src/asn1/crmf/CertTemplateBuilder.cs
@@ -0,0 +1,125 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertTemplateBuilder
+    {
+        private DerInteger version;
+        private DerInteger serialNumber;
+        private AlgorithmIdentifier signingAlg;
+        private X509Name issuer;
+        private OptionalValidity validity;
+        private X509Name subject;
+        private SubjectPublicKeyInfo publicKey;
+        private DerBitString issuerUID;
+        private DerBitString subjectUID;
+        private X509Extensions extensions;
+
+        /** Sets the X.509 version. Note: for X509v3, use 2 here. */
+        public virtual CertTemplateBuilder SetVersion(int ver)
+        {
+            version = new DerInteger(ver);
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetSerialNumber(DerInteger ser)
+        {
+            serialNumber = ser;
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetSigningAlg(AlgorithmIdentifier aid)
+        {
+            signingAlg = aid;
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetIssuer(X509Name name)
+        {
+            issuer = name;
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetValidity(OptionalValidity v)
+        {
+            validity = v;
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetSubject(X509Name name)
+        {
+            subject = name;
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetPublicKey(SubjectPublicKeyInfo spki)
+        {
+            publicKey = spki;
+            return this;
+        }
+
+        /** Sets the issuer unique ID (deprecated in X.509v3) */
+        public virtual CertTemplateBuilder SetIssuerUID(DerBitString uid)
+        {
+            issuerUID = uid;
+            return this;
+        }
+
+        /** Sets the subject unique ID (deprecated in X.509v3) */
+        public virtual CertTemplateBuilder SetSubjectUID(DerBitString uid)
+        {
+            subjectUID = uid;
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetExtensions(X509Extensions extens)
+        {
+            extensions = extens;
+            return this;
+        }
+
+        /**
+         * <pre>
+         *  CertTemplate ::= SEQUENCE {
+         *      version      [0] Version               OPTIONAL,
+         *      serialNumber [1] INTEGER               OPTIONAL,
+         *      signingAlg   [2] AlgorithmIdentifier   OPTIONAL,
+         *      issuer       [3] Name                  OPTIONAL,
+         *      validity     [4] OptionalValidity      OPTIONAL,
+         *      subject      [5] Name                  OPTIONAL,
+         *      publicKey    [6] SubjectPublicKeyInfo  OPTIONAL,
+         *      issuerUID    [7] UniqueIdentifier      OPTIONAL,
+         *      subjectUID   [8] UniqueIdentifier      OPTIONAL,
+         *      extensions   [9] Extensions            OPTIONAL }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public virtual CertTemplate Build()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            AddOptional(v, 0, false, version);
+            AddOptional(v, 1, false, serialNumber);
+            AddOptional(v, 2, false, signingAlg);
+            AddOptional(v, 3, true, issuer); // CHOICE
+            AddOptional(v, 4, false, validity);
+            AddOptional(v, 5, true, subject); // CHOICE
+            AddOptional(v, 6, false, publicKey);
+            AddOptional(v, 7, false, issuerUID);
+            AddOptional(v, 8, false, subjectUID);
+            AddOptional(v, 9, false, extensions);
+
+            return CertTemplate.GetInstance(new DerSequence(v));
+        }
+
+        private void AddOptional(Asn1EncodableVector v, int tagNo, bool isExplicit, Asn1Encodable obj)
+        {
+            if (obj != null)
+            {
+                v.Add(new DerTaggedObject(isExplicit, tagNo, obj));
+            }
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/Controls.cs b/Crypto/src/asn1/crmf/Controls.cs
new file mode 100644
index 000000000..cc52ea4bb
--- /dev/null
+++ b/Crypto/src/asn1/crmf/Controls.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class Controls
+        : Asn1Encodable
+    {
+        private readonly Asn1Sequence content;
+
+        private Controls(Asn1Sequence seq)
+        {
+            content = seq;
+        }
+
+        public static Controls GetInstance(object obj)
+        {
+            if (obj is Controls)
+                return (Controls)obj;
+
+            if (obj is Asn1Sequence)
+                return new Controls((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+		public Controls(params AttributeTypeAndValue[] atvs)
+        {
+            content = new DerSequence(atvs);
+        }
+
+        public virtual AttributeTypeAndValue[] ToAttributeTypeAndValueArray()
+        {
+            AttributeTypeAndValue[] result = new AttributeTypeAndValue[content.Count];
+            for (int i = 0; i != result.Length; ++i)
+            {
+                result[i] = AttributeTypeAndValue.GetInstance(content[i]);
+            }
+            return result;
+        }
+
+        /**
+         * <pre>
+         * Controls  ::= SEQUENCE SIZE(1..MAX) OF AttributeTypeAndValue
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return content;
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/CrmfObjectIdentifiers.cs b/Crypto/src/asn1/crmf/CrmfObjectIdentifiers.cs
new file mode 100644
index 000000000..eaa1f7ba4
--- /dev/null
+++ b/Crypto/src/asn1/crmf/CrmfObjectIdentifiers.cs
@@ -0,0 +1,23 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public abstract class CrmfObjectIdentifiers
+    {
+        public static readonly DerObjectIdentifier id_pkix = new DerObjectIdentifier("1.3.6.1.5.5.7");
+
+        // arc for Internet X.509 PKI protocols and their components
+
+        public static readonly DerObjectIdentifier id_pkip  = id_pkix.Branch("5");
+
+        public static readonly DerObjectIdentifier id_regCtrl = id_pkip.Branch("1");
+        public static readonly DerObjectIdentifier id_regCtrl_regToken = id_regCtrl.Branch("1");
+        public static readonly DerObjectIdentifier id_regCtrl_authenticator = id_regCtrl.Branch("2");
+        public static readonly DerObjectIdentifier id_regCtrl_pkiPublicationInfo = id_regCtrl.Branch("3");
+        public static readonly DerObjectIdentifier id_regCtrl_pkiArchiveOptions = id_regCtrl.Branch("4");
+
+        public static readonly DerObjectIdentifier id_ct_encKeyWithID = new DerObjectIdentifier(PkcsObjectIdentifiers.IdCT + ".21");
+    }
+}
diff --git a/Crypto/src/asn1/crmf/EncKeyWithID.cs b/Crypto/src/asn1/crmf/EncKeyWithID.cs
new file mode 100644
index 000000000..6de56fa0b
--- /dev/null
+++ b/Crypto/src/asn1/crmf/EncKeyWithID.cs
@@ -0,0 +1,103 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class EncKeyWithID
+        : Asn1Encodable
+    {
+        private readonly PrivateKeyInfo privKeyInfo;
+        private readonly Asn1Encodable identifier;
+
+        public static EncKeyWithID GetInstance(object obj)
+        {
+            if (obj is EncKeyWithID)
+                return (EncKeyWithID)obj;
+
+            if (obj != null)
+                return new EncKeyWithID(Asn1Sequence.GetInstance(obj));
+
+            return null;
+        }
+
+        private EncKeyWithID(Asn1Sequence seq)
+        {
+            this.privKeyInfo = PrivateKeyInfo.GetInstance(seq[0]);
+
+            if (seq.Count > 1)
+            {
+                if (!(seq[1] is DerUtf8String))
+                {
+                    this.identifier = GeneralName.GetInstance(seq[1]);
+                }
+                else
+                {
+                    this.identifier = (Asn1Encodable)seq[1];
+                }
+            }
+            else
+            {
+                this.identifier = null;
+            }
+        }
+
+        public EncKeyWithID(PrivateKeyInfo privKeyInfo)
+        {
+            this.privKeyInfo = privKeyInfo;
+            this.identifier = null;
+        }
+
+        public EncKeyWithID(PrivateKeyInfo privKeyInfo, DerUtf8String str)
+        {
+            this.privKeyInfo = privKeyInfo;
+            this.identifier = str;
+        }
+
+        public EncKeyWithID(PrivateKeyInfo privKeyInfo, GeneralName generalName)
+        {
+            this.privKeyInfo = privKeyInfo;
+            this.identifier = generalName;
+        }
+
+        public virtual PrivateKeyInfo PrivateKey
+        {
+            get { return privKeyInfo; }
+        }
+
+        public virtual bool HasIdentifier
+        {
+            get { return identifier != null; }
+        }
+
+        public virtual bool IsIdentifierUtf8String
+        {
+            get { return identifier is DerUtf8String; }
+        }
+
+        public virtual Asn1Encodable Identifier
+        {
+            get { return identifier; }
+        }
+
+        /**
+         * <pre>
+         * EncKeyWithID ::= SEQUENCE {
+         *      privateKey           PrivateKeyInfo,
+         *      identifier CHOICE {
+         *         string               UTF8String,
+         *         generalName          GeneralName
+         *     } OPTIONAL
+         * }
+         * </pre>
+         * @return
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(privKeyInfo);
+            v.AddOptional(identifier);
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/EncryptedKey.cs b/Crypto/src/asn1/crmf/EncryptedKey.cs
new file mode 100644
index 000000000..850fbd219
--- /dev/null
+++ b/Crypto/src/asn1/crmf/EncryptedKey.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Cms;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class EncryptedKey
+        : Asn1Encodable, IAsn1Choice
+    {
+        private readonly EnvelopedData envelopedData;
+        private readonly EncryptedValue encryptedValue;
+
+        public static EncryptedKey GetInstance(object o)
+        {
+            if (o is EncryptedKey)
+            {
+                return (EncryptedKey)o;
+            }
+            else if (o is Asn1TaggedObject)
+            {
+                return new EncryptedKey(EnvelopedData.GetInstance((Asn1TaggedObject)o, false));
+            }
+            else if (o is EncryptedValue)
+            {
+                return new EncryptedKey((EncryptedValue)o);
+            }
+            else
+            {
+                return new EncryptedKey(EncryptedValue.GetInstance(o));
+            }
+        }
+
+        public EncryptedKey(EnvelopedData envelopedData)
+        {
+            this.envelopedData = envelopedData;
+        }
+
+        public EncryptedKey(EncryptedValue encryptedValue)
+        {
+            this.encryptedValue = encryptedValue;
+        }
+
+        public virtual bool IsEncryptedValue
+        {
+            get { return encryptedValue != null; }
+        }
+
+        public virtual Asn1Encodable Value
+        {
+            get
+            {
+                if (encryptedValue != null)
+                    return encryptedValue;
+
+                return envelopedData;
+            }
+        }
+
+        /**
+         * <pre>
+         *    EncryptedKey ::= CHOICE {
+         *        encryptedValue        EncryptedValue, -- deprecated
+         *        envelopedData     [0] EnvelopedData }
+         *        -- The encrypted private key MUST be placed in the envelopedData
+         *        -- encryptedContentInfo encryptedContent OCTET STRING.
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            if (encryptedValue != null)
+            {
+                return encryptedValue.ToAsn1Object();
+            }
+
+            return new DerTaggedObject(false, 0, envelopedData);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/EncryptedValue.cs b/Crypto/src/asn1/crmf/EncryptedValue.cs
new file mode 100644
index 000000000..83122e220
--- /dev/null
+++ b/Crypto/src/asn1/crmf/EncryptedValue.cs
@@ -0,0 +1,154 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class EncryptedValue
+        : Asn1Encodable
+    {
+        private readonly AlgorithmIdentifier intendedAlg;
+        private readonly AlgorithmIdentifier symmAlg;
+        private readonly DerBitString encSymmKey;
+        private readonly AlgorithmIdentifier keyAlg;
+        private readonly Asn1OctetString valueHint;
+        private readonly DerBitString encValue;
+
+        private EncryptedValue(Asn1Sequence seq)
+        {
+            int index = 0;
+            while (seq[index] is Asn1TaggedObject)
+            {
+                Asn1TaggedObject tObj = (Asn1TaggedObject)seq[index];
+
+                switch (tObj.TagNo)
+                {
+                    case 0:
+                        intendedAlg = AlgorithmIdentifier.GetInstance(tObj, false);
+                        break;
+                    case 1:
+                        symmAlg = AlgorithmIdentifier.GetInstance(tObj, false);
+                        break;
+                    case 2:
+                        encSymmKey = DerBitString.GetInstance(tObj, false);
+                        break;
+                    case 3:
+                        keyAlg = AlgorithmIdentifier.GetInstance(tObj, false);
+                        break;
+                    case 4:
+                        valueHint = Asn1OctetString.GetInstance(tObj, false);
+                        break;
+                }
+                ++index;
+            }
+
+            encValue = DerBitString.GetInstance(seq[index]);
+        }
+
+        public static EncryptedValue GetInstance(object obj)
+        {
+            if (obj is EncryptedValue)
+                return (EncryptedValue)obj;
+
+            if (obj != null)
+                return new EncryptedValue(Asn1Sequence.GetInstance(obj));
+
+            return null;
+        }
+
+        public EncryptedValue(
+            AlgorithmIdentifier intendedAlg,
+            AlgorithmIdentifier symmAlg,
+            DerBitString encSymmKey,
+            AlgorithmIdentifier keyAlg,
+            Asn1OctetString valueHint,
+            DerBitString encValue)
+        {
+            if (encValue == null)
+            {
+                throw new ArgumentNullException("encValue");
+            }
+
+            this.intendedAlg = intendedAlg;
+            this.symmAlg = symmAlg;
+            this.encSymmKey = encSymmKey;
+            this.keyAlg = keyAlg;
+            this.valueHint = valueHint;
+            this.encValue = encValue;
+        }
+
+        public virtual AlgorithmIdentifier IntendedAlg
+        {
+            get { return intendedAlg; }
+        }
+
+        public virtual AlgorithmIdentifier SymmAlg
+        {
+            get { return symmAlg; }
+        }
+
+        public virtual DerBitString EncSymmKey
+        {
+            get { return encSymmKey; }
+        }
+
+        public virtual AlgorithmIdentifier KeyAlg
+        {
+            get { return keyAlg; }
+        }
+
+        public virtual Asn1OctetString ValueHint
+        {
+            get { return valueHint; }
+        }
+
+        public virtual DerBitString EncValue
+        {
+            get { return encValue; }
+        }
+
+        /**
+         * <pre>
+         * EncryptedValue ::= SEQUENCE {
+         *                     intendedAlg   [0] AlgorithmIdentifier  OPTIONAL,
+         *                     -- the intended algorithm for which the value will be used
+         *                     symmAlg       [1] AlgorithmIdentifier  OPTIONAL,
+         *                     -- the symmetric algorithm used to encrypt the value
+         *                     encSymmKey    [2] BIT STRING           OPTIONAL,
+         *                     -- the (encrypted) symmetric key used to encrypt the value
+         *                     keyAlg        [3] AlgorithmIdentifier  OPTIONAL,
+         *                     -- algorithm used to encrypt the symmetric key
+         *                     valueHint     [4] OCTET STRING         OPTIONAL,
+         *                     -- a brief description or identifier of the encValue content
+         *                     -- (may be meaningful only to the sending entity, and used only
+         *                     -- if EncryptedValue might be re-examined by the sending entity
+         *                     -- in the future)
+         *                     encValue       BIT STRING }
+         *                     -- the encrypted value itself
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            AddOptional(v, 0, intendedAlg);
+            AddOptional(v, 1, symmAlg);
+            AddOptional(v, 2, encSymmKey);
+            AddOptional(v, 3, keyAlg);
+            AddOptional(v, 4, valueHint);
+
+            v.Add(encValue);
+
+            return new DerSequence(v);
+        }
+
+        private void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+        {
+            if (obj != null)
+            {
+                v.Add(new DerTaggedObject(false, tagNo, obj));
+            }
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/OptionalValidity.cs b/Crypto/src/asn1/crmf/OptionalValidity.cs
new file mode 100644
index 000000000..c0037999a
--- /dev/null
+++ b/Crypto/src/asn1/crmf/OptionalValidity.cs
@@ -0,0 +1,64 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class OptionalValidity
+        : Asn1Encodable
+    {
+        private readonly Time notBefore;
+        private readonly Time notAfter;
+
+        private OptionalValidity(Asn1Sequence seq)
+        {
+            foreach (Asn1TaggedObject tObj in seq)
+            {
+                if (tObj.TagNo == 0)
+                {
+                    notBefore = Time.GetInstance(tObj, true);
+                }
+                else
+                {
+                    notAfter = Time.GetInstance(tObj, true);
+                }
+            }
+        }
+
+        public static OptionalValidity GetInstance(object obj)
+        {
+            if (obj is OptionalValidity)
+                return (OptionalValidity)obj;
+
+            if (obj is Asn1Sequence)
+                return new OptionalValidity((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        /**
+         * <pre>
+         * OptionalValidity ::= SEQUENCE {
+         *                        notBefore  [0] Time OPTIONAL,
+         *                        notAfter   [1] Time OPTIONAL } --at least one MUST be present
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            if (notBefore != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, notBefore));
+            }
+
+            if (notAfter != null)
+            {
+                v.Add(new DerTaggedObject(true, 1, notAfter));
+            }
+
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/PKIArchiveOptions.cs b/Crypto/src/asn1/crmf/PKIArchiveOptions.cs
new file mode 100644
index 000000000..910f73b22
--- /dev/null
+++ b/Crypto/src/asn1/crmf/PKIArchiveOptions.cs
@@ -0,0 +1,105 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class PkiArchiveOptions
+        : Asn1Encodable, IAsn1Choice
+    {
+        public const int encryptedPrivKey = 0;
+        public const int keyGenParameters = 1;
+        public const int archiveRemGenPrivKey = 2;
+
+        private readonly Asn1Encodable value;
+
+        public static PkiArchiveOptions GetInstance(object obj)
+        {
+            if (obj is PkiArchiveOptions)
+                return (PkiArchiveOptions)obj;
+
+            if (obj is Asn1TaggedObject)
+                return new PkiArchiveOptions((Asn1TaggedObject)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        private PkiArchiveOptions(Asn1TaggedObject tagged)
+        {
+            switch (tagged.TagNo)
+            {
+                case encryptedPrivKey:
+                    value = EncryptedKey.GetInstance(tagged.GetObject());
+                    break;
+                case keyGenParameters:
+                    value = Asn1OctetString.GetInstance(tagged, false);
+                    break;
+                case archiveRemGenPrivKey:
+                    value = DerBoolean.GetInstance(tagged, false);
+                    break;
+                default:
+                    throw new ArgumentException("unknown tag number: " + tagged.TagNo, "tagged");
+            }
+        }
+
+        public PkiArchiveOptions(EncryptedKey encKey)
+        {
+            this.value = encKey;
+        }
+
+        public PkiArchiveOptions(Asn1OctetString keyGenParameters)
+        {
+            this.value = keyGenParameters;
+        }
+
+        public PkiArchiveOptions(bool archiveRemGenPrivKey)
+        {
+            this.value = DerBoolean.GetInstance(archiveRemGenPrivKey);
+        }
+
+        public virtual int Type
+        {
+            get
+            {
+                if (value is EncryptedKey)
+                    return encryptedPrivKey;
+
+                if (value is Asn1OctetString)
+                    return keyGenParameters;
+
+                return archiveRemGenPrivKey;
+            }
+        }
+
+        public virtual Asn1Encodable Value
+        {
+            get { return value; }
+        }
+
+        /**
+         * <pre>
+         *  PkiArchiveOptions ::= CHOICE {
+         *      encryptedPrivKey     [0] EncryptedKey,
+         *      -- the actual value of the private key
+         *      keyGenParameters     [1] KeyGenParameters,
+         *      -- parameters which allow the private key to be re-generated
+         *      archiveRemGenPrivKey [2] BOOLEAN }
+         *      -- set to TRUE if sender wishes receiver to archive the private
+         *      -- key of a key pair that the receiver generates in response to
+         *      -- this request; set to FALSE if no archival is desired.
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            if (value is EncryptedKey)
+            {
+                return new DerTaggedObject(true, encryptedPrivKey, value);  // choice
+            }
+
+            if (value is Asn1OctetString)
+            {
+                return new DerTaggedObject(false, keyGenParameters, value);
+            }
+
+            return new DerTaggedObject(false, archiveRemGenPrivKey, value);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/PKIPublicationInfo.cs b/Crypto/src/asn1/crmf/PKIPublicationInfo.cs
new file mode 100644
index 000000000..c8bc1403e
--- /dev/null
+++ b/Crypto/src/asn1/crmf/PKIPublicationInfo.cs
@@ -0,0 +1,64 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class PkiPublicationInfo
+        : Asn1Encodable
+    {
+        private readonly DerInteger action;
+        private readonly Asn1Sequence pubInfos;
+
+        private PkiPublicationInfo(Asn1Sequence seq)
+        {
+            action = DerInteger.GetInstance(seq[0]);
+            pubInfos = Asn1Sequence.GetInstance(seq[1]);
+        }
+
+        public static PkiPublicationInfo GetInstance(object obj)
+        {
+            if (obj is PkiPublicationInfo)
+                return (PkiPublicationInfo)obj;
+
+            if (obj is Asn1Sequence)
+                return new PkiPublicationInfo((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public virtual DerInteger Action
+        {
+            get { return action; }
+        }
+
+        public virtual SinglePubInfo[] GetPubInfos()
+        {
+            if (pubInfos == null)
+                return null;
+
+            SinglePubInfo[] results = new SinglePubInfo[pubInfos.Count];
+            for (int i = 0; i != results.Length; ++i)
+            {
+                results[i] = SinglePubInfo.GetInstance(pubInfos[i]);
+            }
+            return results;
+        }
+
+        /**
+         * <pre>
+         * PkiPublicationInfo ::= SEQUENCE {
+         *                  action     INTEGER {
+         *                                 dontPublish (0),
+         *                                 pleasePublish (1) },
+         *                  pubInfos  SEQUENCE SIZE (1..MAX) OF SinglePubInfo OPTIONAL }
+         * -- pubInfos MUST NOT be present if action is "dontPublish"
+         * -- (if action is "pleasePublish" and pubInfos is omitted,
+         * -- "dontCare" is assumed)
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(action, pubInfos);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/PKMacValue.cs b/Crypto/src/asn1/crmf/PKMacValue.cs
new file mode 100644
index 000000000..20a08fd1d
--- /dev/null
+++ b/Crypto/src/asn1/crmf/PKMacValue.cs
@@ -0,0 +1,89 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    /**
+     * Password-based MAC value for use with POPOSigningKeyInput.
+     */
+    public class PKMacValue
+        : Asn1Encodable
+    {
+        private readonly AlgorithmIdentifier  algID;
+        private readonly DerBitString         macValue;
+
+        private PKMacValue(Asn1Sequence seq)
+        {
+            this.algID = AlgorithmIdentifier.GetInstance(seq[0]);
+            this.macValue = DerBitString.GetInstance(seq[1]);
+        }
+
+        public static PKMacValue GetInstance(object obj)
+        {
+            if (obj is PKMacValue)
+                return (PKMacValue)obj;
+
+            if (obj is Asn1Sequence)
+                return new PKMacValue((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public static PKMacValue GetInstance(Asn1TaggedObject obj, bool isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+        /**
+         * Creates a new PKMACValue.
+         * @param params parameters for password-based MAC
+         * @param value MAC of the DER-encoded SubjectPublicKeyInfo
+         */
+        public PKMacValue(
+            PbmParameter pbmParams,
+            DerBitString macValue)
+            : this(new AlgorithmIdentifier(CmpObjectIdentifiers.passwordBasedMac, pbmParams), macValue)
+        {
+        }
+
+        /**
+         * Creates a new PKMACValue.
+         * @param aid CMPObjectIdentifiers.passwordBasedMAC, with PBMParameter
+         * @param value MAC of the DER-encoded SubjectPublicKeyInfo
+         */
+        public PKMacValue(
+            AlgorithmIdentifier algID,
+            DerBitString        macValue)
+        {
+            this.algID = algID;
+            this.macValue = macValue;
+        }
+
+        public virtual AlgorithmIdentifier AlgID
+        {
+            get { return algID; }
+        }
+
+        public virtual DerBitString MacValue
+        {
+            get { return macValue; }
+        }
+
+        /**
+         * <pre>
+         * PKMACValue ::= SEQUENCE {
+         *      algId  AlgorithmIdentifier,
+         *      -- algorithm value shall be PasswordBasedMac 1.2.840.113533.7.66.13
+         *      -- parameter value is PBMParameter
+         *      value  BIT STRING }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(algID, macValue);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/PopoPrivKey.cs b/Crypto/src/asn1/crmf/PopoPrivKey.cs
new file mode 100644
index 000000000..0cedc5127
--- /dev/null
+++ b/Crypto/src/asn1/crmf/PopoPrivKey.cs
@@ -0,0 +1,84 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Cms;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class PopoPrivKey
+        : Asn1Encodable, IAsn1Choice
+    {
+        public const int thisMessage = 0;
+        public const int subsequentMessage = 1;
+        public const int dhMAC = 2;
+        public const int agreeMAC = 3;
+        public const int encryptedKey = 4;
+
+        private readonly int tagNo;
+        private readonly Asn1Encodable obj;
+
+        private PopoPrivKey(Asn1TaggedObject obj)
+        {
+            this.tagNo = obj.TagNo;
+
+            switch (tagNo)
+            {
+            case thisMessage:
+                this.obj = DerBitString.GetInstance(obj, false);
+                break;
+            case subsequentMessage:
+                this.obj = SubsequentMessage.ValueOf(DerInteger.GetInstance(obj, false).Value.IntValue);
+                break;
+            case dhMAC:
+                this.obj = DerBitString.GetInstance(obj, false);
+                break;
+            case agreeMAC:
+                this.obj = PKMacValue.GetInstance(obj, false);
+                break;
+            case encryptedKey:
+                this.obj = EnvelopedData.GetInstance(obj, false);
+                break;
+            default:
+                throw new ArgumentException("unknown tag in PopoPrivKey", "obj");
+            }
+        }
+
+        public static PopoPrivKey GetInstance(Asn1TaggedObject tagged, bool isExplicit)
+        {
+            return new PopoPrivKey(Asn1TaggedObject.GetInstance(tagged.GetObject()));
+        }
+
+        public PopoPrivKey(SubsequentMessage msg)
+        {
+            this.tagNo = subsequentMessage;
+            this.obj = msg;
+        }
+
+        public virtual int Type
+        {
+            get { return tagNo; }
+        }
+
+        public virtual Asn1Encodable Value
+        {
+            get { return obj; }
+        }
+
+        /**
+         * <pre>
+         * PopoPrivKey ::= CHOICE {
+         *        thisMessage       [0] BIT STRING,         -- Deprecated
+         *         -- possession is proven in this message (which contains the private
+         *         -- key itself (encrypted for the CA))
+         *        subsequentMessage [1] SubsequentMessage,
+         *         -- possession will be proven in a subsequent message
+         *        dhMAC             [2] BIT STRING,         -- Deprecated
+         *        agreeMAC          [3] PKMACValue,
+         *        encryptedKey      [4] EnvelopedData }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerTaggedObject(false, tagNo, obj);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/PopoSigningKey.cs b/Crypto/src/asn1/crmf/PopoSigningKey.cs
new file mode 100644
index 000000000..614278eda
--- /dev/null
+++ b/Crypto/src/asn1/crmf/PopoSigningKey.cs
@@ -0,0 +1,115 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class PopoSigningKey
+        : Asn1Encodable
+    {
+        private readonly PopoSigningKeyInput poposkInput;
+        private readonly AlgorithmIdentifier algorithmIdentifier;
+        private readonly DerBitString signature;
+
+        private PopoSigningKey(Asn1Sequence seq)
+        {
+            int index = 0;
+
+            if (seq[index] is Asn1TaggedObject)
+            {
+                Asn1TaggedObject tagObj
+                    = (Asn1TaggedObject) seq[index++];
+                if (tagObj.TagNo != 0)
+                {
+                    throw new ArgumentException( "Unknown PopoSigningKeyInput tag: " + tagObj.TagNo, "seq");
+                }
+                poposkInput = PopoSigningKeyInput.GetInstance(tagObj.GetObject());
+            }
+            algorithmIdentifier = AlgorithmIdentifier.GetInstance(seq[index++]);
+            signature = DerBitString.GetInstance(seq[index]);
+        }
+
+        public static PopoSigningKey GetInstance(object obj)
+        {
+            if (obj is PopoSigningKey)
+                return (PopoSigningKey)obj;
+
+            if (obj is Asn1Sequence)
+                return new PopoSigningKey((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public static PopoSigningKey GetInstance(Asn1TaggedObject obj, bool isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+        /**
+         * Creates a new Proof of Possession object for a signing key.
+         * @param poposkIn the PopoSigningKeyInput structure, or null if the
+         *     CertTemplate includes both subject and publicKey values.
+         * @param aid the AlgorithmIdentifier used to sign the proof of possession.
+         * @param signature a signature over the DER-encoded value of poposkIn,
+         *     or the DER-encoded value of certReq if poposkIn is null.
+         */
+        public PopoSigningKey(
+            PopoSigningKeyInput poposkIn,
+            AlgorithmIdentifier aid,
+            DerBitString signature)
+        {
+            this.poposkInput = poposkIn;
+            this.algorithmIdentifier = aid;
+            this.signature = signature;
+        }
+
+        public virtual PopoSigningKeyInput PoposkInput
+        {
+            get { return poposkInput; }
+        }
+
+        public virtual AlgorithmIdentifier AlgorithmIdentifier
+        {
+            get { return algorithmIdentifier; }
+        }
+
+        public virtual DerBitString Signature
+        {
+            get { return signature; }
+        }
+
+        /**
+         * <pre>
+         * PopoSigningKey ::= SEQUENCE {
+         *                      poposkInput           [0] PopoSigningKeyInput OPTIONAL,
+         *                      algorithmIdentifier   AlgorithmIdentifier,
+         *                      signature             BIT STRING }
+         *  -- The signature (using "algorithmIdentifier") is on the
+         *  -- DER-encoded value of poposkInput.  NOTE: If the CertReqMsg
+         *  -- certReq CertTemplate contains the subject and publicKey values,
+         *  -- then poposkInput MUST be omitted and the signature MUST be
+         *  -- computed on the DER-encoded value of CertReqMsg certReq.  If
+         *  -- the CertReqMsg certReq CertTemplate does not contain the public
+         *  -- key and subject values, then poposkInput MUST be present and
+         *  -- MUST be signed.  This strategy ensures that the public key is
+         *  -- not present in both the poposkInput and CertReqMsg certReq
+         *  -- CertTemplate fields.
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            if (poposkInput != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, poposkInput));
+            }
+
+            v.Add(algorithmIdentifier);
+            v.Add(signature);
+
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/PopoSigningKeyInput.cs b/Crypto/src/asn1/crmf/PopoSigningKeyInput.cs
new file mode 100644
index 000000000..63695262f
--- /dev/null
+++ b/Crypto/src/asn1/crmf/PopoSigningKeyInput.cs
@@ -0,0 +1,115 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class PopoSigningKeyInput
+        : Asn1Encodable
+    {
+        private readonly GeneralName            sender;
+        private readonly PKMacValue             publicKeyMac;
+        private readonly SubjectPublicKeyInfo   publicKey;
+
+        private PopoSigningKeyInput(Asn1Sequence seq)
+        {
+            Asn1Encodable authInfo = (Asn1Encodable)seq[0];
+
+            if (authInfo is Asn1TaggedObject)
+            {
+                Asn1TaggedObject tagObj = (Asn1TaggedObject)authInfo;
+                if (tagObj.TagNo != 0)
+                {
+                    throw new ArgumentException("Unknown authInfo tag: " + tagObj.TagNo, "seq");
+                }
+                sender = GeneralName.GetInstance(tagObj.GetObject());
+            }
+            else
+            {
+                publicKeyMac = PKMacValue.GetInstance(authInfo);
+            }
+
+            publicKey = SubjectPublicKeyInfo.GetInstance(seq[1]);
+        }
+
+        public static PopoSigningKeyInput GetInstance(object obj)
+        {
+            if (obj is PopoSigningKeyInput)
+                return (PopoSigningKeyInput)obj;
+
+            if (obj is Asn1Sequence)
+                return new PopoSigningKeyInput((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        /** Creates a new PopoSigningKeyInput with sender name as authInfo. */
+        public PopoSigningKeyInput(
+            GeneralName sender,
+            SubjectPublicKeyInfo spki)
+        {
+            this.sender = sender;
+            this.publicKey = spki;
+        }
+
+        /** Creates a new PopoSigningKeyInput using password-based MAC. */
+        public PopoSigningKeyInput(
+            PKMacValue pkmac,
+            SubjectPublicKeyInfo spki)
+        {
+            this.publicKeyMac = pkmac;
+            this.publicKey = spki;
+        }
+
+        /** Returns the sender field, or null if authInfo is publicKeyMac */
+        public virtual GeneralName Sender
+        {
+            get { return sender; }
+        }
+
+        /** Returns the publicKeyMac field, or null if authInfo is sender */
+        public virtual PKMacValue PublicKeyMac
+        {
+            get { return publicKeyMac; }
+        }
+
+        public virtual SubjectPublicKeyInfo PublicKey
+        {
+            get { return publicKey; }
+        }
+
+        /**
+         * <pre>
+         * PopoSigningKeyInput ::= SEQUENCE {
+         *        authInfo             CHOICE {
+         *                                 sender              [0] GeneralName,
+         *                                 -- used only if an authenticated identity has been
+         *                                 -- established for the sender (e.g., a DN from a
+         *                                 -- previously-issued and currently-valid certificate
+         *                                 publicKeyMac        PKMacValue },
+         *                                 -- used if no authenticated GeneralName currently exists for
+         *                                 -- the sender; publicKeyMac contains a password-based MAC
+         *                                 -- on the DER-encoded value of publicKey
+         *        publicKey           SubjectPublicKeyInfo }  -- from CertTemplate
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            if (sender != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, sender));
+            }
+            else
+            {
+                v.Add(publicKeyMac);
+            }
+
+            v.Add(publicKey);
+
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/ProofOfPossession.cs b/Crypto/src/asn1/crmf/ProofOfPossession.cs
new file mode 100644
index 000000000..fc00edb32
--- /dev/null
+++ b/Crypto/src/asn1/crmf/ProofOfPossession.cs
@@ -0,0 +1,98 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class ProofOfPossession
+        : Asn1Encodable, IAsn1Choice
+    {
+        public const int TYPE_RA_VERIFIED = 0;
+        public const int TYPE_SIGNING_KEY = 1;
+        public const int TYPE_KEY_ENCIPHERMENT = 2;
+        public const int TYPE_KEY_AGREEMENT = 3;
+
+        private readonly int tagNo;
+        private readonly Asn1Encodable obj;
+
+        private ProofOfPossession(Asn1TaggedObject tagged)
+        {
+            tagNo = tagged.TagNo;
+            switch (tagNo)
+            {
+            case 0:
+                obj = DerNull.Instance;
+                break;
+            case 1:
+                obj = PopoSigningKey.GetInstance(tagged, false);
+                break;
+            case 2:
+            case 3:
+                obj = PopoPrivKey.GetInstance(tagged, false);
+                break;
+            default:
+                throw new ArgumentException("unknown tag: " + tagNo, "tagged");
+            }
+        }
+
+        public static ProofOfPossession GetInstance(object obj)
+        {
+            if (obj is ProofOfPossession)
+                return (ProofOfPossession)obj;
+
+            if (obj is Asn1TaggedObject)
+                return new ProofOfPossession((Asn1TaggedObject)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        /** Creates a ProofOfPossession with type raVerified. */
+        public ProofOfPossession()
+        {
+            tagNo = TYPE_RA_VERIFIED;
+            obj = DerNull.Instance;
+        }
+
+        /** Creates a ProofOfPossession for a signing key. */
+        public ProofOfPossession(PopoSigningKey Poposk)
+        {
+            tagNo = TYPE_SIGNING_KEY;
+            obj = Poposk;
+        }
+
+        /**
+         * Creates a ProofOfPossession for key encipherment or agreement.
+         * @param type one of TYPE_KEY_ENCIPHERMENT or TYPE_KEY_AGREEMENT
+         */
+        public ProofOfPossession(int type, PopoPrivKey privkey)
+        {
+            tagNo = type;
+            obj = privkey;
+        }
+
+        public virtual int Type
+        {
+            get { return tagNo; }
+        }
+
+        public virtual Asn1Encodable Object
+        {
+            get { return obj; }
+        }
+
+        /**
+         * <pre>
+         * ProofOfPossession ::= CHOICE {
+         *                           raVerified        [0] NULL,
+         *                           -- used if the RA has already verified that the requester is in
+         *                           -- possession of the private key
+         *                           signature         [1] PopoSigningKey,
+         *                           keyEncipherment   [2] PopoPrivKey,
+         *                           keyAgreement      [3] PopoPrivKey }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerTaggedObject(false, tagNo, obj);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/SinglePubInfo.cs b/Crypto/src/asn1/crmf/SinglePubInfo.cs
new file mode 100644
index 000000000..eaf8a3efd
--- /dev/null
+++ b/Crypto/src/asn1/crmf/SinglePubInfo.cs
@@ -0,0 +1,58 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class SinglePubInfo
+        : Asn1Encodable
+    {
+        private readonly DerInteger pubMethod;
+        private readonly GeneralName pubLocation;
+
+        private SinglePubInfo(Asn1Sequence seq)
+        {
+            pubMethod = DerInteger.GetInstance(seq[0]);
+
+            if (seq.Count == 2)
+            {
+                pubLocation = GeneralName.GetInstance(seq[1]);
+            }
+        }
+
+        public static SinglePubInfo GetInstance(object obj)
+        {
+            if (obj is SinglePubInfo)
+                return (SinglePubInfo)obj;
+
+            if (obj is Asn1Sequence)
+                return new SinglePubInfo((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public virtual GeneralName PubLocation
+        {
+            get { return pubLocation; }
+        }
+
+        /**
+         * <pre>
+         * SinglePubInfo ::= SEQUENCE {
+         *        pubMethod    INTEGER {
+         *           dontCare    (0),
+         *           x500        (1),
+         *           web         (2),
+         *           ldap        (3) },
+         *       pubLocation  GeneralName OPTIONAL }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(pubMethod);
+            v.AddOptional(pubLocation);
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/crmf/SubsequentMessage.cs b/Crypto/src/asn1/crmf/SubsequentMessage.cs
new file mode 100644
index 000000000..cc1c16492
--- /dev/null
+++ b/Crypto/src/asn1/crmf/SubsequentMessage.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class SubsequentMessage
+        : DerInteger
+    {
+        public static readonly SubsequentMessage encrCert = new SubsequentMessage(0);
+        public static readonly SubsequentMessage challengeResp = new SubsequentMessage(1);
+    
+        private SubsequentMessage(int value)
+            : base(value)
+        {
+        }
+
+        public static SubsequentMessage ValueOf(int value)
+        {
+            if (value == 0)
+                return encrCert;
+
+            if (value == 1)
+                return challengeResp;
+
+            throw new ArgumentException("unknown value: " + value, "value");
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cryptopro/CryptoProObjectIdentifiers.cs b/Crypto/src/asn1/cryptopro/CryptoProObjectIdentifiers.cs
new file mode 100644
index 000000000..6e0e023b9
--- /dev/null
+++ b/Crypto/src/asn1/cryptopro/CryptoProObjectIdentifiers.cs
@@ -0,0 +1,48 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+    public abstract class CryptoProObjectIdentifiers
+    {
+        // GOST Algorithms OBJECT IDENTIFIERS :
+        // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2)}
+        public const string GostID = "1.2.643.2.2";
+
+		public static readonly DerObjectIdentifier GostR3411 = new DerObjectIdentifier(GostID + ".9");
+
+		public static readonly DerObjectIdentifier GostR28147Cbc = new DerObjectIdentifier(GostID + ".21");
+
+		public static readonly DerObjectIdentifier GostR3410x94 = new DerObjectIdentifier(GostID + ".20");
+        public static readonly DerObjectIdentifier GostR3410x2001 = new DerObjectIdentifier(GostID + ".19");
+        public static readonly DerObjectIdentifier GostR3411x94WithGostR3410x94 = new DerObjectIdentifier(GostID + ".4");
+        public static readonly DerObjectIdentifier GostR3411x94WithGostR3410x2001 = new DerObjectIdentifier(GostID + ".3");
+
+		// { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) hashes(30) }
+        public static readonly DerObjectIdentifier GostR3411x94CryptoProParamSet = new DerObjectIdentifier(GostID + ".30.1");
+
+		// { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) signs(32) }
+        public static readonly DerObjectIdentifier GostR3410x94CryptoProA = new DerObjectIdentifier(GostID + ".32.2");
+        public static readonly DerObjectIdentifier GostR3410x94CryptoProB = new DerObjectIdentifier(GostID + ".32.3");
+        public static readonly DerObjectIdentifier GostR3410x94CryptoProC = new DerObjectIdentifier(GostID + ".32.4");
+        public static readonly DerObjectIdentifier GostR3410x94CryptoProD = new DerObjectIdentifier(GostID + ".32.5");
+
+		// { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) exchanges(33) }
+        public static readonly DerObjectIdentifier GostR3410x94CryptoProXchA = new DerObjectIdentifier(GostID + ".33.1");
+        public static readonly DerObjectIdentifier GostR3410x94CryptoProXchB = new DerObjectIdentifier(GostID + ".33.2");
+        public static readonly DerObjectIdentifier GostR3410x94CryptoProXchC = new DerObjectIdentifier(GostID + ".33.3");
+
+		//{ iso(1) member-body(2)ru(643) rans(2) cryptopro(2) ecc-signs(35) }
+        public static readonly DerObjectIdentifier GostR3410x2001CryptoProA = new DerObjectIdentifier(GostID + ".35.1");
+        public static readonly DerObjectIdentifier GostR3410x2001CryptoProB = new DerObjectIdentifier(GostID + ".35.2");
+        public static readonly DerObjectIdentifier GostR3410x2001CryptoProC = new DerObjectIdentifier(GostID + ".35.3");
+
+		// { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) ecc-exchanges(36) }
+        public static readonly DerObjectIdentifier GostR3410x2001CryptoProXchA  = new DerObjectIdentifier(GostID + ".36.0");
+        public static readonly DerObjectIdentifier GostR3410x2001CryptoProXchB  = new DerObjectIdentifier(GostID + ".36.1");
+
+		public static readonly DerObjectIdentifier GostElSgDH3410Default = new DerObjectIdentifier(GostID + ".36.0");
+        public static readonly DerObjectIdentifier GostElSgDH3410x1 = new DerObjectIdentifier(GostID + ".36.1");
+    }
+}
diff --git a/Crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs b/Crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
new file mode 100644
index 000000000..998e0e06f
--- /dev/null
+++ b/Crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
@@ -0,0 +1,179 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+    /**
+    * table of the available named parameters for GOST 3410-2001.
+    */
+    public sealed class ECGost3410NamedCurves
+    {
+		private ECGost3410NamedCurves()
+		{
+		}
+
+        internal static readonly IDictionary objIds = Platform.CreateHashtable();
+        internal static readonly IDictionary parameters = Platform.CreateHashtable();
+        internal static readonly IDictionary names = Platform.CreateHashtable();
+
+        static ECGost3410NamedCurves()
+        {
+            BigInteger mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319");
+            BigInteger mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323");
+
+            FpCurve curve = new FpCurve(
+                mod_p, // p
+                new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), // a
+                new BigInteger("166")); // b
+
+            ECDomainParameters ecParams = new ECDomainParameters(
+                curve,
+				curve.CreatePoint(
+					BigInteger.One, // x
+					new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612"), // y
+					false),
+                mod_q);
+
+			parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProA] = ecParams;
+
+            mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319");
+            mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323");
+
+            curve = new FpCurve(
+                mod_p, // p
+                new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"),
+                new BigInteger("166"));
+
+            ecParams = new ECDomainParameters(
+                curve,
+				curve.CreatePoint(
+					BigInteger.One, // x
+					new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612"), // y
+					false),
+                mod_q);
+
+            parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchA] = ecParams;
+
+            mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823193"); //p
+            mod_q = new BigInteger("57896044618658097711785492504343953927102133160255826820068844496087732066703"); //q
+
+            curve = new FpCurve(
+                mod_p, // p
+                new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823190"), // a
+                new BigInteger("28091019353058090096996979000309560759124368558014865957655842872397301267595")); // b
+
+            ecParams = new ECDomainParameters(
+                curve,
+                curve.CreatePoint(
+					BigInteger.One, // x
+					new BigInteger("28792665814854611296992347458380284135028636778229113005756334730996303888124"), // y
+					false),
+                mod_q); // q
+
+            parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProB] = ecParams;
+
+            mod_p = new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502619");
+            mod_q = new BigInteger("70390085352083305199547718019018437840920882647164081035322601458352298396601");
+
+            curve = new FpCurve(
+                mod_p, // p
+                new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"),
+                new BigInteger("32858"));
+
+            ecParams = new ECDomainParameters(
+                curve,
+                curve.CreatePoint(
+					BigInteger.Zero, // x
+					new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247"), // y
+					false),
+                mod_q);
+
+            parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchB] = ecParams;
+
+            mod_p = new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502619"); //p
+            mod_q = new BigInteger("70390085352083305199547718019018437840920882647164081035322601458352298396601"); //q
+            curve = new FpCurve(
+                mod_p, // p
+                new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"), // a
+                new BigInteger("32858")); // b
+
+            ecParams = new ECDomainParameters(
+                curve,
+                curve.CreatePoint(
+					BigInteger.Zero, // x
+					new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247"), // y
+					false),
+                mod_q); // q
+
+			parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProC] = ecParams;
+
+            objIds["GostR3410-2001-CryptoPro-A"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProA;
+            objIds["GostR3410-2001-CryptoPro-B"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProB;
+            objIds["GostR3410-2001-CryptoPro-C"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProC;
+            objIds["GostR3410-2001-CryptoPro-XchA"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchA;
+            objIds["GostR3410-2001-CryptoPro-XchB"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchB;
+
+            names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProA] = "GostR3410-2001-CryptoPro-A";
+            names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProB] = "GostR3410-2001-CryptoPro-B";
+            names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProC] = "GostR3410-2001-CryptoPro-C";
+            names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchA] = "GostR3410-2001-CryptoPro-XchA";
+            names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchB] = "GostR3410-2001-CryptoPro-XchB";
+        }
+
+        /**
+        * return the ECDomainParameters object for the given OID, null if it
+        * isn't present.
+        *
+        * @param oid an object identifier representing a named parameters, if present.
+        */
+        public static ECDomainParameters GetByOid(
+            DerObjectIdentifier oid)
+        {
+            return (ECDomainParameters) parameters[oid];
+        }
+
+		/**
+		 * returns an enumeration containing the name strings for curves
+		 * contained in this structure.
+		 */
+		public static IEnumerable Names
+		{
+			get { return new EnumerableProxy(objIds.Keys); }
+		}
+
+        public static ECDomainParameters GetByName(
+            string name)
+        {
+            DerObjectIdentifier oid = (DerObjectIdentifier) objIds[name];
+
+            if (oid != null)
+            {
+                return (ECDomainParameters) parameters[oid];
+            }
+
+            return null;
+        }
+
+        /**
+        * return the named curve name represented by the given object identifier.
+        */
+        public static string GetName(
+            DerObjectIdentifier oid)
+        {
+            return (string) names[oid];
+        }
+
+		public static DerObjectIdentifier GetOid(
+			string name)
+        {
+            return (DerObjectIdentifier) objIds[name];
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cryptopro/ECGOST3410ParamSetParameters.cs b/Crypto/src/asn1/cryptopro/ECGOST3410ParamSetParameters.cs
new file mode 100644
index 000000000..6f4435d7b
--- /dev/null
+++ b/Crypto/src/asn1/cryptopro/ECGOST3410ParamSetParameters.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+    public class ECGost3410ParamSetParameters
+        : Asn1Encodable
+    {
+        internal readonly DerInteger p, q, a, b, x, y;
+
+        public static ECGost3410ParamSetParameters GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+        public static ECGost3410ParamSetParameters GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is ECGost3410ParamSetParameters)
+            {
+                return (ECGost3410ParamSetParameters) obj;
+            }
+
+            if (obj is Asn1Sequence)
+            {
+                return new ECGost3410ParamSetParameters((Asn1Sequence) obj);
+            }
+
+            throw new ArgumentException("Invalid GOST3410Parameter: " + obj.GetType().Name);
+        }
+
+        public ECGost3410ParamSetParameters(
+            BigInteger a,
+            BigInteger b,
+            BigInteger p,
+            BigInteger q,
+            int        x,
+            BigInteger y)
+        {
+            this.a = new DerInteger(a);
+            this.b = new DerInteger(b);
+            this.p = new DerInteger(p);
+            this.q = new DerInteger(q);
+            this.x = new DerInteger(x);
+            this.y = new DerInteger(y);
+        }
+
+        public ECGost3410ParamSetParameters(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 6)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			this.a = DerInteger.GetInstance(seq[0]);
+			this.b = DerInteger.GetInstance(seq[1]);
+			this.p = DerInteger.GetInstance(seq[2]);
+			this.q = DerInteger.GetInstance(seq[3]);
+			this.x = DerInteger.GetInstance(seq[4]);
+			this.y = DerInteger.GetInstance(seq[5]);
+        }
+
+		public BigInteger P
+		{
+			get { return p.PositiveValue; }
+		}
+
+		public BigInteger Q
+		{
+			get { return q.PositiveValue; }
+		}
+
+		public BigInteger A
+		{
+			get { return a.PositiveValue; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(a, b, p, q, x, y);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cryptopro/GOST28147Parameters.cs b/Crypto/src/asn1/cryptopro/GOST28147Parameters.cs
new file mode 100644
index 000000000..eb7e0e3f6
--- /dev/null
+++ b/Crypto/src/asn1/cryptopro/GOST28147Parameters.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+    public class Gost28147Parameters
+        : Asn1Encodable
+    {
+        private readonly Asn1OctetString iv;
+        private readonly DerObjectIdentifier paramSet;
+
+		public static Gost28147Parameters GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static Gost28147Parameters GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is Gost28147Parameters)
+            {
+                return (Gost28147Parameters) obj;
+            }
+
+            if (obj is Asn1Sequence)
+            {
+                return new Gost28147Parameters((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Invalid GOST3410Parameter: " + obj.GetType().Name);
+        }
+
+        private Gost28147Parameters(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			this.iv = Asn1OctetString.GetInstance(seq[0]);
+			this.paramSet = DerObjectIdentifier.GetInstance(seq[1]);
+        }
+
+		/**
+         * <pre>
+         * Gost28147-89-Parameters ::=
+         *               SEQUENCE {
+         *                       iv                   Gost28147-89-IV,
+         *                       encryptionParamSet   OBJECT IDENTIFIER
+         *                }
+         *
+         *   Gost28147-89-IV ::= OCTET STRING (SIZE (8))
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(iv, paramSet);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cryptopro/GOST3410NamedParameters.cs b/Crypto/src/asn1/cryptopro/GOST3410NamedParameters.cs
new file mode 100644
index 000000000..66dba51d7
--- /dev/null
+++ b/Crypto/src/asn1/cryptopro/GOST3410NamedParameters.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+    /**
+    * table of the available named parameters for GOST 3410-94.
+    */
+    public sealed class Gost3410NamedParameters
+    {
+		private Gost3410NamedParameters()
+		{
+		}
+
+        private static readonly IDictionary objIds = Platform.CreateHashtable();
+        private static readonly IDictionary parameters = Platform.CreateHashtable();
+
+        private static readonly Gost3410ParamSetParameters cryptoProA = new Gost3410ParamSetParameters(
+            1024,
+            new BigInteger("127021248288932417465907042777176443525787653508916535812817507265705031260985098497423188333483401180925999995120988934130659205614996724254121049274349357074920312769561451689224110579311248812610229678534638401693520013288995000362260684222750813532307004517341633685004541062586971416883686778842537820383"),
+            new BigInteger("68363196144955700784444165611827252895102170888761442055095051287550314083023"),
+            new BigInteger("100997906755055304772081815535925224869841082572053457874823515875577147990529272777244152852699298796483356699682842027972896052747173175480590485607134746852141928680912561502802222185647539190902656116367847270145019066794290930185446216399730872221732889830323194097355403213400972588322876850946740663962")
+            //            validationAlgorithm {
+            //                    algorithm
+            //                        id-GostR3410-94-bBis,
+            //                    parameters
+            //                        GostR3410-94-ValidationBisParameters: {
+            //                            x0      1376285941,
+            //                            c       3996757427
+            //                        }
+            //                }
+
+            );
+
+        private static readonly Gost3410ParamSetParameters cryptoProB = new Gost3410ParamSetParameters(
+            1024,
+            new BigInteger("139454871199115825601409655107690713107041707059928031797758001454375765357722984094124368522288239833039114681648076688236921220737322672160740747771700911134550432053804647694904686120113087816240740184800477047157336662926249423571248823968542221753660143391485680840520336859458494803187341288580489525163"),
+            new BigInteger("79885141663410976897627118935756323747307951916507639758300472692338873533959"),
+            new BigInteger("42941826148615804143873447737955502392672345968607143066798112994089471231420027060385216699563848719957657284814898909770759462613437669456364882730370838934791080835932647976778601915343474400961034231316672578686920482194932878633360203384797092684342247621055760235016132614780652761028509445403338652341")
+            //    validationAlgorithm {
+            //            algorithm
+            //                id-GostR3410-94-bBis,
+            //            parameters
+            //                GostR3410-94-ValidationBisParameters: {
+            //                    x0      1536654555,
+            //                    c       1855361757,
+            //                    d       14408629386140014567655
+            //4902939282056547857802241461782996702017713059974755104394739915140
+            //6115284791024439062735788342744854120601660303926203867703556828005
+            //8957203818114895398976594425537561271800850306
+            //                }
+            //        }
+            //}
+            );
+
+        private static readonly Gost3410ParamSetParameters cryptoProXchA = new Gost3410ParamSetParameters(
+            1024,
+            new BigInteger("142011741597563481196368286022318089743276138395243738762872573441927459393512718973631166078467600360848946623567625795282774719212241929071046134208380636394084512691828894000571524625445295769349356752728956831541775441763139384457191755096847107846595662547942312293338483924514339614727760681880609734239"),
+            new BigInteger("91771529896554605945588149018382750217296858393520724172743325725474374979801"),
+            new BigInteger("133531813272720673433859519948319001217942375967847486899482359599369642528734712461590403327731821410328012529253871914788598993103310567744136196364803064721377826656898686468463277710150809401182608770201615324990468332931294920912776241137878030224355746606283971659376426832674269780880061631528163475887")
+            );
+
+		static Gost3410NamedParameters()
+        {
+            parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProA] = cryptoProA;
+            parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProB] = cryptoProB;
+            //parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProC] = cryptoProC;
+            //parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProD] = cryptoProD;
+            parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProXchA] = cryptoProXchA;
+            //parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProXchB] = cryptoProXchA;
+            //parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProXchC] = cryptoProXchA;
+
+			objIds["GostR3410-94-CryptoPro-A"] = CryptoProObjectIdentifiers.GostR3410x94CryptoProA;
+            objIds["GostR3410-94-CryptoPro-B"] = CryptoProObjectIdentifiers.GostR3410x94CryptoProB;
+            objIds["GostR3410-94-CryptoPro-XchA"] = CryptoProObjectIdentifiers.GostR3410x94CryptoProXchA;
+        }
+
+		/**
+        * return the GOST3410ParamSetParameters object for the given OID, null if it
+        * isn't present.
+        *
+        * @param oid an object identifier representing a named parameters, if present.
+        */
+        public static Gost3410ParamSetParameters GetByOid(
+            DerObjectIdentifier oid)
+        {
+            return (Gost3410ParamSetParameters) parameters[oid];
+        }
+
+		/**
+        * returns an enumeration containing the name strings for parameters
+        * contained in this structure.
+        */
+        public static IEnumerable Names
+        {
+			get { return new EnumerableProxy(objIds.Keys); }
+        }
+
+		public static Gost3410ParamSetParameters GetByName(
+            string name)
+        {
+            DerObjectIdentifier oid = (DerObjectIdentifier) objIds[name];
+
+            if (oid != null)
+            {
+                return (Gost3410ParamSetParameters) parameters[oid];
+            }
+
+            return null;
+        }
+
+        public static DerObjectIdentifier GetOid(
+			string name)
+        {
+            return (DerObjectIdentifier) objIds[name];
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cryptopro/GOST3410ParamSetParameters.cs b/Crypto/src/asn1/cryptopro/GOST3410ParamSetParameters.cs
new file mode 100644
index 000000000..f133cdf1b
--- /dev/null
+++ b/Crypto/src/asn1/cryptopro/GOST3410ParamSetParameters.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+    public class Gost3410ParamSetParameters
+        : Asn1Encodable
+    {
+        private readonly int keySize;
+        private readonly DerInteger	p, q, a;
+
+		public static Gost3410ParamSetParameters GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static Gost3410ParamSetParameters GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is Gost3410ParamSetParameters)
+            {
+                return (Gost3410ParamSetParameters) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new Gost3410ParamSetParameters((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Invalid GOST3410Parameter: " + obj.GetType().Name);
+        }
+
+		public Gost3410ParamSetParameters(
+            int			keySize,
+            BigInteger	p,
+            BigInteger	q,
+            BigInteger	a)
+        {
+            this.keySize = keySize;
+            this.p = new DerInteger(p);
+            this.q = new DerInteger(q);
+            this.a = new DerInteger(a);
+        }
+
+		private Gost3410ParamSetParameters(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 4)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			this.keySize = DerInteger.GetInstance(seq[0]).Value.IntValue;
+			this.p = DerInteger.GetInstance(seq[1]);
+            this.q = DerInteger.GetInstance(seq[2]);
+			this.a = DerInteger.GetInstance(seq[3]);
+        }
+
+		public int KeySize
+		{
+			get { return keySize; }
+		}
+
+		public BigInteger P
+		{
+			get { return p.PositiveValue; }
+		}
+
+		public BigInteger Q
+		{
+			get { return q.PositiveValue; }
+		}
+
+		public BigInteger A
+		{
+			get { return a.PositiveValue; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(new DerInteger(keySize), p, q, a);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/cryptopro/GOST3410PublicKeyAlgParameters.cs b/Crypto/src/asn1/cryptopro/GOST3410PublicKeyAlgParameters.cs
new file mode 100644
index 000000000..8bc1460af
--- /dev/null
+++ b/Crypto/src/asn1/cryptopro/GOST3410PublicKeyAlgParameters.cs
@@ -0,0 +1,99 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+    public class Gost3410PublicKeyAlgParameters
+        : Asn1Encodable
+    {
+        private DerObjectIdentifier	publicKeyParamSet;
+        private DerObjectIdentifier	digestParamSet;
+        private DerObjectIdentifier	encryptionParamSet;
+
+		public static Gost3410PublicKeyAlgParameters GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static Gost3410PublicKeyAlgParameters GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is Gost3410PublicKeyAlgParameters)
+            {
+                return (Gost3410PublicKeyAlgParameters) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new Gost3410PublicKeyAlgParameters((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Invalid GOST3410Parameter: " + obj.GetType().Name);
+        }
+
+		public Gost3410PublicKeyAlgParameters(
+            DerObjectIdentifier	publicKeyParamSet,
+            DerObjectIdentifier	digestParamSet)
+			: this (publicKeyParamSet, digestParamSet, null)
+        {
+        }
+
+		public Gost3410PublicKeyAlgParameters(
+            DerObjectIdentifier  publicKeyParamSet,
+            DerObjectIdentifier  digestParamSet,
+            DerObjectIdentifier  encryptionParamSet)
+        {
+			if (publicKeyParamSet == null)
+				throw new ArgumentNullException("publicKeyParamSet");
+			if (digestParamSet == null)
+				throw new ArgumentNullException("digestParamSet");
+
+			this.publicKeyParamSet = publicKeyParamSet;
+            this.digestParamSet = digestParamSet;
+            this.encryptionParamSet = encryptionParamSet;
+        }
+
+		public Gost3410PublicKeyAlgParameters(
+            Asn1Sequence seq)
+        {
+            this.publicKeyParamSet = (DerObjectIdentifier) seq[0];
+            this.digestParamSet = (DerObjectIdentifier) seq[1];
+
+			if (seq.Count > 2)
+            {
+                this.encryptionParamSet = (DerObjectIdentifier) seq[2];
+            }
+        }
+
+		public DerObjectIdentifier PublicKeyParamSet
+		{
+			get { return publicKeyParamSet; }
+		}
+
+		public DerObjectIdentifier DigestParamSet
+		{
+			get { return digestParamSet; }
+		}
+
+		public DerObjectIdentifier EncryptionParamSet
+		{
+			get { return encryptionParamSet; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				publicKeyParamSet, digestParamSet);
+
+			if (encryptionParamSet != null)
+            {
+                v.Add(encryptionParamSet);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/eac/EACObjectIdentifiers.cs b/Crypto/src/asn1/eac/EACObjectIdentifiers.cs
new file mode 100644
index 000000000..d54ef0eba
--- /dev/null
+++ b/Crypto/src/asn1/eac/EACObjectIdentifiers.cs
@@ -0,0 +1,50 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Eac
+{
+	public abstract class EacObjectIdentifiers
+	{
+		// bsi-de OBJECT IDENTIFIER ::= {
+		//         itu-t(0) identified-organization(4) etsi(0)
+		//         reserved(127) etsi-identified-organization(0) 7
+		//     }
+		public static readonly DerObjectIdentifier bsi_de = new DerObjectIdentifier("0.4.0.127.0.7");
+
+		// id-PK OBJECT IDENTIFIER ::= {
+		//         bsi-de protocols(2) smartcard(2) 1
+		//     }
+		public static readonly DerObjectIdentifier id_PK = new DerObjectIdentifier(bsi_de + ".2.2.1");
+
+		public static readonly DerObjectIdentifier id_PK_DH = new DerObjectIdentifier(id_PK + ".1");
+		public static readonly DerObjectIdentifier id_PK_ECDH = new DerObjectIdentifier(id_PK + ".2");
+
+		// id-CA OBJECT IDENTIFIER ::= {
+		//         bsi-de protocols(2) smartcard(2) 3
+		//     }
+		public static readonly DerObjectIdentifier id_CA = new DerObjectIdentifier(bsi_de + ".2.2.3");
+		public static readonly DerObjectIdentifier id_CA_DH = new DerObjectIdentifier(id_CA + ".1");
+		public static readonly DerObjectIdentifier id_CA_DH_3DES_CBC_CBC = new DerObjectIdentifier(id_CA_DH + ".1");
+		public static readonly DerObjectIdentifier id_CA_ECDH = new DerObjectIdentifier(id_CA + ".2");
+		public static readonly DerObjectIdentifier id_CA_ECDH_3DES_CBC_CBC = new DerObjectIdentifier(id_CA_ECDH + ".1");
+
+		//
+		// id-TA OBJECT IDENTIFIER ::= {
+		//     bsi-de protocols(2) smartcard(2) 2
+		// }
+		public static readonly DerObjectIdentifier id_TA = new DerObjectIdentifier(bsi_de + ".2.2.2");
+
+		public static readonly DerObjectIdentifier id_TA_RSA = new DerObjectIdentifier(id_TA + ".1");
+		public static readonly DerObjectIdentifier id_TA_RSA_v1_5_SHA_1 = new DerObjectIdentifier(id_TA_RSA + ".1");
+		public static readonly DerObjectIdentifier id_TA_RSA_v1_5_SHA_256 = new DerObjectIdentifier(id_TA_RSA + ".2");
+		public static readonly DerObjectIdentifier id_TA_RSA_PSS_SHA_1 = new DerObjectIdentifier(id_TA_RSA + ".3");
+		public static readonly DerObjectIdentifier id_TA_RSA_PSS_SHA_256 = new DerObjectIdentifier(id_TA_RSA + ".4");
+		public static readonly DerObjectIdentifier id_TA_ECDSA = new DerObjectIdentifier(id_TA + ".2");
+		public static readonly DerObjectIdentifier id_TA_ECDSA_SHA_1 = new DerObjectIdentifier(id_TA_ECDSA + ".1");
+		public static readonly DerObjectIdentifier id_TA_ECDSA_SHA_224 = new DerObjectIdentifier(id_TA_ECDSA + ".2");
+		public static readonly DerObjectIdentifier id_TA_ECDSA_SHA_256 = new DerObjectIdentifier(id_TA_ECDSA + ".3");
+		public static readonly DerObjectIdentifier id_TA_ECDSA_SHA_384 = new DerObjectIdentifier(id_TA_ECDSA + ".4");
+		public static readonly DerObjectIdentifier id_TA_ECDSA_SHA_512 = new DerObjectIdentifier(id_TA_ECDSA + ".5");
+	}
+}
diff --git a/Crypto/src/asn1/esf/CertificateValues.cs b/Crypto/src/asn1/esf/CertificateValues.cs
new file mode 100644
index 000000000..e0fb39b83
--- /dev/null
+++ b/Crypto/src/asn1/esf/CertificateValues.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.3.1 Certificate Values Attribute Definition
+	/// <code>
+	/// CertificateValues ::= SEQUENCE OF Certificate
+	/// </code>
+	/// </remarks>
+	public class CertificateValues
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence certificates;
+
+		public static CertificateValues GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CertificateValues)
+				return (CertificateValues) obj;
+
+			if (obj is Asn1Sequence)
+				return new CertificateValues((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'CertificateValues' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private CertificateValues(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+
+			foreach (Asn1Encodable ae in seq)
+			{
+				X509CertificateStructure.GetInstance(ae.ToAsn1Object());
+			}
+
+			this.certificates = seq;
+		}
+
+		public CertificateValues(
+			params X509CertificateStructure[] certificates)
+		{
+			if (certificates == null)
+				throw new ArgumentNullException("certificates");
+
+			this.certificates = new DerSequence(certificates);
+		}
+
+		public CertificateValues(
+			IEnumerable certificates)
+		{
+			if (certificates == null)
+				throw new ArgumentNullException("certificates");
+			if (!CollectionUtilities.CheckElementsAreOfType(certificates, typeof(X509CertificateStructure)))
+				throw new ArgumentException("Must contain only 'X509CertificateStructure' objects", "certificates");
+
+			this.certificates = new DerSequence(
+				Asn1EncodableVector.FromEnumerable(certificates));
+		}
+
+		public X509CertificateStructure[] GetCertificates()
+		{
+			X509CertificateStructure[] result = new X509CertificateStructure[certificates.Count];
+			for (int i = 0; i < certificates.Count; ++i)
+			{
+				result[i] = X509CertificateStructure.GetInstance(certificates[i]);
+			}
+			return result;
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return certificates;
+		}
+ 	}
+}
diff --git a/Crypto/src/asn1/esf/CommitmentTypeIdentifier.cs b/Crypto/src/asn1/esf/CommitmentTypeIdentifier.cs
new file mode 100644
index 000000000..65cd45b4a
--- /dev/null
+++ b/Crypto/src/asn1/esf/CommitmentTypeIdentifier.cs
@@ -0,0 +1,17 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+    public abstract class CommitmentTypeIdentifier
+    {
+        public static readonly DerObjectIdentifier ProofOfOrigin = PkcsObjectIdentifiers.IdCtiEtsProofOfOrigin;
+        public static readonly DerObjectIdentifier ProofOfReceipt = PkcsObjectIdentifiers.IdCtiEtsProofOfReceipt;
+        public static readonly DerObjectIdentifier ProofOfDelivery = PkcsObjectIdentifiers.IdCtiEtsProofOfDelivery;
+        public static readonly DerObjectIdentifier ProofOfSender = PkcsObjectIdentifiers.IdCtiEtsProofOfSender;
+        public static readonly DerObjectIdentifier ProofOfApproval = PkcsObjectIdentifiers.IdCtiEtsProofOfApproval;
+        public static readonly DerObjectIdentifier ProofOfCreation = PkcsObjectIdentifiers.IdCtiEtsProofOfCreation;
+    }
+}
diff --git a/Crypto/src/asn1/esf/CommitmentTypeIndication.cs b/Crypto/src/asn1/esf/CommitmentTypeIndication.cs
new file mode 100644
index 000000000..8342cbf8d
--- /dev/null
+++ b/Crypto/src/asn1/esf/CommitmentTypeIndication.cs
@@ -0,0 +1,95 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+    public class CommitmentTypeIndication
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	commitmentTypeId;
+        private readonly Asn1Sequence			commitmentTypeQualifier;
+
+		public static CommitmentTypeIndication GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CommitmentTypeIndication)
+				return (CommitmentTypeIndication) obj;
+
+			if (obj is Asn1Sequence)
+				return new CommitmentTypeIndication((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'CommitmentTypeIndication' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		public CommitmentTypeIndication(
+            Asn1Sequence seq)
+        {
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count < 1 || seq.Count > 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.commitmentTypeId = (DerObjectIdentifier) seq[0].ToAsn1Object();
+
+			if (seq.Count > 1)
+            {
+                this.commitmentTypeQualifier = (Asn1Sequence) seq[1].ToAsn1Object();
+            }
+        }
+
+		public CommitmentTypeIndication(
+            DerObjectIdentifier commitmentTypeId)
+			: this(commitmentTypeId, null)
+        {
+        }
+
+		public CommitmentTypeIndication(
+            DerObjectIdentifier	commitmentTypeId,
+            Asn1Sequence		commitmentTypeQualifier)
+        {
+			if (commitmentTypeId == null)
+				throw new ArgumentNullException("commitmentTypeId");
+
+			this.commitmentTypeId = commitmentTypeId;
+
+			if (commitmentTypeQualifier != null)
+			{
+				this.commitmentTypeQualifier = commitmentTypeQualifier;
+			}
+        }
+
+		public DerObjectIdentifier CommitmentTypeID
+		{
+			get { return commitmentTypeId; }
+		}
+
+		public Asn1Sequence CommitmentTypeQualifier
+		{
+			get { return commitmentTypeQualifier; }
+		}
+
+		/**
+        * <pre>
+        * CommitmentTypeIndication ::= SEQUENCE {
+        *      commitmentTypeId   CommitmentTypeIdentifier,
+        *      commitmentTypeQualifier   SEQUENCE SIZE (1..MAX) OF
+        *              CommitmentTypeQualifier OPTIONAL }
+        * </pre>
+        */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(commitmentTypeId);
+
+			if (commitmentTypeQualifier != null)
+            {
+                v.Add(commitmentTypeQualifier);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/esf/CommitmentTypeQualifier.cs b/Crypto/src/asn1/esf/CommitmentTypeQualifier.cs
new file mode 100644
index 000000000..09ff70714
--- /dev/null
+++ b/Crypto/src/asn1/esf/CommitmentTypeQualifier.cs
@@ -0,0 +1,119 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+    /**
+    * Commitment type qualifiers, used in the Commitment-Type-Indication attribute (RFC3126).
+    *
+    * <pre>
+    *   CommitmentTypeQualifier ::= SEQUENCE {
+    *       commitmentTypeIdentifier  CommitmentTypeIdentifier,
+    *       qualifier          ANY DEFINED BY commitmentTypeIdentifier OPTIONAL }
+    * </pre>
+    */
+    public class CommitmentTypeQualifier
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	commitmentTypeIdentifier;
+        private readonly Asn1Object				qualifier;
+
+        /**
+        * Creates a new <code>CommitmentTypeQualifier</code> instance.
+        *
+        * @param commitmentTypeIdentifier a <code>CommitmentTypeIdentifier</code> value
+        */
+        public CommitmentTypeQualifier(
+            DerObjectIdentifier commitmentTypeIdentifier)
+            : this(commitmentTypeIdentifier, null)
+        {
+        }
+
+    /**
+        * Creates a new <code>CommitmentTypeQualifier</code> instance.
+        *
+        * @param commitmentTypeIdentifier a <code>CommitmentTypeIdentifier</code> value
+        * @param qualifier the qualifier, defined by the above field.
+        */
+        public CommitmentTypeQualifier(
+            DerObjectIdentifier	commitmentTypeIdentifier,
+            Asn1Encodable		qualifier)
+        {
+			if (commitmentTypeIdentifier == null)
+				throw new ArgumentNullException("commitmentTypeIdentifier");
+
+			this.commitmentTypeIdentifier = commitmentTypeIdentifier;
+
+			if (qualifier != null)
+			{
+				this.qualifier = qualifier.ToAsn1Object();
+			}
+        }
+
+        /**
+        * Creates a new <code>CommitmentTypeQualifier</code> instance.
+        *
+        * @param as <code>CommitmentTypeQualifier</code> structure
+        * encoded as an Asn1Sequence.
+        */
+        public CommitmentTypeQualifier(
+            Asn1Sequence seq)
+        {
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count < 1 || seq.Count > 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			commitmentTypeIdentifier = (DerObjectIdentifier) seq[0].ToAsn1Object();
+
+			if (seq.Count > 1)
+            {
+                qualifier = seq[1].ToAsn1Object();
+            }
+        }
+
+		public static CommitmentTypeQualifier GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CommitmentTypeQualifier)
+				return (CommitmentTypeQualifier) obj;
+
+			if (obj is Asn1Sequence)
+				return new CommitmentTypeQualifier((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'CommitmentTypeQualifier' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		public DerObjectIdentifier CommitmentTypeIdentifier
+		{
+			get { return commitmentTypeIdentifier; }
+		}
+
+		public Asn1Object Qualifier
+		{
+			get { return qualifier; }
+		}
+
+		/**
+        * Returns a DER-encodable representation of this instance.
+        *
+        * @return a <code>Asn1Object</code> value
+        */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				commitmentTypeIdentifier);
+
+			if (qualifier != null)
+			{
+				v.Add(qualifier);
+			}
+
+			return new DerSequence(v);
+		}
+    }
+}
diff --git a/Crypto/src/asn1/esf/CompleteCertificateRefs.cs b/Crypto/src/asn1/esf/CompleteCertificateRefs.cs
new file mode 100644
index 000000000..7f1c835c9
--- /dev/null
+++ b/Crypto/src/asn1/esf/CompleteCertificateRefs.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.1 Complete Certificate Refs Attribute Definition
+	/// <code>
+	/// CompleteCertificateRefs ::= SEQUENCE OF OtherCertID
+	/// </code>
+	/// </remarks>
+	public class CompleteCertificateRefs
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence otherCertIDs;
+
+		public static CompleteCertificateRefs GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CompleteCertificateRefs)
+				return (CompleteCertificateRefs) obj;
+
+			if (obj is Asn1Sequence)
+				return new CompleteCertificateRefs((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'CompleteCertificateRefs' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private CompleteCertificateRefs(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+
+			foreach (Asn1Encodable ae in seq)
+			{
+				OtherCertID.GetInstance(ae.ToAsn1Object());
+			}
+
+			this.otherCertIDs = seq;
+		}
+
+		public CompleteCertificateRefs(
+			params OtherCertID[] otherCertIDs)
+		{
+			if (otherCertIDs == null)
+				throw new ArgumentNullException("otherCertIDs");
+
+			this.otherCertIDs = new DerSequence(otherCertIDs);
+		}
+
+		public CompleteCertificateRefs(
+			IEnumerable otherCertIDs)
+		{
+			if (otherCertIDs == null)
+				throw new ArgumentNullException("otherCertIDs");
+			if (!CollectionUtilities.CheckElementsAreOfType(otherCertIDs, typeof(OtherCertID)))
+				throw new ArgumentException("Must contain only 'OtherCertID' objects", "otherCertIDs");
+
+			this.otherCertIDs = new DerSequence(
+				Asn1EncodableVector.FromEnumerable(otherCertIDs));
+		}
+
+		public OtherCertID[] GetOtherCertIDs()
+		{
+			OtherCertID[] result = new OtherCertID[otherCertIDs.Count];
+			for (int i = 0; i < otherCertIDs.Count; ++i)
+			{
+				result[i] = OtherCertID.GetInstance(otherCertIDs[i].ToAsn1Object());
+			}
+			return result;
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return otherCertIDs;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/esf/CompleteRevocationRefs.cs b/Crypto/src/asn1/esf/CompleteRevocationRefs.cs
new file mode 100644
index 000000000..4e1fb403d
--- /dev/null
+++ b/Crypto/src/asn1/esf/CompleteRevocationRefs.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+	/// <code>
+	/// CompleteRevocationRefs ::= SEQUENCE OF CrlOcspRef
+	/// </code>
+	/// </remarks>
+	public class CompleteRevocationRefs
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence crlOcspRefs;
+
+		public static CompleteRevocationRefs GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CompleteRevocationRefs)
+				return (CompleteRevocationRefs) obj;
+
+			if (obj is Asn1Sequence)
+				return new CompleteRevocationRefs((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'CompleteRevocationRefs' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private CompleteRevocationRefs(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+
+			foreach (Asn1Encodable ae in seq)
+			{
+				CrlOcspRef.GetInstance(ae.ToAsn1Object());
+			}
+
+			this.crlOcspRefs = seq;
+		}
+
+		public CompleteRevocationRefs(
+			params CrlOcspRef[] crlOcspRefs)
+		{
+			if (crlOcspRefs == null)
+				throw new ArgumentNullException("crlOcspRefs");
+
+			this.crlOcspRefs = new DerSequence(crlOcspRefs);
+		}
+
+		public CompleteRevocationRefs(
+			IEnumerable crlOcspRefs)
+		{
+			if (crlOcspRefs == null)
+				throw new ArgumentNullException("crlOcspRefs");
+			if (!CollectionUtilities.CheckElementsAreOfType(crlOcspRefs, typeof(CrlOcspRef)))
+				throw new ArgumentException("Must contain only 'CrlOcspRef' objects", "crlOcspRefs");
+
+			this.crlOcspRefs = new DerSequence(
+				Asn1EncodableVector.FromEnumerable(crlOcspRefs));
+		}
+
+		public CrlOcspRef[] GetCrlOcspRefs()
+		{
+			CrlOcspRef[] result = new CrlOcspRef[crlOcspRefs.Count];
+			for (int i = 0; i < crlOcspRefs.Count; ++i)
+			{
+				result[i] = CrlOcspRef.GetInstance(crlOcspRefs[i].ToAsn1Object());
+			}
+			return result;
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return crlOcspRefs;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/esf/CrlIdentifier.cs b/Crypto/src/asn1/esf/CrlIdentifier.cs
new file mode 100644
index 000000000..dfff7d838
--- /dev/null
+++ b/Crypto/src/asn1/esf/CrlIdentifier.cs
@@ -0,0 +1,110 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+	/// <code>
+	/// CrlIdentifier ::= SEQUENCE 
+	/// {
+	/// 	crlissuer		Name,
+	/// 	crlIssuedTime	UTCTime,
+	/// 	crlNumber		INTEGER OPTIONAL
+	/// }
+	/// </code>
+	/// </remarks>
+	public class CrlIdentifier
+		: Asn1Encodable
+	{
+		private readonly X509Name	crlIssuer;
+		private readonly DerUtcTime	crlIssuedTime;
+		private readonly DerInteger	crlNumber;
+
+		public static CrlIdentifier GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CrlIdentifier)
+				return (CrlIdentifier) obj;
+
+			if (obj is Asn1Sequence)
+				return new CrlIdentifier((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'CrlIdentifier' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private CrlIdentifier(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count < 2 || seq.Count > 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.crlIssuer = X509Name.GetInstance(seq[0]);
+			this.crlIssuedTime = DerUtcTime.GetInstance(seq[1]);
+
+			if (seq.Count > 2)
+			{
+				this.crlNumber = DerInteger.GetInstance(seq[2]);
+			}
+		}
+
+		public CrlIdentifier(
+			X509Name	crlIssuer,
+			DateTime	crlIssuedTime)
+			: this(crlIssuer, crlIssuedTime, null)
+		{
+		}
+
+		public CrlIdentifier(
+			X509Name	crlIssuer,
+			DateTime	crlIssuedTime,
+			BigInteger	crlNumber)
+		{
+			if (crlIssuer == null)
+				throw new ArgumentNullException("crlIssuer");
+
+			this.crlIssuer = crlIssuer;
+			this.crlIssuedTime = new DerUtcTime(crlIssuedTime);
+
+			if (crlNumber != null)
+			{
+				this.crlNumber = new DerInteger(crlNumber);
+			}
+		}
+
+		public X509Name CrlIssuer
+		{
+			get { return crlIssuer; }
+		}
+
+		public DateTime CrlIssuedTime
+		{
+			get { return crlIssuedTime.ToAdjustedDateTime(); }
+		}
+
+		public BigInteger CrlNumber
+		{
+			get { return crlNumber == null ? null : crlNumber.Value; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				crlIssuer.ToAsn1Object(), crlIssuedTime);
+
+			if (crlNumber != null)
+			{
+				v.Add(crlNumber);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/esf/CrlListID.cs b/Crypto/src/asn1/esf/CrlListID.cs
new file mode 100644
index 000000000..2aae9b965
--- /dev/null
+++ b/Crypto/src/asn1/esf/CrlListID.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+	/// <code>
+	/// CRLListID ::= SEQUENCE 
+	/// {
+	///		crls	SEQUENCE OF CrlValidatedID
+	/// }
+	/// </code>
+	/// </remarks>
+	public class CrlListID
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence crls;
+
+		public static CrlListID GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CrlListID)
+				return (CrlListID) obj;
+
+			if (obj is Asn1Sequence)
+				return new CrlListID((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'CrlListID' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private CrlListID(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count != 1)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.crls = (Asn1Sequence) seq[0].ToAsn1Object();
+
+			foreach (Asn1Encodable ae in this.crls)
+			{
+				CrlValidatedID.GetInstance(ae.ToAsn1Object());
+			}
+		}
+
+		public CrlListID(
+			params CrlValidatedID[] crls)
+		{
+			if (crls == null)
+				throw new ArgumentNullException("crls");
+
+			this.crls = new DerSequence(crls);
+		}
+
+		public CrlListID(
+			IEnumerable crls)
+		{
+			if (crls == null)
+				throw new ArgumentNullException("crls");
+			if (!CollectionUtilities.CheckElementsAreOfType(crls, typeof(CrlValidatedID)))
+				throw new ArgumentException("Must contain only 'CrlValidatedID' objects", "crls");
+
+			this.crls = new DerSequence(
+				Asn1EncodableVector.FromEnumerable(crls));
+		}
+
+		public CrlValidatedID[] GetCrls()
+		{
+			CrlValidatedID[] result = new CrlValidatedID[crls.Count];
+			for (int i = 0; i < crls.Count; ++i)
+			{
+				result[i] = CrlValidatedID.GetInstance(crls[i].ToAsn1Object());
+			}
+			return result;
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(crls);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/esf/CrlOcspRef.cs b/Crypto/src/asn1/esf/CrlOcspRef.cs
new file mode 100644
index 000000000..c8e10d504
--- /dev/null
+++ b/Crypto/src/asn1/esf/CrlOcspRef.cs
@@ -0,0 +1,111 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+	/// <code>
+	/// CrlOcspRef ::= SEQUENCE {
+	///		crlids		[0] CRLListID		OPTIONAL,
+	/// 	ocspids		[1] OcspListID		OPTIONAL,
+	/// 	otherRev	[2] OtherRevRefs	OPTIONAL
+	/// }
+	/// </code>
+	/// </remarks>
+	public class CrlOcspRef
+		: Asn1Encodable
+	{
+		private readonly CrlListID		crlids;
+		private readonly OcspListID		ocspids;
+		private readonly OtherRevRefs	otherRev;
+
+		public static CrlOcspRef GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CrlOcspRef)
+				return (CrlOcspRef) obj;
+
+			if (obj is Asn1Sequence)
+				return new CrlOcspRef((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'CrlOcspRef' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private CrlOcspRef(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+
+			foreach (Asn1TaggedObject taggedObj in seq)
+			{
+				Asn1Object asn1Obj = taggedObj.GetObject();
+
+				switch (taggedObj.TagNo)
+				{
+					case 0:
+						this.crlids = CrlListID.GetInstance(asn1Obj);
+						break;
+					case 1:
+						this.ocspids = OcspListID.GetInstance(asn1Obj);
+						break;
+					case 2:
+						this.otherRev = OtherRevRefs.GetInstance(asn1Obj);
+						break;
+					default:
+						throw new ArgumentException("Illegal tag in CrlOcspRef", "seq");
+				}
+			}
+		}
+
+		public CrlOcspRef(
+			CrlListID		crlids,
+			OcspListID		ocspids,
+			OtherRevRefs	otherRev)
+		{
+			this.crlids = crlids;
+			this.ocspids = ocspids;
+			this.otherRev = otherRev;
+		}
+
+		public CrlListID CrlIDs
+		{
+			get { return crlids; }
+		}
+
+		public OcspListID OcspIDs
+		{
+			get { return ocspids; }
+		}
+
+		public OtherRevRefs OtherRev
+		{
+			get { return otherRev; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (crlids != null)
+			{
+				v.Add(new DerTaggedObject(true, 0, crlids.ToAsn1Object()));
+			}
+
+			if (ocspids != null)
+			{
+				v.Add(new DerTaggedObject(true, 1, ocspids.ToAsn1Object()));
+			}
+
+			if (otherRev != null)
+			{
+				v.Add(new DerTaggedObject(true, 2, otherRev.ToAsn1Object()));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/esf/CrlValidatedID.cs b/Crypto/src/asn1/esf/CrlValidatedID.cs
new file mode 100644
index 000000000..165f547a8
--- /dev/null
+++ b/Crypto/src/asn1/esf/CrlValidatedID.cs
@@ -0,0 +1,89 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+	/// <code>
+	/// CrlValidatedID ::= SEQUENCE {
+	///		crlHash			OtherHash,
+	///		crlIdentifier	CrlIdentifier OPTIONAL}
+	/// </code>
+	/// </remarks>
+	public class CrlValidatedID
+		: Asn1Encodable
+	{
+		private readonly OtherHash		crlHash;
+		private readonly CrlIdentifier	crlIdentifier;
+
+		public static CrlValidatedID GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CrlValidatedID)
+				return (CrlValidatedID) obj;
+
+			if (obj is Asn1Sequence)
+				return new CrlValidatedID((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'CrlValidatedID' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private CrlValidatedID(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count < 1 || seq.Count > 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.crlHash = OtherHash.GetInstance(seq[0].ToAsn1Object());
+
+			if (seq.Count > 1)
+			{
+				this.crlIdentifier = CrlIdentifier.GetInstance(seq[1].ToAsn1Object());
+			}
+		}
+
+		public CrlValidatedID(
+			OtherHash crlHash)
+			: this(crlHash, null)
+		{
+		}
+
+		public CrlValidatedID(
+			OtherHash		crlHash,
+			CrlIdentifier	crlIdentifier)
+		{
+			if (crlHash == null)
+				throw new ArgumentNullException("crlHash");
+
+			this.crlHash = crlHash;
+			this.crlIdentifier = crlIdentifier;
+		}
+
+		public OtherHash CrlHash
+		{
+			get { return crlHash; }
+		}
+
+		public CrlIdentifier CrlIdentifier
+		{
+			get { return crlIdentifier; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(crlHash.ToAsn1Object());
+
+			if (crlIdentifier != null)
+			{
+				v.Add(crlIdentifier.ToAsn1Object());
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/esf/ESFAttributes.cs b/Crypto/src/asn1/esf/ESFAttributes.cs
new file mode 100644
index 000000000..9401ffb8e
--- /dev/null
+++ b/Crypto/src/asn1/esf/ESFAttributes.cs
@@ -0,0 +1,25 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+    public abstract class EsfAttributes
+    {
+        public static readonly DerObjectIdentifier SigPolicyId = PkcsObjectIdentifiers.IdAAEtsSigPolicyID;
+        public static readonly DerObjectIdentifier CommitmentType = PkcsObjectIdentifiers.IdAAEtsCommitmentType;
+        public static readonly DerObjectIdentifier SignerLocation = PkcsObjectIdentifiers.IdAAEtsSignerLocation;
+		public static readonly DerObjectIdentifier SignerAttr = PkcsObjectIdentifiers.IdAAEtsSignerAttr;
+		public static readonly DerObjectIdentifier OtherSigCert = PkcsObjectIdentifiers.IdAAEtsOtherSigCert;
+		public static readonly DerObjectIdentifier ContentTimestamp = PkcsObjectIdentifiers.IdAAEtsContentTimestamp;
+		public static readonly DerObjectIdentifier CertificateRefs = PkcsObjectIdentifiers.IdAAEtsCertificateRefs;
+		public static readonly DerObjectIdentifier RevocationRefs = PkcsObjectIdentifiers.IdAAEtsRevocationRefs;
+		public static readonly DerObjectIdentifier CertValues = PkcsObjectIdentifiers.IdAAEtsCertValues;
+		public static readonly DerObjectIdentifier RevocationValues = PkcsObjectIdentifiers.IdAAEtsRevocationValues;
+		public static readonly DerObjectIdentifier EscTimeStamp = PkcsObjectIdentifiers.IdAAEtsEscTimeStamp;
+		public static readonly DerObjectIdentifier CertCrlTimestamp = PkcsObjectIdentifiers.IdAAEtsCertCrlTimestamp;
+		public static readonly DerObjectIdentifier ArchiveTimestamp = PkcsObjectIdentifiers.IdAAEtsArchiveTimestamp;
+		public static readonly DerObjectIdentifier ArchiveTimestampV2 = new DerObjectIdentifier(PkcsObjectIdentifiers.IdAA + ".48");
+	}
+}
diff --git a/Crypto/src/asn1/esf/OcspIdentifier.cs b/Crypto/src/asn1/esf/OcspIdentifier.cs
new file mode 100644
index 000000000..949b68243
--- /dev/null
+++ b/Crypto/src/asn1/esf/OcspIdentifier.cs
@@ -0,0 +1,77 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Ocsp;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+	/// <code>
+	/// OcspIdentifier ::= SEQUENCE {
+	///		ocspResponderID		ResponderID,
+	///			-- As in OCSP response data
+	///		producedAt			GeneralizedTime
+	///			-- As in OCSP response data
+	/// }
+	/// </code>
+	/// </remarks>
+	public class OcspIdentifier
+		: Asn1Encodable
+	{
+		private readonly ResponderID		ocspResponderID;
+		private readonly DerGeneralizedTime	producedAt;
+
+		public static OcspIdentifier GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OcspIdentifier)
+				return (OcspIdentifier) obj;
+
+			if (obj is Asn1Sequence)
+				return new OcspIdentifier((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'OcspIdentifier' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private OcspIdentifier(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.ocspResponderID = ResponderID.GetInstance(seq[0].ToAsn1Object());
+			this.producedAt = (DerGeneralizedTime) seq[1].ToAsn1Object();
+		}
+
+		public OcspIdentifier(
+			ResponderID	ocspResponderID,
+			DateTime	producedAt)
+		{
+			if (ocspResponderID == null)
+				throw new ArgumentNullException();
+
+			this.ocspResponderID = ocspResponderID;
+			this.producedAt = new DerGeneralizedTime(producedAt);
+		}
+
+		public ResponderID OcspResponderID
+		{
+			get { return ocspResponderID; }
+		}
+
+		public DateTime ProducedAt
+		{
+			get { return producedAt.ToDateTime(); }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(ocspResponderID, producedAt);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/esf/OcspListID.cs b/Crypto/src/asn1/esf/OcspListID.cs
new file mode 100644
index 000000000..1f3f3a337
--- /dev/null
+++ b/Crypto/src/asn1/esf/OcspListID.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+	/// <code>
+	/// OcspListID ::=  SEQUENCE {
+	///		ocspResponses	SEQUENCE OF OcspResponsesID
+	/// }
+	/// </code>
+	/// </remarks>
+	public class OcspListID
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence ocspResponses;
+
+		public static OcspListID GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OcspListID)
+				return (OcspListID) obj;
+
+			if (obj is Asn1Sequence)
+				return new OcspListID((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'OcspListID' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private OcspListID(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count != 1)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.ocspResponses = (Asn1Sequence) seq[0].ToAsn1Object();
+
+			foreach (Asn1Encodable ae in this.ocspResponses)
+			{
+				OcspResponsesID.GetInstance(ae.ToAsn1Object());
+			}
+		}
+
+		public OcspListID(
+			params OcspResponsesID[] ocspResponses)
+		{
+			if (ocspResponses == null)
+				throw new ArgumentNullException("ocspResponses");
+
+			this.ocspResponses = new DerSequence(ocspResponses);
+		}
+
+		public OcspListID(
+			IEnumerable ocspResponses)
+		{
+			if (ocspResponses == null)
+				throw new ArgumentNullException("ocspResponses");
+			if (!CollectionUtilities.CheckElementsAreOfType(ocspResponses, typeof(OcspResponsesID)))
+				throw new ArgumentException("Must contain only 'OcspResponsesID' objects", "ocspResponses");
+
+			this.ocspResponses = new DerSequence(
+				Asn1EncodableVector.FromEnumerable(ocspResponses));
+		}
+
+		public OcspResponsesID[] GetOcspResponses()
+		{
+			OcspResponsesID[] result = new OcspResponsesID[ocspResponses.Count];
+			for (int i = 0; i < ocspResponses.Count; ++i)
+			{
+				result[i] = OcspResponsesID.GetInstance(ocspResponses[i].ToAsn1Object());
+			}
+			return result;
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(ocspResponses);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/esf/OcspResponsesID.cs b/Crypto/src/asn1/esf/OcspResponsesID.cs
new file mode 100644
index 000000000..e09508a01
--- /dev/null
+++ b/Crypto/src/asn1/esf/OcspResponsesID.cs
@@ -0,0 +1,92 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+	/// <code>
+	/// OcspResponsesID ::= SEQUENCE {
+	///		ocspIdentifier	OcspIdentifier,
+	///		ocspRepHash		OtherHash OPTIONAL
+	/// }
+	/// </code>
+	/// </remarks>
+	public class OcspResponsesID
+		: Asn1Encodable
+	{
+		private readonly OcspIdentifier	ocspIdentifier;
+		private readonly OtherHash		ocspRepHash;
+
+		public static OcspResponsesID GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OcspResponsesID)
+				return (OcspResponsesID) obj;
+
+			if (obj is Asn1Sequence)
+				return new OcspResponsesID((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'OcspResponsesID' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private OcspResponsesID(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count < 1 || seq.Count > 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.ocspIdentifier = OcspIdentifier.GetInstance(seq[0].ToAsn1Object());
+
+			if (seq.Count > 1)
+			{
+				this.ocspRepHash = OtherHash.GetInstance(seq[1].ToAsn1Object());
+			}
+		}
+
+		public OcspResponsesID(
+			OcspIdentifier ocspIdentifier)
+			: this(ocspIdentifier, null)
+		{
+		}
+
+		public OcspResponsesID(
+			OcspIdentifier	ocspIdentifier,
+			OtherHash		ocspRepHash)
+		{
+			if (ocspIdentifier == null)
+				throw new ArgumentNullException("ocspIdentifier");
+
+			this.ocspIdentifier = ocspIdentifier;
+			this.ocspRepHash = ocspRepHash;
+		}
+
+		public OcspIdentifier OcspIdentifier
+		{
+			get { return ocspIdentifier; }
+		}
+
+		public OtherHash OcspRepHash
+		{
+			get { return ocspRepHash; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				ocspIdentifier.ToAsn1Object());
+
+			if (ocspRepHash != null)
+			{
+				v.Add(ocspRepHash.ToAsn1Object());
+			}
+
+			return new DerSequence(v);
+		}
+
+	}
+}
diff --git a/Crypto/src/asn1/esf/OtherCertID.cs b/Crypto/src/asn1/esf/OtherCertID.cs
new file mode 100644
index 000000000..6d1255535
--- /dev/null
+++ b/Crypto/src/asn1/esf/OtherCertID.cs
@@ -0,0 +1,93 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// <code>
+	/// OtherCertID ::= SEQUENCE {
+	/// 	otherCertHash	OtherHash,
+	/// 	issuerSerial	IssuerSerial OPTIONAL
+	/// }
+	/// </code>
+	/// </remarks>
+	public class OtherCertID
+		: Asn1Encodable
+	{
+		private readonly OtherHash		otherCertHash;
+		private readonly IssuerSerial	issuerSerial;
+
+		public static OtherCertID GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OtherCertID)
+				return (OtherCertID) obj;
+
+			if (obj is Asn1Sequence)
+				return new OtherCertID((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'OtherCertID' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private OtherCertID(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count < 1 || seq.Count > 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.otherCertHash = OtherHash.GetInstance(seq[0].ToAsn1Object());
+
+			if (seq.Count > 1)
+			{
+				this.issuerSerial = IssuerSerial.GetInstance(seq[1].ToAsn1Object());
+			}
+		}
+
+		public OtherCertID(
+			OtherHash otherCertHash)
+			: this(otherCertHash, null)
+		{
+		}
+
+		public OtherCertID(
+			OtherHash		otherCertHash,
+			IssuerSerial	issuerSerial)
+		{
+			if (otherCertHash == null)
+				throw new ArgumentNullException("otherCertHash");
+
+			this.otherCertHash = otherCertHash;
+			this.issuerSerial = issuerSerial;
+		}
+
+		public OtherHash OtherCertHash
+		{
+			get { return otherCertHash; }
+		}
+
+		public IssuerSerial IssuerSerial
+		{
+			get { return issuerSerial; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				otherCertHash.ToAsn1Object());
+
+			if (issuerSerial != null)
+			{
+				v.Add(issuerSerial.ToAsn1Object());
+			}
+
+			return new DerSequence(v);
+		}
+
+	}
+}
diff --git a/Crypto/src/asn1/esf/OtherHash.cs b/Crypto/src/asn1/esf/OtherHash.cs
new file mode 100644
index 000000000..2ee162478
--- /dev/null
+++ b/Crypto/src/asn1/esf/OtherHash.cs
@@ -0,0 +1,88 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// <code>
+	/// OtherHash ::= CHOICE {
+	///		sha1Hash	OtherHashValue, -- This contains a SHA-1 hash
+	/// 	otherHash	OtherHashAlgAndValue
+	///	}
+	///	
+	///	OtherHashValue ::= OCTET STRING
+	/// </code>
+	/// </remarks>
+	public class OtherHash
+		: Asn1Encodable, IAsn1Choice
+	{
+		private readonly Asn1OctetString		sha1Hash;
+		private readonly OtherHashAlgAndValue	otherHash;
+
+		public static OtherHash GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OtherHash)
+				return (OtherHash) obj;
+
+			if (obj is Asn1OctetString)
+				return new OtherHash((Asn1OctetString) obj);
+
+			return new OtherHash(
+				OtherHashAlgAndValue.GetInstance(obj));
+		}
+
+		public OtherHash(
+			byte[] sha1Hash)
+		{
+			if (sha1Hash == null)
+				throw new ArgumentNullException("sha1Hash");
+
+			this.sha1Hash = new DerOctetString(sha1Hash);
+		}
+
+		public OtherHash(
+			Asn1OctetString sha1Hash)
+		{
+			if (sha1Hash == null)
+				throw new ArgumentNullException("sha1Hash");
+
+			this.sha1Hash = sha1Hash;
+		}
+
+		public OtherHash(
+			OtherHashAlgAndValue otherHash)
+		{
+			if (otherHash == null)
+				throw new ArgumentNullException("otherHash");
+
+			this.otherHash = otherHash;
+		}
+
+		public AlgorithmIdentifier HashAlgorithm
+		{
+			get
+			{
+				return otherHash == null
+					?	new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1)
+					:	otherHash.HashAlgorithm;
+			}
+		}
+
+		public byte[] GetHashValue()
+		{
+			return otherHash == null
+				?	sha1Hash.GetOctets()
+				:	otherHash.GetHashValue();
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return otherHash == null
+				?	sha1Hash
+				:	otherHash.ToAsn1Object();
+		}
+	}
+}
diff --git a/Crypto/src/asn1/esf/OtherHashAlgAndValue.cs b/Crypto/src/asn1/esf/OtherHashAlgAndValue.cs
new file mode 100644
index 000000000..b6bd4f498
--- /dev/null
+++ b/Crypto/src/asn1/esf/OtherHashAlgAndValue.cs
@@ -0,0 +1,94 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <summary>
+	/// Summary description for OtherHashAlgAndValue.
+	/// </summary>
+	/// <remarks>
+	/// <code>
+	/// OtherHashAlgAndValue ::= SEQUENCE {
+	///		hashAlgorithm	AlgorithmIdentifier,
+	/// 	hashValue		OtherHashValue
+	/// }
+	/// 
+	/// OtherHashValue ::= OCTET STRING
+	/// </code>
+	/// </remarks>
+	public class OtherHashAlgAndValue
+		: Asn1Encodable
+	{
+		private readonly AlgorithmIdentifier	hashAlgorithm;
+		private readonly Asn1OctetString		hashValue;
+
+		public static OtherHashAlgAndValue GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OtherHashAlgAndValue)
+				return (OtherHashAlgAndValue) obj;
+
+			if (obj is Asn1Sequence)
+				return new OtherHashAlgAndValue((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'OtherHashAlgAndValue' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private OtherHashAlgAndValue(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0].ToAsn1Object());
+			this.hashValue = (Asn1OctetString) seq[1].ToAsn1Object();
+		}
+
+		public OtherHashAlgAndValue(
+			AlgorithmIdentifier	hashAlgorithm,
+			byte[]				hashValue)
+		{
+			if (hashAlgorithm == null)
+				throw new ArgumentNullException("hashAlgorithm");
+			if (hashValue == null)
+				throw new ArgumentNullException("hashValue");
+
+			this.hashAlgorithm = hashAlgorithm;
+			this.hashValue = new DerOctetString(hashValue);
+		}
+
+		public OtherHashAlgAndValue(
+			AlgorithmIdentifier	hashAlgorithm,
+			Asn1OctetString		hashValue)
+		{
+			if (hashAlgorithm == null)
+				throw new ArgumentNullException("hashAlgorithm");
+			if (hashValue == null)
+				throw new ArgumentNullException("hashValue");
+
+			this.hashAlgorithm = hashAlgorithm;
+			this.hashValue = hashValue;
+		}
+
+		public AlgorithmIdentifier HashAlgorithm
+		{
+			get { return hashAlgorithm; }
+		}
+
+		public byte[] GetHashValue()
+		{
+			return hashValue.GetOctets();
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(hashAlgorithm, hashValue);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/esf/OtherRevRefs.cs b/Crypto/src/asn1/esf/OtherRevRefs.cs
new file mode 100644
index 000000000..56713e3f2
--- /dev/null
+++ b/Crypto/src/asn1/esf/OtherRevRefs.cs
@@ -0,0 +1,78 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+	/// <code>
+	/// OtherRevRefs ::= SEQUENCE 
+	/// {
+	///		otherRevRefType      OtherRevRefType,
+	///		otherRevRefs         ANY DEFINED BY otherRevRefType
+	/// }
+	///
+	/// OtherRevRefType ::= OBJECT IDENTIFIER
+	/// </code>
+	/// </remarks>
+	public class OtherRevRefs
+		: Asn1Encodable
+	{
+		private readonly DerObjectIdentifier	otherRevRefType;
+		private readonly Asn1Object				otherRevRefs;
+
+		public static OtherRevRefs GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OtherRevRefs)
+				return (OtherRevRefs) obj;
+
+			if (obj is Asn1Sequence)
+				return new OtherRevRefs((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'OtherRevRefs' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private OtherRevRefs(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.otherRevRefType = (DerObjectIdentifier) seq[0].ToAsn1Object();
+			this.otherRevRefs = seq[1].ToAsn1Object();
+		}
+
+		public OtherRevRefs(
+			DerObjectIdentifier	otherRevRefType,
+			Asn1Encodable		otherRevRefs)
+		{
+			if (otherRevRefType == null)
+				throw new ArgumentNullException("otherRevRefType");
+			if (otherRevRefs == null)
+				throw new ArgumentNullException("otherRevRefs");
+
+			this.otherRevRefType = otherRevRefType;
+			this.otherRevRefs = otherRevRefs.ToAsn1Object();
+		}
+
+		public DerObjectIdentifier OtherRevRefType
+		{
+			get { return otherRevRefType; }
+		}
+
+		public Asn1Object OtherRevRefsObject
+		{
+			get { return otherRevRefs; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(otherRevRefType, otherRevRefs);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/esf/OtherRevVals.cs b/Crypto/src/asn1/esf/OtherRevVals.cs
new file mode 100644
index 000000000..b88a1a72a
--- /dev/null
+++ b/Crypto/src/asn1/esf/OtherRevVals.cs
@@ -0,0 +1,78 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.3.2 Revocation Values Attribute Definition
+	/// <code>
+	/// OtherRevVals ::= SEQUENCE 
+	/// {
+	///		otherRevValType      OtherRevValType,
+	///		otherRevVals         ANY DEFINED BY otherRevValType
+	/// }
+	///
+	/// OtherRevValType ::= OBJECT IDENTIFIER
+	/// </code>
+	/// </remarks>
+	public class OtherRevVals
+		: Asn1Encodable
+	{
+		private readonly DerObjectIdentifier	otherRevValType;
+		private readonly Asn1Object				otherRevVals;
+
+		public static OtherRevVals GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OtherRevVals)
+				return (OtherRevVals) obj;
+
+			if (obj is Asn1Sequence)
+				return new OtherRevVals((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'OtherRevVals' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private OtherRevVals(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.otherRevValType = (DerObjectIdentifier) seq[0].ToAsn1Object();
+			this.otherRevVals = seq[1].ToAsn1Object();
+		}
+
+		public OtherRevVals(
+			DerObjectIdentifier	otherRevValType,
+			Asn1Encodable		otherRevVals)
+		{
+			if (otherRevValType == null)
+				throw new ArgumentNullException("otherRevValType");
+			if (otherRevVals == null)
+				throw new ArgumentNullException("otherRevVals");
+
+			this.otherRevValType = otherRevValType;
+			this.otherRevVals = otherRevVals.ToAsn1Object();
+		}
+
+		public DerObjectIdentifier OtherRevValType
+		{
+			get { return otherRevValType; }
+		}
+
+		public Asn1Object OtherRevValsObject
+		{
+			get { return otherRevVals; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(otherRevValType, otherRevVals);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/esf/OtherSigningCertificate.cs b/Crypto/src/asn1/esf/OtherSigningCertificate.cs
new file mode 100644
index 000000000..90e385a33
--- /dev/null
+++ b/Crypto/src/asn1/esf/OtherSigningCertificate.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// <code>
+	/// OtherSigningCertificate ::= SEQUENCE {
+	/// 	certs		SEQUENCE OF OtherCertID,
+	/// 	policies	SEQUENCE OF PolicyInformation OPTIONAL
+	/// }
+	/// </code>
+	/// </remarks>
+	public class OtherSigningCertificate
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence	certs;
+		private readonly Asn1Sequence	policies;
+
+		public static OtherSigningCertificate GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OtherSigningCertificate)
+				return (OtherSigningCertificate) obj;
+
+			if (obj is Asn1Sequence)
+				return new OtherSigningCertificate((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'OtherSigningCertificate' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private OtherSigningCertificate(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count < 1 || seq.Count > 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.certs = Asn1Sequence.GetInstance(seq[0].ToAsn1Object());
+
+			if (seq.Count > 1)
+			{
+				this.policies = Asn1Sequence.GetInstance(seq[1].ToAsn1Object());
+			}
+		}
+
+		public OtherSigningCertificate(
+			params OtherCertID[] certs)
+			: this(certs, null)
+		{
+		}
+
+		public OtherSigningCertificate(
+			OtherCertID[]				certs,
+			params PolicyInformation[]	policies)
+		{
+			if (certs == null)
+				throw new ArgumentNullException("certs");
+
+			this.certs = new DerSequence(certs);
+
+			if (policies != null)
+			{
+				this.policies = new DerSequence(policies);
+			}
+		}
+
+		public OtherSigningCertificate(
+			IEnumerable certs)
+			: this(certs, null)
+		{
+		}
+
+		public OtherSigningCertificate(
+			IEnumerable	certs,
+			IEnumerable	policies)
+		{
+			if (certs == null)
+				throw new ArgumentNullException("certs");
+			if (!CollectionUtilities.CheckElementsAreOfType(certs, typeof(OtherCertID)))
+				throw new ArgumentException("Must contain only 'OtherCertID' objects", "certs");
+
+			this.certs = new DerSequence(
+				Asn1EncodableVector.FromEnumerable(certs));
+
+			if (policies != null)
+			{
+				if (!CollectionUtilities.CheckElementsAreOfType(policies, typeof(PolicyInformation)))
+					throw new ArgumentException("Must contain only 'PolicyInformation' objects", "policies");
+
+				this.policies = new DerSequence(
+					Asn1EncodableVector.FromEnumerable(policies));
+			}
+		}
+
+		public OtherCertID[] GetCerts()
+		{
+			OtherCertID[] cs = new OtherCertID[certs.Count];
+			for (int i = 0; i < certs.Count; ++i)
+			{
+				cs[i] = OtherCertID.GetInstance(certs[i].ToAsn1Object());
+			}
+			return cs;
+		}
+
+		public PolicyInformation[] GetPolicies()
+		{
+			if (policies == null)
+				return null;
+
+			PolicyInformation[] ps = new PolicyInformation[policies.Count];
+			for (int i = 0; i < policies.Count; ++i)
+			{
+				ps[i] = PolicyInformation.GetInstance(policies[i].ToAsn1Object());
+			}
+			return ps;
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(certs);
+
+			if (policies != null)
+			{
+				v.Add(policies);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/esf/RevocationValues.cs b/Crypto/src/asn1/esf/RevocationValues.cs
new file mode 100644
index 000000000..a7b47b47a
--- /dev/null
+++ b/Crypto/src/asn1/esf/RevocationValues.cs
@@ -0,0 +1,165 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 5126: 6.3.4.  revocation-values Attribute Definition
+	/// <code>
+	/// RevocationValues ::=  SEQUENCE {
+	///		crlVals			[0] SEQUENCE OF CertificateList     OPTIONAL,
+	///		ocspVals		[1] SEQUENCE OF BasicOCSPResponse   OPTIONAL,
+	///		otherRevVals	[2] OtherRevVals OPTIONAL
+	/// }
+	/// </code>
+	/// </remarks>
+	public class RevocationValues
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence	crlVals;
+		private readonly Asn1Sequence	ocspVals;
+		private readonly OtherRevVals	otherRevVals;
+
+		public static RevocationValues GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is RevocationValues)
+				return (RevocationValues) obj;
+
+			return new RevocationValues(Asn1Sequence.GetInstance(obj));
+		}
+
+		private RevocationValues(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count > 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			foreach (Asn1TaggedObject taggedObj in seq)
+			{
+				Asn1Object asn1Obj = taggedObj.GetObject();
+				switch (taggedObj.TagNo)
+				{
+					case 0:
+						Asn1Sequence crlValsSeq = (Asn1Sequence) asn1Obj;
+						foreach (Asn1Encodable ae in crlValsSeq)
+						{
+							CertificateList.GetInstance(ae.ToAsn1Object());
+						}
+						this.crlVals = crlValsSeq;
+						break;
+					case 1:
+						Asn1Sequence ocspValsSeq = (Asn1Sequence) asn1Obj;
+						foreach (Asn1Encodable ae in ocspValsSeq)
+						{
+							BasicOcspResponse.GetInstance(ae.ToAsn1Object());
+						}
+						this.ocspVals = ocspValsSeq;
+						break;
+					case 2:
+						this.otherRevVals = OtherRevVals.GetInstance(asn1Obj);
+						break;
+					default:
+						throw new ArgumentException("Illegal tag in RevocationValues", "seq");
+				}
+			}
+		}
+
+		public RevocationValues(
+			CertificateList[]	crlVals,
+			BasicOcspResponse[]	ocspVals,
+			OtherRevVals		otherRevVals)
+		{
+			if (crlVals != null)
+			{
+				this.crlVals = new DerSequence(crlVals);
+			}
+
+			if (ocspVals != null)
+			{
+				this.ocspVals = new DerSequence(ocspVals);
+			}
+
+			this.otherRevVals = otherRevVals;
+		}
+
+		public RevocationValues(
+			IEnumerable			crlVals,
+			IEnumerable			ocspVals,
+			OtherRevVals		otherRevVals)
+		{
+			if (crlVals != null)
+			{
+				if (!CollectionUtilities.CheckElementsAreOfType(crlVals, typeof(CertificateList)))
+					throw new ArgumentException("Must contain only 'CertificateList' objects", "crlVals");
+
+				this.crlVals = new DerSequence(
+					Asn1EncodableVector.FromEnumerable(crlVals));
+			}
+
+			if (ocspVals != null)
+			{
+				if (!CollectionUtilities.CheckElementsAreOfType(ocspVals, typeof(BasicOcspResponse)))
+					throw new ArgumentException("Must contain only 'BasicOcspResponse' objects", "ocspVals");
+
+				this.ocspVals = new DerSequence(
+					Asn1EncodableVector.FromEnumerable(ocspVals));
+			}
+
+			this.otherRevVals = otherRevVals;
+		}
+
+		public CertificateList[] GetCrlVals()
+		{
+			CertificateList[] result = new CertificateList[crlVals.Count];
+			for (int i = 0; i < crlVals.Count; ++i)
+			{
+				result[i] = CertificateList.GetInstance(crlVals[i].ToAsn1Object());
+			}
+			return result;
+		}
+
+		public BasicOcspResponse[] GetOcspVals()
+		{
+			BasicOcspResponse[] result = new BasicOcspResponse[ocspVals.Count];
+			for (int i = 0; i < ocspVals.Count; ++i)
+			{
+				result[i] = BasicOcspResponse.GetInstance(ocspVals[i].ToAsn1Object());
+			}
+			return result;
+		}
+
+		public OtherRevVals OtherRevVals
+		{
+			get { return otherRevVals; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (crlVals != null)
+			{
+				v.Add(new DerTaggedObject(true, 0, crlVals));
+			}
+
+			if (ocspVals != null)
+			{
+				v.Add(new DerTaggedObject(true, 1, ocspVals));
+			}
+
+			if (otherRevVals != null)
+			{
+				v.Add(new DerTaggedObject(true, 2, otherRevVals.ToAsn1Object()));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/esf/SigPolicyQualifierInfo.cs b/Crypto/src/asn1/esf/SigPolicyQualifierInfo.cs
new file mode 100644
index 000000000..2d36bc751
--- /dev/null
+++ b/Crypto/src/asn1/esf/SigPolicyQualifierInfo.cs
@@ -0,0 +1,71 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// <code>
+	/// SigPolicyQualifierInfo ::= SEQUENCE {
+    ///		sigPolicyQualifierId  SigPolicyQualifierId,
+	///		sigQualifier          ANY DEFINED BY sigPolicyQualifierId
+	/// }
+	/// 
+	/// SigPolicyQualifierId ::= OBJECT IDENTIFIER
+	/// </code>
+	/// </remarks>
+	public class SigPolicyQualifierInfo
+		: Asn1Encodable
+	{
+		private readonly DerObjectIdentifier	sigPolicyQualifierId;
+		private readonly Asn1Object				sigQualifier;
+
+		public static SigPolicyQualifierInfo GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is SigPolicyQualifierInfo)
+				return (SigPolicyQualifierInfo) obj;
+
+			if (obj is Asn1Sequence)
+				return new SigPolicyQualifierInfo((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'SigPolicyQualifierInfo' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private SigPolicyQualifierInfo(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.sigPolicyQualifierId = (DerObjectIdentifier) seq[0].ToAsn1Object();
+			this.sigQualifier = seq[1].ToAsn1Object();
+		}
+
+		public SigPolicyQualifierInfo(
+			DerObjectIdentifier	sigPolicyQualifierId,
+			Asn1Encodable		sigQualifier)
+		{
+			this.sigPolicyQualifierId = sigPolicyQualifierId;
+			this.sigQualifier = sigQualifier.ToAsn1Object();
+		}
+
+		public DerObjectIdentifier SigPolicyQualifierId
+		{
+			get { return sigPolicyQualifierId; }
+		}
+
+		public Asn1Object SigQualifier
+		{
+			get { return sigQualifier; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(sigPolicyQualifierId, sigQualifier);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/esf/SignaturePolicyId.cs b/Crypto/src/asn1/esf/SignaturePolicyId.cs
new file mode 100644
index 000000000..545be2cf4
--- /dev/null
+++ b/Crypto/src/asn1/esf/SignaturePolicyId.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// <code>
+	/// SignaturePolicyId ::= SEQUENCE {
+	/// 	sigPolicyIdentifier		SigPolicyId,
+	/// 	sigPolicyHash			SigPolicyHash,
+	/// 	sigPolicyQualifiers		SEQUENCE SIZE (1..MAX) OF SigPolicyQualifierInfo OPTIONAL
+	/// }
+	/// 
+	/// SigPolicyId ::= OBJECT IDENTIFIER
+	/// 
+	/// SigPolicyHash ::= OtherHashAlgAndValue
+	/// </code>
+	/// </remarks>
+	public class SignaturePolicyId
+		: Asn1Encodable
+	{
+		private readonly DerObjectIdentifier	sigPolicyIdentifier;
+		private readonly OtherHashAlgAndValue	sigPolicyHash;
+		private readonly Asn1Sequence			sigPolicyQualifiers;
+
+		public static SignaturePolicyId GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is SignaturePolicyId)
+				return (SignaturePolicyId) obj;
+
+			if (obj is Asn1Sequence)
+				return new SignaturePolicyId((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'SignaturePolicyId' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private SignaturePolicyId(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count < 2 || seq.Count > 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.sigPolicyIdentifier = (DerObjectIdentifier) seq[0].ToAsn1Object();
+			this.sigPolicyHash = OtherHashAlgAndValue.GetInstance(seq[1].ToAsn1Object());
+
+			if (seq.Count > 2)
+			{
+				this.sigPolicyQualifiers = (Asn1Sequence) seq[2].ToAsn1Object();
+			}
+		}
+
+		public SignaturePolicyId(
+			DerObjectIdentifier		sigPolicyIdentifier,
+			OtherHashAlgAndValue	sigPolicyHash)
+			: this(sigPolicyIdentifier, sigPolicyHash, null)
+		{
+		}
+
+		public SignaturePolicyId(
+			DerObjectIdentifier				sigPolicyIdentifier,
+			OtherHashAlgAndValue			sigPolicyHash,
+			params SigPolicyQualifierInfo[]	sigPolicyQualifiers)
+		{
+			if (sigPolicyIdentifier == null)
+				throw new ArgumentNullException("sigPolicyIdentifier");
+			if (sigPolicyHash == null)
+				throw new ArgumentNullException("sigPolicyHash");
+
+			this.sigPolicyIdentifier = sigPolicyIdentifier;
+			this.sigPolicyHash = sigPolicyHash;
+
+			if (sigPolicyQualifiers != null)
+			{
+				this.sigPolicyQualifiers = new DerSequence(sigPolicyQualifiers);
+			}
+		}
+
+		public SignaturePolicyId(
+			DerObjectIdentifier		sigPolicyIdentifier,
+			OtherHashAlgAndValue	sigPolicyHash,
+			IEnumerable				sigPolicyQualifiers)
+		{
+			if (sigPolicyIdentifier == null)
+				throw new ArgumentNullException("sigPolicyIdentifier");
+			if (sigPolicyHash == null)
+				throw new ArgumentNullException("sigPolicyHash");
+
+			this.sigPolicyIdentifier = sigPolicyIdentifier;
+			this.sigPolicyHash = sigPolicyHash;
+
+			if (sigPolicyQualifiers != null)
+			{
+				if (!CollectionUtilities.CheckElementsAreOfType(sigPolicyQualifiers, typeof(SigPolicyQualifierInfo)))
+					throw new ArgumentException("Must contain only 'SigPolicyQualifierInfo' objects", "sigPolicyQualifiers");
+
+				this.sigPolicyQualifiers = new DerSequence(
+					Asn1EncodableVector.FromEnumerable(sigPolicyQualifiers));
+			}
+		}
+
+		public DerObjectIdentifier SigPolicyIdentifier
+		{
+			get { return sigPolicyIdentifier; }
+		}
+
+		public OtherHashAlgAndValue SigPolicyHash
+		{
+			get { return sigPolicyHash; }
+		}
+
+		public SigPolicyQualifierInfo[] GetSigPolicyQualifiers()
+		{
+			if (sigPolicyQualifiers == null)
+				return null;
+
+			SigPolicyQualifierInfo[] infos = new SigPolicyQualifierInfo[sigPolicyQualifiers.Count];
+			for (int i = 0; i < sigPolicyQualifiers.Count; ++i)
+			{
+				infos[i] = SigPolicyQualifierInfo.GetInstance(sigPolicyQualifiers[i]);
+			}
+			return infos;
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				sigPolicyIdentifier, sigPolicyHash.ToAsn1Object());
+
+			if (sigPolicyQualifiers != null)
+			{
+				v.Add(sigPolicyQualifiers.ToAsn1Object());
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/esf/SignaturePolicyIdentifier.cs b/Crypto/src/asn1/esf/SignaturePolicyIdentifier.cs
new file mode 100644
index 000000000..3a639f444
--- /dev/null
+++ b/Crypto/src/asn1/esf/SignaturePolicyIdentifier.cs
@@ -0,0 +1,64 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// <code>
+	/// SignaturePolicyIdentifier ::= CHOICE {
+	///		SignaturePolicyId		SignaturePolicyId,
+	///		SignaturePolicyImplied	SignaturePolicyImplied
+	/// }
+	/// 
+	/// SignaturePolicyImplied ::= NULL
+	/// </code>
+	/// </remarks>
+	public class SignaturePolicyIdentifier
+		: Asn1Encodable, IAsn1Choice
+	{
+		private readonly SignaturePolicyId sigPolicy;
+
+		public static SignaturePolicyIdentifier GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is SignaturePolicyIdentifier)
+				return (SignaturePolicyIdentifier) obj;
+
+			if (obj is SignaturePolicyId)
+				return new SignaturePolicyIdentifier((SignaturePolicyId) obj);
+
+			if (obj is Asn1Null)
+				return new SignaturePolicyIdentifier();
+
+			throw new ArgumentException(
+				"Unknown object in 'SignaturePolicyIdentifier' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		public SignaturePolicyIdentifier()
+		{
+			this.sigPolicy = null;
+		}
+
+		public SignaturePolicyIdentifier(
+			SignaturePolicyId signaturePolicyId)
+		{
+			if (signaturePolicyId == null)
+				throw new ArgumentNullException("signaturePolicyId");
+
+			this.sigPolicy = signaturePolicyId;
+		}
+
+		public SignaturePolicyId SignaturePolicyId
+		{
+			get { return sigPolicy; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return sigPolicy == null
+				?	DerNull.Instance
+				:	sigPolicy.ToAsn1Object();
+		}
+	}
+}
diff --git a/Crypto/src/asn1/esf/SignerAttribute.cs b/Crypto/src/asn1/esf/SignerAttribute.cs
new file mode 100644
index 000000000..ddee53c69
--- /dev/null
+++ b/Crypto/src/asn1/esf/SignerAttribute.cs
@@ -0,0 +1,96 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	public class SignerAttribute
+		: Asn1Encodable
+	{
+		private Asn1Sequence			claimedAttributes;
+		private AttributeCertificate	certifiedAttributes;
+
+		public static SignerAttribute GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is SignerAttribute)
+				return (SignerAttribute) obj;
+
+			if (obj is Asn1Sequence)
+				return new SignerAttribute(obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'SignerAttribute' factory: "
+				+ obj.GetType().Name,
+				"obj");
+		}
+
+		private SignerAttribute(
+			object obj)
+		{
+			Asn1Sequence seq = (Asn1Sequence) obj;
+			DerTaggedObject taggedObject = (DerTaggedObject) seq[0];
+			if (taggedObject.TagNo == 0)
+			{
+				claimedAttributes = Asn1Sequence.GetInstance(taggedObject, true);
+			}
+			else if (taggedObject.TagNo == 1)
+			{
+				certifiedAttributes = AttributeCertificate.GetInstance(taggedObject);
+			}
+			else
+			{
+				throw new ArgumentException("illegal tag.", "obj");
+			}
+		}
+
+		public SignerAttribute(
+			Asn1Sequence claimedAttributes)
+		{
+			this.claimedAttributes = claimedAttributes;
+		}
+
+		public SignerAttribute(
+			AttributeCertificate certifiedAttributes)
+		{
+			this.certifiedAttributes = certifiedAttributes;
+		}
+
+		public virtual Asn1Sequence ClaimedAttributes
+		{
+			get { return claimedAttributes; }
+		}
+
+		public virtual AttributeCertificate CertifiedAttributes
+		{
+			get { return certifiedAttributes; }
+		}
+
+		/**
+		*
+		* <pre>
+		*  SignerAttribute ::= SEQUENCE OF CHOICE {
+		*      claimedAttributes   [0] ClaimedAttributes,
+		*      certifiedAttributes [1] CertifiedAttributes }
+		*
+		*  ClaimedAttributes ::= SEQUENCE OF Attribute
+		*  CertifiedAttributes ::= AttributeCertificate -- as defined in RFC 3281: see clause 4.1.
+		* </pre>
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (claimedAttributes != null)
+			{
+				v.Add(new DerTaggedObject(0, claimedAttributes));
+			}
+			else
+			{
+				v.Add(new DerTaggedObject(1, certifiedAttributes));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/esf/SignerLocation.cs b/Crypto/src/asn1/esf/SignerLocation.cs
new file mode 100644
index 000000000..d2cef51bb
--- /dev/null
+++ b/Crypto/src/asn1/esf/SignerLocation.cs
@@ -0,0 +1,144 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/**
+	* Signer-Location attribute (RFC3126).
+	*
+	* <pre>
+	*   SignerLocation ::= SEQUENCE {
+	*       countryName        [0] DirectoryString OPTIONAL,
+	*       localityName       [1] DirectoryString OPTIONAL,
+	*       postalAddress      [2] PostalAddress OPTIONAL }
+	*
+	*   PostalAddress ::= SEQUENCE SIZE(1..6) OF DirectoryString
+	* </pre>
+	*/
+	public class SignerLocation
+		: Asn1Encodable
+	{
+		// TODO Should these be using DirectoryString?
+		private DerUtf8String	countryName;
+		private DerUtf8String	localityName;
+		private Asn1Sequence	postalAddress;
+
+		public SignerLocation(
+			Asn1Sequence seq)
+		{
+			foreach (Asn1TaggedObject obj in seq)
+			{
+				switch (obj.TagNo)
+				{
+					case 0:
+						this.countryName = DerUtf8String.GetInstance(obj, true);
+						break;
+					case 1:
+						this.localityName = DerUtf8String.GetInstance(obj, true);
+						break;
+					case 2:
+						bool isExplicit = obj.IsExplicit();	// handle erroneous implicitly tagged sequences
+						this.postalAddress = Asn1Sequence.GetInstance(obj, isExplicit);
+						if (postalAddress != null && postalAddress.Count > 6)
+							throw new ArgumentException("postal address must contain less than 6 strings");
+						break;
+					default:
+						throw new ArgumentException("illegal tag");
+				}
+			}
+		}
+
+		public SignerLocation(
+			DerUtf8String	countryName,
+			DerUtf8String	localityName,
+			Asn1Sequence	postalAddress)
+		{
+			if (postalAddress != null && postalAddress.Count > 6)
+			{
+				throw new ArgumentException("postal address must contain less than 6 strings");
+			}
+
+			if (countryName != null)
+			{
+				this.countryName = DerUtf8String.GetInstance(countryName.ToAsn1Object());
+			}
+
+			if (localityName != null)
+			{
+				this.localityName = DerUtf8String.GetInstance(localityName.ToAsn1Object());
+			}
+
+			if (postalAddress != null)
+			{
+				this.postalAddress = (Asn1Sequence) postalAddress.ToAsn1Object();
+			}
+		}
+
+		public static SignerLocation GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is SignerLocation)
+			{
+				return (SignerLocation) obj;
+			}
+
+			return new SignerLocation(Asn1Sequence.GetInstance(obj));
+		}
+
+		public DerUtf8String CountryName
+		{
+			get { return countryName; }
+		}
+
+		public DerUtf8String LocalityName
+		{
+			get { return localityName; }
+		}
+
+		public Asn1Sequence PostalAddress
+		{
+			get { return postalAddress; }
+		}
+
+		/**
+		* <pre>
+		*   SignerLocation ::= SEQUENCE {
+		*       countryName        [0] DirectoryString OPTIONAL,
+		*       localityName       [1] DirectoryString OPTIONAL,
+		*       postalAddress      [2] PostalAddress OPTIONAL }
+		*
+		*   PostalAddress ::= SEQUENCE SIZE(1..6) OF DirectoryString
+		*
+		*   DirectoryString ::= CHOICE {
+		*         teletexString           TeletexString (SIZE (1..MAX)),
+		*         printableString         PrintableString (SIZE (1..MAX)),
+		*         universalString         UniversalString (SIZE (1..MAX)),
+		*         utf8String              UTF8String (SIZE (1.. MAX)),
+		*         bmpString               BMPString (SIZE (1..MAX)) }
+		* </pre>
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (countryName != null)
+			{
+				v.Add(new DerTaggedObject(true, 0, countryName));
+			}
+
+			if (localityName != null)
+			{
+				v.Add(new DerTaggedObject(true, 1, localityName));
+			}
+
+			if (postalAddress != null)
+			{
+				v.Add(new DerTaggedObject(true, 2, postalAddress));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/ess/ContentHints.cs b/Crypto/src/asn1/ess/ContentHints.cs
new file mode 100644
index 000000000..a430fea8d
--- /dev/null
+++ b/Crypto/src/asn1/ess/ContentHints.cs
@@ -0,0 +1,92 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+	public class ContentHints
+		: Asn1Encodable
+	{
+		private readonly DerUtf8String contentDescription;
+		private readonly DerObjectIdentifier contentType;
+
+		public static ContentHints GetInstance(
+			object o)
+		{
+			if (o == null || o is ContentHints)
+			{
+				return (ContentHints)o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new ContentHints((Asn1Sequence)o);
+			}
+
+			throw new ArgumentException("unknown object in 'ContentHints' factory : "
+				+ o.GetType().Name + ".");
+		}
+
+		/**
+		 * constructor
+		 */
+		private ContentHints(
+			Asn1Sequence seq)
+		{
+			IAsn1Convertible field = seq[0];
+			if (field.ToAsn1Object() is DerUtf8String)
+			{
+				contentDescription = DerUtf8String.GetInstance(field);
+				contentType = DerObjectIdentifier.GetInstance(seq[1]);
+			}
+			else
+			{
+				contentType = DerObjectIdentifier.GetInstance(seq[0]);
+			}
+		}
+
+		public ContentHints(
+			DerObjectIdentifier contentType)
+		{
+			this.contentType = contentType;
+			this.contentDescription = null;
+		}
+
+		public ContentHints(
+			DerObjectIdentifier	contentType,
+			DerUtf8String		contentDescription)
+		{
+			this.contentType = contentType;
+			this.contentDescription = contentDescription;
+		}
+
+		public DerObjectIdentifier ContentType
+		{
+			get { return contentType; }
+		}
+
+		public DerUtf8String ContentDescription
+		{
+			get { return contentDescription; }
+		}
+
+		/**
+		 * <pre>
+		 * ContentHints ::= SEQUENCE {
+		 *   contentDescription UTF8String (SIZE (1..MAX)) OPTIONAL,
+		 *   contentType ContentType }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (contentDescription != null)
+			{
+				v.Add(contentDescription);
+			}
+
+			v.Add(contentType);
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/ess/ContentIdentifier.cs b/Crypto/src/asn1/ess/ContentIdentifier.cs
new file mode 100644
index 000000000..8058dcc53
--- /dev/null
+++ b/Crypto/src/asn1/ess/ContentIdentifier.cs
@@ -0,0 +1,65 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+	public class ContentIdentifier
+		: Asn1Encodable
+	{
+		private Asn1OctetString value;
+
+		public static ContentIdentifier GetInstance(
+			object o)
+		{
+			if (o == null || o is ContentIdentifier)
+			{
+				return (ContentIdentifier) o;
+			}
+
+			if (o is Asn1OctetString)
+			{
+				return new ContentIdentifier((Asn1OctetString) o);
+			}
+
+			throw new ArgumentException(
+				"unknown object in 'ContentIdentifier' factory : "
+				+ o.GetType().Name + ".");
+		}
+
+		/**
+		 * Create from OCTET STRING whose octets represent the identifier.
+		 */
+		public ContentIdentifier(
+			Asn1OctetString value)
+		{
+			this.value = value;
+		}
+
+		/**
+		 * Create from byte array representing the identifier.
+		 */
+		public ContentIdentifier(
+			byte[] value)
+			: this(new DerOctetString(value))
+		{
+		}
+
+		public Asn1OctetString Value
+		{
+			get { return value; }
+		}
+
+		/**
+		 * The definition of ContentIdentifier is
+		 * <pre>
+		 * ContentIdentifier ::=  OCTET STRING
+		 * </pre>
+		 * id-aa-contentIdentifier OBJECT IDENTIFIER ::= { iso(1)
+		 *  member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
+		 *  smime(16) id-aa(2) 7 }
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return value;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/ess/ESSCertID.cs b/Crypto/src/asn1/ess/ESSCertID.cs
new file mode 100644
index 000000000..4d449a746
--- /dev/null
+++ b/Crypto/src/asn1/ess/ESSCertID.cs
@@ -0,0 +1,93 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+	public class EssCertID
+		: Asn1Encodable
+	{
+		private Asn1OctetString certHash;
+		private IssuerSerial issuerSerial;
+
+		public static EssCertID GetInstance(
+			object o)
+		{
+			if (o == null || o is EssCertID)
+			{
+				return (EssCertID) o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new EssCertID((Asn1Sequence) o);
+			}
+
+			throw new ArgumentException(
+				"unknown object in 'EssCertID' factory : "
+				+ o.GetType().Name + ".");
+		}
+
+		/**
+		 * constructor
+		 */
+		public EssCertID(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1 || seq.Count > 2)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			this.certHash = Asn1OctetString.GetInstance(seq[0]);
+
+			if (seq.Count > 1)
+			{
+				issuerSerial = IssuerSerial.GetInstance(seq[1]);
+			}
+		}
+
+		public EssCertID(
+			byte[] hash)
+		{
+			certHash = new DerOctetString(hash);
+		}
+
+		public EssCertID(
+			byte[]			hash,
+			IssuerSerial	issuerSerial)
+		{
+			this.certHash = new DerOctetString(hash);
+			this.issuerSerial = issuerSerial;
+		}
+
+		public byte[] GetCertHash()
+		{
+			return certHash.GetOctets();
+		}
+
+		public IssuerSerial IssuerSerial
+		{
+			get { return issuerSerial; }
+		}
+
+		/**
+		 * <pre>
+		 * EssCertID ::= SEQUENCE {
+		 *     certHash Hash,
+		 *     issuerSerial IssuerSerial OPTIONAL }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(certHash);
+
+			if (issuerSerial != null)
+			{
+				v.Add(issuerSerial);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/ess/ESSCertIDv2.cs b/Crypto/src/asn1/ess/ESSCertIDv2.cs
new file mode 100644
index 000000000..1d154cd27
--- /dev/null
+++ b/Crypto/src/asn1/ess/ESSCertIDv2.cs
@@ -0,0 +1,138 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+	public class EssCertIDv2
+		: Asn1Encodable
+	{
+		private readonly AlgorithmIdentifier hashAlgorithm;
+		private readonly byte[]              certHash;
+		private readonly IssuerSerial        issuerSerial;
+
+		private static readonly AlgorithmIdentifier DefaultAlgID = new AlgorithmIdentifier(
+			NistObjectIdentifiers.IdSha256);
+
+		public static EssCertIDv2 GetInstance(
+			object o)
+		{
+			if (o == null || o is EssCertIDv2)
+				return (EssCertIDv2) o;
+
+			if (o is Asn1Sequence)
+				return new EssCertIDv2((Asn1Sequence) o);
+
+			throw new ArgumentException(
+				"unknown object in 'EssCertIDv2' factory : "
+				+ o.GetType().Name + ".");
+		}
+
+		private EssCertIDv2(
+			Asn1Sequence seq)
+		{
+			if (seq.Count > 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			int count = 0;
+
+			if (seq[0] is Asn1OctetString)
+			{
+				// Default value
+				this.hashAlgorithm = DefaultAlgID;
+			}
+			else
+			{
+				this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[count++].ToAsn1Object());
+			}
+
+			this.certHash = Asn1OctetString.GetInstance(seq[count++].ToAsn1Object()).GetOctets();
+
+			if (seq.Count > count)
+			{
+				this.issuerSerial = IssuerSerial.GetInstance(
+					Asn1Sequence.GetInstance(seq[count].ToAsn1Object()));
+			}
+		}
+
+		public EssCertIDv2(
+			AlgorithmIdentifier	algId,
+			byte[]				certHash)
+			: this(algId, certHash, null)
+		{
+		}
+
+		public EssCertIDv2(
+			AlgorithmIdentifier	algId,
+			byte[]				certHash,
+			IssuerSerial		issuerSerial)
+		{
+			if (algId == null)
+			{
+				// Default value
+				this.hashAlgorithm = DefaultAlgID;
+			}
+			else
+			{
+				this.hashAlgorithm = algId;
+			}
+
+			this.certHash = certHash;
+			this.issuerSerial = issuerSerial;
+		}
+
+		public AlgorithmIdentifier HashAlgorithm
+		{
+			get { return this.hashAlgorithm; }
+		}
+
+		public byte[] GetCertHash()
+		{
+			return Arrays.Clone(certHash);
+		}
+
+		public IssuerSerial IssuerSerial
+		{
+			get { return issuerSerial; }
+		}
+
+		/**
+		 * <pre>
+		 * EssCertIDv2 ::=  SEQUENCE {
+		 *     hashAlgorithm     AlgorithmIdentifier
+		 *              DEFAULT {algorithm id-sha256},
+		 *     certHash          Hash,
+		 *     issuerSerial      IssuerSerial OPTIONAL
+		 * }
+		 *
+		 * Hash ::= OCTET STRING
+		 *
+		 * IssuerSerial ::= SEQUENCE {
+		 *     issuer         GeneralNames,
+		 *     serialNumber   CertificateSerialNumber
+		 * }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (!hashAlgorithm.Equals(DefaultAlgID))
+			{
+				v.Add(hashAlgorithm);
+			}
+
+			v.Add(new DerOctetString(certHash).ToAsn1Object());
+
+			if (issuerSerial != null)
+			{
+				v.Add(issuerSerial);
+			}
+
+			return new DerSequence(v);
+		}
+
+	}
+}
diff --git a/Crypto/src/asn1/ess/OtherCertID.cs b/Crypto/src/asn1/ess/OtherCertID.cs
new file mode 100644
index 000000000..972ef8c6b
--- /dev/null
+++ b/Crypto/src/asn1/ess/OtherCertID.cs
@@ -0,0 +1,132 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+	[Obsolete("Use version in Asn1.Esf instead")]
+	public class OtherCertID
+		: Asn1Encodable
+	{
+		private Asn1Encodable otherCertHash;
+		private IssuerSerial issuerSerial;
+
+		public static OtherCertID GetInstance(
+			object o)
+		{
+			if (o == null || o is OtherCertID)
+			{
+				return (OtherCertID) o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new OtherCertID((Asn1Sequence) o);
+			}
+
+			throw new ArgumentException(
+				"unknown object in 'OtherCertID' factory : "
+				+ o.GetType().Name + ".");
+		}
+
+		/**
+		 * constructor
+		 */
+		public OtherCertID(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1 || seq.Count > 2)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			if (seq[0].ToAsn1Object() is Asn1OctetString)
+			{
+				otherCertHash = Asn1OctetString.GetInstance(seq[0]);
+			}
+			else
+			{
+				otherCertHash = DigestInfo.GetInstance(seq[0]);
+			}
+
+			if (seq.Count > 1)
+			{
+				issuerSerial = IssuerSerial.GetInstance(Asn1Sequence.GetInstance(seq[1]));
+			}
+		}
+
+		public OtherCertID(
+			AlgorithmIdentifier	algId,
+			byte[]				digest)
+		{
+			this.otherCertHash = new DigestInfo(algId, digest);
+		}
+
+		public OtherCertID(
+			AlgorithmIdentifier	algId,
+			byte[]				digest,
+			IssuerSerial		issuerSerial)
+		{
+			this.otherCertHash = new DigestInfo(algId, digest);
+			this.issuerSerial = issuerSerial;
+		}
+
+		public AlgorithmIdentifier AlgorithmHash
+		{
+			get
+			{
+				if (otherCertHash.ToAsn1Object() is Asn1OctetString)
+				{
+					// SHA-1
+					return new AlgorithmIdentifier("1.3.14.3.2.26");
+				}
+
+				return DigestInfo.GetInstance(otherCertHash).AlgorithmID;
+			}
+		}
+
+		public byte[] GetCertHash()
+		{
+			if (otherCertHash.ToAsn1Object() is Asn1OctetString)
+			{
+				// SHA-1
+				return ((Asn1OctetString) otherCertHash.ToAsn1Object()).GetOctets();
+			}
+
+			return DigestInfo.GetInstance(otherCertHash).GetDigest();
+		}
+
+		public IssuerSerial IssuerSerial
+		{
+			get { return issuerSerial; }
+		}
+
+		/**
+		 * <pre>
+		 * OtherCertID ::= SEQUENCE {
+		 *     otherCertHash    OtherHash,
+		 *     issuerSerial     IssuerSerial OPTIONAL }
+		 *
+		 * OtherHash ::= CHOICE {
+		 *     sha1Hash     OCTET STRING,
+		 *     otherHash    OtherHashAlgAndValue }
+		 *
+		 * OtherHashAlgAndValue ::= SEQUENCE {
+		 *     hashAlgorithm    AlgorithmIdentifier,
+		 *     hashValue        OCTET STRING }
+		 *
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(otherCertHash);
+
+			if (issuerSerial != null)
+			{
+				v.Add(issuerSerial);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/ess/OtherSigningCertificate.cs b/Crypto/src/asn1/ess/OtherSigningCertificate.cs
new file mode 100644
index 000000000..c165fecea
--- /dev/null
+++ b/Crypto/src/asn1/ess/OtherSigningCertificate.cs
@@ -0,0 +1,109 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+	[Obsolete("Use version in Asn1.Esf instead")]
+	public class OtherSigningCertificate
+		: Asn1Encodable
+	{
+		private Asn1Sequence certs, policies;
+
+		public static OtherSigningCertificate GetInstance(
+			object o)
+		{
+			if (o == null || o is OtherSigningCertificate)
+			{
+				return (OtherSigningCertificate) o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new OtherSigningCertificate((Asn1Sequence) o);
+			}
+
+			throw new ArgumentException(
+				"unknown object in 'OtherSigningCertificate' factory : "
+				+ o.GetType().Name + ".");
+		}
+
+		/**
+		 * constructors
+		 */
+		public OtherSigningCertificate(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1 || seq.Count > 2)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			this.certs = Asn1Sequence.GetInstance(seq[0]);
+
+			if (seq.Count > 1)
+			{
+				this.policies = Asn1Sequence.GetInstance(seq[1]);
+			}
+		}
+
+		public OtherSigningCertificate(
+			OtherCertID otherCertID)
+		{
+			certs = new DerSequence(otherCertID);
+		}
+
+		public OtherCertID[] GetCerts()
+		{
+			OtherCertID[] cs = new OtherCertID[certs.Count];
+
+			for (int i = 0; i != certs.Count; ++i)
+			{
+				cs[i] = OtherCertID.GetInstance(certs[i]);
+			}
+
+			return cs;
+		}
+
+		public PolicyInformation[] GetPolicies()
+		{
+			if (policies == null)
+			{
+				return null;
+			}
+
+			PolicyInformation[] ps = new PolicyInformation[policies.Count];
+
+			for (int i = 0; i != policies.Count; i++)
+			{
+				ps[i] = PolicyInformation.GetInstance(policies[i]);
+			}
+
+			return ps;
+		}
+
+		/**
+		 * The definition of OtherSigningCertificate is
+		 * <pre>
+		 * OtherSigningCertificate ::=  SEQUENCE {
+		 *      certs        SEQUENCE OF OtherCertID,
+		 *      policies     SEQUENCE OF PolicyInformation OPTIONAL
+		 * }
+		 * </pre>
+		 * id-aa-ets-otherSigCert OBJECT IDENTIFIER ::= { iso(1)
+		 *  member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
+		 *  smime(16) id-aa(2) 19 }
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(certs);
+
+			if (policies != null)
+			{
+				v.Add(policies);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/ess/SigningCertificate.cs b/Crypto/src/asn1/ess/SigningCertificate.cs
new file mode 100644
index 000000000..366749bc3
--- /dev/null
+++ b/Crypto/src/asn1/ess/SigningCertificate.cs
@@ -0,0 +1,108 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+	public class SigningCertificate
+		: Asn1Encodable
+	{
+		private Asn1Sequence certs, policies;
+
+		public static SigningCertificate GetInstance(
+			object o)
+		{
+			if (o == null || o is SigningCertificate)
+			{
+				return (SigningCertificate) o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new SigningCertificate((Asn1Sequence) o);
+			}
+
+			throw new ArgumentException(
+				"unknown object in 'SigningCertificate' factory : "
+				+ o.GetType().Name + ".");
+		}
+
+		/**
+		 * constructors
+		 */
+		public SigningCertificate(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1 || seq.Count > 2)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			this.certs = Asn1Sequence.GetInstance(seq[0]);
+
+			if (seq.Count > 1)
+			{
+				this.policies = Asn1Sequence.GetInstance(seq[1]);
+			}
+		}
+
+		public SigningCertificate(
+			EssCertID essCertID)
+		{
+			certs = new DerSequence(essCertID);
+		}
+
+		public EssCertID[] GetCerts()
+		{
+			EssCertID[] cs = new EssCertID[certs.Count];
+
+			for (int i = 0; i != certs.Count; i++)
+			{
+				cs[i] = EssCertID.GetInstance(certs[i]);
+			}
+
+			return cs;
+		}
+
+		public PolicyInformation[] GetPolicies()
+		{
+			if (policies == null)
+			{
+				return null;
+			}
+
+			PolicyInformation[] ps = new PolicyInformation[policies.Count];
+
+			for (int i = 0; i != policies.Count; i++)
+			{
+				ps[i] = PolicyInformation.GetInstance(policies[i]);
+			}
+
+			return ps;
+		}
+
+		/**
+		 * The definition of SigningCertificate is
+		 * <pre>
+		 * SigningCertificate ::=  SEQUENCE {
+		 *      certs        SEQUENCE OF EssCertID,
+		 *      policies     SEQUENCE OF PolicyInformation OPTIONAL
+		 * }
+		 * </pre>
+		 * id-aa-signingCertificate OBJECT IDENTIFIER ::= { iso(1)
+		 *  member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
+		 *  smime(16) id-aa(2) 12 }
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(certs);
+
+			if (policies != null)
+			{
+				v.Add(policies);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/ess/SigningCertificateV2.cs b/Crypto/src/asn1/ess/SigningCertificateV2.cs
new file mode 100644
index 000000000..a2aff4866
--- /dev/null
+++ b/Crypto/src/asn1/ess/SigningCertificateV2.cs
@@ -0,0 +1,106 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+	public class SigningCertificateV2
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence certs;
+		private readonly Asn1Sequence policies;
+
+		public static SigningCertificateV2 GetInstance(
+			object o)
+		{
+			if (o == null || o is SigningCertificateV2)
+				return (SigningCertificateV2) o;
+
+			if (o is Asn1Sequence)
+				return new SigningCertificateV2((Asn1Sequence) o);
+
+			throw new ArgumentException(
+				"unknown object in 'SigningCertificateV2' factory : "
+				+ o.GetType().Name + ".");
+		}
+
+		private SigningCertificateV2(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1 || seq.Count > 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.certs = Asn1Sequence.GetInstance(seq[0].ToAsn1Object());
+
+			if (seq.Count > 1)
+			{
+				this.policies = Asn1Sequence.GetInstance(seq[1].ToAsn1Object());
+			}
+		}
+
+		public SigningCertificateV2(
+			EssCertIDv2[] certs)
+		{
+			this.certs = new DerSequence(certs);
+		}
+
+		public SigningCertificateV2(
+			EssCertIDv2[]		certs,
+			PolicyInformation[]	policies)
+		{
+			this.certs = new DerSequence(certs);
+
+			if (policies != null)
+			{
+				this.policies = new DerSequence(policies);
+			}
+		}
+
+		public EssCertIDv2[] GetCerts()
+		{
+			EssCertIDv2[] certIds = new EssCertIDv2[certs.Count];
+			for (int i = 0; i != certs.Count; i++)
+			{
+				certIds[i] = EssCertIDv2.GetInstance(certs[i]);
+			}
+			return certIds;
+		}
+
+		public PolicyInformation[] GetPolicies()
+		{
+			if (policies == null)
+				return null;
+
+			PolicyInformation[] policyInformations = new PolicyInformation[policies.Count];
+			for (int i = 0; i != policies.Count; i++)
+			{
+				policyInformations[i] = PolicyInformation.GetInstance(policies[i]);
+			}
+			return policyInformations;
+		}
+
+		/**
+		 * The definition of SigningCertificateV2 is
+		 * <pre>
+		 * SigningCertificateV2 ::=  SEQUENCE {
+		 *      certs        SEQUENCE OF EssCertIDv2,
+		 *      policies     SEQUENCE OF PolicyInformation OPTIONAL
+		 * }
+		 * </pre>
+		 * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::= { iso(1)
+		 *    member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
+		 *    smime(16) id-aa(2) 47 }
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(certs);
+
+			if (policies != null)
+			{
+				v.Add(policies);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/gnu/GNUObjectIdentifiers.cs b/Crypto/src/asn1/gnu/GNUObjectIdentifiers.cs
new file mode 100644
index 000000000..9311a3ac1
--- /dev/null
+++ b/Crypto/src/asn1/gnu/GNUObjectIdentifiers.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Gnu
+{
+	public abstract class GnuObjectIdentifiers
+	{
+		public static readonly DerObjectIdentifier Gnu					= new DerObjectIdentifier("1.3.6.1.4.1.11591.1"); // GNU Radius
+		public static readonly DerObjectIdentifier GnuPG				= new DerObjectIdentifier("1.3.6.1.4.1.11591.2"); // GnuPG (Ägypten)
+		public static readonly DerObjectIdentifier Notation				= new DerObjectIdentifier("1.3.6.1.4.1.11591.2.1"); // notation
+		public static readonly DerObjectIdentifier PkaAddress			= new DerObjectIdentifier("1.3.6.1.4.1.11591.2.1.1"); // pkaAddress
+		public static readonly DerObjectIdentifier GnuRadar				= new DerObjectIdentifier("1.3.6.1.4.1.11591.3"); // GNU Radar
+		public static readonly DerObjectIdentifier DigestAlgorithm		= new DerObjectIdentifier("1.3.6.1.4.1.11591.12"); // digestAlgorithm
+		public static readonly DerObjectIdentifier Tiger192				= new DerObjectIdentifier("1.3.6.1.4.1.11591.12.2"); // TIGER/192
+		public static readonly DerObjectIdentifier EncryptionAlgorithm	= new DerObjectIdentifier("1.3.6.1.4.1.11591.13"); // encryptionAlgorithm
+		public static readonly DerObjectIdentifier Serpent				= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2"); // Serpent
+		public static readonly DerObjectIdentifier Serpent128Ecb		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.1"); // Serpent-128-ECB
+		public static readonly DerObjectIdentifier Serpent128Cbc		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.2"); // Serpent-128-CBC
+		public static readonly DerObjectIdentifier Serpent128Ofb		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.3"); // Serpent-128-OFB
+		public static readonly DerObjectIdentifier Serpent128Cfb		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.4"); // Serpent-128-CFB
+		public static readonly DerObjectIdentifier Serpent192Ecb		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.21"); // Serpent-192-ECB
+		public static readonly DerObjectIdentifier Serpent192Cbc		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.22"); // Serpent-192-CBC
+		public static readonly DerObjectIdentifier Serpent192Ofb		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.23"); // Serpent-192-OFB
+		public static readonly DerObjectIdentifier Serpent192Cfb		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.24"); // Serpent-192-CFB
+		public static readonly DerObjectIdentifier Serpent256Ecb		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.41"); // Serpent-256-ECB
+		public static readonly DerObjectIdentifier Serpent256Cbc		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.42"); // Serpent-256-CBC
+		public static readonly DerObjectIdentifier Serpent256Ofb		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.43"); // Serpent-256-OFB
+		public static readonly DerObjectIdentifier Serpent256Cfb		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.44"); // Serpent-256-CFB
+		public static readonly DerObjectIdentifier Crc					= new DerObjectIdentifier("1.3.6.1.4.1.11591.14"); // CRC algorithms
+		public static readonly DerObjectIdentifier Crc32				= new DerObjectIdentifier("1.3.6.1.4.1.11591.14.1"); // CRC 32
+	}
+}
diff --git a/Crypto/src/asn1/iana/IANAObjectIdentifiers.cs b/Crypto/src/asn1/iana/IANAObjectIdentifiers.cs
new file mode 100644
index 000000000..63343f5ce
--- /dev/null
+++ b/Crypto/src/asn1/iana/IANAObjectIdentifiers.cs
@@ -0,0 +1,18 @@
+namespace Org.BouncyCastle.Asn1.Iana
+{
+	public abstract class IanaObjectIdentifiers
+	{
+		// id-SHA1 OBJECT IDENTIFIER ::=
+		// {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) ipsec(8) isakmpOakley(1)}
+		//
+
+		public static readonly DerObjectIdentifier IsakmpOakley = new DerObjectIdentifier("1.3.6.1.5.5.8.1");
+
+		public static readonly DerObjectIdentifier HmacMD5 = new DerObjectIdentifier(IsakmpOakley + ".1");
+		public static readonly DerObjectIdentifier HmacSha1 = new DerObjectIdentifier(IsakmpOakley + ".2");
+
+		public static readonly DerObjectIdentifier HmacTiger = new DerObjectIdentifier(IsakmpOakley + ".3");
+
+		public static readonly DerObjectIdentifier HmacRipeMD160 = new DerObjectIdentifier(IsakmpOakley + ".4");
+	}
+}
diff --git a/Crypto/src/asn1/icao/CscaMasterList.cs b/Crypto/src/asn1/icao/CscaMasterList.cs
new file mode 100644
index 000000000..6890d8a2e
--- /dev/null
+++ b/Crypto/src/asn1/icao/CscaMasterList.cs
@@ -0,0 +1,83 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+	/**
+	 * The CscaMasterList object. This object can be wrapped in a
+	 * CMSSignedData to be published in LDAP.
+	 *
+	 * <pre>
+	 * CscaMasterList ::= SEQUENCE {
+	 *   version                CscaMasterListVersion,
+	 *   certList               SET OF Certificate }
+	 *   
+	 * CscaMasterListVersion :: INTEGER {v0(0)}
+	 * </pre>
+	 */
+	public class CscaMasterList 
+		: Asn1Encodable 
+	{
+		private DerInteger version = new DerInteger(0);
+		private X509CertificateStructure[] certList;
+
+		public static CscaMasterList GetInstance(
+			object obj)
+		{
+			if (obj is CscaMasterList)
+				return (CscaMasterList)obj;
+
+			if (obj != null)
+				return new CscaMasterList(Asn1Sequence.GetInstance(obj));            
+
+			return null;
+		}
+
+		private CscaMasterList(
+			Asn1Sequence seq)
+		{
+			if (seq == null || seq.Count == 0)
+				throw new ArgumentException("null or empty sequence passed.");
+
+			if (seq.Count != 2)
+				throw new ArgumentException("Incorrect sequence size: " + seq.Count);
+
+			this.version = DerInteger.GetInstance(seq[0]);
+
+			Asn1Set certSet = Asn1Set.GetInstance(seq[1]);
+
+			this.certList = new X509CertificateStructure[certSet.Count];
+			for (int i = 0; i < certList.Length; i++)
+			{
+				certList[i] = X509CertificateStructure.GetInstance(certSet[i]);
+			}
+		}
+
+		public CscaMasterList(
+			X509CertificateStructure[] certStructs)
+		{
+			certList = CopyCertList(certStructs);
+		}
+
+		public virtual int Version
+		{
+			get { return version.Value.IntValue; }
+		}
+
+		public X509CertificateStructure[] GetCertStructs()
+		{
+			return CopyCertList(certList);
+		}
+
+		private static X509CertificateStructure[] CopyCertList(X509CertificateStructure[] orig)
+		{
+			return (X509CertificateStructure[])orig.Clone();
+		}
+
+		public override Asn1Object ToAsn1Object() 
+		{
+			return new DerSequence(version, new DerSet(certList));
+		}
+	}
+}
diff --git a/Crypto/src/asn1/icao/DataGroupHash.cs b/Crypto/src/asn1/icao/DataGroupHash.cs
new file mode 100644
index 000000000..e0d7eee7b
--- /dev/null
+++ b/Crypto/src/asn1/icao/DataGroupHash.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+    /**
+    * The DataGroupHash object.
+    * <pre>
+    * DataGroupHash  ::=  SEQUENCE {
+    *      dataGroupNumber         DataGroupNumber,
+    *      dataGroupHashValue     OCTET STRING }
+    *
+    * DataGroupNumber ::= INTEGER {
+    *         dataGroup1    (1),
+    *         dataGroup1    (2),
+    *         dataGroup1    (3),
+    *         dataGroup1    (4),
+    *         dataGroup1    (5),
+    *         dataGroup1    (6),
+    *         dataGroup1    (7),
+    *         dataGroup1    (8),
+    *         dataGroup1    (9),
+    *         dataGroup1    (10),
+    *         dataGroup1    (11),
+    *         dataGroup1    (12),
+    *         dataGroup1    (13),
+    *         dataGroup1    (14),
+    *         dataGroup1    (15),
+    *         dataGroup1    (16) }
+    *
+    * </pre>
+    */
+    public class DataGroupHash
+        : Asn1Encodable
+    {
+        private readonly DerInteger dataGroupNumber;
+        private readonly Asn1OctetString dataGroupHashValue;
+
+		public static DataGroupHash GetInstance(
+            object obj)
+        {
+            if (obj is DataGroupHash)
+                return (DataGroupHash)obj;
+
+			if (obj != null)
+				return new DataGroupHash(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		private DataGroupHash(
+			Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			this.dataGroupNumber = DerInteger.GetInstance(seq[0]);
+            this.dataGroupHashValue = Asn1OctetString.GetInstance(seq[1]);
+        }
+
+		public DataGroupHash(
+            int				dataGroupNumber,
+            Asn1OctetString	dataGroupHashValue)
+        {
+            this.dataGroupNumber = new DerInteger(dataGroupNumber);
+            this.dataGroupHashValue = dataGroupHashValue;
+        }
+
+		public int DataGroupNumber
+		{
+			get { return dataGroupNumber.Value.IntValue; }
+		}
+
+		public Asn1OctetString DataGroupHashValue
+		{
+			get { return dataGroupHashValue; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(dataGroupNumber, dataGroupHashValue);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/icao/ICAOObjectIdentifiers.cs b/Crypto/src/asn1/icao/ICAOObjectIdentifiers.cs
new file mode 100644
index 000000000..389d4dacd
--- /dev/null
+++ b/Crypto/src/asn1/icao/ICAOObjectIdentifiers.cs
@@ -0,0 +1,34 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+	public abstract class IcaoObjectIdentifiers
+	{
+		//
+		// base id
+		//
+		public static readonly DerObjectIdentifier IdIcao = new DerObjectIdentifier("2.23.136");
+
+		public static readonly DerObjectIdentifier IdIcaoMrtd = IdIcao.Branch("1");
+		public static readonly DerObjectIdentifier IdIcaoMrtdSecurity = IdIcaoMrtd.Branch("1");
+
+		// LDS security object, see ICAO Doc 9303-Volume 2-Section IV-A3.2
+		public static readonly DerObjectIdentifier IdIcaoLdsSecurityObject = IdIcaoMrtdSecurity.Branch("1");
+
+		// CSCA master list, see TR CSCA Countersigning and Master List issuance
+		public static readonly DerObjectIdentifier IdIcaoCscaMasterList = IdIcaoMrtdSecurity.Branch("2");
+		public static readonly DerObjectIdentifier IdIcaoCscaMasterListSigningKey = IdIcaoMrtdSecurity.Branch("3");
+
+		// document type list, see draft TR LDS and PKI Maintenance, par. 3.2.1
+		public static readonly DerObjectIdentifier IdIcaoDocumentTypeList = IdIcaoMrtdSecurity.Branch("4");
+
+		// Active Authentication protocol, see draft TR LDS and PKI Maintenance,
+		// par. 5.2.2
+		public static readonly DerObjectIdentifier IdIcaoAAProtocolObject = IdIcaoMrtdSecurity.Branch("5");
+
+		// CSCA name change and key reoll-over, see draft TR LDS and PKI
+		// Maintenance, par. 3.2.1
+		public static readonly DerObjectIdentifier IdIcaoExtensions = IdIcaoMrtdSecurity.Branch("6");
+		public static readonly DerObjectIdentifier IdIcaoExtensionsNamechangekeyrollover = IdIcaoExtensions.Branch("1");
+	}
+}
diff --git a/Crypto/src/asn1/icao/LDSSecurityObject.cs b/Crypto/src/asn1/icao/LDSSecurityObject.cs
new file mode 100644
index 000000000..c33ca6877
--- /dev/null
+++ b/Crypto/src/asn1/icao/LDSSecurityObject.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+	/**
+	 * The LDSSecurityObject object (V1.8).
+	 * <pre>
+	 * LDSSecurityObject ::= SEQUENCE {
+	 *   version                LDSSecurityObjectVersion,
+	 *   hashAlgorithm          DigestAlgorithmIdentifier,
+	 *   dataGroupHashValues    SEQUENCE SIZE (2..ub-DataGroups) OF DataHashGroup,
+	 *   ldsVersionInfo         LDSVersionInfo OPTIONAL
+	 *     -- if present, version MUST be v1 }
+	 *
+	 * DigestAlgorithmIdentifier ::= AlgorithmIdentifier,
+	 *
+	 * LDSSecurityObjectVersion :: INTEGER {V0(0)}
+	 * </pre>
+	 */
+	public class LdsSecurityObject
+		: Asn1Encodable
+	{
+		public const int UBDataGroups = 16;
+
+		private DerInteger version = new DerInteger(0);
+		private AlgorithmIdentifier digestAlgorithmIdentifier;
+		private DataGroupHash[] datagroupHash;
+		private LdsVersionInfo versionInfo;
+
+		public static LdsSecurityObject GetInstance(
+			object obj)
+		{
+			if (obj is LdsSecurityObject)
+				return (LdsSecurityObject)obj;
+
+			if (obj != null)
+				return new LdsSecurityObject(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		private LdsSecurityObject(
+			Asn1Sequence seq)
+		{
+			if (seq == null || seq.Count == 0)
+				throw new ArgumentException("null or empty sequence passed.");
+
+			IEnumerator e = seq.GetEnumerator();
+
+			// version
+			e.MoveNext();
+			version = DerInteger.GetInstance(e.Current);
+			// digestAlgorithmIdentifier
+			e.MoveNext();
+			digestAlgorithmIdentifier = AlgorithmIdentifier.GetInstance(e.Current);
+
+			e.MoveNext();
+			Asn1Sequence datagroupHashSeq = Asn1Sequence.GetInstance(e.Current);
+
+			if (version.Value.Equals(BigInteger.One))
+			{
+				e.MoveNext();
+				versionInfo = LdsVersionInfo.GetInstance(e.Current);
+			}
+
+			CheckDatagroupHashSeqSize(datagroupHashSeq.Count);
+
+			datagroupHash = new DataGroupHash[datagroupHashSeq.Count];
+			for (int i= 0; i< datagroupHashSeq.Count; i++)
+			{
+				datagroupHash[i] = DataGroupHash.GetInstance(datagroupHashSeq[i]);
+			}
+		}
+
+		public LdsSecurityObject(
+			AlgorithmIdentifier	digestAlgorithmIdentifier,
+			DataGroupHash[]		datagroupHash)
+		{
+			this.version = new DerInteger(0);
+			this.digestAlgorithmIdentifier = digestAlgorithmIdentifier;
+			this.datagroupHash = datagroupHash;
+
+			CheckDatagroupHashSeqSize(datagroupHash.Length);
+		}
+
+
+		public LdsSecurityObject(
+			AlgorithmIdentifier	digestAlgorithmIdentifier,
+			DataGroupHash[]		datagroupHash,
+			LdsVersionInfo		versionInfo)
+		{
+			this.version = new DerInteger(1);
+			this.digestAlgorithmIdentifier = digestAlgorithmIdentifier;
+			this.datagroupHash = datagroupHash;
+			this.versionInfo = versionInfo;
+
+			CheckDatagroupHashSeqSize(datagroupHash.Length);
+		}
+
+		private void CheckDatagroupHashSeqSize(int size)
+		{
+			if (size < 2 || size > UBDataGroups)
+				throw new ArgumentException("wrong size in DataGroupHashValues : not in (2.."+ UBDataGroups +")");
+		}
+
+		public BigInteger Version
+		{
+			get { return version.Value; }
+		}
+
+		public AlgorithmIdentifier DigestAlgorithmIdentifier
+		{
+			get { return digestAlgorithmIdentifier; }
+		}
+
+		public DataGroupHash[] GetDatagroupHash()
+		{
+			return datagroupHash;
+		}
+
+		public LdsVersionInfo VersionInfo
+		{
+			get { return versionInfo; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			DerSequence hashSeq = new DerSequence(datagroupHash);
+
+			Asn1EncodableVector v = new Asn1EncodableVector(version, digestAlgorithmIdentifier, hashSeq);
+
+			if (versionInfo != null)
+			{
+				v.Add(versionInfo);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/icao/LDSVersionInfo.cs b/Crypto/src/asn1/icao/LDSVersionInfo.cs
new file mode 100644
index 000000000..2cdcad2db
--- /dev/null
+++ b/Crypto/src/asn1/icao/LDSVersionInfo.cs
@@ -0,0 +1,61 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+	public class LdsVersionInfo
+		: Asn1Encodable
+	{
+		private DerPrintableString ldsVersion;
+		private DerPrintableString unicodeVersion;
+
+		public LdsVersionInfo(string ldsVersion, string unicodeVersion)
+		{
+			this.ldsVersion = new DerPrintableString(ldsVersion);
+			this.unicodeVersion = new DerPrintableString(unicodeVersion);
+		}
+
+		private LdsVersionInfo(Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("sequence wrong size for LDSVersionInfo", "seq");
+
+			this.ldsVersion = DerPrintableString.GetInstance(seq[0]);
+			this.unicodeVersion = DerPrintableString.GetInstance(seq[1]);
+		}
+
+		public static LdsVersionInfo GetInstance(object obj)
+		{
+			if (obj is LdsVersionInfo)
+				return (LdsVersionInfo)obj;
+
+			if (obj != null)
+				return new LdsVersionInfo(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		public virtual string GetLdsVersion()
+		{
+			return ldsVersion.GetString();
+		}
+
+		public virtual string GetUnicodeVersion()
+		{
+			return unicodeVersion.GetString();
+		}
+
+		/**
+		 * <pre>
+		 * LDSVersionInfo ::= SEQUENCE {
+		 *    ldsVersion PRINTABLE STRING
+		 *    unicodeVersion PRINTABLE STRING
+		 *  }
+		 * </pre>
+		 * @return
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(ldsVersion, unicodeVersion);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/isismtt/ISISMTTObjectIdentifiers.cs b/Crypto/src/asn1/isismtt/ISISMTTObjectIdentifiers.cs
new file mode 100644
index 000000000..af60b030a
--- /dev/null
+++ b/Crypto/src/asn1/isismtt/ISISMTTObjectIdentifiers.cs
@@ -0,0 +1,177 @@
+namespace Org.BouncyCastle.Asn1.IsisMtt
+{
+	public abstract class IsisMttObjectIdentifiers
+	{
+		public static readonly DerObjectIdentifier IdIsisMtt = new DerObjectIdentifier("1.3.36.8");
+
+		public static readonly DerObjectIdentifier IdIsisMttCP = new DerObjectIdentifier(IdIsisMtt + ".1");
+
+		/**
+		 * The id-isismtt-cp-accredited OID indicates that the certificate is a
+		 * qualified certificate according to Directive 1999/93/EC of the European
+		 * Parliament and of the Council of 13 December 1999 on a Community
+		 * Framework for Electronic Signatures, which additionally conforms the
+		 * special requirements of the SigG and has been issued by an accredited CA.
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttCPAccredited = new DerObjectIdentifier(IdIsisMttCP + ".1");
+
+		public static readonly DerObjectIdentifier IdIsisMttAT = new DerObjectIdentifier(IdIsisMtt + ".3");
+
+		/**
+		 * Certificate extensionDate of certificate generation
+		 * 
+		 * <pre>
+		 *		DateOfCertGenSyntax ::= GeneralizedTime
+		 * </pre>
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATDateOfCertGen = new DerObjectIdentifier(IdIsisMttAT + ".1");
+
+		/**
+		 * Attribute to indicate that the certificate holder may sign in the name of
+		 * a third person. May also be used as extension in a certificate.
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATProcuration = new DerObjectIdentifier(IdIsisMttAT + ".2");
+
+		/**
+		 * Attribute to indicate admissions to certain professions. May be used as
+		 * attribute in attribute certificate or as extension in a certificate
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATAdmission = new DerObjectIdentifier(IdIsisMttAT + ".3");
+
+		/**
+		 * Monetary limit for transactions. The QcEuMonetaryLimit QC statement MUST
+		 * be used in new certificates in place of the extension/attribute
+		 * MonetaryLimit since January 1, 2004. For the sake of backward
+		 * compatibility with certificates already in use, SigG conforming
+		 * components MUST support MonetaryLimit (as well as QcEuLimitValue).
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATMonetaryLimit = new DerObjectIdentifier(IdIsisMttAT + ".4");
+
+		/**
+		 * A declaration of majority. May be used as attribute in attribute
+		 * certificate or as extension in a certificate
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATDeclarationOfMajority = new DerObjectIdentifier(IdIsisMttAT + ".5");
+
+		/**
+		 * 
+		 * Serial number of the smart card containing the corresponding private key
+		 * 
+		 * <pre>
+		 *		ICCSNSyntax ::= OCTET STRING (SIZE(8..20))
+		 * </pre>
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATIccsn = new DerObjectIdentifier(IdIsisMttAT + ".6");
+
+		/**
+		 * 
+		 * Reference for a file of a smartcard that stores the public key of this
+		 * certificate and that is used as �security anchor�.
+		 * 
+		 * <pre>
+		 *		PKReferenceSyntax ::= OCTET STRING (SIZE(20))
+		 * </pre>
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATPKReference = new DerObjectIdentifier(IdIsisMttAT + ".7");
+
+		/**
+		 * Some other restriction regarding the usage of this certificate. May be
+		 * used as attribute in attribute certificate or as extension in a
+		 * certificate.
+		 * 
+		 * <pre>
+		 *		RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+		 * </pre>
+		 * 
+		 * @see Org.BouncyCastle.Asn1.IsisMtt.X509.Restriction
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATRestriction = new DerObjectIdentifier(IdIsisMttAT + ".8");
+
+		/**
+		 * 
+		 * (Single)Request extension: Clients may include this extension in a
+		 * (single) Request to request the responder to send the certificate in the
+		 * response message along with the status information. Besides the LDAP
+		 * service, this extension provides another mechanism for the distribution
+		 * of certificates, which MAY optionally be provided by certificate
+		 * repositories.
+		 * 
+		 * <pre>
+		 *		RetrieveIfAllowed ::= BOOLEAN
+		 * </pre>
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATRetrieveIfAllowed = new DerObjectIdentifier(IdIsisMttAT + ".9");
+
+		/**
+		 * SingleOCSPResponse extension: The certificate requested by the client by
+		 * inserting the RetrieveIfAllowed extension in the request, will be
+		 * returned in this extension.
+		 * 
+		 * @see Org.BouncyCastle.Asn1.IsisMtt.Ocsp.RequestedCertificate
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATRequestedCertificate = new DerObjectIdentifier(IdIsisMttAT + ".10");
+
+		/**
+		 * Base ObjectIdentifier for naming authorities
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATNamingAuthorities = new DerObjectIdentifier(IdIsisMttAT + ".11");
+
+		/**
+		 * SingleOCSPResponse extension: Date, when certificate has been published
+		 * in the directory and status information has become available. Currently,
+		 * accrediting authorities enforce that SigG-conforming OCSP servers include
+		 * this extension in the responses.
+		 * 
+		 * <pre>
+		 *		CertInDirSince ::= GeneralizedTime
+		 * </pre>
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATCertInDirSince = new DerObjectIdentifier(IdIsisMttAT + ".12");
+
+		/**
+		 * Hash of a certificate in OCSP.
+		 *
+		 * @see Org.BouncyCastle.Asn1.IsisMtt.Ocsp.CertHash
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATCertHash = new DerObjectIdentifier(IdIsisMttAT + ".13");
+
+		/**
+		 * <pre>
+		 *		NameAtBirth ::= DirectoryString(SIZE(1..64)
+		 * </pre>
+		 * 
+		 * Used in
+		 * {@link Org.BouncyCastle.Asn1.X509.SubjectDirectoryAttributes SubjectDirectoryAttributes}
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATNameAtBirth = new DerObjectIdentifier(IdIsisMttAT + ".14");
+
+		/**
+		 * Some other information of non-restrictive nature regarding the usage of
+		 * this certificate. May be used as attribute in atribute certificate or as
+		 * extension in a certificate.
+		 * 
+		 * <pre>
+		 *               AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
+		 * </pre>
+		 * 
+		 * @see Org.BouncyCastle.Asn1.IsisMtt.X509.AdditionalInformationSyntax
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATAdditionalInformation = new DerObjectIdentifier(IdIsisMttAT + ".15");
+
+		/**
+		 * Indicates that an attribute certificate exists, which limits the
+		 * usability of this public key certificate. Whenever verifying a signature
+		 * with the help of this certificate, the content of the corresponding
+		 * attribute certificate should be concerned. This extension MUST be
+		 * included in a PKC, if a corresponding attribute certificate (having the
+		 * PKC as base certificate) contains some attribute that restricts the
+		 * usability of the PKC too. Attribute certificates with restricting content
+		 * MUST always be included in the signed document.
+		 * 
+		 * <pre>
+		 *		LiabilityLimitationFlagSyntax ::= BOOLEAN
+		 * </pre>
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATLiabilityLimitationFlag = new DerObjectIdentifier("0.2.262.1.10.12.0");
+	}
+}
diff --git a/Crypto/src/asn1/isismtt/ocsp/CertHash.cs b/Crypto/src/asn1/isismtt/ocsp/CertHash.cs
new file mode 100644
index 000000000..da5b530e4
--- /dev/null
+++ b/Crypto/src/asn1/isismtt/ocsp/CertHash.cs
@@ -0,0 +1,121 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp
+{
+	/**
+	* ISIS-MTT PROFILE: The responder may include this extension in a response to
+	* send the hash of the requested certificate to the responder. This hash is
+	* cryptographically bound to the certificate and serves as evidence that the
+	* certificate is known to the responder (i.e. it has been issued and is present
+	* in the directory). Hence, this extension is a means to provide a positive
+	* statement of availability as described in T8.[8]. As explained in T13.[1],
+	* clients may rely on this information to be able to validate signatures after
+	* the expiry of the corresponding certificate. Hence, clients MUST support this
+	* extension. If a positive statement of availability is to be delivered, this
+	* extension syntax and OID MUST be used.
+	* <p/>
+	* <p/>
+	* <pre>
+	*     CertHash ::= SEQUENCE {
+	*       hashAlgorithm AlgorithmIdentifier,
+	*       certificateHash OCTET STRING
+	*     }
+	* </pre>
+	*/
+	public class CertHash
+		: Asn1Encodable
+	{
+		private readonly AlgorithmIdentifier	hashAlgorithm;
+		private readonly byte[]					certificateHash;
+
+		public static CertHash GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CertHash)
+			{
+				return (CertHash) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new CertHash((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		* Constructor from Asn1Sequence.
+		* <p/>
+		* The sequence is of type CertHash:
+		* <p/>
+		* <pre>
+		*     CertHash ::= SEQUENCE {
+		*       hashAlgorithm AlgorithmIdentifier,
+		*       certificateHash OCTET STRING
+		*     }
+		* </pre>
+		*
+		* @param seq The ASN.1 sequence.
+		*/
+		private CertHash(
+			Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]);
+			this.certificateHash = DerOctetString.GetInstance(seq[1]).GetOctets();
+		}
+
+		/**
+		* Constructor from a given details.
+		*
+		* @param hashAlgorithm   The hash algorithm identifier.
+		* @param certificateHash The hash of the whole DER encoding of the certificate.
+		*/
+		public CertHash(
+			AlgorithmIdentifier	hashAlgorithm,
+			byte[]				certificateHash)
+		{
+			if (hashAlgorithm == null)
+				throw new ArgumentNullException("hashAlgorithm");
+			if (certificateHash == null)
+				throw new ArgumentNullException("certificateHash");
+
+			this.hashAlgorithm = hashAlgorithm;
+			this.certificateHash = (byte[]) certificateHash.Clone();
+		}
+
+		public AlgorithmIdentifier HashAlgorithm
+		{
+			get { return hashAlgorithm; }
+		}
+
+		public byte[] CertificateHash
+		{
+			get { return (byte[]) certificateHash.Clone(); }
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*     CertHash ::= SEQUENCE {
+		*       hashAlgorithm AlgorithmIdentifier,
+		*       certificateHash OCTET STRING
+		*     }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(hashAlgorithm, new DerOctetString(certificateHash));
+		}
+	}
+}
diff --git a/Crypto/src/asn1/isismtt/ocsp/RequestedCertificate.cs b/Crypto/src/asn1/isismtt/ocsp/RequestedCertificate.cs
new file mode 100644
index 000000000..7724bfed6
--- /dev/null
+++ b/Crypto/src/asn1/isismtt/ocsp/RequestedCertificate.cs
@@ -0,0 +1,186 @@
+using System;
+using System.IO;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp
+{
+	/**
+	* ISIS-MTT-Optional: The certificate requested by the client by inserting the
+	* RetrieveIfAllowed extension in the request, will be returned in this
+	* extension.
+	* <p/>
+	* ISIS-MTT-SigG: The signature act allows publishing certificates only then,
+	* when the certificate owner gives his isExplicit permission. Accordingly, there
+	* may be �nondownloadable� certificates, about which the responder must provide
+	* status information, but MUST NOT include them in the response. Clients may
+	* get therefore the following three kind of answers on a single request
+	* including the RetrieveIfAllowed extension:
+	* <ul>
+	* <li> a) the responder supports the extension and is allowed to publish the
+	* certificate: RequestedCertificate returned including the requested
+	* certificate</li>
+	* <li>b) the responder supports the extension but is NOT allowed to publish
+	* the certificate: RequestedCertificate returned including an empty OCTET
+	* STRING</li>
+	* <li>c) the responder does not support the extension: RequestedCertificate is
+	* not included in the response</li>
+	* </ul>
+	* Clients requesting RetrieveIfAllowed MUST be able to handle these cases. If
+	* any of the OCTET STRING options is used, it MUST contain the DER encoding of
+	* the requested certificate.
+	* <p/>
+	* <pre>
+	*            RequestedCertificate ::= CHOICE {
+	*              Certificate Certificate,
+	*              publicKeyCertificate [0] EXPLICIT OCTET STRING,
+	*              attributeCertificate [1] EXPLICIT OCTET STRING
+	*            }
+	* </pre>
+	*/
+	public class RequestedCertificate
+		: Asn1Encodable, IAsn1Choice
+	{
+		public enum Choice
+		{
+			Certificate = -1,
+			PublicKeyCertificate = 0,
+			AttributeCertificate = 1
+		}
+
+		private readonly X509CertificateStructure	cert;
+		private readonly byte[]						publicKeyCert;
+		private readonly byte[]						attributeCert;
+
+		public static RequestedCertificate GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is RequestedCertificate)
+			{
+				return (RequestedCertificate) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new RequestedCertificate(X509CertificateStructure.GetInstance(obj));
+			}
+
+			if (obj is Asn1TaggedObject)
+			{
+				return new RequestedCertificate((Asn1TaggedObject) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public static RequestedCertificate GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			if (!isExplicit)
+				throw new ArgumentException("choice item must be explicitly tagged");
+
+			return GetInstance(obj.GetObject());
+		}
+
+		private RequestedCertificate(
+			Asn1TaggedObject tagged)
+		{
+			switch ((Choice) tagged.TagNo)
+			{
+				case Choice.AttributeCertificate:
+					this.attributeCert = Asn1OctetString.GetInstance(tagged, true).GetOctets();
+					break;
+				case Choice.PublicKeyCertificate:
+					this.publicKeyCert = Asn1OctetString.GetInstance(tagged, true).GetOctets();
+					break;
+				default:
+					throw new ArgumentException("unknown tag number: " + tagged.TagNo);
+			}
+		}
+
+		/**
+		* Constructor from a given details.
+		* <p/>
+		* Only one parameter can be given. All other must be <code>null</code>.
+		*
+		* @param certificate Given as Certificate
+		*/
+		public RequestedCertificate(
+			X509CertificateStructure certificate)
+		{
+			this.cert = certificate;
+		}
+
+		public RequestedCertificate(
+			Choice	type,
+			byte[]	certificateOctets)
+			: this(new DerTaggedObject((int) type, new DerOctetString(certificateOctets)))
+		{
+		}
+
+		public Choice Type
+		{
+			get
+			{
+				if (cert != null)
+					return Choice.Certificate;
+
+				if (publicKeyCert != null)
+					return Choice.PublicKeyCertificate;
+
+				return Choice.AttributeCertificate;
+			}
+		}
+
+		public byte[] GetCertificateBytes()
+		{
+			if (cert != null)
+			{
+				try
+				{
+					return cert.GetEncoded();
+				}
+				catch (IOException e)
+				{
+					throw new InvalidOperationException("can't decode certificate: " + e);
+				}
+			}
+
+			if (publicKeyCert != null)
+				return publicKeyCert;
+
+			return attributeCert;
+		}
+    
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*            RequestedCertificate ::= CHOICE {
+		*              Certificate Certificate,
+		*              publicKeyCertificate [0] EXPLICIT OCTET STRING,
+		*              attributeCertificate [1] EXPLICIT OCTET STRING
+		*            }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			if (publicKeyCert != null)
+			{
+				return new DerTaggedObject(0, new DerOctetString(publicKeyCert));
+			}
+
+			if (attributeCert != null)
+			{
+				return new DerTaggedObject(1, new DerOctetString(attributeCert));
+			}
+
+			return cert.ToAsn1Object();
+		}
+	}
+}
diff --git a/Crypto/src/asn1/isismtt/x509/AdditionalInformationSyntax.cs b/Crypto/src/asn1/isismtt/x509/AdditionalInformationSyntax.cs
new file mode 100644
index 000000000..f81d459c6
--- /dev/null
+++ b/Crypto/src/asn1/isismtt/x509/AdditionalInformationSyntax.cs
@@ -0,0 +1,70 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X500;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+	/**
+	* Some other information of non-restrictive nature regarding the usage of this
+	* certificate.
+	* 
+	* <pre>
+	*    AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
+	* </pre>
+	*/
+	public class AdditionalInformationSyntax
+		: Asn1Encodable
+	{
+		private readonly DirectoryString information;
+
+		public static AdditionalInformationSyntax GetInstance(
+			object obj)
+		{
+			if (obj is AdditionalInformationSyntax)
+				return (AdditionalInformationSyntax) obj;
+
+			if (obj is IAsn1String)
+				return new AdditionalInformationSyntax(DirectoryString.GetInstance(obj));
+
+			throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().Name, "obj");
+		}
+
+		private AdditionalInformationSyntax(
+			DirectoryString information)
+		{
+			this.information = information;
+		}
+
+		/**
+		* Constructor from a given details.
+		*
+		* @param information The describtion of the information.
+		*/
+		public AdditionalInformationSyntax(
+			string information)
+		{
+			this.information = new DirectoryString(information);
+		}
+
+		public virtual DirectoryString Information
+		{
+			get { return information; }
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*   AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			return information.ToAsn1Object();
+		}
+	}
+}
diff --git a/Crypto/src/asn1/isismtt/x509/AdmissionSyntax.cs b/Crypto/src/asn1/isismtt/x509/AdmissionSyntax.cs
new file mode 100644
index 000000000..f322ef88f
--- /dev/null
+++ b/Crypto/src/asn1/isismtt/x509/AdmissionSyntax.cs
Binary files differdiff --git a/Crypto/src/asn1/isismtt/x509/Admissions.cs b/Crypto/src/asn1/isismtt/x509/Admissions.cs
new file mode 100644
index 000000000..40290c608
--- /dev/null
+++ b/Crypto/src/asn1/isismtt/x509/Admissions.cs
@@ -0,0 +1,186 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+	/**
+	* An Admissions structure.
+	* <p/>
+	* <pre>
+	*            Admissions ::= SEQUENCE
+	*            {
+	*              admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
+	*              namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
+	*              professionInfos SEQUENCE OF ProfessionInfo
+	*            }
+	* <p/>
+	* </pre>
+	*
+	* @see Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax
+	* @see Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo
+	* @see Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority
+	*/
+	public class Admissions
+		: Asn1Encodable
+	{
+		private readonly GeneralName		admissionAuthority;
+		private readonly NamingAuthority	namingAuthority;
+		private readonly Asn1Sequence		professionInfos;
+
+		public static Admissions GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is Admissions)
+			{
+				return (Admissions) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new Admissions((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		* Constructor from Asn1Sequence.
+		* <p/>
+		* The sequence is of type ProcurationSyntax:
+		* <p/>
+		* <pre>
+		*            Admissions ::= SEQUENCE
+		*            {
+		*              admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
+		*              namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
+		*              professionInfos SEQUENCE OF ProfessionInfo
+		*            }
+		* </pre>
+		*
+		* @param seq The ASN.1 sequence.
+		*/
+		private Admissions(
+			Asn1Sequence seq)
+		{
+			if (seq.Count > 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			IEnumerator e = seq.GetEnumerator();
+
+			e.MoveNext();
+			Asn1Encodable o = (Asn1Encodable) e.Current;
+			if (o is Asn1TaggedObject)
+			{
+				switch (((Asn1TaggedObject)o).TagNo)
+				{
+					case 0:
+						admissionAuthority = GeneralName.GetInstance((Asn1TaggedObject)o, true);
+						break;
+					case 1:
+						namingAuthority = NamingAuthority.GetInstance((Asn1TaggedObject)o, true);
+						break;
+					default:
+						throw new ArgumentException("Bad tag number: " + ((Asn1TaggedObject)o).TagNo);
+				}
+				e.MoveNext();
+				o = (Asn1Encodable) e.Current;
+			}
+			if (o is Asn1TaggedObject)
+			{
+				switch (((Asn1TaggedObject)o).TagNo)
+				{
+					case 1:
+						namingAuthority = NamingAuthority.GetInstance((Asn1TaggedObject)o, true);
+						break;
+					default:
+						throw new ArgumentException("Bad tag number: " + ((Asn1TaggedObject)o).TagNo);
+				}
+				e.MoveNext();
+				o = (Asn1Encodable) e.Current;
+			}
+			professionInfos = Asn1Sequence.GetInstance(o);
+			if (e.MoveNext())
+			{
+				throw new ArgumentException("Bad object encountered: " + e.Current.GetType().Name);
+			}
+		}
+
+		/**
+		* Constructor from a given details.
+		* <p/>
+		* Parameter <code>professionInfos</code> is mandatory.
+		*
+		* @param admissionAuthority The admission authority.
+		* @param namingAuthority    The naming authority.
+		* @param professionInfos    The profession infos.
+		*/
+		public Admissions(
+			GeneralName			admissionAuthority,
+			NamingAuthority		namingAuthority,
+			ProfessionInfo[]	professionInfos)
+		{
+			this.admissionAuthority = admissionAuthority;
+			this.namingAuthority = namingAuthority;
+			this.professionInfos = new DerSequence(professionInfos);
+		}
+
+		public virtual GeneralName AdmissionAuthority
+		{
+			get { return admissionAuthority; }
+		}
+
+		public virtual NamingAuthority NamingAuthority
+		{
+			get { return namingAuthority; }
+		}
+
+		public ProfessionInfo[] GetProfessionInfos()
+		{
+			ProfessionInfo[] infos = new ProfessionInfo[professionInfos.Count];
+			int count = 0;
+			foreach (Asn1Encodable ae in professionInfos)
+			{
+				infos[count++] = ProfessionInfo.GetInstance(ae);
+			}
+			return infos;
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*       Admissions ::= SEQUENCE
+		*       {
+		*         admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
+		*         namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
+		*         professionInfos SEQUENCE OF ProfessionInfo
+		*       }
+		* <p/>
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector vec = new Asn1EncodableVector();
+
+			if (admissionAuthority != null)
+			{
+				vec.Add(new DerTaggedObject(true, 0, admissionAuthority));
+			}
+
+			if (namingAuthority != null)
+			{
+				vec.Add(new DerTaggedObject(true, 1, namingAuthority));
+			}
+
+			vec.Add(professionInfos);
+
+			return new DerSequence(vec);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs b/Crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs
new file mode 100644
index 000000000..dfac65040
--- /dev/null
+++ b/Crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs
@@ -0,0 +1,170 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+	/**
+	* A declaration of majority.
+	* <p/>
+	* <pre>
+	*           DeclarationOfMajoritySyntax ::= CHOICE
+	*           {
+	*             notYoungerThan [0] IMPLICIT INTEGER,
+	*             fullAgeAtCountry [1] IMPLICIT SEQUENCE
+	*             {
+	*               fullAge BOOLEAN DEFAULT TRUE,
+	*               country PrintableString (SIZE(2))
+	*             }
+	*             dateOfBirth [2] IMPLICIT GeneralizedTime
+	*           }
+	* </pre>
+	* <p/>
+	* fullAgeAtCountry indicates the majority of the owner with respect to the laws
+	* of a specific country.
+	*/
+	public class DeclarationOfMajority
+		: Asn1Encodable, IAsn1Choice
+	{
+		public enum Choice
+		{
+			NotYoungerThan = 0,
+			FullAgeAtCountry = 1,
+			DateOfBirth = 2
+		};
+
+		private readonly Asn1TaggedObject declaration;
+
+		public DeclarationOfMajority(
+			int notYoungerThan)
+		{
+			declaration = new DerTaggedObject(false, 0, new DerInteger(notYoungerThan));
+		}
+
+		public DeclarationOfMajority(
+			bool	fullAge,
+			string	country)
+		{
+			if (country.Length > 2)
+				throw new ArgumentException("country can only be 2 characters");
+
+			DerPrintableString countryString = new DerPrintableString(country, true);
+
+			DerSequence seq;
+			if (fullAge)
+			{
+				seq = new DerSequence(countryString);
+			}
+			else
+			{
+				seq = new DerSequence(DerBoolean.False, countryString);
+			}
+
+			this.declaration = new DerTaggedObject(false, 1, seq);
+		}
+
+		public DeclarationOfMajority(
+			DerGeneralizedTime dateOfBirth)
+		{
+			this.declaration = new DerTaggedObject(false, 2, dateOfBirth);
+		}
+
+		public static DeclarationOfMajority GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is DeclarationOfMajority)
+			{
+				return (DeclarationOfMajority) obj;
+			}
+
+			if (obj is Asn1TaggedObject)
+			{
+				return new DeclarationOfMajority((Asn1TaggedObject) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private DeclarationOfMajority(
+			Asn1TaggedObject o)
+		{
+			if (o.TagNo > 2)
+				throw new ArgumentException("Bad tag number: " + o.TagNo);
+
+			this.declaration = o;
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*           DeclarationOfMajoritySyntax ::= CHOICE
+		*           {
+		*             notYoungerThan [0] IMPLICIT INTEGER,
+		*             fullAgeAtCountry [1] IMPLICIT SEQUENCE
+		*             {
+		*               fullAge BOOLEAN DEFAULT TRUE,
+		*               country PrintableString (SIZE(2))
+		*             }
+		*             dateOfBirth [2] IMPLICIT GeneralizedTime
+		*           }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			return declaration;
+		}
+
+		public Choice Type
+		{
+			get { return (Choice) declaration.TagNo; }
+		}
+
+		/**
+		* @return notYoungerThan if that's what we are, -1 otherwise
+		*/
+		public virtual int NotYoungerThan
+		{
+			get
+			{
+				switch ((Choice) declaration.TagNo)
+				{
+					case Choice.NotYoungerThan:
+						return DerInteger.GetInstance(declaration, false).Value.IntValue;
+					default:
+						return -1;
+				}
+			}
+		}
+
+		public virtual Asn1Sequence FullAgeAtCountry
+		{
+			get
+			{
+				switch ((Choice) declaration.TagNo)
+				{
+					case Choice.FullAgeAtCountry:
+						return Asn1Sequence.GetInstance(declaration, false);
+					default:
+						return null;
+				}
+			}
+		}
+
+		public virtual DerGeneralizedTime DateOfBirth
+		{
+			get
+			{
+				switch ((Choice) declaration.TagNo)
+				{
+					case Choice.DateOfBirth:
+						return DerGeneralizedTime.GetInstance(declaration, false);
+					default:
+						return null;
+				}
+			}
+		}
+	}
+}
diff --git a/Crypto/src/asn1/isismtt/x509/MonetaryLimit.cs b/Crypto/src/asn1/isismtt/x509/MonetaryLimit.cs
new file mode 100644
index 000000000..80b6b684b
--- /dev/null
+++ b/Crypto/src/asn1/isismtt/x509/MonetaryLimit.cs
@@ -0,0 +1,121 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+	/**
+	* Monetary limit for transactions. The QcEuMonetaryLimit QC statement MUST be
+	* used in new certificates in place of the extension/attribute MonetaryLimit
+	* since January 1, 2004. For the sake of backward compatibility with
+	* certificates already in use, components SHOULD support MonetaryLimit (as well
+	* as QcEuLimitValue).
+	* <p/>
+	* Indicates a monetary limit within which the certificate holder is authorized
+	* to act. (This value DOES NOT express a limit on the liability of the
+	* certification authority).
+	* <p/>
+	* <pre>
+	*    MonetaryLimitSyntax ::= SEQUENCE
+	*    {
+	*      currency PrintableString (SIZE(3)),
+	*      amount INTEGER,
+	*      exponent INTEGER
+	*    }
+	* </pre>
+	* <p/>
+	* currency must be the ISO code.
+	* <p/>
+	* value = amount�10*exponent
+	*/
+	public class MonetaryLimit
+		: Asn1Encodable
+	{
+		private readonly DerPrintableString	currency;
+		private readonly DerInteger			amount;
+		private readonly DerInteger			exponent;
+
+		public static MonetaryLimit GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is MonetaryLimit)
+			{
+				return (MonetaryLimit) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new MonetaryLimit(Asn1Sequence.GetInstance(obj));
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private MonetaryLimit(
+			Asn1Sequence seq)
+		{
+			if (seq.Count != 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			currency = DerPrintableString.GetInstance(seq[0]);
+			amount = DerInteger.GetInstance(seq[1]);
+			exponent = DerInteger.GetInstance(seq[2]);
+		}
+
+		/**
+		* Constructor from a given details.
+		* <p/>
+		* <p/>
+		* value = amount�10^exponent
+		*
+		* @param currency The currency. Must be the ISO code.
+		* @param amount   The amount
+		* @param exponent The exponent
+		*/
+		public MonetaryLimit(
+			string	currency,
+			int		amount,
+			int		exponent)
+		{
+			this.currency = new DerPrintableString(currency, true);
+			this.amount = new DerInteger(amount);
+			this.exponent = new DerInteger(exponent);
+		}
+
+		public virtual string Currency
+		{
+			get { return currency.GetString(); }
+		}
+
+		public virtual BigInteger Amount
+		{
+			get { return amount.Value; }
+		}
+
+		public virtual BigInteger Exponent
+		{
+			get { return exponent.Value; }
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*    MonetaryLimitSyntax ::= SEQUENCE
+		*    {
+		*      currency PrintableString (SIZE(3)),
+		*      amount INTEGER,
+		*      exponent INTEGER
+		*    }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(currency, amount, exponent);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/isismtt/x509/NamingAuthority.cs b/Crypto/src/asn1/isismtt/x509/NamingAuthority.cs
new file mode 100644
index 000000000..4262fd0f4
--- /dev/null
+++ b/Crypto/src/asn1/isismtt/x509/NamingAuthority.cs
@@ -0,0 +1,214 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X500;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+	/**
+	* Names of authorities which are responsible for the administration of title
+	* registers.
+	* 
+	* <pre>
+	*             NamingAuthority ::= SEQUENCE 
+	*             {
+	*               namingAuthorityID OBJECT IDENTIFIER OPTIONAL,
+	*               namingAuthorityUrl IA5String OPTIONAL,
+	*               namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
+	*             }
+	* </pre>
+	* @see Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax
+	* 
+	*/
+	public class NamingAuthority
+		: Asn1Encodable
+	{
+		/**
+		* Profession OIDs should always be defined under the OID branch of the
+		* responsible naming authority. At the time of this writing, the work group
+		* �Recht, Wirtschaft, Steuern� (�Law, Economy, Taxes�) is registered as the
+		* first naming authority under the OID id-isismtt-at-namingAuthorities.
+		*/
+		public static readonly DerObjectIdentifier IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern
+			= new DerObjectIdentifier(IsisMttObjectIdentifiers.IdIsisMttATNamingAuthorities + ".1");
+
+		private readonly DerObjectIdentifier	namingAuthorityID;
+		private readonly string					namingAuthorityUrl;
+		private readonly DirectoryString		namingAuthorityText;
+
+		public static NamingAuthority GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is NamingAuthority)
+			{
+				return (NamingAuthority) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new NamingAuthority((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public static NamingAuthority GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+
+		/**
+		* Constructor from Asn1Sequence.
+		* <p/>
+		* <p/>
+		* <pre>
+		*             NamingAuthority ::= SEQUENCE
+		*             {
+		*               namingAuthorityID OBJECT IDENTIFIER OPTIONAL,
+		*               namingAuthorityUrl IA5String OPTIONAL,
+		*               namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
+		*             }
+		* </pre>
+		*
+		* @param seq The ASN.1 sequence.
+		*/
+		private NamingAuthority(
+			Asn1Sequence seq)
+		{
+			if (seq.Count > 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			IEnumerator e = seq.GetEnumerator();
+
+			if (e.MoveNext())
+			{
+				Asn1Encodable o = (Asn1Encodable) e.Current;
+				if (o is DerObjectIdentifier)
+				{
+					namingAuthorityID = (DerObjectIdentifier) o;
+				}
+				else if (o is DerIA5String)
+				{
+					namingAuthorityUrl = DerIA5String.GetInstance(o).GetString();
+				}
+				else if (o is IAsn1String)
+				{
+					namingAuthorityText = DirectoryString.GetInstance(o);
+				}
+				else
+				{
+					throw new ArgumentException("Bad object encountered: " + o.GetType().Name);
+				}
+			}
+
+			if (e.MoveNext())
+			{
+				Asn1Encodable o = (Asn1Encodable) e.Current;
+				if (o is DerIA5String)
+				{
+					namingAuthorityUrl = DerIA5String.GetInstance(o).GetString();
+				}
+				else if (o is IAsn1String)
+				{
+					namingAuthorityText = DirectoryString.GetInstance(o);
+				}
+				else
+				{
+					throw new ArgumentException("Bad object encountered: " + o.GetType().Name);
+				}
+			}
+
+			if (e.MoveNext())
+			{
+				Asn1Encodable o = (Asn1Encodable) e.Current;
+				if (o is IAsn1String)
+				{
+					namingAuthorityText = DirectoryString.GetInstance(o);
+				}
+				else
+				{
+					throw new ArgumentException("Bad object encountered: " + o.GetType().Name);
+				}
+			}
+		}
+
+		/**
+		* @return Returns the namingAuthorityID.
+		*/
+		public virtual DerObjectIdentifier NamingAuthorityID
+		{
+			get { return namingAuthorityID; }
+		}
+
+		/**
+		* @return Returns the namingAuthorityText.
+		*/
+		public virtual DirectoryString NamingAuthorityText
+		{
+			get { return namingAuthorityText; }
+		}
+
+		/**
+		* @return Returns the namingAuthorityUrl.
+		*/
+		public virtual string NamingAuthorityUrl
+		{
+			get { return namingAuthorityUrl; }
+		}
+
+		/**
+		* Constructor from given details.
+		* <p/>
+		* All parameters can be combined.
+		*
+		* @param namingAuthorityID   ObjectIdentifier for naming authority.
+		* @param namingAuthorityUrl  URL for naming authority.
+		* @param namingAuthorityText Textual representation of naming authority.
+		*/
+		public NamingAuthority(
+			DerObjectIdentifier	namingAuthorityID,
+			string				namingAuthorityUrl,
+			DirectoryString		namingAuthorityText)
+		{
+			this.namingAuthorityID = namingAuthorityID;
+			this.namingAuthorityUrl = namingAuthorityUrl;
+			this.namingAuthorityText = namingAuthorityText;
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*             NamingAuthority ::= SEQUENCE
+		*             {
+		*               namingAuthorityID OBJECT IDENTIFIER OPTIONAL,
+		*               namingAuthorityUrl IA5String OPTIONAL,
+		*               namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
+		*             }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector vec = new Asn1EncodableVector();
+			if (namingAuthorityID != null)
+			{
+				vec.Add(namingAuthorityID);
+			}
+			if (namingAuthorityUrl != null)
+			{
+				vec.Add(new DerIA5String(namingAuthorityUrl, true));
+			}
+			if (namingAuthorityText != null)
+			{
+				vec.Add(namingAuthorityText);
+			}
+			return new DerSequence(vec);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/isismtt/x509/ProcurationSyntax.cs b/Crypto/src/asn1/isismtt/x509/ProcurationSyntax.cs
new file mode 100644
index 000000000..a25df225e
--- /dev/null
+++ b/Crypto/src/asn1/isismtt/x509/ProcurationSyntax.cs
@@ -0,0 +1,232 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+	/**
+	* Attribute to indicate that the certificate holder may sign in the name of a
+	* third person.
+	* <p>
+	* ISIS-MTT PROFILE: The corresponding ProcurationSyntax contains either the
+	* name of the person who is represented (subcomponent thirdPerson) or a
+	* reference to his/her base certificate (in the component signingFor,
+	* subcomponent certRef), furthermore the optional components country and
+	* typeSubstitution to indicate the country whose laws apply, and respectively
+	* the type of procuration (e.g. manager, procuration, custody).
+	* </p>
+	* <p>
+	* ISIS-MTT PROFILE: The GeneralName MUST be of type directoryName and MAY only
+	* contain: - RFC3039 attributes, except pseudonym (countryName, commonName,
+	* surname, givenName, serialNumber, organizationName, organizationalUnitName,
+	* stateOrProvincename, localityName, postalAddress) and - SubjectDirectoryName
+	* attributes (title, dateOfBirth, placeOfBirth, gender, countryOfCitizenship,
+	* countryOfResidence and NameAtBirth).
+	* </p>
+	* <pre>
+	*               ProcurationSyntax ::= SEQUENCE {
+	*                 country [1] EXPLICIT PrintableString(SIZE(2)) OPTIONAL,
+	*                 typeOfSubstitution [2] EXPLICIT DirectoryString (SIZE(1..128)) OPTIONAL,
+	*                 signingFor [3] EXPLICIT SigningFor 
+	*               }
+	*               
+	*               SigningFor ::= CHOICE 
+	*               { 
+	*                 thirdPerson GeneralName,
+	*                 certRef IssuerSerial 
+	*               }
+	* </pre>
+	* 
+	*/
+	public class ProcurationSyntax
+		: Asn1Encodable
+	{
+		private readonly string				country;
+		private readonly DirectoryString	typeOfSubstitution;
+		private readonly GeneralName		thirdPerson;
+		private readonly IssuerSerial		certRef;
+
+		public static ProcurationSyntax GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is ProcurationSyntax)
+			{
+				return (ProcurationSyntax) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new ProcurationSyntax((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		* Constructor from Asn1Sequence.
+		* <p/>
+		* The sequence is of type ProcurationSyntax:
+		* <p/>
+		* <pre>
+		*               ProcurationSyntax ::= SEQUENCE {
+		*                 country [1] EXPLICIT PrintableString(SIZE(2)) OPTIONAL,
+		*                 typeOfSubstitution [2] EXPLICIT DirectoryString (SIZE(1..128)) OPTIONAL,
+		*                 signingFor [3] EXPLICIT SigningFor
+		*               }
+		* <p/>
+		*               SigningFor ::= CHOICE
+		*               {
+		*                 thirdPerson GeneralName,
+		*                 certRef IssuerSerial
+		*               }
+		* </pre>
+		*
+		* @param seq The ASN.1 sequence.
+		*/
+		private ProcurationSyntax(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1 || seq.Count > 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			IEnumerator e = seq.GetEnumerator();
+
+			while (e.MoveNext())
+			{
+				Asn1TaggedObject o = Asn1TaggedObject.GetInstance(e.Current);
+				switch (o.TagNo)
+				{
+					case 1:
+						country = DerPrintableString.GetInstance(o, true).GetString();
+						break;
+					case 2:
+						typeOfSubstitution = DirectoryString.GetInstance(o, true);
+						break;
+					case 3:
+						Asn1Object signingFor = o.GetObject();
+						if (signingFor is Asn1TaggedObject)
+						{
+							thirdPerson = GeneralName.GetInstance(signingFor);
+						}
+						else
+						{
+							certRef = IssuerSerial.GetInstance(signingFor);
+						}
+						break;
+					default:
+						throw new ArgumentException("Bad tag number: " + o.TagNo);
+				}
+			}
+		}
+
+		/**
+		* Constructor from a given details.
+		* <p/>
+		* <p/>
+		* Either <code>generalName</code> or <code>certRef</code> MUST be
+		* <code>null</code>.
+		*
+		* @param country            The country code whose laws apply.
+		* @param typeOfSubstitution The type of procuration.
+		* @param certRef            Reference to certificate of the person who is represented.
+		*/
+		public ProcurationSyntax(
+			string			country,
+			DirectoryString	typeOfSubstitution,
+			IssuerSerial	certRef)
+		{
+			this.country = country;
+			this.typeOfSubstitution = typeOfSubstitution;
+			this.thirdPerson = null;
+			this.certRef = certRef;
+		}
+
+		/**
+		 * Constructor from a given details.
+		 * <p/>
+		 * <p/>
+		 * Either <code>generalName</code> or <code>certRef</code> MUST be
+		 * <code>null</code>.
+		 *
+		 * @param country            The country code whose laws apply.
+		 * @param typeOfSubstitution The type of procuration.
+		 * @param thirdPerson        The GeneralName of the person who is represented.
+		 */
+		public ProcurationSyntax(
+			string			country,
+			DirectoryString	typeOfSubstitution,
+			GeneralName		thirdPerson)
+		{
+			this.country = country;
+			this.typeOfSubstitution = typeOfSubstitution;
+			this.thirdPerson = thirdPerson;
+			this.certRef = null;
+		}
+
+		public virtual string Country
+		{
+			get { return country; }
+		}
+
+		public virtual DirectoryString TypeOfSubstitution
+		{
+			get { return typeOfSubstitution; }
+		}
+
+		public virtual GeneralName ThirdPerson
+		{
+			get { return thirdPerson; }
+		}
+
+		public virtual IssuerSerial CertRef
+		{
+			get { return certRef; }
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*               ProcurationSyntax ::= SEQUENCE {
+		*                 country [1] EXPLICIT PrintableString(SIZE(2)) OPTIONAL,
+		*                 typeOfSubstitution [2] EXPLICIT DirectoryString (SIZE(1..128)) OPTIONAL,
+		*                 signingFor [3] EXPLICIT SigningFor
+		*               }
+		* <p/>
+		*               SigningFor ::= CHOICE
+		*               {
+		*                 thirdPerson GeneralName,
+		*                 certRef IssuerSerial
+		*               }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector vec = new Asn1EncodableVector();
+			if (country != null)
+			{
+				vec.Add(new DerTaggedObject(true, 1, new DerPrintableString(country, true)));
+			}
+			if (typeOfSubstitution != null)
+			{
+				vec.Add(new DerTaggedObject(true, 2, typeOfSubstitution));
+			}
+			if (thirdPerson != null)
+			{
+				vec.Add(new DerTaggedObject(true, 3, thirdPerson));
+			}
+			else
+			{
+				vec.Add(new DerTaggedObject(true, 3, certRef));
+			}
+
+			return new DerSequence(vec);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/isismtt/x509/ProfessionInfo.cs b/Crypto/src/asn1/isismtt/x509/ProfessionInfo.cs
new file mode 100644
index 000000000..3bad2cbc4
--- /dev/null
+++ b/Crypto/src/asn1/isismtt/x509/ProfessionInfo.cs
@@ -0,0 +1,386 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X500;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+	/**
+	* Professions, specializations, disciplines, fields of activity, etc.
+	* 
+	* <pre>
+	*               ProfessionInfo ::= SEQUENCE 
+	*               {
+	*                 namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL,
+	*                 professionItems SEQUENCE OF DirectoryString (SIZE(1..128)),
+	*                 professionOids SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
+	*                 registrationNumber PrintableString(SIZE(1..128)) OPTIONAL,
+	*                 addProfessionInfo OCTET STRING OPTIONAL 
+	*               }
+	* </pre>
+	* 
+	* @see Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax
+	*/
+	public class ProfessionInfo
+		: Asn1Encodable
+	{
+		/**
+		* Rechtsanw�ltin
+		*/
+		public static readonly DerObjectIdentifier Rechtsanwltin = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".1");
+
+		/**
+		* Rechtsanwalt
+		*/
+		public static readonly DerObjectIdentifier Rechtsanwalt = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".2");
+
+		/**
+		* Rechtsbeistand
+		*/
+		public static readonly DerObjectIdentifier Rechtsbeistand = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".3");
+
+		/**
+		* Steuerberaterin
+		*/
+		public static readonly DerObjectIdentifier Steuerberaterin = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".4");
+
+		/**
+		* Steuerberater
+		*/
+		public static readonly DerObjectIdentifier Steuerberater = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".5");
+
+		/**
+		* Steuerbevollm�chtigte
+		*/
+		public static readonly DerObjectIdentifier Steuerbevollmchtigte = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".6");
+
+		/**
+		* Steuerbevollm�chtigter
+		*/
+		public static readonly DerObjectIdentifier Steuerbevollmchtigter = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".7");
+
+		/**
+		* Notarin
+		*/
+		public static readonly DerObjectIdentifier Notarin = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".8");
+
+		/**
+		* Notar
+		*/
+		public static readonly DerObjectIdentifier Notar = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".9");
+
+		/**
+		* Notarvertreterin
+		*/
+		public static readonly DerObjectIdentifier Notarvertreterin = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".10");
+
+		/**
+		* Notarvertreter
+		*/
+		public static readonly DerObjectIdentifier Notarvertreter = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".11");
+
+		/**
+		* Notariatsverwalterin
+		*/
+		public static readonly DerObjectIdentifier Notariatsverwalterin = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".12");
+
+		/**
+		* Notariatsverwalter
+		*/
+		public static readonly DerObjectIdentifier Notariatsverwalter = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".13");
+
+		/**
+		* Wirtschaftspr�ferin
+		*/
+		public static readonly DerObjectIdentifier Wirtschaftsprferin = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".14");
+
+		/**
+		* Wirtschaftspr�fer
+		*/
+		public static readonly DerObjectIdentifier Wirtschaftsprfer = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".15");
+
+		/**
+		* Vereidigte Buchpr�ferin
+		*/
+		public static readonly DerObjectIdentifier VereidigteBuchprferin = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".16");
+
+		/**
+		* Vereidigter Buchpr�fer
+		*/
+		public static readonly DerObjectIdentifier VereidigterBuchprfer = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".17");
+
+		/**
+		* Patentanw�ltin
+		*/
+		public static readonly DerObjectIdentifier Patentanwltin = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".18");
+
+		/**
+		* Patentanwalt
+		*/
+		public static readonly DerObjectIdentifier Patentanwalt = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".19");
+
+		private readonly NamingAuthority	namingAuthority;
+		private readonly Asn1Sequence		professionItems;
+		private readonly Asn1Sequence		professionOids;
+		private readonly string				registrationNumber;
+		private readonly Asn1OctetString	addProfessionInfo;
+
+		public static ProfessionInfo GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is ProfessionInfo)
+			{
+				return (ProfessionInfo) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new ProfessionInfo((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		* Constructor from Asn1Sequence.
+		* <p/>
+		* <p/>
+		* <pre>
+		*               ProfessionInfo ::= SEQUENCE
+		*               {
+		*                 namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL,
+		*                 professionItems SEQUENCE OF DirectoryString (SIZE(1..128)),
+		*                 professionOids SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
+		*                 registrationNumber PrintableString(SIZE(1..128)) OPTIONAL,
+		*                 addProfessionInfo OCTET STRING OPTIONAL
+		*               }
+		* </pre>
+		*
+		* @param seq The ASN.1 sequence.
+		*/
+		private ProfessionInfo(
+			Asn1Sequence seq)
+		{
+			if (seq.Count > 5)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			IEnumerator e = seq.GetEnumerator();
+
+			e.MoveNext();
+			Asn1Encodable o = (Asn1Encodable) e.Current;
+
+			if (o is Asn1TaggedObject)
+			{
+				Asn1TaggedObject ato = (Asn1TaggedObject) o;
+				if (ato.TagNo != 0)
+					throw new ArgumentException("Bad tag number: " + ato.TagNo);
+
+				namingAuthority = NamingAuthority.GetInstance(ato, true);
+				e.MoveNext();
+				o = (Asn1Encodable) e.Current;
+			}
+
+			professionItems = Asn1Sequence.GetInstance(o);
+
+			if (e.MoveNext())
+			{
+				o = (Asn1Encodable) e.Current;
+				if (o is Asn1Sequence)
+				{
+					professionOids = Asn1Sequence.GetInstance(o);
+				}
+				else if (o is DerPrintableString)
+				{
+					registrationNumber = DerPrintableString.GetInstance(o).GetString();
+				}
+				else if (o is Asn1OctetString)
+				{
+					addProfessionInfo = Asn1OctetString.GetInstance(o);
+				}
+				else
+				{
+					throw new ArgumentException("Bad object encountered: " + o.GetType().Name);
+				}
+			}
+
+			if (e.MoveNext())
+			{
+				o = (Asn1Encodable) e.Current;
+				if (o is DerPrintableString)
+				{
+					registrationNumber = DerPrintableString.GetInstance(o).GetString();
+				}
+				else if (o is DerOctetString)
+				{
+					addProfessionInfo = (DerOctetString) o;
+				}
+				else
+				{
+					throw new ArgumentException("Bad object encountered: " + o.GetType().Name);
+				}
+			}
+
+			if (e.MoveNext())
+			{
+				o = (Asn1Encodable) e.Current;
+				if (o is DerOctetString)
+				{
+					addProfessionInfo = (DerOctetString) o;
+				}
+				else
+				{
+					throw new ArgumentException("Bad object encountered: " + o.GetType().Name);
+				}
+			}
+		}
+
+		/**
+		* Constructor from given details.
+		* <p/>
+		* <code>professionItems</code> is mandatory, all other parameters are
+		* optional.
+		*
+		* @param namingAuthority    The naming authority.
+		* @param professionItems    Directory strings of the profession.
+		* @param professionOids     DERObjectIdentfier objects for the
+		*                           profession.
+		* @param registrationNumber Registration number.
+		* @param addProfessionInfo  Additional infos in encoded form.
+		*/
+		public ProfessionInfo(
+			NamingAuthority			namingAuthority,
+			DirectoryString[]		professionItems,
+			DerObjectIdentifier[]	professionOids,
+			string					registrationNumber,
+			Asn1OctetString			addProfessionInfo)
+		{
+			this.namingAuthority = namingAuthority;
+			this.professionItems = new DerSequence(professionItems);
+			if (professionOids != null)
+			{
+				this.professionOids = new DerSequence(professionOids);
+			}
+			this.registrationNumber = registrationNumber;
+			this.addProfessionInfo = addProfessionInfo;
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*               ProfessionInfo ::= SEQUENCE
+		*               {
+		*                 namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL,
+		*                 professionItems SEQUENCE OF DirectoryString (SIZE(1..128)),
+		*                 professionOids SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
+		*                 registrationNumber PrintableString(SIZE(1..128)) OPTIONAL,
+		*                 addProfessionInfo OCTET STRING OPTIONAL
+		*               }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector vec = new Asn1EncodableVector();
+			if (namingAuthority != null)
+			{
+				vec.Add(new DerTaggedObject(true, 0, namingAuthority));
+			}
+			vec.Add(professionItems);
+			if (professionOids != null)
+			{
+				vec.Add(professionOids);
+			}
+			if (registrationNumber != null)
+			{
+				vec.Add(new DerPrintableString(registrationNumber, true));
+			}
+			if (addProfessionInfo != null)
+			{
+				vec.Add(addProfessionInfo);
+			}
+			return new DerSequence(vec);
+		}
+
+		/**
+		* @return Returns the addProfessionInfo.
+		*/
+		public virtual Asn1OctetString AddProfessionInfo
+		{
+			get { return addProfessionInfo; }
+		}
+
+		/**
+		* @return Returns the namingAuthority.
+		*/
+		public virtual NamingAuthority NamingAuthority
+		{
+			get { return namingAuthority; }
+		}
+
+		/**
+		* @return Returns the professionItems.
+		*/
+		public virtual DirectoryString[] GetProfessionItems()
+		{
+			DirectoryString[] result = new DirectoryString[professionItems.Count];
+
+			for (int i = 0; i < professionItems.Count; ++i)
+			{
+				result[i] = DirectoryString.GetInstance(professionItems[i]);
+			}
+
+			return result;
+		}
+
+		/**
+		* @return Returns the professionOids.
+		*/
+		public virtual DerObjectIdentifier[] GetProfessionOids()
+		{
+			if (professionOids == null)
+			{
+				return new DerObjectIdentifier[0];
+			}
+
+			DerObjectIdentifier[] result = new DerObjectIdentifier[professionOids.Count];
+
+			for (int i = 0; i < professionOids.Count; ++i)
+			{
+				result[i] = DerObjectIdentifier.GetInstance(professionOids[i]);
+			}
+
+			return result;
+		}
+
+		/**
+		* @return Returns the registrationNumber.
+		*/
+		public virtual string RegistrationNumber
+		{
+			get { return registrationNumber; }
+		}
+	}
+}
diff --git a/Crypto/src/asn1/isismtt/x509/Restriction.cs b/Crypto/src/asn1/isismtt/x509/Restriction.cs
new file mode 100644
index 000000000..c97766999
--- /dev/null
+++ b/Crypto/src/asn1/isismtt/x509/Restriction.cs
@@ -0,0 +1,81 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X500;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+	/**
+	* Some other restriction regarding the usage of this certificate.
+	* <p/>
+	* <pre>
+	*  RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+	* </pre>
+	*/
+	public class Restriction
+		: Asn1Encodable
+	{
+		private readonly DirectoryString restriction;
+
+		public static Restriction GetInstance(
+			object obj)
+		{
+			if (obj is Restriction)
+				return (Restriction) obj;
+
+			if (obj is IAsn1String)
+				return new Restriction(DirectoryString.GetInstance(obj));
+
+			throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		* Constructor from DirectoryString.
+		* <p/>
+		* The DirectoryString is of type RestrictionSyntax:
+		* <p/>
+		* <pre>
+		*      RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+		* </pre>
+		*
+		* @param restriction A IAsn1String.
+		*/
+		private Restriction(
+			DirectoryString restriction)
+		{
+			this.restriction = restriction;
+		}
+
+		/**
+		* Constructor from a given details.
+		*
+		* @param restriction The description of the restriction.
+		*/
+		public Restriction(
+			string restriction)
+		{
+			this.restriction = new DirectoryString(restriction);
+		}
+
+		public virtual DirectoryString RestrictionString
+		{
+			get { return restriction; }
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*      RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+		* <p/>
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			return restriction.ToAsn1Object();
+		}
+	}
+}
diff --git a/Crypto/src/asn1/kisa/KISAObjectIdentifiers.cs b/Crypto/src/asn1/kisa/KISAObjectIdentifiers.cs
new file mode 100644
index 000000000..05351ec75
--- /dev/null
+++ b/Crypto/src/asn1/kisa/KISAObjectIdentifiers.cs
@@ -0,0 +1,8 @@
+namespace Org.BouncyCastle.Asn1.Kisa
+{
+	public abstract class KisaObjectIdentifiers
+	{
+		public static readonly DerObjectIdentifier IdSeedCbc = new DerObjectIdentifier("1.2.410.200004.1.4");
+		public static readonly DerObjectIdentifier IdNpkiAppCmsSeedWrap = new DerObjectIdentifier("1.2.410.200004.7.1.1.1");
+	}
+}
diff --git a/Crypto/src/asn1/microsoft/MicrosoftObjectIdentifiers.cs b/Crypto/src/asn1/microsoft/MicrosoftObjectIdentifiers.cs
new file mode 100644
index 000000000..b8aba7ee9
--- /dev/null
+++ b/Crypto/src/asn1/microsoft/MicrosoftObjectIdentifiers.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Microsoft
+{
+	public abstract class MicrosoftObjectIdentifiers
+	{
+		//
+		// Microsoft
+		//       iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprise(1) Microsoft(311)
+		//
+		public static readonly DerObjectIdentifier Microsoft               = new DerObjectIdentifier("1.3.6.1.4.1.311");
+		public static readonly DerObjectIdentifier MicrosoftCertTemplateV1 = new DerObjectIdentifier(Microsoft + ".20.2");
+		public static readonly DerObjectIdentifier MicrosoftCAVersion      = new DerObjectIdentifier(Microsoft + ".21.1");
+		public static readonly DerObjectIdentifier MicrosoftPrevCACertHash = new DerObjectIdentifier(Microsoft + ".21.2");
+		public static readonly DerObjectIdentifier MicrosoftCertTemplateV2 = new DerObjectIdentifier(Microsoft + ".21.7");
+		public static readonly DerObjectIdentifier MicrosoftAppPolicies    = new DerObjectIdentifier(Microsoft + ".21.10");
+	}
+}
diff --git a/Crypto/src/asn1/misc/CAST5CBCParameters.cs b/Crypto/src/asn1/misc/CAST5CBCParameters.cs
new file mode 100644
index 000000000..51fd6607a
--- /dev/null
+++ b/Crypto/src/asn1/misc/CAST5CBCParameters.cs
@@ -0,0 +1,74 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Misc
+{
+    public class Cast5CbcParameters
+        : Asn1Encodable
+    {
+        private readonly DerInteger keyLength;
+        private readonly Asn1OctetString iv;
+
+		public static Cast5CbcParameters GetInstance(
+            object o)
+        {
+            if (o is Cast5CbcParameters)
+            {
+                return (Cast5CbcParameters) o;
+            }
+
+			if (o is Asn1Sequence)
+            {
+                return new Cast5CbcParameters((Asn1Sequence) o);
+            }
+
+			throw new ArgumentException("unknown object in Cast5CbcParameters factory");
+        }
+
+		public Cast5CbcParameters(
+            byte[]	iv,
+            int		keyLength)
+        {
+            this.iv = new DerOctetString(iv);
+            this.keyLength = new DerInteger(keyLength);
+        }
+
+		private Cast5CbcParameters(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			iv = (Asn1OctetString) seq[0];
+            keyLength = (DerInteger) seq[1];
+        }
+
+		public byte[] GetIV()
+        {
+			return Arrays.Clone(iv.GetOctets());
+		}
+
+		public int KeyLength
+		{
+			get { return keyLength.Value.IntValue; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * cast5CBCParameters ::= Sequence {
+         *                           iv         OCTET STRING DEFAULT 0,
+         *                                  -- Initialization vector
+         *                           keyLength  Integer
+         *                                  -- Key length, in bits
+         *                      }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(iv, keyLength);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/misc/IDEACBCPar.cs b/Crypto/src/asn1/misc/IDEACBCPar.cs
new file mode 100644
index 000000000..72a60b9dc
--- /dev/null
+++ b/Crypto/src/asn1/misc/IDEACBCPar.cs
@@ -0,0 +1,68 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Misc
+{
+    public class IdeaCbcPar
+        : Asn1Encodable
+    {
+        internal Asn1OctetString iv;
+
+		public static IdeaCbcPar GetInstance(
+            object o)
+        {
+            if (o is IdeaCbcPar)
+            {
+                return (IdeaCbcPar) o;
+            }
+
+			if (o is Asn1Sequence)
+            {
+                return new IdeaCbcPar((Asn1Sequence) o);
+            }
+
+			throw new ArgumentException("unknown object in IDEACBCPar factory");
+        }
+
+		public IdeaCbcPar(
+            byte[] iv)
+        {
+            this.iv = new DerOctetString(iv);
+        }
+
+		private IdeaCbcPar(
+            Asn1Sequence seq)
+        {
+			if (seq.Count == 1)
+			{
+				iv = (Asn1OctetString) seq[0];
+			}
+        }
+
+		public byte[] GetIV()
+        {
+			return iv == null ? null : iv.GetOctets();
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * IDEA-CBCPar ::= Sequence {
+         *                      iv    OCTET STRING OPTIONAL -- exactly 8 octets
+         *                  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (iv != null)
+            {
+                v.Add(iv);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/misc/MiscObjectIdentifiers.cs b/Crypto/src/asn1/misc/MiscObjectIdentifiers.cs
new file mode 100644
index 000000000..01004d889
--- /dev/null
+++ b/Crypto/src/asn1/misc/MiscObjectIdentifiers.cs
@@ -0,0 +1,48 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Misc
+{
+    public abstract class MiscObjectIdentifiers
+    {
+        //
+        // Netscape
+        //       iso/itu(2) joint-assign(16) us(840) uscompany(1) Netscape(113730) cert-extensions(1) }
+        //
+        public static readonly DerObjectIdentifier Netscape                = new DerObjectIdentifier("2.16.840.1.113730.1");
+        public static readonly DerObjectIdentifier NetscapeCertType        = new DerObjectIdentifier(Netscape + ".1");
+        public static readonly DerObjectIdentifier NetscapeBaseUrl         = new DerObjectIdentifier(Netscape + ".2");
+        public static readonly DerObjectIdentifier NetscapeRevocationUrl   = new DerObjectIdentifier(Netscape + ".3");
+        public static readonly DerObjectIdentifier NetscapeCARevocationUrl = new DerObjectIdentifier(Netscape + ".4");
+        public static readonly DerObjectIdentifier NetscapeRenewalUrl      = new DerObjectIdentifier(Netscape + ".7");
+        public static readonly DerObjectIdentifier NetscapeCAPolicyUrl     = new DerObjectIdentifier(Netscape + ".8");
+        public static readonly DerObjectIdentifier NetscapeSslServerName   = new DerObjectIdentifier(Netscape + ".12");
+        public static readonly DerObjectIdentifier NetscapeCertComment     = new DerObjectIdentifier(Netscape + ".13");
+        //
+        // Verisign
+        //       iso/itu(2) joint-assign(16) us(840) uscompany(1) verisign(113733) cert-extensions(1) }
+        //
+        internal const string Verisign = "2.16.840.1.113733.1";
+
+		//
+        // CZAG - country, zip, age, and gender
+        //
+        public static readonly DerObjectIdentifier VerisignCzagExtension = new DerObjectIdentifier(Verisign + ".6.3");
+
+		// D&B D-U-N-S number
+		public static readonly DerObjectIdentifier VerisignDnbDunsNumber = new DerObjectIdentifier(Verisign + ".6.15");
+
+		//
+		// Novell
+		//       iso/itu(2) country(16) us(840) organization(1) novell(113719)
+		//
+		public static readonly string				Novell					= "2.16.840.1.113719";
+		public static readonly DerObjectIdentifier	NovellSecurityAttribs	= new DerObjectIdentifier(Novell + ".1.9.4.1");
+
+		//
+		// Entrust
+		//       iso(1) member-body(16) us(840) nortelnetworks(113533) entrust(7)
+		//
+		public static readonly string				Entrust					= "1.2.840.113533.7";
+		public static readonly DerObjectIdentifier	EntrustVersionExtension = new DerObjectIdentifier(Entrust + ".65.0");
+	}
+}
diff --git a/Crypto/src/asn1/misc/NetscapeCertType.cs b/Crypto/src/asn1/misc/NetscapeCertType.cs
new file mode 100644
index 000000000..d5db6523d
--- /dev/null
+++ b/Crypto/src/asn1/misc/NetscapeCertType.cs
@@ -0,0 +1,54 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Misc
+{
+    /**
+     * The NetscapeCertType object.
+     * <pre>
+     *    NetscapeCertType ::= BIT STRING {
+     *         SSLClient               (0),
+     *         SSLServer               (1),
+     *         S/MIME                  (2),
+     *         Object Signing          (3),
+     *         Reserved                (4),
+     *         SSL CA                  (5),
+     *         S/MIME CA               (6),
+     *         Object Signing CA       (7) }
+     * </pre>
+     */
+    public class NetscapeCertType
+        : DerBitString
+    {
+        public const int SslClient        = (1 << 7);
+        public const int SslServer        = (1 << 6);
+        public const int Smime            = (1 << 5);
+        public const int ObjectSigning    = (1 << 4);
+        public const int Reserved         = (1 << 3);
+        public const int SslCA            = (1 << 2);
+        public const int SmimeCA          = (1 << 1);
+        public const int ObjectSigningCA  = (1 << 0);
+
+		/**
+         * Basic constructor.
+         *
+         * @param usage - the bitwise OR of the Key Usage flags giving the
+         * allowed uses for the key.
+         * e.g. (X509NetscapeCertType.sslCA | X509NetscapeCertType.smimeCA)
+         */
+        public NetscapeCertType(int usage)
+			: base(GetBytes(usage), GetPadBits(usage))
+        {
+        }
+
+		public NetscapeCertType(DerBitString usage)
+			: base(usage.GetBytes(), usage.PadBits)
+        {
+        }
+
+		public override string ToString()
+        {
+			byte[] data = GetBytes();
+			return "NetscapeCertType: 0x" + (data[0] & 0xff).ToString("X");
+        }
+    }
+}
diff --git a/Crypto/src/asn1/misc/NetscapeRevocationURL.cs b/Crypto/src/asn1/misc/NetscapeRevocationURL.cs
new file mode 100644
index 000000000..6cac031f2
--- /dev/null
+++ b/Crypto/src/asn1/misc/NetscapeRevocationURL.cs
@@ -0,0 +1,18 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Misc
+{
+    public class NetscapeRevocationUrl
+        : DerIA5String
+    {
+        public NetscapeRevocationUrl(DerIA5String str)
+			: base(str.GetString())
+        {
+        }
+
+        public override string ToString()
+        {
+            return "NetscapeRevocationUrl: " + this.GetString();
+        }
+    }
+}
diff --git a/Crypto/src/asn1/misc/VerisignCzagExtension.cs b/Crypto/src/asn1/misc/VerisignCzagExtension.cs
new file mode 100644
index 000000000..1c3054b32
--- /dev/null
+++ b/Crypto/src/asn1/misc/VerisignCzagExtension.cs
@@ -0,0 +1,18 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Misc
+{
+    public class VerisignCzagExtension
+        : DerIA5String
+    {
+        public VerisignCzagExtension(DerIA5String str)
+			: base(str.GetString())
+        {
+        }
+
+        public override string ToString()
+        {
+            return "VerisignCzagExtension: " + this.GetString();
+        }
+    }
+}
diff --git a/Crypto/src/asn1/mozilla/PublicKeyAndChallenge.cs b/Crypto/src/asn1/mozilla/PublicKeyAndChallenge.cs
new file mode 100644
index 000000000..1e08b809d
--- /dev/null
+++ b/Crypto/src/asn1/mozilla/PublicKeyAndChallenge.cs
@@ -0,0 +1,67 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Mozilla
+{
+	/**
+	 * This is designed to parse
+	 * the PublicKeyAndChallenge created by the KEYGEN tag included by
+	 * Mozilla based browsers.
+	 *  <pre>
+	 *  PublicKeyAndChallenge ::= SEQUENCE {
+	 *    spki SubjectPublicKeyInfo,
+	 *    challenge IA5STRING
+	 *  }
+	 *
+	 *  </pre>
+	 */
+	public class PublicKeyAndChallenge
+		: Asn1Encodable
+	{
+		private Asn1Sequence			pkacSeq;
+		private SubjectPublicKeyInfo	spki;
+		private DerIA5String			challenge;
+
+		public static PublicKeyAndChallenge GetInstance(
+			object obj)
+		{
+			if (obj is PublicKeyAndChallenge)
+			{
+				return (PublicKeyAndChallenge) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new PublicKeyAndChallenge((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException(
+				"unknown object in 'PublicKeyAndChallenge' factory : "
+				+ obj.GetType().Name + ".");
+		}
+
+		public PublicKeyAndChallenge(
+			Asn1Sequence seq)
+		{
+			pkacSeq = seq;
+			spki = SubjectPublicKeyInfo.GetInstance(seq[0]);
+			challenge = DerIA5String.GetInstance(seq[1]);
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return pkacSeq;
+		}
+
+		public SubjectPublicKeyInfo SubjectPublicKeyInfo
+		{
+			get { return spki; }
+		}
+
+		public DerIA5String Challenge
+		{
+			get { return challenge; }
+		}
+	}
+}
diff --git a/Crypto/src/asn1/nist/NISTNamedCurves.cs b/Crypto/src/asn1/nist/NISTNamedCurves.cs
new file mode 100644
index 000000000..3b4c59df2
--- /dev/null
+++ b/Crypto/src/asn1/nist/NISTNamedCurves.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Nist
+{
+	/**
+	* Utility class for fetching curves using their NIST names as published in FIPS-PUB 186-2
+	*/
+	public sealed class NistNamedCurves
+	{
+		private NistNamedCurves()
+		{
+		}
+
+		private static readonly IDictionary objIds = Platform.CreateHashtable();
+        private static readonly IDictionary names = Platform.CreateHashtable();
+
+		private static void DefineCurve(
+			string				name,
+			DerObjectIdentifier	oid)
+		{
+			objIds.Add(name, oid);
+			names.Add(oid, name);
+		}
+
+		static NistNamedCurves()
+		{
+			DefineCurve("B-571", SecObjectIdentifiers.SecT571r1);
+			DefineCurve("B-409", SecObjectIdentifiers.SecT409r1);
+			DefineCurve("B-283", SecObjectIdentifiers.SecT283r1);
+			DefineCurve("B-233", SecObjectIdentifiers.SecT233r1);
+			DefineCurve("B-163", SecObjectIdentifiers.SecT163r2);
+			DefineCurve("P-521", SecObjectIdentifiers.SecP521r1);
+			DefineCurve("P-384", SecObjectIdentifiers.SecP384r1);
+			DefineCurve("P-256", SecObjectIdentifiers.SecP256r1);
+			DefineCurve("P-224", SecObjectIdentifiers.SecP224r1);
+			DefineCurve("P-192", SecObjectIdentifiers.SecP192r1);
+		}
+
+		public static X9ECParameters GetByName(
+			string name)
+		{
+			DerObjectIdentifier oid = (DerObjectIdentifier) objIds[name.ToUpperInvariant()];
+
+			if (oid != null)
+			{
+				return GetByOid(oid);
+			}
+
+			return null;
+		}
+
+		/**
+		* return the X9ECParameters object for the named curve represented by
+		* the passed in object identifier. Null if the curve isn't present.
+		*
+		* @param oid an object identifier representing a named curve, if present.
+		*/
+		public static X9ECParameters GetByOid(
+			DerObjectIdentifier oid)
+		{
+			return SecNamedCurves.GetByOid(oid);
+		}
+
+		/**
+		* return the object identifier signified by the passed in name. Null
+		* if there is no object identifier associated with name.
+		*
+		* @return the object identifier associated with name, if present.
+		*/
+		public static DerObjectIdentifier GetOid(
+			string name)
+		{
+			return (DerObjectIdentifier) objIds[name.ToUpperInvariant()];
+		}
+
+		/**
+		* return the named curve name represented by the given object identifier.
+		*/
+		public static string GetName(
+			DerObjectIdentifier  oid)
+		{
+			return (string) names[oid];
+		}
+
+		/**
+		* returns an enumeration containing the name strings for curves
+		* contained in this structure.
+		*/
+		public static IEnumerable Names
+		{
+			get { return new EnumerableProxy(objIds.Keys); }
+		}
+	}
+}
diff --git a/Crypto/src/asn1/nist/NISTObjectIdentifiers.cs b/Crypto/src/asn1/nist/NISTObjectIdentifiers.cs
new file mode 100644
index 000000000..f3957062f
--- /dev/null
+++ b/Crypto/src/asn1/nist/NISTObjectIdentifiers.cs
@@ -0,0 +1,61 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Nist
+{
+    public sealed class NistObjectIdentifiers
+    {
+		private NistObjectIdentifiers()
+		{
+		}
+
+        //
+        // NIST
+        //     iso/itu(2) joint-assign(16) us(840) organization(1) gov(101) csor(3)
+
+        //
+        // nistalgorithms(4)
+        //
+        public static readonly DerObjectIdentifier NistAlgorithm = new DerObjectIdentifier("2.16.840.1.101.3.4");
+
+        public static readonly DerObjectIdentifier IdSha256 = new DerObjectIdentifier(NistAlgorithm + ".2.1");
+        public static readonly DerObjectIdentifier IdSha384 = new DerObjectIdentifier(NistAlgorithm + ".2.2");
+        public static readonly DerObjectIdentifier IdSha512 = new DerObjectIdentifier(NistAlgorithm + ".2.3");
+        public static readonly DerObjectIdentifier IdSha224 = new DerObjectIdentifier(NistAlgorithm + ".2.4");
+
+        public static readonly DerObjectIdentifier Aes = new DerObjectIdentifier(NistAlgorithm + ".1");
+
+        public static readonly DerObjectIdentifier IdAes128Ecb	= new DerObjectIdentifier(Aes + ".1");
+        public static readonly DerObjectIdentifier IdAes128Cbc	= new DerObjectIdentifier(Aes + ".2");
+        public static readonly DerObjectIdentifier IdAes128Ofb	= new DerObjectIdentifier(Aes + ".3");
+        public static readonly DerObjectIdentifier IdAes128Cfb	= new DerObjectIdentifier(Aes + ".4");
+        public static readonly DerObjectIdentifier IdAes128Wrap	= new DerObjectIdentifier(Aes + ".5");
+        public static readonly DerObjectIdentifier IdAes128Gcm	= new DerObjectIdentifier(Aes + ".6");
+        public static readonly DerObjectIdentifier IdAes128Ccm	= new DerObjectIdentifier(Aes + ".7");
+
+        public static readonly DerObjectIdentifier IdAes192Ecb	= new DerObjectIdentifier(Aes + ".21");
+        public static readonly DerObjectIdentifier IdAes192Cbc	= new DerObjectIdentifier(Aes + ".22");
+        public static readonly DerObjectIdentifier IdAes192Ofb	= new DerObjectIdentifier(Aes + ".23");
+        public static readonly DerObjectIdentifier IdAes192Cfb	= new DerObjectIdentifier(Aes + ".24");
+        public static readonly DerObjectIdentifier IdAes192Wrap	= new DerObjectIdentifier(Aes + ".25");
+        public static readonly DerObjectIdentifier IdAes192Gcm	= new DerObjectIdentifier(Aes + ".26");
+        public static readonly DerObjectIdentifier IdAes192Ccm	= new DerObjectIdentifier(Aes + ".27");
+
+        public static readonly DerObjectIdentifier IdAes256Ecb	= new DerObjectIdentifier(Aes + ".41");
+        public static readonly DerObjectIdentifier IdAes256Cbc	= new DerObjectIdentifier(Aes + ".42");
+        public static readonly DerObjectIdentifier IdAes256Ofb	= new DerObjectIdentifier(Aes + ".43");
+        public static readonly DerObjectIdentifier IdAes256Cfb	= new DerObjectIdentifier(Aes + ".44");
+        public static readonly DerObjectIdentifier IdAes256Wrap	= new DerObjectIdentifier(Aes + ".45");
+        public static readonly DerObjectIdentifier IdAes256Gcm	= new DerObjectIdentifier(Aes + ".46");
+        public static readonly DerObjectIdentifier IdAes256Ccm	= new DerObjectIdentifier(Aes + ".47");
+
+		//
+		// signatures
+		//
+		public static readonly DerObjectIdentifier IdDsaWithSha2 = new DerObjectIdentifier(NistAlgorithm + ".3");
+
+		public static readonly DerObjectIdentifier DsaWithSha224 = new DerObjectIdentifier(IdDsaWithSha2 + ".1");
+		public static readonly DerObjectIdentifier DsaWithSha256 = new DerObjectIdentifier(IdDsaWithSha2 + ".2");
+		public static readonly DerObjectIdentifier DsaWithSha384 = new DerObjectIdentifier(IdDsaWithSha2 + ".3");
+		public static readonly DerObjectIdentifier DsaWithSha512 = new DerObjectIdentifier(IdDsaWithSha2 + ".4"); 
+	}
+}
diff --git a/Crypto/src/asn1/ntt/NTTObjectIdentifiers.cs b/Crypto/src/asn1/ntt/NTTObjectIdentifiers.cs
new file mode 100644
index 000000000..cd2595600
--- /dev/null
+++ b/Crypto/src/asn1/ntt/NTTObjectIdentifiers.cs
@@ -0,0 +1,14 @@
+namespace Org.BouncyCastle.Asn1.Ntt
+{
+	/// <summary>From RFC 3657</summary>
+	public abstract class NttObjectIdentifiers
+	{
+		public static readonly DerObjectIdentifier IdCamellia128Cbc = new DerObjectIdentifier("1.2.392.200011.61.1.1.1.2");
+		public static readonly DerObjectIdentifier IdCamellia192Cbc = new DerObjectIdentifier("1.2.392.200011.61.1.1.1.3");
+		public static readonly DerObjectIdentifier IdCamellia256Cbc = new DerObjectIdentifier("1.2.392.200011.61.1.1.1.4");
+
+		public static readonly DerObjectIdentifier IdCamellia128Wrap = new DerObjectIdentifier("1.2.392.200011.61.1.1.3.2");
+		public static readonly DerObjectIdentifier IdCamellia192Wrap = new DerObjectIdentifier("1.2.392.200011.61.1.1.3.3");
+		public static readonly DerObjectIdentifier IdCamellia256Wrap = new DerObjectIdentifier("1.2.392.200011.61.1.1.3.4");
+	}
+}
diff --git a/Crypto/src/asn1/ocsp/BasicOCSPResponse.cs b/Crypto/src/asn1/ocsp/BasicOCSPResponse.cs
new file mode 100644
index 000000000..dd666addf
--- /dev/null
+++ b/Crypto/src/asn1/ocsp/BasicOCSPResponse.cs
@@ -0,0 +1,131 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class BasicOcspResponse
+        : Asn1Encodable
+    {
+        private readonly ResponseData			tbsResponseData;
+        private readonly AlgorithmIdentifier	signatureAlgorithm;
+        private readonly DerBitString			signature;
+        private readonly Asn1Sequence			certs;
+
+		public static BasicOcspResponse GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static BasicOcspResponse GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is BasicOcspResponse)
+			{
+				return (BasicOcspResponse)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new BasicOcspResponse((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public BasicOcspResponse(
+            ResponseData		tbsResponseData,
+            AlgorithmIdentifier	signatureAlgorithm,
+            DerBitString		signature,
+            Asn1Sequence		certs)
+        {
+            this.tbsResponseData = tbsResponseData;
+            this.signatureAlgorithm = signatureAlgorithm;
+            this.signature = signature;
+            this.certs = certs;
+        }
+
+		private BasicOcspResponse(
+            Asn1Sequence seq)
+        {
+            this.tbsResponseData = ResponseData.GetInstance(seq[0]);
+            this.signatureAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+            this.signature = (DerBitString)seq[2];
+
+			if (seq.Count > 3)
+            {
+                this.certs = Asn1Sequence.GetInstance((Asn1TaggedObject)seq[3], true);
+            }
+        }
+
+		[Obsolete("Use TbsResponseData property instead")]
+		public ResponseData GetTbsResponseData()
+        {
+            return tbsResponseData;
+        }
+
+		public ResponseData TbsResponseData
+		{
+			get { return tbsResponseData; }
+		}
+
+		[Obsolete("Use SignatureAlgorithm property instead")]
+		public AlgorithmIdentifier GetSignatureAlgorithm()
+        {
+            return signatureAlgorithm;
+        }
+
+		public AlgorithmIdentifier SignatureAlgorithm
+		{
+			get { return signatureAlgorithm; }
+		}
+
+		[Obsolete("Use Signature property instead")]
+		public DerBitString GetSignature()
+        {
+            return signature;
+        }
+
+		public DerBitString Signature
+		{
+			get { return signature; }
+		}
+
+		[Obsolete("Use Certs property instead")]
+		public Asn1Sequence GetCerts()
+        {
+            return certs;
+        }
+
+		public Asn1Sequence Certs
+		{
+			get { return certs; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * BasicOcspResponse       ::= Sequence {
+         *      tbsResponseData      ResponseData,
+         *      signatureAlgorithm   AlgorithmIdentifier,
+         *      signature            BIT STRING,
+         *      certs                [0] EXPLICIT Sequence OF Certificate OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				tbsResponseData, signatureAlgorithm, signature);
+
+			if (certs != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, certs));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/ocsp/CertID.cs b/Crypto/src/asn1/ocsp/CertID.cs
new file mode 100644
index 000000000..4b251095b
--- /dev/null
+++ b/Crypto/src/asn1/ocsp/CertID.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class CertID
+        : Asn1Encodable
+    {
+        private readonly AlgorithmIdentifier    hashAlgorithm;
+        private readonly Asn1OctetString        issuerNameHash;
+        private readonly Asn1OctetString        issuerKeyHash;
+        private readonly DerInteger             serialNumber;
+
+		public static CertID GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static CertID GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CertID)
+			{
+				return (CertID)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new CertID((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public CertID(
+            AlgorithmIdentifier hashAlgorithm,
+            Asn1OctetString     issuerNameHash,
+            Asn1OctetString     issuerKeyHash,
+            DerInteger          serialNumber)
+        {
+            this.hashAlgorithm = hashAlgorithm;
+            this.issuerNameHash = issuerNameHash;
+            this.issuerKeyHash = issuerKeyHash;
+            this.serialNumber = serialNumber;
+        }
+
+		private CertID(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 4)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]);
+            this.issuerNameHash = Asn1OctetString.GetInstance(seq[1]);
+            this.issuerKeyHash = Asn1OctetString.GetInstance(seq[2]);
+            this.serialNumber = DerInteger.GetInstance(seq[3]);
+        }
+
+		public AlgorithmIdentifier HashAlgorithm
+		{
+			get { return hashAlgorithm; }
+		}
+
+		public Asn1OctetString IssuerNameHash
+		{
+			get { return issuerNameHash; }
+		}
+
+		public Asn1OctetString IssuerKeyHash
+		{
+			get { return issuerKeyHash; }
+		}
+
+		public DerInteger SerialNumber
+		{
+			get { return serialNumber; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * CertID          ::=     Sequence {
+         *     hashAlgorithm       AlgorithmIdentifier,
+         *     issuerNameHash      OCTET STRING, -- Hash of Issuer's DN
+         *     issuerKeyHash       OCTET STRING, -- Hash of Issuers public key
+         *     serialNumber        CertificateSerialNumber }
+         * </pre>
+         */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(hashAlgorithm, issuerNameHash, issuerKeyHash, serialNumber);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/ocsp/CertStatus.cs b/Crypto/src/asn1/ocsp/CertStatus.cs
new file mode 100644
index 000000000..d5b1a94a2
--- /dev/null
+++ b/Crypto/src/asn1/ocsp/CertStatus.cs
@@ -0,0 +1,94 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class CertStatus
+        : Asn1Encodable, IAsn1Choice
+    {
+        private readonly int			tagNo;
+        private readonly Asn1Encodable	value;
+
+		/**
+         * create a CertStatus object with a tag of zero.
+         */
+        public CertStatus()
+        {
+            tagNo = 0;
+            value = DerNull.Instance;
+        }
+
+		public CertStatus(
+            RevokedInfo info)
+        {
+            tagNo = 1;
+            value = info;
+        }
+
+		public CertStatus(
+            int				tagNo,
+            Asn1Encodable	value)
+        {
+            this.tagNo = tagNo;
+            this.value = value;
+        }
+
+		public CertStatus(
+            Asn1TaggedObject choice)
+        {
+            this.tagNo = choice.TagNo;
+
+			switch (choice.TagNo)
+            {
+				case 1:
+					value = RevokedInfo.GetInstance(choice, false);
+					break;
+				case 0:
+				case 2:
+					value = DerNull.Instance;
+					break;
+            }
+        }
+
+		public static CertStatus GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is CertStatus)
+            {
+                return (CertStatus)obj;
+            }
+
+			if (obj is Asn1TaggedObject)
+            {
+                return new CertStatus((Asn1TaggedObject)obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        }
+
+		public int TagNo
+		{
+			get { return tagNo; }
+		}
+
+		public Asn1Encodable Status
+		{
+			get { return value; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  CertStatus ::= CHOICE {
+         *                  good        [0]     IMPLICIT Null,
+         *                  revoked     [1]     IMPLICIT RevokedInfo,
+         *                  unknown     [2]     IMPLICIT UnknownInfo }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerTaggedObject(false, tagNo, value);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/ocsp/CrlID.cs b/Crypto/src/asn1/ocsp/CrlID.cs
new file mode 100644
index 000000000..cfb3d6fcb
--- /dev/null
+++ b/Crypto/src/asn1/ocsp/CrlID.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class CrlID
+        : Asn1Encodable
+    {
+        private readonly DerIA5String		crlUrl;
+        private readonly DerInteger			crlNum;
+        private readonly DerGeneralizedTime	crlTime;
+
+		// TODO Add GetInstance method(s) and amke this private?
+		public CrlID(
+            Asn1Sequence seq)
+        {
+			foreach (Asn1TaggedObject o in seq)
+			{
+				switch (o.TagNo)
+                {
+                case 0:
+                    crlUrl = DerIA5String.GetInstance(o, true);
+                    break;
+                case 1:
+                    crlNum = DerInteger.GetInstance(o, true);
+                    break;
+                case 2:
+                    crlTime = DerGeneralizedTime.GetInstance(o, true);
+                    break;
+                default:
+                    throw new ArgumentException("unknown tag number: " + o.TagNo);
+                }
+            }
+        }
+
+		public DerIA5String CrlUrl
+		{
+			get { return crlUrl; }
+		}
+
+		public DerInteger CrlNum
+		{
+			get { return crlNum; }
+		}
+
+		public DerGeneralizedTime CrlTime
+		{
+			get { return crlTime; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * CrlID ::= Sequence {
+         *     crlUrl               [0]     EXPLICIT IA5String OPTIONAL,
+         *     crlNum               [1]     EXPLICIT Integer OPTIONAL,
+         *     crlTime              [2]     EXPLICIT GeneralizedTime OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (crlUrl != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, crlUrl));
+            }
+
+			if (crlNum != null)
+            {
+                v.Add(new DerTaggedObject(true, 1, crlNum));
+            }
+
+			if (crlTime != null)
+            {
+                v.Add(new DerTaggedObject(true, 2, crlTime));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/ocsp/OCSPObjectIdentifiers.cs b/Crypto/src/asn1/ocsp/OCSPObjectIdentifiers.cs
new file mode 100644
index 000000000..a37c8552d
--- /dev/null
+++ b/Crypto/src/asn1/ocsp/OCSPObjectIdentifiers.cs
@@ -0,0 +1,23 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public abstract class OcspObjectIdentifiers
+    {
+        internal const string PkixOcspId = "1.3.6.1.5.5.7.48.1";
+
+		public static readonly DerObjectIdentifier PkixOcsp = new DerObjectIdentifier(PkixOcspId);
+        public static readonly DerObjectIdentifier PkixOcspBasic = new DerObjectIdentifier(PkixOcspId + ".1");
+
+		//
+		// extensions
+		//
+		public static readonly DerObjectIdentifier PkixOcspNonce = new DerObjectIdentifier(PkixOcsp + ".2");
+		public static readonly DerObjectIdentifier PkixOcspCrl = new DerObjectIdentifier(PkixOcsp + ".3");
+
+		public static readonly DerObjectIdentifier PkixOcspResponse = new DerObjectIdentifier(PkixOcsp + ".4");
+		public static readonly DerObjectIdentifier PkixOcspNocheck = new DerObjectIdentifier(PkixOcsp + ".5");
+		public static readonly DerObjectIdentifier PkixOcspArchiveCutoff = new DerObjectIdentifier(PkixOcsp + ".6");
+		public static readonly DerObjectIdentifier PkixOcspServiceLocator = new DerObjectIdentifier(PkixOcsp + ".7");
+	}
+}
diff --git a/Crypto/src/asn1/ocsp/OCSPRequest.cs b/Crypto/src/asn1/ocsp/OCSPRequest.cs
new file mode 100644
index 000000000..1e804d78e
--- /dev/null
+++ b/Crypto/src/asn1/ocsp/OCSPRequest.cs
@@ -0,0 +1,89 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class OcspRequest
+        : Asn1Encodable
+    {
+        private readonly TbsRequest	tbsRequest;
+        private readonly Signature	optionalSignature;
+
+		public static OcspRequest GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static OcspRequest GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OcspRequest)
+			{
+				return (OcspRequest)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new OcspRequest((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public OcspRequest(
+            TbsRequest	tbsRequest,
+            Signature	optionalSignature)
+        {
+			if (tbsRequest == null)
+				throw new ArgumentNullException("tbsRequest");
+
+			this.tbsRequest = tbsRequest;
+            this.optionalSignature = optionalSignature;
+        }
+
+		private OcspRequest(
+            Asn1Sequence seq)
+        {
+            tbsRequest = TbsRequest.GetInstance(seq[0]);
+
+			if (seq.Count == 2)
+            {
+                optionalSignature = Signature.GetInstance(
+					(Asn1TaggedObject)seq[1], true);
+            }
+        }
+
+		public TbsRequest TbsRequest
+		{
+			get { return tbsRequest; }
+		}
+
+		public Signature OptionalSignature
+		{
+			get { return optionalSignature; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * OcspRequest     ::=     Sequence {
+         *     tbsRequest                  TBSRequest,
+         *     optionalSignature   [0]     EXPLICIT Signature OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(tbsRequest);
+
+			if (optionalSignature != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, optionalSignature));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/ocsp/OCSPResponse.cs b/Crypto/src/asn1/ocsp/OCSPResponse.cs
new file mode 100644
index 000000000..e9aad8100
--- /dev/null
+++ b/Crypto/src/asn1/ocsp/OCSPResponse.cs
@@ -0,0 +1,90 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class OcspResponse
+        : Asn1Encodable
+    {
+        private readonly OcspResponseStatus	responseStatus;
+        private readonly ResponseBytes		responseBytes;
+
+		public static OcspResponse GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static OcspResponse GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OcspResponse)
+			{
+				return (OcspResponse)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new OcspResponse((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public OcspResponse(
+            OcspResponseStatus	responseStatus,
+            ResponseBytes		responseBytes)
+        {
+			if (responseStatus == null)
+				throw new ArgumentNullException("responseStatus");
+
+			this.responseStatus = responseStatus;
+            this.responseBytes = responseBytes;
+        }
+
+		private OcspResponse(
+            Asn1Sequence seq)
+        {
+            responseStatus = new OcspResponseStatus(
+				DerEnumerated.GetInstance(seq[0]));
+
+			if (seq.Count == 2)
+            {
+                responseBytes = ResponseBytes.GetInstance(
+					(Asn1TaggedObject)seq[1], true);
+            }
+        }
+
+		public OcspResponseStatus ResponseStatus
+		{
+			get { return responseStatus; }
+		}
+
+		public ResponseBytes ResponseBytes
+		{
+			get { return responseBytes; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * OcspResponse ::= Sequence {
+         *     responseStatus         OcspResponseStatus,
+         *     responseBytes          [0] EXPLICIT ResponseBytes OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(responseStatus);
+
+			if (responseBytes != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, responseBytes));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/ocsp/OCSPResponseStatus.cs b/Crypto/src/asn1/ocsp/OCSPResponseStatus.cs
new file mode 100644
index 000000000..653317e33
--- /dev/null
+++ b/Crypto/src/asn1/ocsp/OCSPResponseStatus.cs
@@ -0,0 +1,41 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class OcspResponseStatus
+        : DerEnumerated
+    {
+        public const int Successful = 0;
+        public const int MalformedRequest = 1;
+        public const int InternalError = 2;
+        public const int TryLater = 3;
+        public const int SignatureRequired = 5;
+        public const int Unauthorized = 6;
+
+		/**
+         * The OcspResponseStatus enumeration.
+         * <pre>
+         * OcspResponseStatus ::= Enumerated {
+         *     successful            (0),  --Response has valid confirmations
+         *     malformedRequest      (1),  --Illegal confirmation request
+         *     internalError         (2),  --Internal error in issuer
+         *     tryLater              (3),  --Try again later
+         *                                 --(4) is not used
+         *     sigRequired           (5),  --Must sign the request
+         *     unauthorized          (6)   --Request unauthorized
+         * }
+         * </pre>
+         */
+        public OcspResponseStatus(int value)
+			: base(value)
+        {
+        }
+
+		public OcspResponseStatus(DerEnumerated value)
+			: base(value.Value.IntValue)
+        {
+        }
+    }
+}
diff --git a/Crypto/src/asn1/ocsp/Request.cs b/Crypto/src/asn1/ocsp/Request.cs
new file mode 100644
index 000000000..116c15e73
--- /dev/null
+++ b/Crypto/src/asn1/ocsp/Request.cs
@@ -0,0 +1,90 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class Request
+        : Asn1Encodable
+    {
+        private readonly CertID			reqCert;
+        private readonly X509Extensions	singleRequestExtensions;
+
+		public static Request GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static Request GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is Request)
+			{
+				return (Request)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new Request((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public Request(
+            CertID			reqCert,
+            X509Extensions	singleRequestExtensions)
+        {
+			if (reqCert == null)
+				throw new ArgumentNullException("reqCert");
+
+			this.reqCert = reqCert;
+            this.singleRequestExtensions = singleRequestExtensions;
+        }
+
+		private Request(
+			Asn1Sequence seq)
+        {
+			reqCert = CertID.GetInstance(seq[0]);
+
+			if (seq.Count == 2)
+            {
+                singleRequestExtensions = X509Extensions.GetInstance(
+					(Asn1TaggedObject)seq[1], true);
+            }
+        }
+
+		public CertID ReqCert
+		{
+			get { return reqCert; }
+		}
+
+		public X509Extensions SingleRequestExtensions
+		{
+			get { return singleRequestExtensions; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * Request         ::=     Sequence {
+         *     reqCert                     CertID,
+         *     singleRequestExtensions     [0] EXPLICIT Extensions OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(reqCert);
+
+			if (singleRequestExtensions != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, singleRequestExtensions));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/ocsp/ResponderID.cs b/Crypto/src/asn1/ocsp/ResponderID.cs
new file mode 100644
index 000000000..143b17339
--- /dev/null
+++ b/Crypto/src/asn1/ocsp/ResponderID.cs
@@ -0,0 +1,107 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class ResponderID
+        : Asn1Encodable, IAsn1Choice
+    {
+        private readonly Asn1Encodable id;
+
+		public static ResponderID GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is ResponderID)
+			{
+				return (ResponderID)obj;
+			}
+
+			if (obj is DerOctetString)
+			{
+				return new ResponderID((DerOctetString)obj);
+			}
+
+			if (obj is Asn1TaggedObject)
+			{
+				Asn1TaggedObject o = (Asn1TaggedObject)obj;
+
+				if (o.TagNo == 1)
+				{
+					return new ResponderID(X509Name.GetInstance(o, true));
+				}
+
+				return new ResponderID(Asn1OctetString.GetInstance(o, true));
+			}
+
+			return new ResponderID(X509Name.GetInstance(obj));
+		}
+
+		public ResponderID(
+            Asn1OctetString id)
+        {
+			if (id == null)
+				throw new ArgumentNullException("id");
+
+			this.id = id;
+        }
+
+		public ResponderID(
+            X509Name id)
+        {
+			if (id == null)
+				throw new ArgumentNullException("id");
+
+			this.id = id;
+        }
+
+		public static ResponderID GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			return GetInstance(obj.GetObject()); // must be explicitly tagged
+		}
+
+		public virtual byte[] GetKeyHash()
+		{
+			if (id is Asn1OctetString)
+			{
+				return ((Asn1OctetString)id).GetOctets();
+			}
+
+			return null;
+		}
+
+		public virtual X509Name Name
+		{
+			get
+			{
+				if (id is Asn1OctetString)
+				{
+					return null;
+				}
+
+				return X509Name.GetInstance(id);
+			}
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * ResponderID ::= CHOICE {
+         *      byName          [1] Name,
+         *      byKey           [2] KeyHash }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            if (id is Asn1OctetString)
+            {
+                return new DerTaggedObject(true, 2, id);
+            }
+
+			return new DerTaggedObject(true, 1, id);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/ocsp/ResponseBytes.cs b/Crypto/src/asn1/ocsp/ResponseBytes.cs
new file mode 100644
index 000000000..2ce59faea
--- /dev/null
+++ b/Crypto/src/asn1/ocsp/ResponseBytes.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class ResponseBytes
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier responseType;
+        private readonly Asn1OctetString response;
+
+		public static ResponseBytes GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static ResponseBytes GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is ResponseBytes)
+			{
+				return (ResponseBytes)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new ResponseBytes((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public ResponseBytes(
+            DerObjectIdentifier	responseType,
+            Asn1OctetString		response)
+        {
+			if (responseType == null)
+				throw new ArgumentNullException("responseType");
+			if (response == null)
+				throw new ArgumentNullException("response");
+
+			this.responseType = responseType;
+            this.response = response;
+        }
+
+		private ResponseBytes(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			this.responseType = DerObjectIdentifier.GetInstance(seq[0]);
+            this.response = Asn1OctetString.GetInstance(seq[1]);
+        }
+
+		public DerObjectIdentifier ResponseType
+		{
+			get { return responseType; }
+		}
+
+		public Asn1OctetString Response
+		{
+			get { return response; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * ResponseBytes ::=       Sequence {
+         *     responseType   OBJECT IDENTIFIER,
+         *     response       OCTET STRING }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(responseType, response);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/ocsp/ResponseData.cs b/Crypto/src/asn1/ocsp/ResponseData.cs
new file mode 100644
index 000000000..173829db8
--- /dev/null
+++ b/Crypto/src/asn1/ocsp/ResponseData.cs
@@ -0,0 +1,158 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+	public class ResponseData
+		: Asn1Encodable
+	{
+		private static readonly DerInteger V1 = new DerInteger(0);
+
+		private readonly bool                versionPresent;
+		private readonly DerInteger          version;
+		private readonly ResponderID         responderID;
+		private readonly DerGeneralizedTime  producedAt;
+		private readonly Asn1Sequence        responses;
+		private readonly X509Extensions      responseExtensions;
+
+		public static ResponseData GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static ResponseData GetInstance(
+			object  obj)
+		{
+			if (obj == null || obj is ResponseData)
+			{
+				return (ResponseData)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new ResponseData((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public ResponseData(
+			DerInteger          version,
+			ResponderID         responderID,
+			DerGeneralizedTime  producedAt,
+			Asn1Sequence        responses,
+			X509Extensions      responseExtensions)
+		{
+			this.version = version;
+			this.responderID = responderID;
+			this.producedAt = producedAt;
+			this.responses = responses;
+			this.responseExtensions = responseExtensions;
+		}
+
+		public ResponseData(
+			ResponderID         responderID,
+			DerGeneralizedTime  producedAt,
+			Asn1Sequence        responses,
+			X509Extensions      responseExtensions)
+			: this(V1, responderID, producedAt, responses, responseExtensions)
+		{
+		}
+
+		private ResponseData(
+			Asn1Sequence seq)
+		{
+			int index = 0;
+
+			Asn1Encodable enc = seq[0];
+			if (enc is Asn1TaggedObject)
+			{
+				Asn1TaggedObject o = (Asn1TaggedObject)enc;
+
+				if (o.TagNo == 0)
+				{
+					this.versionPresent = true;
+					this.version = DerInteger.GetInstance(o, true);
+					index++;
+				}
+				else
+				{
+					this.version = V1;
+				}
+			}
+			else
+			{
+				this.version = V1;
+			}
+
+			this.responderID = ResponderID.GetInstance(seq[index++]);
+			this.producedAt = (DerGeneralizedTime)seq[index++];
+			this.responses = (Asn1Sequence)seq[index++];
+
+			if (seq.Count > index)
+			{
+				this.responseExtensions = X509Extensions.GetInstance(
+					(Asn1TaggedObject)seq[index], true);
+			}
+		}
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public ResponderID ResponderID
+		{
+			get { return responderID; }
+		}
+
+		public DerGeneralizedTime ProducedAt
+		{
+			get { return producedAt; }
+		}
+
+		public Asn1Sequence Responses
+		{
+			get { return responses; }
+		}
+
+		public X509Extensions ResponseExtensions
+		{
+			get { return responseExtensions; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * ResponseData ::= Sequence {
+         *     version              [0] EXPLICIT Version DEFAULT v1,
+         *     responderID              ResponderID,
+         *     producedAt               GeneralizedTime,
+         *     responses                Sequence OF SingleResponse,
+         *     responseExtensions   [1] EXPLICIT Extensions OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (versionPresent || !version.Equals(V1))
+			{
+				v.Add(new DerTaggedObject(true, 0, version));
+			}
+
+			v.Add(responderID, producedAt, responses);
+
+			if (responseExtensions != null)
+            {
+                v.Add(new DerTaggedObject(true, 1, responseExtensions));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/ocsp/RevokedInfo.cs b/Crypto/src/asn1/ocsp/RevokedInfo.cs
new file mode 100644
index 000000000..7d9d590e3
--- /dev/null
+++ b/Crypto/src/asn1/ocsp/RevokedInfo.cs
@@ -0,0 +1,96 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class RevokedInfo
+        : Asn1Encodable
+    {
+        private readonly DerGeneralizedTime revocationTime;
+        private readonly CrlReason revocationReason;
+
+		public static RevokedInfo GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static RevokedInfo GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is RevokedInfo)
+			{
+				return (RevokedInfo) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new RevokedInfo((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public RevokedInfo(
+			DerGeneralizedTime revocationTime)
+			: this(revocationTime, null)
+		{
+		}
+
+		public RevokedInfo(
+            DerGeneralizedTime  revocationTime,
+            CrlReason           revocationReason)
+        {
+			if (revocationTime == null)
+				throw new ArgumentNullException("revocationTime");
+
+			this.revocationTime = revocationTime;
+            this.revocationReason = revocationReason;
+        }
+
+		private RevokedInfo(
+            Asn1Sequence seq)
+        {
+            this.revocationTime = (DerGeneralizedTime) seq[0];
+
+			if (seq.Count > 1)
+            {
+                this.revocationReason = new CrlReason(
+					DerEnumerated.GetInstance((Asn1TaggedObject) seq[1], true));
+            }
+        }
+
+		public DerGeneralizedTime RevocationTime
+		{
+			get { return revocationTime; }
+		}
+
+		public CrlReason RevocationReason
+		{
+			get { return revocationReason; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * RevokedInfo ::= Sequence {
+         *      revocationTime              GeneralizedTime,
+         *      revocationReason    [0]     EXPLICIT CRLReason OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			Asn1EncodableVector v = new Asn1EncodableVector(revocationTime);
+
+			if (revocationReason != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, revocationReason));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/ocsp/ServiceLocator.cs b/Crypto/src/asn1/ocsp/ServiceLocator.cs
new file mode 100644
index 000000000..56bc49ded
--- /dev/null
+++ b/Crypto/src/asn1/ocsp/ServiceLocator.cs
@@ -0,0 +1,95 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class ServiceLocator
+        : Asn1Encodable
+    {
+        private readonly X509Name issuer;
+        private readonly Asn1Object locator;
+
+		public static ServiceLocator GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static ServiceLocator GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is ServiceLocator)
+			{
+				return (ServiceLocator) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new ServiceLocator((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public ServiceLocator(
+			X509Name	issuer)
+			: this(issuer, null)
+		{
+		}
+
+		public ServiceLocator(
+			X509Name	issuer,
+			Asn1Object	locator)
+		{
+			if (issuer == null)
+				throw new ArgumentNullException("issuer");
+
+			this.issuer = issuer;
+			this.locator = locator;
+		}
+
+		private ServiceLocator(
+			Asn1Sequence seq)
+		{
+			this.issuer = X509Name.GetInstance(seq[0]);
+
+			if (seq.Count > 1)
+			{
+				this.locator = seq[1].ToAsn1Object();
+			}
+		}
+
+		public X509Name Issuer
+		{
+			get { return issuer; }
+		}
+
+		public Asn1Object Locator
+		{
+			get { return locator; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * ServiceLocator ::= Sequence {
+         *     issuer    Name,
+         *     locator   AuthorityInfoAccessSyntax OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(issuer);
+
+			if (locator != null)
+            {
+                v.Add(locator);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/ocsp/Signature.cs b/Crypto/src/asn1/ocsp/Signature.cs
new file mode 100644
index 000000000..a07e7a709
--- /dev/null
+++ b/Crypto/src/asn1/ocsp/Signature.cs
@@ -0,0 +1,110 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class Signature
+        : Asn1Encodable
+    {
+        internal AlgorithmIdentifier	signatureAlgorithm;
+        internal DerBitString			signatureValue;
+        internal Asn1Sequence			certs;
+
+		public static Signature GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static Signature GetInstance(
+			object  obj)
+		{
+			if (obj == null || obj is Signature)
+			{
+				return (Signature)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new Signature((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public Signature(
+            AlgorithmIdentifier signatureAlgorithm,
+            DerBitString        signatureValue)
+			: this(signatureAlgorithm, signatureValue, null)
+        {
+        }
+
+		public Signature(
+            AlgorithmIdentifier	signatureAlgorithm,
+            DerBitString		signatureValue,
+            Asn1Sequence		certs)
+        {
+			if (signatureAlgorithm == null)
+				throw new ArgumentException("signatureAlgorithm");
+			if (signatureValue == null)
+				throw new ArgumentException("signatureValue");
+
+			this.signatureAlgorithm = signatureAlgorithm;
+            this.signatureValue = signatureValue;
+            this.certs = certs;
+        }
+
+		private Signature(
+            Asn1Sequence seq)
+        {
+            signatureAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]);
+            signatureValue = (DerBitString)seq[1];
+
+			if (seq.Count == 3)
+            {
+                certs = Asn1Sequence.GetInstance(
+					(Asn1TaggedObject)seq[2], true);
+            }
+        }
+
+		public AlgorithmIdentifier SignatureAlgorithm
+		{
+			get { return signatureAlgorithm; }
+		}
+
+		public DerBitString SignatureValue
+		{
+			get { return signatureValue; }
+		}
+
+		public Asn1Sequence Certs
+		{
+			get { return certs; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * Signature       ::=     Sequence {
+         *     signatureAlgorithm      AlgorithmIdentifier,
+         *     signature               BIT STRING,
+         *     certs               [0] EXPLICIT Sequence OF Certificate OPTIONAL}
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				signatureAlgorithm, signatureValue);
+
+			if (certs != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, certs));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/ocsp/SingleResponse.cs b/Crypto/src/asn1/ocsp/SingleResponse.cs
new file mode 100644
index 000000000..93d4c21d6
--- /dev/null
+++ b/Crypto/src/asn1/ocsp/SingleResponse.cs
@@ -0,0 +1,137 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+using System;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class SingleResponse
+        : Asn1Encodable
+    {
+        private readonly CertID              certID;
+        private readonly CertStatus          certStatus;
+        private readonly DerGeneralizedTime  thisUpdate;
+        private readonly DerGeneralizedTime  nextUpdate;
+        private readonly X509Extensions      singleExtensions;
+
+		public SingleResponse(
+            CertID              certID,
+            CertStatus          certStatus,
+            DerGeneralizedTime  thisUpdate,
+            DerGeneralizedTime  nextUpdate,
+            X509Extensions      singleExtensions)
+        {
+            this.certID = certID;
+            this.certStatus = certStatus;
+            this.thisUpdate = thisUpdate;
+            this.nextUpdate = nextUpdate;
+            this.singleExtensions = singleExtensions;
+        }
+
+		public SingleResponse(
+            Asn1Sequence seq)
+        {
+            this.certID = CertID.GetInstance(seq[0]);
+            this.certStatus = CertStatus.GetInstance(seq[1]);
+            this.thisUpdate = (DerGeneralizedTime)seq[2];
+
+			if (seq.Count > 4)
+            {
+                this.nextUpdate = DerGeneralizedTime.GetInstance(
+					(Asn1TaggedObject) seq[3], true);
+                this.singleExtensions = X509Extensions.GetInstance(
+					(Asn1TaggedObject) seq[4], true);
+            }
+            else if (seq.Count > 3)
+            {
+                Asn1TaggedObject o = (Asn1TaggedObject) seq[3];
+
+				if (o.TagNo == 0)
+                {
+                    this.nextUpdate = DerGeneralizedTime.GetInstance(o, true);
+                }
+                else
+                {
+                    this.singleExtensions = X509Extensions.GetInstance(o, true);
+                }
+            }
+        }
+
+		public static SingleResponse GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static SingleResponse GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is SingleResponse)
+            {
+                return (SingleResponse)obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new SingleResponse((Asn1Sequence)obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        }
+
+		public CertID CertId
+		{
+			get { return certID; }
+		}
+
+		public CertStatus CertStatus
+		{
+			get { return certStatus; }
+		}
+
+		public DerGeneralizedTime ThisUpdate
+		{
+			get { return thisUpdate; }
+		}
+
+		public DerGeneralizedTime NextUpdate
+		{
+			get { return nextUpdate; }
+		}
+
+		public X509Extensions SingleExtensions
+		{
+			get { return singleExtensions; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  SingleResponse ::= Sequence {
+         *          certID                       CertID,
+         *          certStatus                   CertStatus,
+         *          thisUpdate                   GeneralizedTime,
+         *          nextUpdate         [0]       EXPLICIT GeneralizedTime OPTIONAL,
+         *          singleExtensions   [1]       EXPLICIT Extensions OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				certID, certStatus, thisUpdate);
+
+			if (nextUpdate != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, nextUpdate));
+            }
+
+			if (singleExtensions != null)
+            {
+                v.Add(new DerTaggedObject(true, 1, singleExtensions));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/ocsp/TBSRequest.cs b/Crypto/src/asn1/ocsp/TBSRequest.cs
new file mode 100644
index 000000000..6bf75eb96
--- /dev/null
+++ b/Crypto/src/asn1/ocsp/TBSRequest.cs
@@ -0,0 +1,151 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+using System;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class TbsRequest
+        : Asn1Encodable
+    {
+		private static readonly DerInteger V1 = new DerInteger(0);
+
+		private readonly DerInteger      version;
+        private readonly GeneralName     requestorName;
+        private readonly Asn1Sequence    requestList;
+        private readonly X509Extensions  requestExtensions;
+
+		private bool versionSet;
+
+		public static TbsRequest GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static TbsRequest GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is TbsRequest)
+			{
+				return (TbsRequest)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new TbsRequest((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public TbsRequest(
+            GeneralName     requestorName,
+            Asn1Sequence    requestList,
+            X509Extensions  requestExtensions)
+        {
+            this.version = V1;
+            this.requestorName = requestorName;
+            this.requestList = requestList;
+            this.requestExtensions = requestExtensions;
+        }
+
+		private TbsRequest(
+            Asn1Sequence seq)
+        {
+            int index = 0;
+
+			Asn1Encodable enc = seq[0];
+			if (enc is Asn1TaggedObject)
+            {
+                Asn1TaggedObject o = (Asn1TaggedObject) enc;
+
+				if (o.TagNo == 0)
+                {
+					versionSet = true;
+					version = DerInteger.GetInstance(o, true);
+                    index++;
+                }
+                else
+                {
+                    version = V1;
+                }
+            }
+            else
+            {
+                version = V1;
+            }
+
+			if (seq[index] is Asn1TaggedObject)
+            {
+                requestorName = GeneralName.GetInstance((Asn1TaggedObject) seq[index++], true);
+            }
+
+			requestList = (Asn1Sequence) seq[index++];
+
+			if (seq.Count == (index + 1))
+            {
+                requestExtensions = X509Extensions.GetInstance((Asn1TaggedObject) seq[index], true);
+            }
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public GeneralName RequestorName
+		{
+			get { return requestorName; }
+		}
+
+		public Asn1Sequence RequestList
+		{
+			get { return requestList; }
+		}
+
+		public X509Extensions RequestExtensions
+		{
+			get { return requestExtensions; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * TBSRequest      ::=     Sequence {
+         *     version             [0]     EXPLICIT Version DEFAULT v1,
+         *     requestorName       [1]     EXPLICIT GeneralName OPTIONAL,
+         *     requestList                 Sequence OF Request,
+         *     requestExtensions   [2]     EXPLICIT Extensions OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			//
+			// if default don't include - unless explicitly provided. Not strictly correct
+			// but required for some requests
+			//
+			if (!version.Equals(V1) || versionSet)
+			{
+                v.Add(new DerTaggedObject(true, 0, version));
+            }
+
+			if (requestorName != null)
+            {
+                v.Add(new DerTaggedObject(true, 1, requestorName));
+            }
+
+			v.Add(requestList);
+
+			if (requestExtensions != null)
+            {
+                v.Add(new DerTaggedObject(true, 2, requestExtensions));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/oiw/ElGamalParameter.cs b/Crypto/src/asn1/oiw/ElGamalParameter.cs
new file mode 100644
index 000000000..3e020f059
--- /dev/null
+++ b/Crypto/src/asn1/oiw/ElGamalParameter.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Oiw
+{
+    public class ElGamalParameter
+        : Asn1Encodable
+    {
+        internal DerInteger p, g;
+
+		public ElGamalParameter(
+            BigInteger	p,
+            BigInteger	g)
+        {
+            this.p = new DerInteger(p);
+            this.g = new DerInteger(g);
+        }
+
+		public ElGamalParameter(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			p = DerInteger.GetInstance(seq[0]);
+			g = DerInteger.GetInstance(seq[1]);
+        }
+
+		public BigInteger P
+		{
+			get { return p.PositiveValue; }
+		}
+
+		public BigInteger G
+		{
+			get { return g.PositiveValue; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(p, g);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/oiw/OIWObjectIdentifiers.cs b/Crypto/src/asn1/oiw/OIWObjectIdentifiers.cs
new file mode 100644
index 000000000..3da226301
--- /dev/null
+++ b/Crypto/src/asn1/oiw/OIWObjectIdentifiers.cs
@@ -0,0 +1,29 @@
+namespace Org.BouncyCastle.Asn1.Oiw
+{
+	public abstract class OiwObjectIdentifiers
+	{
+		public static readonly DerObjectIdentifier MD4WithRsa			= new DerObjectIdentifier("1.3.14.3.2.2");
+		public static readonly DerObjectIdentifier MD5WithRsa			= new DerObjectIdentifier("1.3.14.3.2.3");
+		public static readonly DerObjectIdentifier MD4WithRsaEncryption	= new DerObjectIdentifier("1.3.14.3.2.4");
+
+		public static readonly DerObjectIdentifier DesEcb				= new DerObjectIdentifier("1.3.14.3.2.6");
+		public static readonly DerObjectIdentifier DesCbc				= new DerObjectIdentifier("1.3.14.3.2.7");
+		public static readonly DerObjectIdentifier DesOfb				= new DerObjectIdentifier("1.3.14.3.2.8");
+		public static readonly DerObjectIdentifier DesCfb				= new DerObjectIdentifier("1.3.14.3.2.9");
+
+		public static readonly DerObjectIdentifier DesEde				= new DerObjectIdentifier("1.3.14.3.2.17");
+
+		// id-SHA1 OBJECT IDENTIFIER ::=
+		//   {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 }    //
+		public static readonly DerObjectIdentifier IdSha1				= new DerObjectIdentifier("1.3.14.3.2.26");
+
+		public static readonly DerObjectIdentifier DsaWithSha1			= new DerObjectIdentifier("1.3.14.3.2.27");
+
+		public static readonly DerObjectIdentifier Sha1WithRsa			= new DerObjectIdentifier("1.3.14.3.2.29");
+
+		// ElGamal Algorithm OBJECT IDENTIFIER ::=
+		// {iso(1) identified-organization(3) oiw(14) dirservsig(7) algorithm(2) encryption(1) 1 }
+		//
+		public static readonly DerObjectIdentifier ElGamalAlgorithm		= new DerObjectIdentifier("1.3.14.7.2.1.1");
+	}
+}
diff --git a/Crypto/src/asn1/pkcs/Attribute.cs b/Crypto/src/asn1/pkcs/Attribute.cs
new file mode 100644
index 000000000..ceec115bd
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/Attribute.cs
@@ -0,0 +1,79 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class AttributePkcs
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier attrType;
+        private readonly Asn1Set attrValues;
+
+		/**
+         * return an Attribute object from the given object.
+         *
+         * @param o the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static AttributePkcs GetInstance(
+            object obj)
+        {
+            AttributePkcs attr = obj as AttributePkcs;
+            if (obj == null || attr != null)
+            {
+                return attr;
+            }
+
+			Asn1Sequence seq = obj as Asn1Sequence;
+            if (seq != null)
+            {
+                return new AttributePkcs(seq);
+            }
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		private AttributePkcs(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			attrType = DerObjectIdentifier.GetInstance(seq[0]);
+            attrValues = Asn1Set.GetInstance(seq[1]);
+        }
+
+		public AttributePkcs(
+            DerObjectIdentifier	attrType,
+            Asn1Set				attrValues)
+        {
+            this.attrType = attrType;
+            this.attrValues = attrValues;
+        }
+
+		public DerObjectIdentifier AttrType
+		{
+			get { return attrType; }
+		}
+
+		public Asn1Set AttrValues
+		{
+			get { return attrValues; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * Attr ::= Sequence {
+         *     attrType OBJECT IDENTIFIER,
+         *     attrValues Set OF AttributeValue
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(attrType, attrValues);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/AuthenticatedSafe.cs b/Crypto/src/asn1/pkcs/AuthenticatedSafe.cs
new file mode 100644
index 000000000..f3dabb89c
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/AuthenticatedSafe.cs
@@ -0,0 +1,37 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class AuthenticatedSafe
+        : Asn1Encodable
+    {
+        private readonly ContentInfo[] info;
+
+		public AuthenticatedSafe(
+            Asn1Sequence seq)
+        {
+            info = new ContentInfo[seq.Count];
+
+			for (int i = 0; i != info.Length; i++)
+            {
+                info[i] = ContentInfo.GetInstance(seq[i]);
+            }
+        }
+
+		public AuthenticatedSafe(
+            ContentInfo[] info)
+        {
+            this.info = (ContentInfo[]) info.Clone();
+        }
+
+		public ContentInfo[] GetContentInfo()
+        {
+            return (ContentInfo[]) info.Clone();
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new BerSequence(info);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/CertBag.cs b/Crypto/src/asn1/pkcs/CertBag.cs
new file mode 100644
index 000000000..b6f4c8a30
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/CertBag.cs
@@ -0,0 +1,46 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class CertBag
+        : Asn1Encodable
+    {
+//		private readonly Asn1Sequence seq;
+        private readonly DerObjectIdentifier certID;
+        private readonly Asn1Object certValue;
+
+		public CertBag(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+//			this.seq = seq;
+            this.certID = DerObjectIdentifier.GetInstance(seq[0]);
+            this.certValue = DerTaggedObject.GetInstance(seq[1]).GetObject();
+        }
+
+		public CertBag(
+            DerObjectIdentifier	certID,
+            Asn1Object			certValue)
+        {
+            this.certID = certID;
+            this.certValue = certValue;
+        }
+
+		public DerObjectIdentifier CertID
+		{
+			get { return certID; }
+		}
+
+		public Asn1Object CertValue
+		{
+			get { return certValue; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(certID, new DerTaggedObject(0, certValue));
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/CertificationRequest.cs b/Crypto/src/asn1/pkcs/CertificationRequest.cs
new file mode 100644
index 000000000..32b1612d2
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/CertificationRequest.cs
@@ -0,0 +1,81 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    /**
+     * Pkcs10 Certfication request object.
+     * <pre>
+     * CertificationRequest ::= Sequence {
+     *   certificationRequestInfo  CertificationRequestInfo,
+     *   signatureAlgorithm        AlgorithmIdentifier{{ SignatureAlgorithms }},
+     *   signature                 BIT STRING
+     * }
+     * </pre>
+     */
+    public class CertificationRequest
+        : Asn1Encodable
+    {
+        protected CertificationRequestInfo	reqInfo;
+        protected AlgorithmIdentifier		sigAlgId;
+        protected DerBitString				sigBits;
+
+		public static CertificationRequest GetInstance(
+			object obj)
+		{
+			if (obj is CertificationRequest)
+				return (CertificationRequest)obj;
+
+			if (obj != null)
+				return new CertificationRequest((Asn1Sequence)obj);
+
+			return null;
+		}
+
+		protected CertificationRequest()
+        {
+        }
+
+		public CertificationRequest(
+            CertificationRequestInfo	requestInfo,
+            AlgorithmIdentifier			algorithm,
+            DerBitString				signature)
+        {
+            this.reqInfo = requestInfo;
+            this.sigAlgId = algorithm;
+            this.sigBits = signature;
+        }
+
+		public CertificationRequest(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 3)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			reqInfo = CertificationRequestInfo.GetInstance(seq[0]);
+            sigAlgId = AlgorithmIdentifier.GetInstance(seq[1]);
+            sigBits = DerBitString.GetInstance(seq[2]);
+        }
+
+		public CertificationRequestInfo GetCertificationRequestInfo()
+        {
+            return reqInfo;
+        }
+
+		public AlgorithmIdentifier SignatureAlgorithm
+		{
+			get { return sigAlgId; }
+		}
+
+		public DerBitString Signature
+		{
+			get { return sigBits; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(reqInfo, sigAlgId, sigBits);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/CertificationRequestInfo.cs b/Crypto/src/asn1/pkcs/CertificationRequestInfo.cs
new file mode 100644
index 000000000..690d06878
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/CertificationRequestInfo.cs
@@ -0,0 +1,123 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    /**
+     * Pkcs10 CertificationRequestInfo object.
+     * <pre>
+     *  CertificationRequestInfo ::= Sequence {
+     *   version             Integer { v1(0) } (v1,...),
+     *   subject             Name,
+     *   subjectPKInfo   SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+     *   attributes          [0] Attributes{{ CRIAttributes }}
+     *  }
+     *
+     *  Attributes { ATTRIBUTE:IOSet } ::= Set OF Attr{{ IOSet }}
+     *
+     *  Attr { ATTRIBUTE:IOSet } ::= Sequence {
+     *    type    ATTRIBUTE.&amp;id({IOSet}),
+     *    values  Set SIZE(1..MAX) OF ATTRIBUTE.&amp;Type({IOSet}{\@type})
+     *  }
+     * </pre>
+     */
+    public class CertificationRequestInfo
+        : Asn1Encodable
+    {
+        internal DerInteger				version = new DerInteger(0);
+        internal X509Name				subject;
+        internal SubjectPublicKeyInfo	subjectPKInfo;
+        internal Asn1Set				attributes;
+
+		public static CertificationRequestInfo GetInstance(
+            object  obj)
+        {
+            if (obj is CertificationRequestInfo)
+            {
+                return (CertificationRequestInfo) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new CertificationRequestInfo((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		public CertificationRequestInfo(
+            X509Name				subject,
+            SubjectPublicKeyInfo	pkInfo,
+            Asn1Set					attributes)
+        {
+            this.subject = subject;
+            this.subjectPKInfo = pkInfo;
+            this.attributes = attributes;
+
+			if (subject == null || version == null || subjectPKInfo == null)
+            {
+                throw new ArgumentException(
+					"Not all mandatory fields set in CertificationRequestInfo generator.");
+            }
+        }
+
+		private CertificationRequestInfo(
+            Asn1Sequence seq)
+        {
+            version = (DerInteger) seq[0];
+
+			subject = X509Name.GetInstance(seq[1]);
+            subjectPKInfo = SubjectPublicKeyInfo.GetInstance(seq[2]);
+
+			//
+            // some CertificationRequestInfo objects seem to treat this field
+            // as optional.
+            //
+            if (seq.Count > 3)
+            {
+                DerTaggedObject tagobj = (DerTaggedObject) seq[3];
+                attributes = Asn1Set.GetInstance(tagobj, false);
+            }
+
+			if (subject == null || version == null || subjectPKInfo == null)
+            {
+                throw new ArgumentException(
+					"Not all mandatory fields set in CertificationRequestInfo generator.");
+            }
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public X509Name Subject
+		{
+			get { return subject; }
+		}
+
+		public SubjectPublicKeyInfo SubjectPublicKeyInfo
+		{
+			get { return subjectPKInfo; }
+		}
+
+		public Asn1Set Attributes
+		{
+			get { return attributes; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				version, subject, subjectPKInfo);
+
+			if (attributes != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, attributes));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/ContentInfo.cs b/Crypto/src/asn1/pkcs/ContentInfo.cs
new file mode 100644
index 000000000..78213c138
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/ContentInfo.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class ContentInfo
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	contentType;
+        private readonly Asn1Encodable			content;
+
+		public static ContentInfo GetInstance(
+            object obj)
+        {
+            if (obj is ContentInfo)
+            {
+                return (ContentInfo) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new ContentInfo((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+        }
+
+		private ContentInfo(
+            Asn1Sequence seq)
+        {
+			contentType = (DerObjectIdentifier) seq[0];
+
+			if (seq.Count > 1)
+			{
+				content = ((Asn1TaggedObject) seq[1]).GetObject();
+			}
+        }
+
+		public ContentInfo(
+            DerObjectIdentifier	contentType,
+            Asn1Encodable		content)
+        {
+            this.contentType = contentType;
+            this.content = content;
+        }
+
+		public DerObjectIdentifier ContentType
+		{
+			get { return contentType; }
+		}
+
+		public Asn1Encodable Content
+		{
+			get { return content; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * ContentInfo ::= Sequence {
+         *          contentType ContentType,
+         *          content
+         *          [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(contentType);
+
+			if (content != null)
+            {
+                v.Add(new BerTaggedObject(0, content));
+            }
+
+			return new BerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/DHParameter.cs b/Crypto/src/asn1/pkcs/DHParameter.cs
new file mode 100644
index 000000000..25a091a97
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/DHParameter.cs
@@ -0,0 +1,72 @@
+using Org.BouncyCastle.Asn1;
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class DHParameter
+        : Asn1Encodable
+    {
+        internal DerInteger p, g, l;
+
+		public DHParameter(
+            BigInteger	p,
+            BigInteger	g,
+            int			l)
+        {
+            this.p = new DerInteger(p);
+            this.g = new DerInteger(g);
+
+			if (l != 0)
+            {
+                this.l = new DerInteger(l);
+            }
+        }
+
+		public DHParameter(
+            Asn1Sequence seq)
+        {
+            IEnumerator e = seq.GetEnumerator();
+
+			e.MoveNext();
+            p = (DerInteger)e.Current;
+
+			e.MoveNext();
+            g = (DerInteger)e.Current;
+
+			if (e.MoveNext())
+            {
+                l = (DerInteger) e.Current;
+            }
+        }
+
+		public BigInteger P
+		{
+			get { return p.PositiveValue; }
+		}
+
+		public BigInteger G
+		{
+			get { return g.PositiveValue; }
+		}
+
+		public BigInteger L
+		{
+            get { return l == null ? null : l.PositiveValue; }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(p, g);
+
+			if (this.l != null)
+            {
+                v.Add(l);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/EncryptedData.cs b/Crypto/src/asn1/pkcs/EncryptedData.cs
new file mode 100644
index 000000000..912064ace
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/EncryptedData.cs
@@ -0,0 +1,104 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    /**
+     * The EncryptedData object.
+     * <pre>
+     *      EncryptedData ::= Sequence {
+     *           version Version,
+     *           encryptedContentInfo EncryptedContentInfo
+     *      }
+     *
+     *
+     *      EncryptedContentInfo ::= Sequence {
+     *          contentType ContentType,
+     *          contentEncryptionAlgorithm  ContentEncryptionAlgorithmIdentifier,
+     *          encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+     *    }
+     *
+     *    EncryptedContent ::= OCTET STRING
+     * </pre>
+     */
+    public class EncryptedData
+        : Asn1Encodable
+    {
+        private readonly Asn1Sequence data;
+//        private readonly DerObjectIdentifier bagId;
+//        private readonly Asn1Object bagValue;
+
+		public static EncryptedData GetInstance(
+             object obj)
+        {
+			if (obj is EncryptedData)
+			{
+				return (EncryptedData) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new EncryptedData((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		private EncryptedData(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			int version = ((DerInteger) seq[0]).Value.IntValue;
+			if (version != 0)
+            {
+                throw new ArgumentException("sequence not version 0");
+            }
+
+			this.data = (Asn1Sequence) seq[1];
+        }
+
+		public EncryptedData(
+            DerObjectIdentifier	contentType,
+            AlgorithmIdentifier	encryptionAlgorithm,
+            Asn1Encodable		content)
+        {
+			data = new BerSequence(
+				contentType,
+				encryptionAlgorithm.ToAsn1Object(),
+				new BerTaggedObject(false, 0, content));
+        }
+
+		public DerObjectIdentifier ContentType
+        {
+            get { return (DerObjectIdentifier) data[0]; }
+        }
+
+		public AlgorithmIdentifier EncryptionAlgorithm
+        {
+			get { return AlgorithmIdentifier.GetInstance(data[1]); }
+        }
+
+		public Asn1OctetString Content
+        {
+			get
+			{
+				if (data.Count == 3)
+				{
+					DerTaggedObject o = (DerTaggedObject) data[2];
+
+					return Asn1OctetString.GetInstance(o, false);
+				}
+
+				return null;
+			}
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new BerSequence(new DerInteger(0), data);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/EncryptedPrivateKeyInfo.cs b/Crypto/src/asn1/pkcs/EncryptedPrivateKeyInfo.cs
new file mode 100644
index 000000000..b97b8f5ea
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/EncryptedPrivateKeyInfo.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class EncryptedPrivateKeyInfo
+        : Asn1Encodable
+    {
+        private readonly AlgorithmIdentifier algId;
+        private readonly Asn1OctetString data;
+
+		private EncryptedPrivateKeyInfo(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+            algId = AlgorithmIdentifier.GetInstance(seq[0]);
+            data = Asn1OctetString.GetInstance(seq[1]);
+        }
+
+		public EncryptedPrivateKeyInfo(
+            AlgorithmIdentifier	algId,
+            byte[]				encoding)
+        {
+            this.algId = algId;
+            this.data = new DerOctetString(encoding);
+        }
+
+		public static EncryptedPrivateKeyInfo GetInstance(
+             object obj)
+        {
+			if (obj is EncryptedPrivateKeyInfo)
+			{
+				return (EncryptedPrivateKeyInfo) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new EncryptedPrivateKeyInfo((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		public AlgorithmIdentifier EncryptionAlgorithm
+		{
+			get { return algId; }
+		}
+
+		public byte[] GetEncryptedData()
+        {
+            return data.GetOctets();
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * EncryptedPrivateKeyInfo ::= Sequence {
+         *      encryptionAlgorithm AlgorithmIdentifier {{KeyEncryptionAlgorithms}},
+         *      encryptedData EncryptedData
+         * }
+         *
+         * EncryptedData ::= OCTET STRING
+         *
+         * KeyEncryptionAlgorithms ALGORITHM-IDENTIFIER ::= {
+         *          ... -- For local profiles
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(algId, data);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/EncryptionScheme.cs b/Crypto/src/asn1/pkcs/EncryptionScheme.cs
new file mode 100644
index 000000000..5b64d6f67
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/EncryptionScheme.cs
@@ -0,0 +1,49 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class EncryptionScheme
+        : AlgorithmIdentifier
+    {
+		public EncryptionScheme(
+            DerObjectIdentifier	objectID,
+            Asn1Encodable		parameters)
+			: base(objectID, parameters)
+		{
+		}
+
+		internal EncryptionScheme(
+			Asn1Sequence seq)
+			: this((DerObjectIdentifier)seq[0], seq[1])
+        {
+        }
+
+		public new static EncryptionScheme GetInstance(object obj)
+		{
+			if (obj is EncryptionScheme)
+			{
+				return (EncryptionScheme)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new EncryptionScheme((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		public Asn1Object Asn1Object
+		{
+			get { return Parameters.ToAsn1Object(); }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(ObjectID, Parameters);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/IssuerAndSerialNumber.cs b/Crypto/src/asn1/pkcs/IssuerAndSerialNumber.cs
new file mode 100644
index 000000000..ff608f15b
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/IssuerAndSerialNumber.cs
@@ -0,0 +1,71 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class IssuerAndSerialNumber
+        : Asn1Encodable
+    {
+        private readonly X509Name name;
+        private readonly DerInteger certSerialNumber;
+
+		public static IssuerAndSerialNumber GetInstance(
+            object obj)
+        {
+            if (obj is IssuerAndSerialNumber)
+            {
+                return (IssuerAndSerialNumber) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new IssuerAndSerialNumber((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		private IssuerAndSerialNumber(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			this.name = X509Name.GetInstance(seq[0]);
+            this.certSerialNumber = DerInteger.GetInstance(seq[1]);
+        }
+
+		public IssuerAndSerialNumber(
+            X509Name	name,
+            BigInteger	certSerialNumber)
+        {
+            this.name = name;
+            this.certSerialNumber = new DerInteger(certSerialNumber);
+        }
+
+		public IssuerAndSerialNumber(
+            X509Name	name,
+            DerInteger	certSerialNumber)
+        {
+            this.name = name;
+            this.certSerialNumber = certSerialNumber;
+        }
+
+		public X509Name Name
+		{
+			get { return name; }
+		}
+
+		public DerInteger CertificateSerialNumber
+		{
+			get { return certSerialNumber; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(name, certSerialNumber);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/KeyDerivationFunc.cs b/Crypto/src/asn1/pkcs/KeyDerivationFunc.cs
new file mode 100644
index 000000000..9fc89853b
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/KeyDerivationFunc.cs
@@ -0,0 +1,21 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+	public class KeyDerivationFunc
+		: AlgorithmIdentifier
+	{
+		internal KeyDerivationFunc(Asn1Sequence seq)
+			: base(seq)
+		{
+		}
+
+		public KeyDerivationFunc(
+			DerObjectIdentifier	id,
+			Asn1Encodable		parameters)
+			: base(id, parameters)
+		{
+		}
+	}
+}
\ No newline at end of file
diff --git a/Crypto/src/asn1/pkcs/MacData.cs b/Crypto/src/asn1/pkcs/MacData.cs
new file mode 100644
index 000000000..780b24153
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/MacData.cs
@@ -0,0 +1,96 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class MacData
+        : Asn1Encodable
+    {
+        internal DigestInfo	digInfo;
+        internal byte[]		salt;
+        internal BigInteger	iterationCount;
+
+		public static MacData GetInstance(
+            object obj)
+        {
+            if (obj is MacData)
+            {
+                return (MacData) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new MacData((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		private MacData(
+            Asn1Sequence seq)
+        {
+            this.digInfo = DigestInfo.GetInstance(seq[0]);
+            this.salt = ((Asn1OctetString) seq[1]).GetOctets();
+
+			if (seq.Count == 3)
+            {
+                this.iterationCount = ((DerInteger) seq[2]).Value;
+            }
+            else
+            {
+                this.iterationCount = BigInteger.One;
+            }
+        }
+
+		public MacData(
+            DigestInfo	digInfo,
+            byte[]		salt,
+            int			iterationCount)
+        {
+            this.digInfo = digInfo;
+            this.salt = (byte[]) salt.Clone();
+            this.iterationCount = BigInteger.ValueOf(iterationCount);
+        }
+
+		public DigestInfo Mac
+		{
+			get { return digInfo; }
+		}
+
+		public byte[] GetSalt()
+        {
+            return (byte[]) salt.Clone();
+        }
+
+		public BigInteger IterationCount
+		{
+			get { return iterationCount; }
+		}
+
+		/**
+		 * <pre>
+		 * MacData ::= SEQUENCE {
+		 *     mac      DigestInfo,
+		 *     macSalt  OCTET STRING,
+		 *     iterations INTEGER DEFAULT 1
+		 *     -- Note: The default is for historic reasons and its use is deprecated. A
+		 *     -- higher value, like 1024 is recommended.
+		 * </pre>
+		 * @return the basic DERObject construction.
+		 */
+		public override Asn1Object ToAsn1Object()
+        {
+			Asn1EncodableVector v = new Asn1EncodableVector(digInfo, new DerOctetString(salt));
+
+			if (!iterationCount.Equals(BigInteger.One))
+			{
+				v.Add(new DerInteger(iterationCount));
+			}
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/PBEParameter.cs b/Crypto/src/asn1/pkcs/PBEParameter.cs
new file mode 100644
index 000000000..80d5ec3e1
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/PBEParameter.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+	public class PbeParameter
+		: Asn1Encodable
+	{
+		private readonly Asn1OctetString	salt;
+		private readonly DerInteger			iterationCount;
+
+		public static PbeParameter GetInstance(object obj)
+		{
+			if (obj is PbeParameter || obj == null)
+			{
+				return (PbeParameter) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new PbeParameter((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		private PbeParameter(Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			salt = Asn1OctetString.GetInstance(seq[0]);
+			iterationCount = DerInteger.GetInstance(seq[1]);
+		}
+
+		public PbeParameter(byte[] salt, int iterationCount)
+		{
+			this.salt = new DerOctetString(salt);
+			this.iterationCount = new DerInteger(iterationCount);
+		}
+
+		public byte[] GetSalt()
+		{
+			return salt.GetOctets();
+		}
+
+		public BigInteger IterationCount
+		{
+			get { return iterationCount.Value; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(salt, iterationCount);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/pkcs/PBES2Parameters.cs b/Crypto/src/asn1/pkcs/PBES2Parameters.cs
new file mode 100644
index 000000000..645bb867c
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/PBES2Parameters.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class PbeS2Parameters
+        : Asn1Encodable
+    {
+        private readonly KeyDerivationFunc func;
+        private readonly EncryptionScheme scheme;
+
+		public static PbeS2Parameters GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is PbeS2Parameters)
+				return (PbeS2Parameters) obj;
+
+			if (obj is Asn1Sequence)
+				return new PbeS2Parameters((Asn1Sequence) obj);
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		public PbeS2Parameters(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			Asn1Sequence funcSeq = (Asn1Sequence)seq[0].ToAsn1Object();
+
+			// TODO Not sure if this special case is really necessary/appropriate
+			if (funcSeq[0].Equals(PkcsObjectIdentifiers.IdPbkdf2))
+            {
+				func = new KeyDerivationFunc(PkcsObjectIdentifiers.IdPbkdf2,
+					Pbkdf2Params.GetInstance(funcSeq[1]));
+			}
+            else
+            {
+                func = new KeyDerivationFunc(funcSeq);
+            }
+
+			scheme = EncryptionScheme.GetInstance(seq[1].ToAsn1Object());
+        }
+
+		public KeyDerivationFunc KeyDerivationFunc
+		{
+			get { return func; }
+		}
+
+		public EncryptionScheme EncryptionScheme
+		{
+			get { return scheme; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(func, scheme);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/PBKDF2Params.cs b/Crypto/src/asn1/pkcs/PBKDF2Params.cs
new file mode 100644
index 000000000..1351b94cf
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/PBKDF2Params.cs
@@ -0,0 +1,86 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+	public class Pbkdf2Params
+		: Asn1Encodable
+	{
+		private readonly Asn1OctetString	octStr;
+		private readonly DerInteger			iterationCount;
+		private readonly DerInteger			keyLength;
+
+		public static Pbkdf2Params GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is Pbkdf2Params)
+				return (Pbkdf2Params)obj;
+
+			if (obj is Asn1Sequence)
+				return new Pbkdf2Params((Asn1Sequence)obj);
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		public Pbkdf2Params(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 2 || seq.Count > 3)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			octStr = (Asn1OctetString)seq[0];
+			iterationCount = (DerInteger)seq[1];
+
+			if (seq.Count > 2)
+			{
+				keyLength = (DerInteger)seq[2];
+			}
+		}
+
+		public Pbkdf2Params(
+			byte[] salt,
+			int iterationCount)
+		{
+			this.octStr = new DerOctetString(salt);
+			this.iterationCount = new DerInteger(iterationCount);
+		}
+
+        public Pbkdf2Params(
+            byte[]  salt,
+            int     iterationCount,
+            int     keyLength)
+            : this(salt, iterationCount)
+        {
+            this.keyLength = new DerInteger(keyLength);
+        }
+
+		public byte[] GetSalt()
+		{
+			return octStr.GetOctets();
+		}
+
+		public BigInteger IterationCount
+		{
+			get { return iterationCount.Value; }
+		}
+
+		public BigInteger KeyLength
+		{
+			get { return keyLength == null ? null : keyLength.Value; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				octStr, iterationCount);
+
+			if (keyLength != null)
+			{
+				v.Add(keyLength);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/pkcs/PKCS12PBEParams.cs b/Crypto/src/asn1/pkcs/PKCS12PBEParams.cs
new file mode 100644
index 000000000..7521f93ea
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/PKCS12PBEParams.cs
@@ -0,0 +1,63 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class Pkcs12PbeParams
+        : Asn1Encodable
+    {
+        private readonly DerInteger iterations;
+        private readonly Asn1OctetString iv;
+
+		public Pkcs12PbeParams(
+            byte[]	salt,
+            int		iterations)
+        {
+            this.iv = new DerOctetString(salt);
+            this.iterations = new DerInteger(iterations);
+        }
+
+		private Pkcs12PbeParams(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			iv = Asn1OctetString.GetInstance(seq[0]);
+            iterations = DerInteger.GetInstance(seq[1]);
+        }
+
+		public static Pkcs12PbeParams GetInstance(
+            object obj)
+        {
+            if (obj is Pkcs12PbeParams)
+            {
+                return (Pkcs12PbeParams) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new Pkcs12PbeParams((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		public BigInteger Iterations
+		{
+			get { return iterations.Value; }
+		}
+
+		public byte[] GetIV()
+        {
+            return iv.GetOctets();
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(iv, iterations);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs b/Crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs
new file mode 100644
index 000000000..0b2ffa0d1
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs
@@ -0,0 +1,256 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public abstract class PkcsObjectIdentifiers
+    {
+        //
+        // pkcs-1 OBJECT IDENTIFIER ::= {
+        //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
+        //
+        public const string Pkcs1 = "1.2.840.113549.1.1";
+
+		public static readonly DerObjectIdentifier RsaEncryption			= new DerObjectIdentifier(Pkcs1 + ".1");
+        public static readonly DerObjectIdentifier MD2WithRsaEncryption		= new DerObjectIdentifier(Pkcs1 + ".2");
+        public static readonly DerObjectIdentifier MD4WithRsaEncryption		= new DerObjectIdentifier(Pkcs1 + ".3");
+        public static readonly DerObjectIdentifier MD5WithRsaEncryption		= new DerObjectIdentifier(Pkcs1 + ".4");
+        public static readonly DerObjectIdentifier Sha1WithRsaEncryption	= new DerObjectIdentifier(Pkcs1 + ".5");
+        public static readonly DerObjectIdentifier SrsaOaepEncryptionSet	= new DerObjectIdentifier(Pkcs1 + ".6");
+        public static readonly DerObjectIdentifier IdRsaesOaep				= new DerObjectIdentifier(Pkcs1 + ".7");
+        public static readonly DerObjectIdentifier IdMgf1					= new DerObjectIdentifier(Pkcs1 + ".8");
+        public static readonly DerObjectIdentifier IdPSpecified				= new DerObjectIdentifier(Pkcs1 + ".9");
+        public static readonly DerObjectIdentifier IdRsassaPss				= new DerObjectIdentifier(Pkcs1 + ".10");
+        public static readonly DerObjectIdentifier Sha256WithRsaEncryption	= new DerObjectIdentifier(Pkcs1 + ".11");
+        public static readonly DerObjectIdentifier Sha384WithRsaEncryption	= new DerObjectIdentifier(Pkcs1 + ".12");
+        public static readonly DerObjectIdentifier Sha512WithRsaEncryption	= new DerObjectIdentifier(Pkcs1 + ".13");
+        public static readonly DerObjectIdentifier Sha224WithRsaEncryption	= new DerObjectIdentifier(Pkcs1 + ".14");
+
+		//
+        // pkcs-3 OBJECT IDENTIFIER ::= {
+        //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 3 }
+        //
+        public const string Pkcs3 = "1.2.840.113549.1.3";
+
+		public static readonly DerObjectIdentifier    DhKeyAgreement          = new DerObjectIdentifier(Pkcs3 + ".1");
+
+		//
+        // pkcs-5 OBJECT IDENTIFIER ::= {
+        //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 }
+        //
+        public const string Pkcs5 = "1.2.840.113549.1.5";
+
+		public static readonly DerObjectIdentifier PbeWithMD2AndDesCbc    = new DerObjectIdentifier(Pkcs5 + ".1");
+        public static readonly DerObjectIdentifier PbeWithMD2AndRC2Cbc    = new DerObjectIdentifier(Pkcs5 + ".4");
+        public static readonly DerObjectIdentifier PbeWithMD5AndDesCbc    = new DerObjectIdentifier(Pkcs5 + ".3");
+        public static readonly DerObjectIdentifier PbeWithMD5AndRC2Cbc    = new DerObjectIdentifier(Pkcs5 + ".6");
+        public static readonly DerObjectIdentifier PbeWithSha1AndDesCbc   = new DerObjectIdentifier(Pkcs5 + ".10");
+        public static readonly DerObjectIdentifier PbeWithSha1AndRC2Cbc   = new DerObjectIdentifier(Pkcs5 + ".11");
+
+        public static readonly DerObjectIdentifier IdPbeS2 = new DerObjectIdentifier(Pkcs5 + ".13");
+        public static readonly DerObjectIdentifier IdPbkdf2	= new DerObjectIdentifier(Pkcs5 + ".12");
+
+		//
+        // encryptionAlgorithm OBJECT IDENTIFIER ::= {
+        //       iso(1) member-body(2) us(840) rsadsi(113549) 3 }
+        //
+        public const string EncryptionAlgorithm = "1.2.840.113549.3";
+
+		public static readonly DerObjectIdentifier DesEde3Cbc	= new DerObjectIdentifier(EncryptionAlgorithm + ".7");
+        public static readonly DerObjectIdentifier RC2Cbc		= new DerObjectIdentifier(EncryptionAlgorithm + ".2");
+
+		//
+        // object identifiers for digests
+        //
+        public const string DigestAlgorithm = "1.2.840.113549.2";
+
+		//
+        // md2 OBJECT IDENTIFIER ::=
+        //      {iso(1) member-body(2) US(840) rsadsi(113549) DigestAlgorithm(2) 2}
+        //
+        public static readonly DerObjectIdentifier MD2 = new DerObjectIdentifier(DigestAlgorithm + ".2");
+
+        //
+        // md4 OBJECT IDENTIFIER ::=
+        //      {iso(1) member-body(2) US(840) rsadsi(113549) DigestAlgorithm(2) 4}
+        //
+        public static readonly DerObjectIdentifier MD4 = new DerObjectIdentifier(DigestAlgorithm + ".4");
+
+        //
+        // md5 OBJECT IDENTIFIER ::=
+        //      {iso(1) member-body(2) US(840) rsadsi(113549) DigestAlgorithm(2) 5}
+        //
+        public static readonly DerObjectIdentifier MD5 = new DerObjectIdentifier(DigestAlgorithm + ".5");
+
+		public static readonly DerObjectIdentifier IdHmacWithSha1	= new DerObjectIdentifier(DigestAlgorithm + ".7");
+        public static readonly DerObjectIdentifier IdHmacWithSha224	= new DerObjectIdentifier(DigestAlgorithm + ".8");
+        public static readonly DerObjectIdentifier IdHmacWithSha256	= new DerObjectIdentifier(DigestAlgorithm + ".9");
+        public static readonly DerObjectIdentifier IdHmacWithSha384	= new DerObjectIdentifier(DigestAlgorithm + ".10");
+        public static readonly DerObjectIdentifier IdHmacWithSha512	= new DerObjectIdentifier(DigestAlgorithm + ".11");
+
+		//
+        // pkcs-7 OBJECT IDENTIFIER ::= {
+        //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 7 }
+        //
+        public const string Pkcs7 = "1.2.840.113549.1.7";
+
+		public static readonly DerObjectIdentifier Data                    = new DerObjectIdentifier(Pkcs7 + ".1");
+        public static readonly DerObjectIdentifier SignedData              = new DerObjectIdentifier(Pkcs7 + ".2");
+        public static readonly DerObjectIdentifier EnvelopedData           = new DerObjectIdentifier(Pkcs7 + ".3");
+        public static readonly DerObjectIdentifier SignedAndEnvelopedData  = new DerObjectIdentifier(Pkcs7 + ".4");
+        public static readonly DerObjectIdentifier DigestedData            = new DerObjectIdentifier(Pkcs7 + ".5");
+        public static readonly DerObjectIdentifier EncryptedData           = new DerObjectIdentifier(Pkcs7 + ".6");
+
+        //
+        // pkcs-9 OBJECT IDENTIFIER ::= {
+        //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 }
+        //
+        public const string Pkcs9 = "1.2.840.113549.1.9";
+
+		public static readonly DerObjectIdentifier Pkcs9AtEmailAddress					= new DerObjectIdentifier(Pkcs9 + ".1");
+        public static readonly DerObjectIdentifier Pkcs9AtUnstructuredName				= new DerObjectIdentifier(Pkcs9 + ".2");
+        public static readonly DerObjectIdentifier Pkcs9AtContentType					= new DerObjectIdentifier(Pkcs9 + ".3");
+        public static readonly DerObjectIdentifier Pkcs9AtMessageDigest					= new DerObjectIdentifier(Pkcs9 + ".4");
+        public static readonly DerObjectIdentifier Pkcs9AtSigningTime					= new DerObjectIdentifier(Pkcs9 + ".5");
+        public static readonly DerObjectIdentifier Pkcs9AtCounterSignature				= new DerObjectIdentifier(Pkcs9 + ".6");
+        public static readonly DerObjectIdentifier Pkcs9AtChallengePassword				= new DerObjectIdentifier(Pkcs9 + ".7");
+        public static readonly DerObjectIdentifier Pkcs9AtUnstructuredAddress			= new DerObjectIdentifier(Pkcs9 + ".8");
+        public static readonly DerObjectIdentifier Pkcs9AtExtendedCertificateAttributes	= new DerObjectIdentifier(Pkcs9 + ".9");
+        public static readonly DerObjectIdentifier Pkcs9AtSigningDescription			= new DerObjectIdentifier(Pkcs9 + ".13");
+        public static readonly DerObjectIdentifier Pkcs9AtExtensionRequest				= new DerObjectIdentifier(Pkcs9 + ".14");
+        public static readonly DerObjectIdentifier Pkcs9AtSmimeCapabilities				= new DerObjectIdentifier(Pkcs9 + ".15");
+        public static readonly DerObjectIdentifier Pkcs9AtFriendlyName					= new DerObjectIdentifier(Pkcs9 + ".20");
+        public static readonly DerObjectIdentifier Pkcs9AtLocalKeyID					= new DerObjectIdentifier(Pkcs9 + ".21");
+
+		[Obsolete("Use X509Certificate instead")]
+        public static readonly DerObjectIdentifier X509CertType = new DerObjectIdentifier(Pkcs9 + ".22.1");
+
+		public const string CertTypes = Pkcs9 + ".22";
+		public static readonly DerObjectIdentifier X509Certificate = new DerObjectIdentifier(CertTypes + ".1");
+		public static readonly DerObjectIdentifier SdsiCertificate = new DerObjectIdentifier(CertTypes + ".2");
+
+		public const string CrlTypes = Pkcs9 + ".23";
+		public static readonly DerObjectIdentifier X509Crl = new DerObjectIdentifier(CrlTypes + ".1");
+
+		public static readonly DerObjectIdentifier IdAlgPwriKek = new DerObjectIdentifier(Pkcs9 + ".16.3.9");
+
+        //
+        // SMIME capability sub oids.
+        //
+        public static readonly DerObjectIdentifier PreferSignedData				= new DerObjectIdentifier(Pkcs9 + ".15.1");
+        public static readonly DerObjectIdentifier CannotDecryptAny				= new DerObjectIdentifier(Pkcs9 + ".15.2");
+        public static readonly DerObjectIdentifier SmimeCapabilitiesVersions	= new DerObjectIdentifier(Pkcs9 + ".15.3");
+
+        //
+        // other SMIME attributes
+        //
+		public static readonly DerObjectIdentifier IdAAReceiptRequest = new DerObjectIdentifier(Pkcs9 + ".16.2.1");
+
+        //
+        // id-ct OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+        // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) ct(1)}
+        //
+        public const string IdCT = "1.2.840.113549.1.9.16.1";
+
+        public static readonly DerObjectIdentifier IdCTAuthData          = new DerObjectIdentifier(IdCT + ".2");
+        public static readonly DerObjectIdentifier IdCTTstInfo           = new DerObjectIdentifier(IdCT + ".4");
+        public static readonly DerObjectIdentifier IdCTCompressedData    = new DerObjectIdentifier(IdCT + ".9");
+		public static readonly DerObjectIdentifier IdCTAuthEnvelopedData = new DerObjectIdentifier(IdCT + ".23");
+		public static readonly DerObjectIdentifier IdCTTimestampedData   = new DerObjectIdentifier(IdCT + ".31");
+
+        //
+        // id-cti OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+        // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) cti(6)}
+        //
+        public const string IdCti = "1.2.840.113549.1.9.16.6";
+
+        public static readonly DerObjectIdentifier IdCtiEtsProofOfOrigin	= new DerObjectIdentifier(IdCti + ".1");
+        public static readonly DerObjectIdentifier IdCtiEtsProofOfReceipt	= new DerObjectIdentifier(IdCti + ".2");
+        public static readonly DerObjectIdentifier IdCtiEtsProofOfDelivery	= new DerObjectIdentifier(IdCti + ".3");
+        public static readonly DerObjectIdentifier IdCtiEtsProofOfSender	= new DerObjectIdentifier(IdCti + ".4");
+        public static readonly DerObjectIdentifier IdCtiEtsProofOfApproval	= new DerObjectIdentifier(IdCti + ".5");
+        public static readonly DerObjectIdentifier IdCtiEtsProofOfCreation	= new DerObjectIdentifier(IdCti + ".6");
+
+        //
+        // id-aa OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+        // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) attributes(2)}
+        //
+        public const string IdAA = "1.2.840.113549.1.9.16.2";
+
+		public static readonly DerObjectIdentifier IdAAContentHint = new DerObjectIdentifier(IdAA + ".4"); // See RFC 2634
+    	public static readonly DerObjectIdentifier IdAAMsgSigDigest = new DerObjectIdentifier(IdAA + ".5");
+    	public static readonly DerObjectIdentifier IdAAContentReference = new DerObjectIdentifier(IdAA + ".10");
+
+		/*
+        * id-aa-encrypKeyPref OBJECT IDENTIFIER ::= {id-aa 11}
+        *
+        */
+        public static readonly DerObjectIdentifier IdAAEncrypKeyPref = new DerObjectIdentifier(IdAA + ".11");
+        public static readonly DerObjectIdentifier IdAASigningCertificate = new DerObjectIdentifier(IdAA + ".12");
+		public static readonly DerObjectIdentifier IdAASigningCertificateV2 = new DerObjectIdentifier(IdAA + ".47");
+
+		public static readonly DerObjectIdentifier IdAAContentIdentifier = new DerObjectIdentifier(IdAA + ".7"); // See RFC 2634
+
+		/*
+		 * RFC 3126
+		 */
+		public static readonly DerObjectIdentifier IdAASignatureTimeStampToken = new DerObjectIdentifier(IdAA + ".14");
+
+		public static readonly DerObjectIdentifier IdAAEtsSigPolicyID = new DerObjectIdentifier(IdAA + ".15");
+		public static readonly DerObjectIdentifier IdAAEtsCommitmentType = new DerObjectIdentifier(IdAA + ".16");
+		public static readonly DerObjectIdentifier IdAAEtsSignerLocation = new DerObjectIdentifier(IdAA + ".17");
+		public static readonly DerObjectIdentifier IdAAEtsSignerAttr = new DerObjectIdentifier(IdAA + ".18");
+		public static readonly DerObjectIdentifier IdAAEtsOtherSigCert = new DerObjectIdentifier(IdAA + ".19");
+		public static readonly DerObjectIdentifier IdAAEtsContentTimestamp = new DerObjectIdentifier(IdAA + ".20");
+		public static readonly DerObjectIdentifier IdAAEtsCertificateRefs = new DerObjectIdentifier(IdAA + ".21");
+		public static readonly DerObjectIdentifier IdAAEtsRevocationRefs = new DerObjectIdentifier(IdAA + ".22");
+		public static readonly DerObjectIdentifier IdAAEtsCertValues = new DerObjectIdentifier(IdAA + ".23");
+		public static readonly DerObjectIdentifier IdAAEtsRevocationValues = new DerObjectIdentifier(IdAA + ".24");
+		public static readonly DerObjectIdentifier IdAAEtsEscTimeStamp = new DerObjectIdentifier(IdAA + ".25");
+		public static readonly DerObjectIdentifier IdAAEtsCertCrlTimestamp = new DerObjectIdentifier(IdAA + ".26");
+		public static readonly DerObjectIdentifier IdAAEtsArchiveTimestamp = new DerObjectIdentifier(IdAA + ".27");
+
+		[Obsolete("Use 'IdAAEtsSigPolicyID' instead")]
+		public static readonly DerObjectIdentifier IdAASigPolicyID = IdAAEtsSigPolicyID;
+		[Obsolete("Use 'IdAAEtsCommitmentType' instead")]
+		public static readonly DerObjectIdentifier IdAACommitmentType = IdAAEtsCommitmentType;
+		[Obsolete("Use 'IdAAEtsSignerLocation' instead")]
+		public static readonly DerObjectIdentifier IdAASignerLocation = IdAAEtsSignerLocation;
+		[Obsolete("Use 'IdAAEtsOtherSigCert' instead")]
+		public static readonly DerObjectIdentifier IdAAOtherSigCert = IdAAEtsOtherSigCert;
+
+		//
+		// id-spq OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+		// rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-spq(5)}
+		//
+		public const string IdSpq = "1.2.840.113549.1.9.16.5";
+
+		public static readonly DerObjectIdentifier IdSpqEtsUri = new DerObjectIdentifier(IdSpq + ".1");
+		public static readonly DerObjectIdentifier IdSpqEtsUNotice = new DerObjectIdentifier(IdSpq + ".2");
+
+		//
+        // pkcs-12 OBJECT IDENTIFIER ::= {
+        //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 }
+        //
+        public const string Pkcs12 = "1.2.840.113549.1.12";
+        public const string BagTypes = Pkcs12 + ".10.1";
+
+        public static readonly DerObjectIdentifier KeyBag				= new DerObjectIdentifier(BagTypes + ".1");
+        public static readonly DerObjectIdentifier Pkcs8ShroudedKeyBag	= new DerObjectIdentifier(BagTypes + ".2");
+        public static readonly DerObjectIdentifier CertBag				= new DerObjectIdentifier(BagTypes + ".3");
+        public static readonly DerObjectIdentifier CrlBag				= new DerObjectIdentifier(BagTypes + ".4");
+        public static readonly DerObjectIdentifier SecretBag			= new DerObjectIdentifier(BagTypes + ".5");
+        public static readonly DerObjectIdentifier SafeContentsBag		= new DerObjectIdentifier(BagTypes + ".6");
+
+        public const string Pkcs12PbeIds = Pkcs12 + ".1";
+
+        public static readonly DerObjectIdentifier PbeWithShaAnd128BitRC4			= new DerObjectIdentifier(Pkcs12PbeIds + ".1");
+        public static readonly DerObjectIdentifier PbeWithShaAnd40BitRC4			= new DerObjectIdentifier(Pkcs12PbeIds + ".2");
+        public static readonly DerObjectIdentifier PbeWithShaAnd3KeyTripleDesCbc	= new DerObjectIdentifier(Pkcs12PbeIds + ".3");
+        public static readonly DerObjectIdentifier PbeWithShaAnd2KeyTripleDesCbc	= new DerObjectIdentifier(Pkcs12PbeIds + ".4");
+        public static readonly DerObjectIdentifier PbeWithShaAnd128BitRC2Cbc		= new DerObjectIdentifier(Pkcs12PbeIds + ".5");
+        public static readonly DerObjectIdentifier PbewithShaAnd40BitRC2Cbc			= new DerObjectIdentifier(Pkcs12PbeIds + ".6");
+
+		public static readonly DerObjectIdentifier IdAlgCms3DesWrap = new DerObjectIdentifier("1.2.840.113549.1.9.16.3.6");
+		public static readonly DerObjectIdentifier IdAlgCmsRC2Wrap = new DerObjectIdentifier("1.2.840.113549.1.9.16.3.7");
+	}
+}
diff --git a/Crypto/src/asn1/pkcs/Pfx.cs b/Crypto/src/asn1/pkcs/Pfx.cs
new file mode 100644
index 000000000..9676f64fc
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/Pfx.cs
@@ -0,0 +1,65 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    /**
+     * the infamous Pfx from Pkcs12
+     */
+    public class Pfx
+        : Asn1Encodable
+    {
+        private ContentInfo	contentInfo;
+        private MacData		macData;
+
+		public Pfx(
+            Asn1Sequence seq)
+        {
+            BigInteger version = ((DerInteger) seq[0]).Value;
+            if (version.IntValue != 3)
+            {
+                throw new ArgumentException("wrong version for PFX PDU");
+            }
+
+			contentInfo = ContentInfo.GetInstance(seq[1]);
+
+			if (seq.Count == 3)
+            {
+                macData = MacData.GetInstance(seq[2]);
+            }
+        }
+
+		public Pfx(
+            ContentInfo	contentInfo,
+            MacData		macData)
+        {
+            this.contentInfo = contentInfo;
+            this.macData = macData;
+        }
+
+		public ContentInfo AuthSafe
+		{
+			get { return contentInfo; }
+		}
+
+		public MacData MacData
+		{
+			get { return macData; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				new DerInteger(3), contentInfo);
+
+			if (macData != null)
+            {
+                v.Add(macData);
+            }
+
+			return new BerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/PrivateKeyInfo.cs b/Crypto/src/asn1/pkcs/PrivateKeyInfo.cs
new file mode 100644
index 000000000..bd0ef7d1e
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/PrivateKeyInfo.cs
@@ -0,0 +1,126 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class PrivateKeyInfo
+        : Asn1Encodable
+    {
+        private readonly Asn1Object				privKey;
+        private readonly AlgorithmIdentifier	algID;
+		private readonly Asn1Set				attributes;
+
+		public static PrivateKeyInfo GetInstance(
+			object obj)
+		{
+			if (obj is PrivateKeyInfo)
+				return (PrivateKeyInfo) obj;
+
+			if (obj != null)
+				return new PrivateKeyInfo(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		public PrivateKeyInfo(
+            AlgorithmIdentifier	algID,
+            Asn1Object			privateKey)
+			: this(algID, privateKey, null)
+		{
+		}
+
+		public PrivateKeyInfo(
+			AlgorithmIdentifier	algID,
+			Asn1Object			privateKey,
+			Asn1Set				attributes)
+		{
+			this.privKey = privateKey;
+			this.algID = algID;
+			this.attributes = attributes;
+		}
+
+		private PrivateKeyInfo(
+            Asn1Sequence seq)
+        {
+            IEnumerator e = seq.GetEnumerator();
+
+			e.MoveNext();
+            BigInteger version = ((DerInteger) e.Current).Value;
+            if (version.IntValue != 0)
+            {
+                throw new ArgumentException("wrong version for private key info");
+            }
+
+			e.MoveNext();
+            algID = AlgorithmIdentifier.GetInstance(e.Current);
+
+			try
+            {
+				e.MoveNext();
+				Asn1OctetString data = (Asn1OctetString) e.Current;
+
+				privKey = Asn1Object.FromByteArray(data.GetOctets());
+            }
+            catch (IOException)
+            {
+				throw new ArgumentException("Error recoverying private key from sequence");
+            }
+
+			if (e.MoveNext())
+			{
+				attributes = Asn1Set.GetInstance((Asn1TaggedObject) e.Current, false);
+			}
+		}
+
+		public AlgorithmIdentifier AlgorithmID
+		{
+			get { return algID; }
+		}
+
+		public Asn1Object PrivateKey
+		{
+			get { return privKey; }
+		}
+
+    	public Asn1Set Attributes
+    	{
+    		get { return attributes; }
+    	}
+
+		/**
+         * write out an RSA private key with its associated information
+         * as described in Pkcs8.
+         * <pre>
+         *      PrivateKeyInfo ::= Sequence {
+         *                              version Version,
+         *                              privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
+         *                              privateKey PrivateKey,
+         *                              attributes [0] IMPLICIT Attributes OPTIONAL
+         *                          }
+         *      Version ::= Integer {v1(0)} (v1,...)
+         *
+         *      PrivateKey ::= OCTET STRING
+         *
+         *      Attributes ::= Set OF Attr
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				new DerInteger(0),
+				algID,
+				new DerOctetString(privKey));
+
+			if (attributes != null)
+			{
+				v.Add(new DerTaggedObject(false, 0, attributes));
+			}
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/RC2CBCParameter.cs b/Crypto/src/asn1/pkcs/RC2CBCParameter.cs
new file mode 100644
index 000000000..f5355d012
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/RC2CBCParameter.cs
@@ -0,0 +1,81 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class RC2CbcParameter
+        : Asn1Encodable
+    {
+        internal DerInteger			version;
+        internal Asn1OctetString	iv;
+
+		public static RC2CbcParameter GetInstance(
+            object obj)
+        {
+            if (obj is Asn1Sequence)
+            {
+                return new RC2CbcParameter((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		public RC2CbcParameter(
+            byte[] iv)
+        {
+            this.iv = new DerOctetString(iv);
+        }
+
+		public RC2CbcParameter(
+            int		parameterVersion,
+            byte[]	iv)
+        {
+            this.version = new DerInteger(parameterVersion);
+            this.iv = new DerOctetString(iv);
+        }
+
+		private RC2CbcParameter(
+            Asn1Sequence seq)
+        {
+            if (seq.Count == 1)
+            {
+                iv = (Asn1OctetString)seq[0];
+            }
+            else
+            {
+                version = (DerInteger)seq[0];
+                iv = (Asn1OctetString)seq[1];
+            }
+        }
+
+		public BigInteger RC2ParameterVersion
+        {
+            get
+            {
+				return version == null ? null : version.Value;
+            }
+        }
+
+		public byte[] GetIV()
+        {
+			return Arrays.Clone(iv.GetOctets());
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (version != null)
+            {
+                v.Add(version);
+            }
+
+			v.Add(iv);
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/RSAESOAEPparams.cs b/Crypto/src/asn1/pkcs/RSAESOAEPparams.cs
new file mode 100644
index 000000000..5ecb394fd
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/RSAESOAEPparams.cs
@@ -0,0 +1,145 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+	public class RsaesOaepParameters
+		: Asn1Encodable
+	{
+		private AlgorithmIdentifier hashAlgorithm;
+		private AlgorithmIdentifier maskGenAlgorithm;
+		private AlgorithmIdentifier pSourceAlgorithm;
+
+		public readonly static AlgorithmIdentifier DefaultHashAlgorithm = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+		public readonly static AlgorithmIdentifier DefaultMaskGenFunction = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, DefaultHashAlgorithm);
+		public readonly static AlgorithmIdentifier DefaultPSourceAlgorithm = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdPSpecified, new DerOctetString(new byte[0]));
+
+		public static RsaesOaepParameters GetInstance(
+			object obj)
+		{
+			if (obj is RsaesOaepParameters)
+			{
+				return (RsaesOaepParameters)obj;
+			}
+			else if (obj is Asn1Sequence)
+			{
+				return new RsaesOaepParameters((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		/**
+		 * The default version
+		 */
+		public RsaesOaepParameters()
+		{
+			hashAlgorithm = DefaultHashAlgorithm;
+			maskGenAlgorithm = DefaultMaskGenFunction;
+			pSourceAlgorithm = DefaultPSourceAlgorithm;
+		}
+
+		public RsaesOaepParameters(
+			AlgorithmIdentifier hashAlgorithm,
+			AlgorithmIdentifier maskGenAlgorithm,
+			AlgorithmIdentifier pSourceAlgorithm)
+		{
+			this.hashAlgorithm = hashAlgorithm;
+			this.maskGenAlgorithm = maskGenAlgorithm;
+			this.pSourceAlgorithm = pSourceAlgorithm;
+		}
+
+		public RsaesOaepParameters(
+			Asn1Sequence seq)
+		{
+			hashAlgorithm = DefaultHashAlgorithm;
+			maskGenAlgorithm = DefaultMaskGenFunction;
+			pSourceAlgorithm = DefaultPSourceAlgorithm;
+
+			for (int i = 0; i != seq.Count; i++)
+			{
+				Asn1TaggedObject o = (Asn1TaggedObject)seq[i];
+
+				switch (o.TagNo)
+				{
+					case 0:
+						hashAlgorithm = AlgorithmIdentifier.GetInstance(o, true);
+						break;
+					case 1:
+						maskGenAlgorithm = AlgorithmIdentifier.GetInstance(o, true);
+						break;
+					case 2:
+						pSourceAlgorithm = AlgorithmIdentifier.GetInstance(o, true);
+						break;
+					default:
+						throw new ArgumentException("unknown tag");
+				}
+			}
+		}
+
+		public AlgorithmIdentifier HashAlgorithm
+		{
+			get { return hashAlgorithm; }
+		}
+
+		public AlgorithmIdentifier MaskGenAlgorithm
+		{
+			get { return maskGenAlgorithm; }
+		}
+
+		public AlgorithmIdentifier PSourceAlgorithm
+		{
+			get { return pSourceAlgorithm; }
+		}
+
+		/**
+		 * <pre>
+		 *  RSAES-OAEP-params ::= SEQUENCE {
+		 *     hashAlgorithm      [0] OAEP-PSSDigestAlgorithms     DEFAULT sha1,
+		 *     maskGenAlgorithm   [1] PKCS1MGFAlgorithms  DEFAULT mgf1SHA1,
+		 *     pSourceAlgorithm   [2] PKCS1PSourceAlgorithms  DEFAULT pSpecifiedEmpty
+		 *   }
+		 *
+		 *   OAEP-PSSDigestAlgorithms    ALGORITHM-IDENTIFIER ::= {
+		 *     { OID id-sha1 PARAMETERS NULL   }|
+		 *     { OID id-sha256 PARAMETERS NULL }|
+		 *     { OID id-sha384 PARAMETERS NULL }|
+		 *     { OID id-sha512 PARAMETERS NULL },
+		 *     ...  -- Allows for future expansion --
+		 *   }
+		 *   PKCS1MGFAlgorithms    ALGORITHM-IDENTIFIER ::= {
+		 *     { OID id-mgf1 PARAMETERS OAEP-PSSDigestAlgorithms },
+		 *    ...  -- Allows for future expansion --
+		 *   }
+		 *   PKCS1PSourceAlgorithms    ALGORITHM-IDENTIFIER ::= {
+		 *     { OID id-pSpecified PARAMETERS OCTET STRING },
+		 *     ...  -- Allows for future expansion --
+		 *  }
+		 * </pre>
+		 * @return the asn1 primitive representing the parameters.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (!hashAlgorithm.Equals(DefaultHashAlgorithm))
+			{
+				v.Add(new DerTaggedObject(true, 0, hashAlgorithm));
+			}
+
+			if (!maskGenAlgorithm.Equals(DefaultMaskGenFunction))
+			{
+				v.Add(new DerTaggedObject(true, 1, maskGenAlgorithm));
+			}
+
+			if (!pSourceAlgorithm.Equals(DefaultPSourceAlgorithm))
+			{
+				v.Add(new DerTaggedObject(true, 2, pSourceAlgorithm));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs b/Crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs
new file mode 100644
index 000000000..dbb07c744
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs
@@ -0,0 +1,131 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class RsaPrivateKeyStructure
+        : Asn1Encodable
+    {
+        private readonly BigInteger	modulus;
+        private readonly BigInteger	publicExponent;
+        private readonly BigInteger	privateExponent;
+        private readonly BigInteger	prime1;
+        private readonly BigInteger	prime2;
+        private readonly BigInteger	exponent1;
+        private readonly BigInteger	exponent2;
+        private readonly BigInteger	coefficient;
+
+		public RsaPrivateKeyStructure(
+            BigInteger	modulus,
+            BigInteger	publicExponent,
+            BigInteger	privateExponent,
+            BigInteger	prime1,
+            BigInteger	prime2,
+            BigInteger	exponent1,
+            BigInteger	exponent2,
+            BigInteger	coefficient)
+        {
+            this.modulus = modulus;
+            this.publicExponent = publicExponent;
+            this.privateExponent = privateExponent;
+            this.prime1 = prime1;
+            this.prime2 = prime2;
+            this.exponent1 = exponent1;
+            this.exponent2 = exponent2;
+            this.coefficient = coefficient;
+        }
+
+		public RsaPrivateKeyStructure(
+            Asn1Sequence seq)
+        {
+			BigInteger version = ((DerInteger) seq[0]).Value;
+			if (version.IntValue != 0)
+                throw new ArgumentException("wrong version for RSA private key");
+
+			modulus = ((DerInteger) seq[1]).Value;
+			publicExponent = ((DerInteger) seq[2]).Value;
+			privateExponent = ((DerInteger) seq[3]).Value;
+			prime1 = ((DerInteger) seq[4]).Value;
+			prime2 = ((DerInteger) seq[5]).Value;
+			exponent1 = ((DerInteger) seq[6]).Value;
+			exponent2 = ((DerInteger) seq[7]).Value;
+			coefficient = ((DerInteger) seq[8]).Value;
+		}
+
+		public BigInteger Modulus
+		{
+			get { return modulus; }
+		}
+
+		public BigInteger PublicExponent
+		{
+			get { return publicExponent; }
+		}
+
+		public BigInteger PrivateExponent
+		{
+			get { return privateExponent; }
+		}
+
+		public BigInteger Prime1
+		{
+			get { return prime1; }
+		}
+
+		public BigInteger Prime2
+		{
+			get { return prime2; }
+		}
+
+		public BigInteger Exponent1
+		{
+			get { return exponent1; }
+		}
+
+		public BigInteger Exponent2
+		{
+			get { return exponent2; }
+		}
+
+		public BigInteger Coefficient
+		{
+			get { return coefficient; }
+		}
+
+		/**
+         * This outputs the key in Pkcs1v2 format.
+         * <pre>
+         *      RsaPrivateKey ::= Sequence {
+         *                          version Version,
+         *                          modulus Integer, -- n
+         *                          publicExponent Integer, -- e
+         *                          privateExponent Integer, -- d
+         *                          prime1 Integer, -- p
+         *                          prime2 Integer, -- q
+         *                          exponent1 Integer, -- d mod (p-1)
+         *                          exponent2 Integer, -- d mod (q-1)
+         *                          coefficient Integer -- (inverse of q) mod p
+         *                      }
+         *
+         *      Version ::= Integer
+         * </pre>
+         * <p>This routine is written to output Pkcs1 version 0, private keys.</p>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(
+				new DerInteger(0), // version
+				new DerInteger(Modulus),
+				new DerInteger(PublicExponent),
+				new DerInteger(PrivateExponent),
+				new DerInteger(Prime1),
+				new DerInteger(Prime2),
+				new DerInteger(Exponent1),
+				new DerInteger(Exponent2),
+				new DerInteger(Coefficient));
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/RSASSAPSSparams.cs b/Crypto/src/asn1/pkcs/RSASSAPSSparams.cs
new file mode 100644
index 000000000..941620761
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/RSASSAPSSparams.cs
@@ -0,0 +1,165 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+	public class RsassaPssParameters
+		: Asn1Encodable
+	{
+		private AlgorithmIdentifier hashAlgorithm;
+		private AlgorithmIdentifier maskGenAlgorithm;
+		private DerInteger saltLength;
+		private DerInteger trailerField;
+
+		public readonly static AlgorithmIdentifier DefaultHashAlgorithm = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+		public readonly static AlgorithmIdentifier DefaultMaskGenFunction = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, DefaultHashAlgorithm);
+		public readonly static DerInteger DefaultSaltLength = new DerInteger(20);
+		public readonly static DerInteger DefaultTrailerField = new DerInteger(1);
+
+		public static RsassaPssParameters GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is RsassaPssParameters)
+			{
+				return (RsassaPssParameters)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new RsassaPssParameters((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		/**
+		 * The default version
+		 */
+		public RsassaPssParameters()
+		{
+			hashAlgorithm = DefaultHashAlgorithm;
+			maskGenAlgorithm = DefaultMaskGenFunction;
+			saltLength = DefaultSaltLength;
+			trailerField = DefaultTrailerField;
+		}
+
+		public RsassaPssParameters(
+			AlgorithmIdentifier hashAlgorithm,
+			AlgorithmIdentifier maskGenAlgorithm,
+			DerInteger saltLength,
+			DerInteger trailerField)
+		{
+			this.hashAlgorithm = hashAlgorithm;
+			this.maskGenAlgorithm = maskGenAlgorithm;
+			this.saltLength = saltLength;
+			this.trailerField = trailerField;
+		}
+
+		public RsassaPssParameters(
+			Asn1Sequence seq)
+		{
+			hashAlgorithm = DefaultHashAlgorithm;
+			maskGenAlgorithm = DefaultMaskGenFunction;
+			saltLength = DefaultSaltLength;
+			trailerField = DefaultTrailerField;
+
+			for (int i = 0; i != seq.Count; i++)
+			{
+				Asn1TaggedObject o = (Asn1TaggedObject)seq[i];
+
+				switch (o.TagNo)
+				{
+					case 0:
+						hashAlgorithm = AlgorithmIdentifier.GetInstance(o, true);
+						break;
+					case 1:
+						maskGenAlgorithm = AlgorithmIdentifier.GetInstance(o, true);
+						break;
+					case 2:
+						saltLength = DerInteger.GetInstance(o, true);
+						break;
+					case 3:
+						trailerField = DerInteger.GetInstance(o, true);
+						break;
+					default:
+						throw new ArgumentException("unknown tag");
+				}
+			}
+		}
+
+		public AlgorithmIdentifier HashAlgorithm
+		{
+			get { return hashAlgorithm; }
+		}
+
+		public AlgorithmIdentifier MaskGenAlgorithm
+		{
+			get { return maskGenAlgorithm; }
+		}
+
+		public DerInteger SaltLength
+		{
+			get { return saltLength; }
+		}
+
+		public DerInteger TrailerField
+		{
+			get { return trailerField; }
+		}
+
+		/**
+		 * <pre>
+		 * RSASSA-PSS-params ::= SEQUENCE {
+		 *   hashAlgorithm      [0] OAEP-PSSDigestAlgorithms  DEFAULT sha1,
+		 *    maskGenAlgorithm   [1] PKCS1MGFAlgorithms  DEFAULT mgf1SHA1,
+		 *    saltLength         [2] INTEGER  DEFAULT 20,
+		 *    trailerField       [3] TrailerField  DEFAULT trailerFieldBC
+		 *  }
+		 *
+		 * OAEP-PSSDigestAlgorithms    ALGORITHM-IDENTIFIER ::= {
+		 *    { OID id-sha1 PARAMETERS NULL   }|
+		 *    { OID id-sha256 PARAMETERS NULL }|
+		 *    { OID id-sha384 PARAMETERS NULL }|
+		 *    { OID id-sha512 PARAMETERS NULL },
+		 *    ...  -- Allows for future expansion --
+		 * }
+		 *
+		 * PKCS1MGFAlgorithms    ALGORITHM-IDENTIFIER ::= {
+		 *   { OID id-mgf1 PARAMETERS OAEP-PSSDigestAlgorithms },
+		 *    ...  -- Allows for future expansion --
+		 * }
+		 *
+		 * TrailerField ::= INTEGER { trailerFieldBC(1) }
+		 * </pre>
+		 * @return the asn1 primitive representing the parameters.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (!hashAlgorithm.Equals(DefaultHashAlgorithm))
+			{
+				v.Add(new DerTaggedObject(true, 0, hashAlgorithm));
+			}
+
+			if (!maskGenAlgorithm.Equals(DefaultMaskGenFunction))
+			{
+				v.Add(new DerTaggedObject(true, 1, maskGenAlgorithm));
+			}
+
+			if (!saltLength.Equals(DefaultSaltLength))
+			{
+				v.Add(new DerTaggedObject(true, 2, saltLength));
+			}
+
+			if (!trailerField.Equals(DefaultTrailerField))
+			{
+				v.Add(new DerTaggedObject(true, 3, trailerField));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/pkcs/SafeBag.cs b/Crypto/src/asn1/pkcs/SafeBag.cs
new file mode 100644
index 000000000..4b9350bac
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/SafeBag.cs
@@ -0,0 +1,70 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class SafeBag
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier bagID;
+        private readonly Asn1Object bagValue;
+        private readonly Asn1Set bagAttributes;
+
+		public SafeBag(
+            DerObjectIdentifier	oid,
+            Asn1Object			obj)
+        {
+            this.bagID = oid;
+            this.bagValue = obj;
+            this.bagAttributes = null;
+        }
+
+		public SafeBag(
+            DerObjectIdentifier	oid,
+            Asn1Object			obj,
+            Asn1Set				bagAttributes)
+        {
+            this.bagID = oid;
+            this.bagValue = obj;
+            this.bagAttributes = bagAttributes;
+        }
+
+		public SafeBag(
+            Asn1Sequence seq)
+        {
+            this.bagID = (DerObjectIdentifier) seq[0];
+            this.bagValue = ((DerTaggedObject) seq[1]).GetObject();
+            if (seq.Count == 3)
+            {
+                this.bagAttributes = (Asn1Set) seq[2];
+            }
+        }
+
+		public DerObjectIdentifier BagID
+		{
+			get { return bagID; }
+		}
+
+		public Asn1Object BagValue
+		{
+			get { return bagValue; }
+		}
+
+		public Asn1Set BagAttributes
+		{
+			get { return bagAttributes; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				bagID, new DerTaggedObject(0, bagValue));
+
+			if (bagAttributes != null)
+            {
+                v.Add(bagAttributes);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/SignedData.cs b/Crypto/src/asn1/pkcs/SignedData.cs
new file mode 100644
index 000000000..10951d37a
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/SignedData.cs
@@ -0,0 +1,163 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    /**
+     * a Pkcs#7 signed data object.
+     */
+    public class SignedData
+        : Asn1Encodable
+    {
+        private readonly DerInteger		version;
+        private readonly Asn1Set		digestAlgorithms;
+        private readonly ContentInfo	contentInfo;
+        private readonly Asn1Set		certificates;
+        private readonly Asn1Set		crls;
+        private readonly Asn1Set		signerInfos;
+
+		public static SignedData GetInstance(
+            object obj)
+        {
+            if (obj is SignedData)
+            {
+                return (SignedData) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new SignedData((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		public SignedData(
+            DerInteger        _version,
+            Asn1Set           _digestAlgorithms,
+            ContentInfo       _contentInfo,
+            Asn1Set           _certificates,
+            Asn1Set           _crls,
+            Asn1Set           _signerInfos)
+        {
+            version          = _version;
+            digestAlgorithms = _digestAlgorithms;
+            contentInfo      = _contentInfo;
+            certificates     = _certificates;
+            crls             = _crls;
+            signerInfos      = _signerInfos;
+        }
+
+		private SignedData(
+            Asn1Sequence seq)
+        {
+            IEnumerator e = seq.GetEnumerator();
+
+			e.MoveNext();
+            version = (DerInteger) e.Current;
+
+			e.MoveNext();
+            digestAlgorithms = (Asn1Set) e.Current;
+
+			e.MoveNext();
+            contentInfo = ContentInfo.GetInstance(e.Current);
+
+			while (e.MoveNext())
+            {
+                Asn1Object o = (Asn1Object) e.Current;
+
+				//
+                // an interesting feature of SignedData is that there appear to be varying implementations...
+                // for the moment we ignore anything which doesn't fit.
+                //
+                if (o is DerTaggedObject)
+                {
+                    DerTaggedObject tagged = (DerTaggedObject) o;
+
+					switch (tagged.TagNo)
+                    {
+						case 0:
+							certificates = Asn1Set.GetInstance(tagged, false);
+							break;
+						case 1:
+							crls = Asn1Set.GetInstance(tagged, false);
+							break;
+						default:
+							throw new ArgumentException("unknown tag value " + tagged.TagNo);
+                    }
+                }
+                else
+                {
+                    signerInfos = (Asn1Set) o;
+                }
+            }
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public Asn1Set DigestAlgorithms
+		{
+			get { return digestAlgorithms; }
+		}
+
+		public ContentInfo ContentInfo
+		{
+			get { return contentInfo; }
+		}
+
+		public Asn1Set Certificates
+		{
+			get { return certificates; }
+		}
+
+		public Asn1Set Crls
+		{
+			get { return crls; }
+		}
+
+		public Asn1Set SignerInfos
+		{
+			get { return signerInfos; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  SignedData ::= Sequence {
+         *      version Version,
+         *      digestAlgorithms DigestAlgorithmIdentifiers,
+         *      contentInfo ContentInfo,
+         *      certificates
+         *          [0] IMPLICIT ExtendedCertificatesAndCertificates
+         *                   OPTIONAL,
+         *      crls
+         *          [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+         *      signerInfos SignerInfos }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				version, digestAlgorithms, contentInfo);
+
+			if (certificates != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, certificates));
+            }
+
+			if (crls != null)
+            {
+                v.Add(new DerTaggedObject(false, 1, crls));
+            }
+
+			v.Add(signerInfos);
+
+			return new BerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/pkcs/SignerInfo.cs b/Crypto/src/asn1/pkcs/SignerInfo.cs
new file mode 100644
index 000000000..1e4694547
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/SignerInfo.cs
@@ -0,0 +1,154 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    /**
+     * a Pkcs#7 signer info object.
+     */
+    public class SignerInfo
+        : Asn1Encodable
+    {
+        private DerInteger              version;
+        private IssuerAndSerialNumber   issuerAndSerialNumber;
+        private AlgorithmIdentifier     digAlgorithm;
+        private Asn1Set                 authenticatedAttributes;
+        private AlgorithmIdentifier     digEncryptionAlgorithm;
+        private Asn1OctetString         encryptedDigest;
+        private Asn1Set                 unauthenticatedAttributes;
+
+		public static SignerInfo GetInstance(
+            object obj)
+        {
+            if (obj is SignerInfo)
+            {
+                return (SignerInfo) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new SignerInfo((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		public SignerInfo(
+            DerInteger              version,
+            IssuerAndSerialNumber   issuerAndSerialNumber,
+            AlgorithmIdentifier     digAlgorithm,
+            Asn1Set                 authenticatedAttributes,
+            AlgorithmIdentifier     digEncryptionAlgorithm,
+            Asn1OctetString         encryptedDigest,
+            Asn1Set                 unauthenticatedAttributes)
+        {
+            this.version = version;
+            this.issuerAndSerialNumber = issuerAndSerialNumber;
+            this.digAlgorithm = digAlgorithm;
+            this.authenticatedAttributes = authenticatedAttributes;
+            this.digEncryptionAlgorithm = digEncryptionAlgorithm;
+            this.encryptedDigest = encryptedDigest;
+            this.unauthenticatedAttributes = unauthenticatedAttributes;
+        }
+
+		public SignerInfo(
+            Asn1Sequence seq)
+        {
+            IEnumerator e = seq.GetEnumerator();
+
+			e.MoveNext();
+            version = (DerInteger) e.Current;
+
+			e.MoveNext();
+            issuerAndSerialNumber = IssuerAndSerialNumber.GetInstance(e.Current);
+
+			e.MoveNext();
+            digAlgorithm = AlgorithmIdentifier.GetInstance(e.Current);
+
+			e.MoveNext();
+            object obj = e.Current;
+
+			if (obj is Asn1TaggedObject)
+            {
+                authenticatedAttributes = Asn1Set.GetInstance((Asn1TaggedObject) obj, false);
+
+				e.MoveNext();
+                digEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(e.Current);
+            }
+            else
+            {
+                authenticatedAttributes = null;
+                digEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(obj);
+            }
+
+			e.MoveNext();
+            encryptedDigest = DerOctetString.GetInstance(e.Current);
+
+			if (e.MoveNext())
+            {
+                unauthenticatedAttributes = Asn1Set.GetInstance((Asn1TaggedObject)e.Current, false);
+            }
+            else
+            {
+                unauthenticatedAttributes = null;
+            }
+        }
+
+		public DerInteger Version { get { return version; } }
+
+		public IssuerAndSerialNumber IssuerAndSerialNumber { get { return issuerAndSerialNumber; } }
+
+		public Asn1Set AuthenticatedAttributes { get { return authenticatedAttributes; } }
+
+		public AlgorithmIdentifier DigestAlgorithm { get { return digAlgorithm; } }
+
+		public Asn1OctetString EncryptedDigest { get { return encryptedDigest; } }
+
+		public AlgorithmIdentifier DigestEncryptionAlgorithm { get { return digEncryptionAlgorithm; } }
+
+		public Asn1Set UnauthenticatedAttributes { get { return unauthenticatedAttributes; } }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  SignerInfo ::= Sequence {
+         *      version Version,
+         *      issuerAndSerialNumber IssuerAndSerialNumber,
+         *      digestAlgorithm DigestAlgorithmIdentifier,
+         *      authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
+         *      digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
+         *      encryptedDigest EncryptedDigest,
+         *      unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
+         *  }
+         *
+         *  EncryptedDigest ::= OCTET STRING
+         *
+         *  DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+         *
+         *  DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				version, issuerAndSerialNumber, digAlgorithm);
+
+			if (authenticatedAttributes != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, authenticatedAttributes));
+            }
+
+			v.Add(digEncryptionAlgorithm, encryptedDigest);
+
+			if (unauthenticatedAttributes != null)
+            {
+                v.Add(new DerTaggedObject(false, 1, unauthenticatedAttributes));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/sec/ECPrivateKeyStructure.cs b/Crypto/src/asn1/sec/ECPrivateKeyStructure.cs
new file mode 100644
index 000000000..2e9c27fd2
--- /dev/null
+++ b/Crypto/src/asn1/sec/ECPrivateKeyStructure.cs
@@ -0,0 +1,118 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Sec
+{
+	/**
+	 * the elliptic curve private key object from SEC 1
+	 */
+	public class ECPrivateKeyStructure
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence seq;
+
+		public ECPrivateKeyStructure(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+
+			this.seq = seq;
+		}
+
+		public ECPrivateKeyStructure(
+			BigInteger key)
+		{
+			if (key == null)
+				throw new ArgumentNullException("key");
+
+			this.seq = new DerSequence(
+				new DerInteger(1),
+				new DerOctetString(key.ToByteArrayUnsigned()));
+		}
+
+		public ECPrivateKeyStructure(
+			BigInteger		key,
+			Asn1Encodable	parameters)
+			: this(key, null, parameters)
+		{
+		}
+
+		public ECPrivateKeyStructure(
+			BigInteger		key,
+			DerBitString	publicKey,
+			Asn1Encodable	parameters)
+		{
+			if (key == null)
+				throw new ArgumentNullException("key");
+
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				new DerInteger(1),
+				new DerOctetString(key.ToByteArrayUnsigned()));
+
+			if (parameters != null)
+			{
+				v.Add(new DerTaggedObject(true, 0, parameters));
+			}
+
+			if (publicKey != null)
+			{
+				v.Add(new DerTaggedObject(true, 1, publicKey));
+			}
+
+			this.seq = new DerSequence(v);
+		}
+
+		public BigInteger GetKey()
+		{
+			Asn1OctetString octs = (Asn1OctetString) seq[1];
+
+			return new BigInteger(1, octs.GetOctets());
+		}
+
+		public DerBitString GetPublicKey()
+		{
+			return (DerBitString) GetObjectInTag(1);
+		}
+
+		public Asn1Object GetParameters()
+		{
+			return GetObjectInTag(0);
+		}
+
+		private Asn1Object GetObjectInTag(
+			int tagNo)
+		{
+			foreach (Asn1Encodable ae in seq)
+			{
+				Asn1Object obj = ae.ToAsn1Object();
+
+				if (obj is Asn1TaggedObject)
+				{
+					Asn1TaggedObject tag = (Asn1TaggedObject) obj;
+					if (tag.TagNo == tagNo)
+					{
+						return tag.GetObject();
+					}
+				}
+			}
+
+			return null;
+		}
+
+		/**
+		 * ECPrivateKey ::= SEQUENCE {
+		 *     version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+		 *     privateKey OCTET STRING,
+		 *     parameters [0] Parameters OPTIONAL,
+		 *     publicKey [1] BIT STRING OPTIONAL }
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return seq;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/sec/SECNamedCurves.cs b/Crypto/src/asn1/sec/SECNamedCurves.cs
new file mode 100644
index 000000000..c7503144f
--- /dev/null
+++ b/Crypto/src/asn1/sec/SECNamedCurves.cs
@@ -0,0 +1,1192 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.Sec
+{
+	public sealed class SecNamedCurves
+	{
+		private SecNamedCurves()
+		{
+		}
+
+		private static BigInteger FromHex(
+			string hex)
+		{
+			return new BigInteger(1, Hex.Decode(hex));
+		}
+
+		/*
+		 * secp112r1
+		 */
+		internal class Secp112r1Holder
+			: X9ECParametersHolder
+		{
+			private Secp112r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Secp112r1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				// p = (2^128 - 3) / 76439
+				BigInteger p = FromHex("DB7C2ABF62E35E668076BEAD208B");
+				BigInteger a = FromHex("DB7C2ABF62E35E668076BEAD2088");
+				BigInteger b = FromHex("659EF8BA043916EEDE8911702B22");
+				byte[] S = Hex.Decode("00F50B028E4D696E676875615175290472783FB1");
+				BigInteger n = FromHex("DB7C2ABF62E35E7628DFAC6561C5");
+				BigInteger h = BigInteger.ValueOf(1);
+
+				ECCurve curve = new FpCurve(p, a, b);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("02"
+				//+ "09487239995A5EE76B55F9C2F098"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "09487239995A5EE76B55F9C2F098"
+					+ "A89CE5AF8724C0A23E0E0FF77500"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * secp112r2
+		 */
+		internal class Secp112r2Holder
+			: X9ECParametersHolder
+		{
+			private Secp112r2Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Secp112r2Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				// p = (2^128 - 3) / 76439
+				BigInteger p = FromHex("DB7C2ABF62E35E668076BEAD208B");
+				BigInteger a = FromHex("6127C24C05F38A0AAAF65C0EF02C");
+				BigInteger b = FromHex("51DEF1815DB5ED74FCC34C85D709");
+				byte[] S = Hex.Decode("002757A1114D696E6768756151755316C05E0BD4");
+				BigInteger n = FromHex("36DF0AAFD8B8D7597CA10520D04B");
+				BigInteger h = BigInteger.ValueOf(4);
+
+				ECCurve curve = new FpCurve(p, a, b);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "4BA30AB5E892B4E1649DD0928643"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "4BA30AB5E892B4E1649DD0928643"
+					+ "ADCD46F5882E3747DEF36E956E97"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * secp128r1
+		 */
+		internal class Secp128r1Holder
+			: X9ECParametersHolder
+		{
+			private Secp128r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Secp128r1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				// p = 2^128 - 2^97 - 1
+				BigInteger p = FromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF");
+				BigInteger a = FromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC");
+				BigInteger b = FromHex("E87579C11079F43DD824993C2CEE5ED3");
+				byte[] S = Hex.Decode("000E0D4D696E6768756151750CC03A4473D03679");
+				BigInteger n = FromHex("FFFFFFFE0000000075A30D1B9038A115");
+				BigInteger h = BigInteger.ValueOf(1);
+
+				ECCurve curve = new FpCurve(p, a, b);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "161FF7528B899B2D0C28607CA52C5B86"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "161FF7528B899B2D0C28607CA52C5B86"
+					+ "CF5AC8395BAFEB13C02DA292DDED7A83"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * secp128r2
+		 */
+		internal class Secp128r2Holder
+			: X9ECParametersHolder
+		{
+			private Secp128r2Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Secp128r2Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				// p = 2^128 - 2^97 - 1
+				BigInteger p = FromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF");
+				BigInteger a = FromHex("D6031998D1B3BBFEBF59CC9BBFF9AEE1");
+				BigInteger b = FromHex("5EEEFCA380D02919DC2C6558BB6D8A5D");
+				byte[] S = Hex.Decode("004D696E67687561517512D8F03431FCE63B88F4");
+				BigInteger n = FromHex("3FFFFFFF7FFFFFFFBE0024720613B5A3");
+				BigInteger h = BigInteger.ValueOf(4);
+
+				ECCurve curve = new FpCurve(p, a, b);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("02"
+				//+ "7B6AA5D85E572983E6FB32A7CDEBC140"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "7B6AA5D85E572983E6FB32A7CDEBC140"
+					+ "27B6916A894D3AEE7106FE805FC34B44"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * secp160k1
+		 */
+		internal class Secp160k1Holder
+			: X9ECParametersHolder
+		{
+			private Secp160k1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Secp160k1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				// p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1
+				BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73");
+				BigInteger a = BigInteger.Zero;
+				BigInteger b = BigInteger.ValueOf(7);
+				byte[] S = null;
+				BigInteger n = FromHex("0100000000000000000001B8FA16DFAB9ACA16B6B3");
+				BigInteger h = BigInteger.ValueOf(1);
+
+				ECCurve curve = new FpCurve(p, a, b);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("02"
+					//+ "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"
+					+ "938CF935318FDCED6BC28286531733C3F03C4FEE"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * secp160r1
+		 */
+		internal class Secp160r1Holder
+			: X9ECParametersHolder
+		{
+			private Secp160r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Secp160r1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				// p = 2^160 - 2^31 - 1
+				BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF");
+				BigInteger a = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC");
+				BigInteger b = FromHex("1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45");
+				byte[] S = Hex.Decode("1053CDE42C14D696E67687561517533BF3F83345");
+				BigInteger n = FromHex("0100000000000000000001F4C8F927AED3CA752257");
+				BigInteger h = BigInteger.ValueOf(1);
+
+				ECCurve curve = new FpCurve(p, a, b);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("02"
+					//+ "4A96B5688EF573284664698968C38BB913CBFC82"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "4A96B5688EF573284664698968C38BB913CBFC82"
+					+ "23A628553168947D59DCC912042351377AC5FB32"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * secp160r2
+		 */
+		internal class Secp160r2Holder
+			: X9ECParametersHolder
+		{
+			private Secp160r2Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Secp160r2Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				// p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1
+				BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73");
+				BigInteger a = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70");
+				BigInteger b = FromHex("B4E134D3FB59EB8BAB57274904664D5AF50388BA");
+				byte[] S = Hex.Decode("B99B99B099B323E02709A4D696E6768756151751");
+				BigInteger n = FromHex("0100000000000000000000351EE786A818F3A1A16B");
+				BigInteger h = BigInteger.ValueOf(1);
+
+				ECCurve curve = new FpCurve(p, a, b);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("02"
+				//+ "52DCB034293A117E1F4FF11B30F7199D3144CE6D"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "52DCB034293A117E1F4FF11B30F7199D3144CE6D"
+					+ "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * secp192k1
+		 */
+		internal class Secp192k1Holder
+			: X9ECParametersHolder
+		{
+			private Secp192k1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Secp192k1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				// p = 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1
+				BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37");
+				BigInteger a = BigInteger.Zero;
+				BigInteger b = BigInteger.ValueOf(3);
+				byte[] S = null;
+				BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D");
+				BigInteger h = BigInteger.ValueOf(1);
+
+				ECCurve curve = new FpCurve(p, a, b);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"
+					+ "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * secp192r1
+		 */
+		internal class Secp192r1Holder
+			: X9ECParametersHolder
+		{
+			private Secp192r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Secp192r1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				// p = 2^192 - 2^64 - 1
+				BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF");
+				BigInteger a = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC");
+				BigInteger b = FromHex("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1");
+				byte[] S = Hex.Decode("3045AE6FC8422F64ED579528D38120EAE12196D5");
+				BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831");
+				BigInteger h = BigInteger.ValueOf(1);
+
+				ECCurve curve = new FpCurve(p, a, b);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"
+					+ "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * secp224k1
+		 */
+		internal class Secp224k1Holder
+			: X9ECParametersHolder
+		{
+			private Secp224k1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Secp224k1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				// p = 2^224 - 2^32 - 2^12 - 2^11 - 2^9 - 2^7 - 2^4 - 2 - 1
+				BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D");
+				BigInteger a = BigInteger.Zero;
+				BigInteger b = BigInteger.ValueOf(5);
+				byte[] S = null;
+				BigInteger n = FromHex("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7");
+				BigInteger h = BigInteger.ValueOf(1);
+
+				ECCurve curve = new FpCurve(p, a, b);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"
+					+ "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * secp224r1
+		 */
+		internal class Secp224r1Holder
+			: X9ECParametersHolder
+		{
+			private Secp224r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Secp224r1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				// p = 2^224 - 2^96 + 1
+				BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001");
+				BigInteger a = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE");
+				BigInteger b = FromHex("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4");
+				byte[] S = Hex.Decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5");
+				BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D");
+				BigInteger h = BigInteger.ValueOf(1);
+
+				ECCurve curve = new FpCurve(p, a, b);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("02"
+				//+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
+					+ "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * secp256k1
+		 */
+		internal class Secp256k1Holder
+			: X9ECParametersHolder
+		{
+			private Secp256k1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Secp256k1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				// p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
+				BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F");
+				BigInteger a = BigInteger.Zero;
+				BigInteger b = BigInteger.ValueOf(7);
+				byte[] S = null;
+				BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
+				BigInteger h = BigInteger.ValueOf(1);
+
+				ECCurve curve = new FpCurve(p, a, b);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("02"
+				//+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
+					+ "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * secp256r1
+		 */
+		internal class Secp256r1Holder
+			: X9ECParametersHolder
+		{
+			private Secp256r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Secp256r1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				// p = 2^224 (2^32 - 1) + 2^192 + 2^96 - 1
+				BigInteger p = FromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF");
+				BigInteger a = FromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC");
+				BigInteger b = FromHex("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B");
+				byte[] S = Hex.Decode("C49D360886E704936A6678E1139D26B7819F7E90");
+				BigInteger n = FromHex("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
+				BigInteger h = BigInteger.ValueOf(1);
+
+				ECCurve curve = new FpCurve(p, a, b);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
+					+ "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * secp384r1
+		 */
+		internal class Secp384r1Holder
+			: X9ECParametersHolder
+		{
+			private Secp384r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Secp384r1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				// p = 2^384 - 2^128 - 2^96 + 2^32 - 1
+				BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF");
+				BigInteger a = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC");
+				BigInteger b = FromHex("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF");
+				byte[] S = Hex.Decode("A335926AA319A27A1D00896A6773A4827ACDAC73");
+				BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973");
+				BigInteger h = BigInteger.ValueOf(1);
+
+				ECCurve curve = new FpCurve(p, a, b);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"
+					+ "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * secp521r1
+		 */
+		internal class Secp521r1Holder
+			: X9ECParametersHolder
+		{
+			private Secp521r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Secp521r1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				// p = 2^521 - 1
+				BigInteger p = FromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+				BigInteger a = FromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC");
+				BigInteger b = FromHex("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00");
+				byte[] S = Hex.Decode("D09E8800291CB85396CC6717393284AAA0DA64BA");
+				BigInteger n = FromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409");
+				BigInteger h = BigInteger.ValueOf(1);
+
+				ECCurve curve = new FpCurve(p, a, b);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("02"
+				//+ "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"
+					+ "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * sect113r1
+		 */
+		internal class Sect113r1Holder
+			: X9ECParametersHolder
+		{
+			private Sect113r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Sect113r1Holder();
+
+			private const int m = 113;
+			private const int k = 9;
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger a = FromHex("003088250CA6E7C7FE649CE85820F7");
+				BigInteger b = FromHex("00E8BEE4D3E2260744188BE0E9C723");
+				byte[] S = Hex.Decode("10E723AB14D696E6768756151756FEBF8FCB49A9");
+				BigInteger n = FromHex("0100000000000000D9CCEC8A39E56F");
+				BigInteger h = BigInteger.ValueOf(2);
+
+				ECCurve curve = new F2mCurve(m, k, a, b, n, h);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "009D73616F35F4AB1407D73562C10F"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "009D73616F35F4AB1407D73562C10F"
+					+ "00A52830277958EE84D1315ED31886"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * sect113r2
+		 */
+		internal class Sect113r2Holder
+			: X9ECParametersHolder
+		{
+			private Sect113r2Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Sect113r2Holder();
+
+			private const int m = 113;
+			private const int k = 9;
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger a = FromHex("00689918DBEC7E5A0DD6DFC0AA55C7");
+				BigInteger b = FromHex("0095E9A9EC9B297BD4BF36E059184F");
+				byte[] S = Hex.Decode("10C0FB15760860DEF1EEF4D696E676875615175D");
+				BigInteger n = FromHex("010000000000000108789B2496AF93");
+				BigInteger h = BigInteger.ValueOf(2);
+
+				ECCurve curve = new F2mCurve(m, k, a, b, n, h);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "01A57A6A7B26CA5EF52FCDB8164797"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "01A57A6A7B26CA5EF52FCDB8164797"
+					+ "00B3ADC94ED1FE674C06E695BABA1D"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * sect131r1
+		 */
+		internal class Sect131r1Holder
+			: X9ECParametersHolder
+		{
+			private Sect131r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Sect131r1Holder();
+
+			private const int m = 131;
+			private const int k1 = 2;
+			private const int k2 = 3;
+			private const int k3 = 8;
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger a = FromHex("07A11B09A76B562144418FF3FF8C2570B8");
+				BigInteger b = FromHex("0217C05610884B63B9C6C7291678F9D341");
+				byte[] S = Hex.Decode("4D696E676875615175985BD3ADBADA21B43A97E2");
+				BigInteger n = FromHex("0400000000000000023123953A9464B54D");
+				BigInteger h = BigInteger.ValueOf(2);
+
+				ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "0081BAF91FDF9833C40F9C181343638399"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "0081BAF91FDF9833C40F9C181343638399"
+					+ "078C6E7EA38C001F73C8134B1B4EF9E150"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * sect131r2
+		 */
+		internal class Sect131r2Holder
+			: X9ECParametersHolder
+		{
+			private Sect131r2Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Sect131r2Holder();
+
+			private const int m = 131;
+			private const int k1 = 2;
+			private const int k2 = 3;
+			private const int k3 = 8;
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger a = FromHex("03E5A88919D7CAFCBF415F07C2176573B2");
+				BigInteger b = FromHex("04B8266A46C55657AC734CE38F018F2192");
+				byte[] S = Hex.Decode("985BD3ADBAD4D696E676875615175A21B43A97E3");
+				BigInteger n = FromHex("0400000000000000016954A233049BA98F");
+				BigInteger h = BigInteger.ValueOf(2);
+
+				ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "0356DCD8F2F95031AD652D23951BB366A8"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "0356DCD8F2F95031AD652D23951BB366A8"
+					+ "0648F06D867940A5366D9E265DE9EB240F"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * sect163k1
+		 */
+		internal class Sect163k1Holder
+			: X9ECParametersHolder
+		{
+			private Sect163k1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Sect163k1Holder();
+
+			private const int m = 163;
+			private const int k1 = 3;
+			private const int k2 = 6;
+			private const int k3 = 7;
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger a = BigInteger.ValueOf(1);
+				BigInteger b = BigInteger.ValueOf(1);
+				byte[] S = null;
+				BigInteger n = FromHex("04000000000000000000020108A2E0CC0D99F8A5EF");
+				BigInteger h = BigInteger.ValueOf(2);
+
+				ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8"
+					+ "0289070FB05D38FF58321F2E800536D538CCDAA3D9"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * sect163r1
+		 */
+		internal class Sect163r1Holder
+			: X9ECParametersHolder
+		{
+			private Sect163r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Sect163r1Holder();
+
+			private const int m = 163;
+			private const int k1 = 3;
+			private const int k2 = 6;
+			private const int k3 = 7;
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger a = FromHex("07B6882CAAEFA84F9554FF8428BD88E246D2782AE2");
+				BigInteger b = FromHex("0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9");
+				byte[] S = Hex.Decode("24B7B137C8A14D696E6768756151756FD0DA2E5C");
+				BigInteger n = FromHex("03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B");
+				BigInteger h = BigInteger.ValueOf(2);
+
+				ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "0369979697AB43897789566789567F787A7876A654"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "0369979697AB43897789566789567F787A7876A654"
+					+ "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * sect163r2
+		 */
+		internal class Sect163r2Holder
+			: X9ECParametersHolder
+		{
+			private Sect163r2Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Sect163r2Holder();
+
+			private const int m = 163;
+			private const int k1 = 3;
+			private const int k2 = 6;
+			private const int k3 = 7;
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger a = BigInteger.ValueOf(1);
+				BigInteger b = FromHex("020A601907B8C953CA1481EB10512F78744A3205FD");
+				byte[] S = Hex.Decode("85E25BFE5C86226CDB12016F7553F9D0E693A268");
+				BigInteger n = FromHex("040000000000000000000292FE77E70C12A4234C33");
+				BigInteger h = BigInteger.ValueOf(2);
+
+				ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "03F0EBA16286A2D57EA0991168D4994637E8343E36"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "03F0EBA16286A2D57EA0991168D4994637E8343E36"
+					+ "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * sect193r1
+		 */
+		internal class Sect193r1Holder
+			: X9ECParametersHolder
+		{
+			private Sect193r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Sect193r1Holder();
+
+			private const int m = 193;
+			private const int k = 15;
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger a = FromHex("0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01");
+				BigInteger b = FromHex("00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814");
+				byte[] S = Hex.Decode("103FAEC74D696E676875615175777FC5B191EF30");
+				BigInteger n = FromHex("01000000000000000000000000C7F34A778F443ACC920EBA49");
+				BigInteger h = BigInteger.ValueOf(2);
+
+				ECCurve curve = new F2mCurve(m, k, a, b, n, h);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1"
+					+ "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * sect193r2
+		 */
+		internal class Sect193r2Holder
+			: X9ECParametersHolder
+		{
+			private Sect193r2Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Sect193r2Holder();
+
+			private const int m = 193;
+			private const int k = 15;
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger a = FromHex("0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B");
+				BigInteger b = FromHex("00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE");
+				byte[] S = Hex.Decode("10B7B4D696E676875615175137C8A16FD0DA2211");
+				BigInteger n = FromHex("010000000000000000000000015AAB561B005413CCD4EE99D5");
+				BigInteger h = BigInteger.ValueOf(2);
+
+				ECCurve curve = new F2mCurve(m, k, a, b, n, h);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F"
+					+ "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * sect233k1
+		 */
+		internal class Sect233k1Holder
+			: X9ECParametersHolder
+		{
+			private Sect233k1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Sect233k1Holder();
+
+			private const int m = 233;
+			private const int k = 74;
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger a = BigInteger.Zero;
+				BigInteger b = BigInteger.ValueOf(1);
+				byte[] S = null;
+				BigInteger n = FromHex("8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF");
+				BigInteger h = BigInteger.ValueOf(4);
+
+				ECCurve curve = new F2mCurve(m, k, a, b, n, h);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("02"
+				//+ "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126"
+					+ "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * sect233r1
+		 */
+		internal class Sect233r1Holder
+			: X9ECParametersHolder
+		{
+			private Sect233r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Sect233r1Holder();
+
+			private const int m = 233;
+			private const int k = 74;
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger a = BigInteger.ValueOf(1);
+				BigInteger b = FromHex("0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD");
+				byte[] S = Hex.Decode("74D59FF07F6B413D0EA14B344B20A2DB049B50C3");
+				BigInteger n = FromHex("01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7");
+				BigInteger h = BigInteger.ValueOf(2);
+
+				ECCurve curve = new F2mCurve(m, k, a, b, n, h);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"
+					+ "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * sect239k1
+		 */
+		internal class Sect239k1Holder
+			: X9ECParametersHolder
+		{
+			private Sect239k1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Sect239k1Holder();
+
+			private const int m = 239;
+			private const int k = 158;
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger a = BigInteger.Zero;
+				BigInteger b = BigInteger.ValueOf(1);
+				byte[] S = null;
+				BigInteger n = FromHex("2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5");
+				BigInteger h = BigInteger.ValueOf(4);
+
+				ECCurve curve = new F2mCurve(m, k, a, b, n, h);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC"
+					+ "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * sect283k1
+		 */
+		internal class Sect283k1Holder
+			: X9ECParametersHolder
+		{
+			private Sect283k1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Sect283k1Holder();
+
+			private const int m = 283;
+			private const int k1 = 5;
+			private const int k2 = 7;
+			private const int k3 = 12;
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger a = BigInteger.Zero;
+				BigInteger b = BigInteger.ValueOf(1);
+				byte[] S = null;
+				BigInteger n = FromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61");
+				BigInteger h = BigInteger.ValueOf(4);
+
+				ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("02"
+				//+ "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836"
+					+ "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * sect283r1
+		 */
+		internal class Sect283r1Holder
+			: X9ECParametersHolder
+		{
+			private Sect283r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Sect283r1Holder();
+
+			private const int m = 283;
+			private const int k1 = 5;
+			private const int k2 = 7;
+			private const int k3 = 12;
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger a = BigInteger.ValueOf(1);
+				BigInteger b = FromHex("027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5");
+				byte[] S = Hex.Decode("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE");
+				BigInteger n = FromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307");
+				BigInteger h = BigInteger.ValueOf(2);
+
+				ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053"
+					+ "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * sect409k1
+		 */
+		internal class Sect409k1Holder
+			: X9ECParametersHolder
+		{
+			private Sect409k1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Sect409k1Holder();
+
+			private const int m = 409;
+			private const int k = 87;
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger a = BigInteger.Zero;
+				BigInteger b = BigInteger.ValueOf(1);
+				byte[] S = null;
+				BigInteger n = FromHex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF");
+				BigInteger h = BigInteger.ValueOf(4);
+
+				ECCurve curve = new F2mCurve(m, k, a, b, n, h);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746"
+					+ "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * sect409r1
+		 */
+		internal class Sect409r1Holder
+			: X9ECParametersHolder
+		{
+			private Sect409r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Sect409r1Holder();
+
+			private const int m = 409;
+			private const int k = 87;
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger a = BigInteger.ValueOf(1);
+				BigInteger b = FromHex("0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F");
+				byte[] S = Hex.Decode("4099B5A457F9D69F79213D094C4BCD4D4262210B");
+				BigInteger n = FromHex("010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173");
+				BigInteger h = BigInteger.ValueOf(2);
+
+				ECCurve curve = new F2mCurve(m, k, a, b, n, h);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7"
+					+ "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * sect571k1
+		 */
+		internal class Sect571k1Holder
+			: X9ECParametersHolder
+		{
+			private Sect571k1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Sect571k1Holder();
+
+			private const int m = 571;
+			private const int k1 = 2;
+			private const int k2 = 5;
+			private const int k3 = 10;
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger a = BigInteger.Zero;
+				BigInteger b = BigInteger.ValueOf(1);
+				byte[] S = null;
+				BigInteger n = FromHex("020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001");
+				BigInteger h = BigInteger.ValueOf(4);
+
+				ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("02"
+				//+ "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972"
+					+ "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+		/*
+		 * sect571r1
+		 */
+		internal class Sect571r1Holder
+			: X9ECParametersHolder
+		{
+			private Sect571r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Sect571r1Holder();
+
+			private const int m = 571;
+			private const int k1 = 2;
+			private const int k2 = 5;
+			private const int k3 = 10;
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger a = BigInteger.ValueOf(1);
+				BigInteger b = FromHex("02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A");
+				byte[] S = Hex.Decode("2AA058F73A0E33AB486B0F610410C53A7F132310");
+				BigInteger n = FromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47");
+				BigInteger h = BigInteger.ValueOf(2);
+
+				ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
+				//ECPoint G = curve.DecodePoint(Hex.Decode("03"
+				//+ "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19"));
+				ECPoint G = curve.DecodePoint(Hex.Decode("04"
+					+ "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19"
+					+ "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B"));
+
+				return new X9ECParameters(curve, G, n, h, S);
+			}
+		}
+
+
+		private static readonly IDictionary objIds = Platform.CreateHashtable();
+        private static readonly IDictionary curves = Platform.CreateHashtable();
+        private static readonly IDictionary names = Platform.CreateHashtable();
+
+		private static void DefineCurve(
+			string					name,
+			DerObjectIdentifier		oid,
+			X9ECParametersHolder	holder)
+		{
+			objIds.Add(name, oid);
+			names.Add(oid, name);
+			curves.Add(oid, holder);
+		}
+
+		static SecNamedCurves()
+		{
+			DefineCurve("secp112r1", SecObjectIdentifiers.SecP112r1, Secp112r1Holder.Instance);
+			DefineCurve("secp112r2", SecObjectIdentifiers.SecP112r2, Secp112r2Holder.Instance);
+			DefineCurve("secp128r1", SecObjectIdentifiers.SecP128r1, Secp128r1Holder.Instance);
+			DefineCurve("secp128r2", SecObjectIdentifiers.SecP128r2, Secp128r2Holder.Instance);
+			DefineCurve("secp160k1", SecObjectIdentifiers.SecP160k1, Secp160k1Holder.Instance);
+			DefineCurve("secp160r1", SecObjectIdentifiers.SecP160r1, Secp160r1Holder.Instance);
+			DefineCurve("secp160r2", SecObjectIdentifiers.SecP160r2, Secp160r2Holder.Instance);
+			DefineCurve("secp192k1", SecObjectIdentifiers.SecP192k1, Secp192k1Holder.Instance);
+			DefineCurve("secp192r1", SecObjectIdentifiers.SecP192r1, Secp192r1Holder.Instance);
+			DefineCurve("secp224k1", SecObjectIdentifiers.SecP224k1, Secp224k1Holder.Instance);
+			DefineCurve("secp224r1", SecObjectIdentifiers.SecP224r1, Secp224r1Holder.Instance);
+			DefineCurve("secp256k1", SecObjectIdentifiers.SecP256k1, Secp256k1Holder.Instance);
+			DefineCurve("secp256r1", SecObjectIdentifiers.SecP256r1, Secp256r1Holder.Instance);
+			DefineCurve("secp384r1", SecObjectIdentifiers.SecP384r1, Secp384r1Holder.Instance);
+			DefineCurve("secp521r1", SecObjectIdentifiers.SecP521r1, Secp521r1Holder.Instance);
+
+			DefineCurve("sect113r1", SecObjectIdentifiers.SecT113r1, Sect113r1Holder.Instance);
+			DefineCurve("sect113r2", SecObjectIdentifiers.SecT113r2, Sect113r2Holder.Instance);
+			DefineCurve("sect131r1", SecObjectIdentifiers.SecT131r1, Sect131r1Holder.Instance);
+			DefineCurve("sect131r2", SecObjectIdentifiers.SecT131r2, Sect131r2Holder.Instance);
+			DefineCurve("sect163k1", SecObjectIdentifiers.SecT163k1, Sect163k1Holder.Instance);
+			DefineCurve("sect163r1", SecObjectIdentifiers.SecT163r1, Sect163r1Holder.Instance);
+			DefineCurve("sect163r2", SecObjectIdentifiers.SecT163r2, Sect163r2Holder.Instance);
+			DefineCurve("sect193r1", SecObjectIdentifiers.SecT193r1, Sect193r1Holder.Instance);
+			DefineCurve("sect193r2", SecObjectIdentifiers.SecT193r2, Sect193r2Holder.Instance);
+			DefineCurve("sect233k1", SecObjectIdentifiers.SecT233k1, Sect233k1Holder.Instance);
+			DefineCurve("sect233r1", SecObjectIdentifiers.SecT233r1, Sect233r1Holder.Instance);
+			DefineCurve("sect239k1", SecObjectIdentifiers.SecT239k1, Sect239k1Holder.Instance);
+			DefineCurve("sect283k1", SecObjectIdentifiers.SecT283k1, Sect283k1Holder.Instance);
+			DefineCurve("sect283r1", SecObjectIdentifiers.SecT283r1, Sect283r1Holder.Instance);
+			DefineCurve("sect409k1", SecObjectIdentifiers.SecT409k1, Sect409k1Holder.Instance);
+			DefineCurve("sect409r1", SecObjectIdentifiers.SecT409r1, Sect409r1Holder.Instance);
+			DefineCurve("sect571k1", SecObjectIdentifiers.SecT571k1, Sect571k1Holder.Instance);
+			DefineCurve("sect571r1", SecObjectIdentifiers.SecT571r1, Sect571r1Holder.Instance);
+		}
+
+		public static X9ECParameters GetByName(
+			string name)
+		{
+			DerObjectIdentifier oid = (DerObjectIdentifier)
+				objIds[name.ToLowerInvariant()];
+
+			return oid == null ? null : GetByOid(oid);
+		}
+
+		/**
+		 * return the X9ECParameters object for the named curve represented by
+		 * the passed in object identifier. Null if the curve isn't present.
+		 *
+		 * @param oid an object identifier representing a named curve, if present.
+		 */
+		public static X9ECParameters GetByOid(
+			DerObjectIdentifier oid)
+		{
+			X9ECParametersHolder holder = (X9ECParametersHolder) curves[oid];
+
+			return holder == null ? null : holder.Parameters;
+		}
+
+		/**
+		 * return the object identifier signified by the passed in name. Null
+		 * if there is no object identifier associated with name.
+		 *
+		 * @return the object identifier associated with name, if present.
+		 */
+		public static DerObjectIdentifier GetOid(
+			string name)
+		{
+			return (DerObjectIdentifier) objIds[name.ToLowerInvariant()];
+		}
+
+		/**
+		 * return the named curve name represented by the given object identifier.
+		 */
+		public static string GetName(
+			DerObjectIdentifier oid)
+		{
+			return (string) names[oid];
+		}
+
+		/**
+		 * returns an enumeration containing the name strings for curves
+		 * contained in this structure.
+		 */
+		public static IEnumerable Names
+		{
+			get { return new EnumerableProxy(objIds.Keys); }
+		}
+	}
+}
diff --git a/Crypto/src/asn1/sec/SECObjectIdentifiers.cs b/Crypto/src/asn1/sec/SECObjectIdentifiers.cs
new file mode 100644
index 000000000..afc10e1d6
--- /dev/null
+++ b/Crypto/src/asn1/sec/SECObjectIdentifiers.cs
@@ -0,0 +1,52 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X9;
+
+namespace Org.BouncyCastle.Asn1.Sec
+{
+	public abstract class SecObjectIdentifiers
+	{
+		/**
+		 *  EllipticCurve OBJECT IDENTIFIER ::= {
+		 *        iso(1) identified-organization(3) certicom(132) curve(0)
+		 *  }
+		 */
+		public static readonly DerObjectIdentifier EllipticCurve = new DerObjectIdentifier("1.3.132.0");
+
+		public static readonly DerObjectIdentifier SecT163k1 = new DerObjectIdentifier(EllipticCurve + ".1");
+		public static readonly DerObjectIdentifier SecT163r1 = new DerObjectIdentifier(EllipticCurve + ".2");
+		public static readonly DerObjectIdentifier SecT239k1 = new DerObjectIdentifier(EllipticCurve + ".3");
+		public static readonly DerObjectIdentifier SecT113r1 = new DerObjectIdentifier(EllipticCurve + ".4");
+		public static readonly DerObjectIdentifier SecT113r2 = new DerObjectIdentifier(EllipticCurve + ".5");
+		public static readonly DerObjectIdentifier SecP112r1 = new DerObjectIdentifier(EllipticCurve + ".6");
+		public static readonly DerObjectIdentifier SecP112r2 = new DerObjectIdentifier(EllipticCurve + ".7");
+		public static readonly DerObjectIdentifier SecP160r1 = new DerObjectIdentifier(EllipticCurve + ".8");
+		public static readonly DerObjectIdentifier SecP160k1 = new DerObjectIdentifier(EllipticCurve + ".9");
+		public static readonly DerObjectIdentifier SecP256k1 = new DerObjectIdentifier(EllipticCurve + ".10");
+		public static readonly DerObjectIdentifier SecT163r2 = new DerObjectIdentifier(EllipticCurve + ".15");
+		public static readonly DerObjectIdentifier SecT283k1 = new DerObjectIdentifier(EllipticCurve + ".16");
+		public static readonly DerObjectIdentifier SecT283r1 = new DerObjectIdentifier(EllipticCurve + ".17");
+		public static readonly DerObjectIdentifier SecT131r1 = new DerObjectIdentifier(EllipticCurve + ".22");
+		public static readonly DerObjectIdentifier SecT131r2 = new DerObjectIdentifier(EllipticCurve + ".23");
+		public static readonly DerObjectIdentifier SecT193r1 = new DerObjectIdentifier(EllipticCurve + ".24");
+		public static readonly DerObjectIdentifier SecT193r2 = new DerObjectIdentifier(EllipticCurve + ".25");
+		public static readonly DerObjectIdentifier SecT233k1 = new DerObjectIdentifier(EllipticCurve + ".26");
+		public static readonly DerObjectIdentifier SecT233r1 = new DerObjectIdentifier(EllipticCurve + ".27");
+		public static readonly DerObjectIdentifier SecP128r1 = new DerObjectIdentifier(EllipticCurve + ".28");
+		public static readonly DerObjectIdentifier SecP128r2 = new DerObjectIdentifier(EllipticCurve + ".29");
+		public static readonly DerObjectIdentifier SecP160r2 = new DerObjectIdentifier(EllipticCurve + ".30");
+		public static readonly DerObjectIdentifier SecP192k1 = new DerObjectIdentifier(EllipticCurve + ".31");
+		public static readonly DerObjectIdentifier SecP224k1 = new DerObjectIdentifier(EllipticCurve + ".32");
+		public static readonly DerObjectIdentifier SecP224r1 = new DerObjectIdentifier(EllipticCurve + ".33");
+		public static readonly DerObjectIdentifier SecP384r1 = new DerObjectIdentifier(EllipticCurve + ".34");
+		public static readonly DerObjectIdentifier SecP521r1 = new DerObjectIdentifier(EllipticCurve + ".35");
+		public static readonly DerObjectIdentifier SecT409k1 = new DerObjectIdentifier(EllipticCurve + ".36");
+		public static readonly DerObjectIdentifier SecT409r1 = new DerObjectIdentifier(EllipticCurve + ".37");
+		public static readonly DerObjectIdentifier SecT571k1 = new DerObjectIdentifier(EllipticCurve + ".38");
+		public static readonly DerObjectIdentifier SecT571r1 = new DerObjectIdentifier(EllipticCurve + ".39");
+
+		public static readonly DerObjectIdentifier SecP192r1 = X9ObjectIdentifiers.Prime192v1;
+		public static readonly DerObjectIdentifier SecP256r1 = X9ObjectIdentifiers.Prime256v1;
+	}
+}
\ No newline at end of file
diff --git a/Crypto/src/asn1/smime/SMIMEAttributes.cs b/Crypto/src/asn1/smime/SMIMEAttributes.cs
new file mode 100644
index 000000000..e154e5e74
--- /dev/null
+++ b/Crypto/src/asn1/smime/SMIMEAttributes.cs
@@ -0,0 +1,11 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Smime
+{
+    public abstract class SmimeAttributes
+    {
+        public static readonly DerObjectIdentifier SmimeCapabilities = PkcsObjectIdentifiers.Pkcs9AtSmimeCapabilities;
+        public static readonly DerObjectIdentifier EncrypKeyPref = PkcsObjectIdentifiers.IdAAEncrypKeyPref;
+    }
+}
diff --git a/Crypto/src/asn1/smime/SMIMECapabilities.cs b/Crypto/src/asn1/smime/SMIMECapabilities.cs
new file mode 100644
index 000000000..adf254e56
--- /dev/null
+++ b/Crypto/src/asn1/smime/SMIMECapabilities.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Smime
+{
+    /**
+     * Handler class for dealing with S/MIME Capabilities
+     */
+    public class SmimeCapabilities
+        : Asn1Encodable
+    {
+        /**
+         * general preferences
+         */
+        public static readonly DerObjectIdentifier PreferSignedData = PkcsObjectIdentifiers.PreferSignedData;
+        public static readonly DerObjectIdentifier CannotDecryptAny = PkcsObjectIdentifiers.CannotDecryptAny;
+        public static readonly DerObjectIdentifier SmimeCapabilitesVersions = PkcsObjectIdentifiers.SmimeCapabilitiesVersions;
+
+		/**
+         * encryption algorithms preferences
+         */
+        public static readonly DerObjectIdentifier DesCbc = new DerObjectIdentifier("1.3.14.3.2.7");
+        public static readonly DerObjectIdentifier DesEde3Cbc = PkcsObjectIdentifiers.DesEde3Cbc;
+        public static readonly DerObjectIdentifier RC2Cbc = PkcsObjectIdentifiers.RC2Cbc;
+
+		private Asn1Sequence capabilities;
+
+		/**
+         * return an Attr object from the given object.
+         *
+         * @param o the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static SmimeCapabilities GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is SmimeCapabilities)
+            {
+                return (SmimeCapabilities) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new SmimeCapabilities((Asn1Sequence) obj);
+            }
+
+			if (obj is AttributeX509)
+            {
+                return new SmimeCapabilities(
+                    (Asn1Sequence)(((AttributeX509) obj).AttrValues[0]));
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        }
+
+		public SmimeCapabilities(
+            Asn1Sequence seq)
+        {
+            capabilities = seq;
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete("Use 'GetCapabilitiesForOid' instead")]
+        public ArrayList GetCapabilities(
+            DerObjectIdentifier capability)
+        {
+            ArrayList list = new ArrayList();
+            DoGetCapabilitiesForOid(capability, list);
+			return list;
+        }
+#endif
+
+        /**
+         * returns an ArrayList with 0 or more objects of all the capabilities
+         * matching the passed in capability Oid. If the Oid passed is null the
+         * entire set is returned.
+         */
+        public IList GetCapabilitiesForOid(
+            DerObjectIdentifier capability)
+        {
+            IList list = Platform.CreateArrayList();
+            DoGetCapabilitiesForOid(capability, list);
+			return list;
+        }
+
+        private void DoGetCapabilitiesForOid(DerObjectIdentifier capability, IList list)
+        {
+			if (capability == null)
+            {
+				foreach (object o in capabilities)
+				{
+                    SmimeCapability cap = SmimeCapability.GetInstance(o);
+
+					list.Add(cap);
+                }
+            }
+            else
+            {
+				foreach (object o in capabilities)
+				{
+                    SmimeCapability cap = SmimeCapability.GetInstance(o);
+
+					if (capability.Equals(cap.CapabilityID))
+                    {
+                        list.Add(cap);
+                    }
+                }
+            }
+        }
+
+        /**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * SMIMECapabilities ::= Sequence OF SMIMECapability
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return capabilities;
+        }
+    }
+}
diff --git a/Crypto/src/asn1/smime/SMIMECapabilitiesAttribute.cs b/Crypto/src/asn1/smime/SMIMECapabilitiesAttribute.cs
new file mode 100644
index 000000000..310c478fe
--- /dev/null
+++ b/Crypto/src/asn1/smime/SMIMECapabilitiesAttribute.cs
@@ -0,0 +1,16 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Smime
+{
+    public class SmimeCapabilitiesAttribute
+        : AttributeX509
+    {
+        public SmimeCapabilitiesAttribute(
+            SmimeCapabilityVector capabilities)
+            : base(SmimeAttributes.SmimeCapabilities,
+                    new DerSet(new DerSequence(capabilities.ToAsn1EncodableVector())))
+        {
+        }
+    }
+}
diff --git a/Crypto/src/asn1/smime/SMIMECapability.cs b/Crypto/src/asn1/smime/SMIMECapability.cs
new file mode 100644
index 000000000..5709cb815
--- /dev/null
+++ b/Crypto/src/asn1/smime/SMIMECapability.cs
@@ -0,0 +1,101 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Smime
+{
+    public class SmimeCapability
+        : Asn1Encodable
+    {
+        /**
+         * general preferences
+         */
+        public static readonly DerObjectIdentifier PreferSignedData = PkcsObjectIdentifiers.PreferSignedData;
+        public static readonly DerObjectIdentifier CannotDecryptAny = PkcsObjectIdentifiers.CannotDecryptAny;
+        public static readonly DerObjectIdentifier SmimeCapabilitiesVersions = PkcsObjectIdentifiers.SmimeCapabilitiesVersions;
+
+		/**
+         * encryption algorithms preferences
+         */
+        public static readonly DerObjectIdentifier DesCbc = new DerObjectIdentifier("1.3.14.3.2.7");
+        public static readonly DerObjectIdentifier DesEde3Cbc = PkcsObjectIdentifiers.DesEde3Cbc;
+        public static readonly DerObjectIdentifier RC2Cbc = PkcsObjectIdentifiers.RC2Cbc;
+
+		private DerObjectIdentifier capabilityID;
+        private Asn1Object			parameters;
+
+		public SmimeCapability(
+            Asn1Sequence seq)
+        {
+            capabilityID = (DerObjectIdentifier) seq[0].ToAsn1Object();
+
+			if (seq.Count > 1)
+            {
+                parameters = seq[1].ToAsn1Object();
+            }
+        }
+
+		public SmimeCapability(
+            DerObjectIdentifier	capabilityID,
+            Asn1Encodable		parameters)
+        {
+			if (capabilityID == null)
+				throw new ArgumentNullException("capabilityID");
+
+			this.capabilityID = capabilityID;
+
+			if (parameters != null)
+			{
+				this.parameters = parameters.ToAsn1Object();
+			}
+        }
+
+		public static SmimeCapability GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is SmimeCapability)
+            {
+                return (SmimeCapability) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new SmimeCapability((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Invalid SmimeCapability");
+        }
+
+		public DerObjectIdentifier CapabilityID
+		{
+			get { return capabilityID; }
+		}
+
+		public Asn1Object Parameters
+		{
+			get { return parameters; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * SMIMECapability ::= Sequence {
+         *     capabilityID OBJECT IDENTIFIER,
+         *     parameters ANY DEFINED BY capabilityID OPTIONAL
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(capabilityID);
+
+			if (parameters != null)
+            {
+                v.Add(parameters);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/smime/SMIMECapabilityVector.cs b/Crypto/src/asn1/smime/SMIMECapabilityVector.cs
new file mode 100644
index 000000000..842825b88
--- /dev/null
+++ b/Crypto/src/asn1/smime/SMIMECapabilityVector.cs
@@ -0,0 +1,37 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Smime
+{
+    /**
+     * Handler for creating a vector S/MIME Capabilities
+     */
+    public class SmimeCapabilityVector
+    {
+        private readonly Asn1EncodableVector capabilities = new Asn1EncodableVector();
+
+		public void AddCapability(
+            DerObjectIdentifier capability)
+        {
+            capabilities.Add(new DerSequence(capability));
+        }
+
+		public void AddCapability(
+            DerObjectIdentifier capability,
+            int                 value)
+        {
+			capabilities.Add(new DerSequence(capability, new DerInteger(value)));
+        }
+
+		public void AddCapability(
+            DerObjectIdentifier capability,
+            Asn1Encodable		parameters)
+        {
+			capabilities.Add(new DerSequence(capability, parameters));
+        }
+
+		public Asn1EncodableVector ToAsn1EncodableVector()
+        {
+            return capabilities;
+        }
+    }
+}
diff --git a/Crypto/src/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.cs b/Crypto/src/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.cs
new file mode 100644
index 000000000..19c5fd78a
--- /dev/null
+++ b/Crypto/src/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.cs
@@ -0,0 +1,44 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Smime
+{
+    /**
+     * The SmimeEncryptionKeyPreference object.
+     * <pre>
+     * SmimeEncryptionKeyPreference ::= CHOICE {
+     *     issuerAndSerialNumber   [0] IssuerAndSerialNumber,
+     *     receipentKeyId          [1] RecipientKeyIdentifier,
+     *     subjectAltKeyIdentifier [2] SubjectKeyIdentifier
+     * }
+     * </pre>
+     */
+    public class SmimeEncryptionKeyPreferenceAttribute
+        : AttributeX509
+    {
+        public SmimeEncryptionKeyPreferenceAttribute(
+            IssuerAndSerialNumber issAndSer)
+            : base(SmimeAttributes.EncrypKeyPref,
+                new DerSet(new DerTaggedObject(false, 0, issAndSer)))
+        {
+        }
+
+        public SmimeEncryptionKeyPreferenceAttribute(
+            RecipientKeyIdentifier rKeyID)
+            : base(SmimeAttributes.EncrypKeyPref,
+                new DerSet(new DerTaggedObject(false, 1, rKeyID)))
+        {
+        }
+
+        /**
+         * @param sKeyId the subjectKeyIdentifier value (normally the X.509 one)
+         */
+        public SmimeEncryptionKeyPreferenceAttribute(
+            Asn1OctetString sKeyID)
+            : base(SmimeAttributes.EncrypKeyPref,
+                new DerSet(new DerTaggedObject(false, 2, sKeyID)))
+        {
+        }
+    }
+}
diff --git a/Crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs b/Crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
new file mode 100644
index 000000000..0cfdb8483
--- /dev/null
+++ b/Crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
@@ -0,0 +1,428 @@
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.TeleTrust
+{
+	/**
+	* elliptic curves defined in "ECC Brainpool Standard Curves and Curve Generation"
+	* http://www.ecc-brainpool.org/download/draft_pkix_additional_ecc_dp.txt
+	*/
+	public class TeleTrusTNamedCurves
+	{
+		internal class BrainpoolP160r1Holder
+			: X9ECParametersHolder
+		{
+			private BrainpoolP160r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new BrainpoolP160r1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve curve = new FpCurve(
+					new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620F", 16), // q
+					new BigInteger("340E7BE2A280EB74E2BE61BADA745D97E8F7C300", 16), // a
+					new BigInteger("1E589A8595423412134FAA2DBDEC95C8D8675E58", 16)); // b
+
+				return new X9ECParameters(
+					curve,
+					curve.DecodePoint(Hex.Decode("04BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC31667CB477A1A8EC338F94741669C976316DA6321")), // G
+					new BigInteger("E95E4A5F737059DC60DF5991D45029409E60FC09", 16), //n
+					new BigInteger("01", 16)); // h
+			}
+		}
+
+		internal class BrainpoolP160t1Holder
+			: X9ECParametersHolder
+		{
+			private BrainpoolP160t1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new BrainpoolP160t1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve curve = new FpCurve(
+					//   new BigInteger("24DBFF5DEC9B986BBFE5295A29BFBAE45E0F5D0B", 16), // Z
+					new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620F", 16), // q
+					new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620C", 16), // a'
+					new BigInteger("7A556B6DAE535B7B51ED2C4D7DAA7A0B5C55F380", 16)); // b'
+
+				return new X9ECParameters(
+					curve,
+					curve.DecodePoint(Hex.Decode("04B199B13B9B34EFC1397E64BAEB05ACC265FF2378ADD6718B7C7C1961F0991B842443772152C9E0AD")), // G
+					new BigInteger("E95E4A5F737059DC60DF5991D45029409E60FC09", 16), //n
+					new BigInteger("01", 16)); // h
+			}
+		}
+
+		internal class BrainpoolP192r1Holder
+			: X9ECParametersHolder
+		{
+			private BrainpoolP192r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new BrainpoolP192r1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve curve = new FpCurve(
+					new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", 16), // q
+					new BigInteger("6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF", 16), // a
+					new BigInteger("469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9", 16)); // b
+
+				return new X9ECParameters(
+					curve,
+					curve.DecodePoint(Hex.Decode("04C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD614B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F")), // G
+					new BigInteger("C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", 16), //n
+					new BigInteger("01", 16)); // h
+			}
+		}
+
+		internal class BrainpoolP192t1Holder
+			: X9ECParametersHolder
+		{
+			private BrainpoolP192t1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new BrainpoolP192t1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve curve = new FpCurve(
+					//new BigInteger("1B6F5CC8DB4DC7AF19458A9CB80DC2295E5EB9C3732104CB") //Z
+					new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", 16), // q
+					new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86294", 16), // a'
+					new BigInteger("13D56FFAEC78681E68F9DEB43B35BEC2FB68542E27897B79", 16)); // b'
+
+				return new X9ECParameters(
+					curve,
+					curve.DecodePoint(Hex.Decode("043AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9")), // G'
+					new BigInteger("C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", 16), //n
+					new BigInteger("01", 16)); // h
+			}
+		}
+
+		internal class BrainpoolP224r1Holder
+			: X9ECParametersHolder
+		{
+			private BrainpoolP224r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new BrainpoolP224r1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve curve = new FpCurve(
+					new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", 16), // q
+					new BigInteger("68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43", 16), // a
+					new BigInteger("2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B", 16)); // b
+
+				return new X9ECParameters(
+					curve,
+					curve.DecodePoint(Hex.Decode("040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD")), // G
+					new BigInteger("D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", 16), //n
+					new BigInteger("01", 16)); // n
+			}
+		}
+
+		internal class BrainpoolP224t1Holder
+			: X9ECParametersHolder
+		{
+			private BrainpoolP224t1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new BrainpoolP224t1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve curve = new FpCurve(
+					//new BigInteger("2DF271E14427A346910CF7A2E6CFA7B3F484E5C2CCE1C8B730E28B3F") //Z
+					new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", 16), // q
+					new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FC", 16), // a'
+					new BigInteger("4B337D934104CD7BEF271BF60CED1ED20DA14C08B3BB64F18A60888D", 16)); // b'
+
+				return new X9ECParameters(
+					curve,
+					curve.DecodePoint(Hex.Decode("046AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D5800374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C")), // G'
+					new BigInteger("D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", 16), //n
+					new BigInteger("01", 16)); // h
+			}
+		}
+
+		internal class BrainpoolP256r1Holder
+			: X9ECParametersHolder
+		{
+			private BrainpoolP256r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new BrainpoolP256r1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve curve = new FpCurve(
+					new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16), // q
+					new BigInteger("7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", 16), // a
+					new BigInteger("26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", 16)); // b
+
+				return new X9ECParameters(
+					curve,
+					curve.DecodePoint(Hex.Decode("048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997")), // G
+					new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16), //n
+					new BigInteger("01", 16)); // h
+			}
+		}
+
+		internal class BrainpoolP256t1Holder
+			: X9ECParametersHolder
+		{
+			private BrainpoolP256t1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new BrainpoolP256t1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve curve = new FpCurve(
+					//new BigInteger("3E2D4BD9597B58639AE7AA669CAB9837CF5CF20A2C852D10F655668DFC150EF0") //Z
+					new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16), // q
+					new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5374", 16), // a'
+					new BigInteger("662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04", 16)); // b'
+
+				return new X9ECParameters(
+					curve,
+					curve.DecodePoint(Hex.Decode("04A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F42D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE")), // G'
+					new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16), //n
+					new BigInteger("01", 16)); // h
+			}
+		}
+
+		internal class BrainpoolP320r1Holder
+			: X9ECParametersHolder
+		{
+			private BrainpoolP320r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new BrainpoolP320r1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve curve = new FpCurve(
+					new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", 16), // q
+					new BigInteger("3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4", 16), // a
+					new BigInteger("520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6", 16)); // b
+
+				return new X9ECParameters(
+					curve,
+					curve.DecodePoint(Hex.Decode("0443BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E2061114FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1")), // G
+					new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", 16), //n
+					new BigInteger("01", 16)); // h
+			}
+		}
+
+		internal class BrainpoolP320t1Holder
+			: X9ECParametersHolder
+		{
+			private BrainpoolP320t1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new BrainpoolP320t1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve curve = new FpCurve(
+					//new BigInteger("15F75CAF668077F7E85B42EB01F0A81FF56ECD6191D55CB82B7D861458A18FEFC3E5AB7496F3C7B1") //Z
+					new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", 16), // q
+					new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E24", 16), // a'
+					new BigInteger("A7F561E038EB1ED560B3D147DB782013064C19F27ED27C6780AAF77FB8A547CEB5B4FEF422340353", 16)); // b'
+
+				return new X9ECParameters(
+					curve,
+					curve.DecodePoint(Hex.Decode("04925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF3357F624A21BED5263BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B1B9BC0455FB0D2C3")), // G'
+					new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", 16), //n
+					new BigInteger("01", 16)); // h
+			}
+		}
+
+		internal class BrainpoolP384r1Holder
+			: X9ECParametersHolder
+		{
+			private BrainpoolP384r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new BrainpoolP384r1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve curve = new FpCurve(
+					new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16), // q
+					new BigInteger("7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826", 16), // a
+					new BigInteger("4A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11", 16)); // b
+
+				return new X9ECParameters(
+					curve,
+					curve.DecodePoint(Hex.Decode("041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315")), // G
+					new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16), //n
+					new BigInteger("01", 16)); // h
+			}
+		}
+
+		internal class BrainpoolP384t1Holder
+			: X9ECParametersHolder
+		{
+			private BrainpoolP384t1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new BrainpoolP384t1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve curve = new FpCurve(
+					//new BigInteger("41DFE8DD399331F7166A66076734A89CD0D2BCDB7D068E44E1F378F41ECBAE97D2D63DBC87BCCDDCCC5DA39E8589291C") //Z
+					new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16), // q
+					new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC50", 16), // a'
+					new BigInteger("7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B88805CED70355A33B471EE", 16)); // b'
+
+				return new X9ECParameters(
+					curve,
+					curve.DecodePoint(Hex.Decode("0418DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928")), // G'
+					new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16), //n
+					new BigInteger("01", 16)); // h
+			}
+		}
+
+		internal class BrainpoolP512r1Holder
+			: X9ECParametersHolder
+		{
+			private BrainpoolP512r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new BrainpoolP512r1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve curve = new FpCurve(
+					new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16), // q
+					new BigInteger("7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA", 16), // a
+					new BigInteger("3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723", 16)); // b
+
+				return new X9ECParameters(
+					curve,
+					curve.DecodePoint(Hex.Decode("0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892")), // G
+					new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16), //n
+					new BigInteger("01", 16)); // h
+			}
+		}
+
+		internal class BrainpoolP512t1Holder
+			: X9ECParametersHolder
+		{
+			private BrainpoolP512t1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new BrainpoolP512t1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve curve = new FpCurve(
+					//new BigInteger("12EE58E6764838B69782136F0F2D3BA06E27695716054092E60A80BEDB212B64E585D90BCE13761F85C3F1D2A64E3BE8FEA2220F01EBA5EEB0F35DBD29D922AB") //Z
+					new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16), // q
+					new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F0", 16), // a'
+					new BigInteger("7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA2304976540F6450085F2DAE145C22553B465763689180EA2571867423E", 16)); // b'
+
+				return new X9ECParameters(
+					curve,
+					curve.DecodePoint(Hex.Decode("04640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332")), // G'
+					new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16), //n
+					new BigInteger("01", 16)); // h
+			}
+		}
+
+
+		private static readonly IDictionary objIds = Platform.CreateHashtable();
+        private static readonly IDictionary curves = Platform.CreateHashtable();
+        private static readonly IDictionary names = Platform.CreateHashtable();
+
+		private static void DefineCurve(
+			string					name,
+			DerObjectIdentifier		oid,
+			X9ECParametersHolder	holder)
+		{
+			objIds.Add(name, oid);
+			names.Add(oid, name);
+			curves.Add(oid, holder);
+		}
+
+		static TeleTrusTNamedCurves()
+		{
+			DefineCurve("brainpoolp160r1", TeleTrusTObjectIdentifiers.BrainpoolP160R1, BrainpoolP160r1Holder.Instance);
+			DefineCurve("brainpoolp160t1", TeleTrusTObjectIdentifiers.BrainpoolP160T1, BrainpoolP160t1Holder.Instance);
+			DefineCurve("brainpoolp192r1", TeleTrusTObjectIdentifiers.BrainpoolP192R1, BrainpoolP192r1Holder.Instance);
+			DefineCurve("brainpoolp192t1", TeleTrusTObjectIdentifiers.BrainpoolP192T1, BrainpoolP192t1Holder.Instance);
+			DefineCurve("brainpoolp224r1", TeleTrusTObjectIdentifiers.BrainpoolP224R1, BrainpoolP224r1Holder.Instance);
+			DefineCurve("brainpoolp224t1", TeleTrusTObjectIdentifiers.BrainpoolP224T1, BrainpoolP224t1Holder.Instance);
+			DefineCurve("brainpoolp256r1", TeleTrusTObjectIdentifiers.BrainpoolP256R1, BrainpoolP256r1Holder.Instance);
+			DefineCurve("brainpoolp256t1", TeleTrusTObjectIdentifiers.BrainpoolP256T1, BrainpoolP256t1Holder.Instance);
+			DefineCurve("brainpoolp320r1", TeleTrusTObjectIdentifiers.BrainpoolP320R1, BrainpoolP320r1Holder.Instance);
+			DefineCurve("brainpoolp320t1", TeleTrusTObjectIdentifiers.BrainpoolP320T1, BrainpoolP320t1Holder.Instance);
+			DefineCurve("brainpoolp384r1", TeleTrusTObjectIdentifiers.BrainpoolP384R1, BrainpoolP384r1Holder.Instance);
+			DefineCurve("brainpoolp384t1", TeleTrusTObjectIdentifiers.BrainpoolP384T1, BrainpoolP384t1Holder.Instance);
+			DefineCurve("brainpoolp512r1", TeleTrusTObjectIdentifiers.BrainpoolP512R1, BrainpoolP512r1Holder.Instance);
+			DefineCurve("brainpoolp512t1", TeleTrusTObjectIdentifiers.BrainpoolP512T1, BrainpoolP512t1Holder.Instance);
+		}
+
+		public static X9ECParameters GetByName(
+			string name)
+		{
+			DerObjectIdentifier oid = (DerObjectIdentifier)
+				objIds[name.ToLowerInvariant()];
+
+			return oid == null ? null : GetByOid(oid);
+		}
+
+		/**
+		* return the X9ECParameters object for the named curve represented by
+		* the passed in object identifier. Null if the curve isn't present.
+		*
+		* @param oid an object identifier representing a named curve, if present.
+		*/
+		public static X9ECParameters GetByOid(
+			DerObjectIdentifier oid)
+		{
+			X9ECParametersHolder holder = (X9ECParametersHolder) curves[oid];
+
+			return holder == null ? null : holder.Parameters;
+		}
+
+		/**
+		* return the object identifier signified by the passed in name. Null
+		* if there is no object identifier associated with name.
+		*
+		* @return the object identifier associated with name, if present.
+		*/
+		public static DerObjectIdentifier GetOid(
+			string name)
+		{
+			return (DerObjectIdentifier) objIds[name.ToLowerInvariant()];
+		}
+
+		/**
+		* return the named curve name represented by the given object identifier.
+		*/
+		public static string GetName(
+			DerObjectIdentifier oid)
+		{
+			return (string) names[oid];
+		}
+
+
+		/**
+		 * returns an enumeration containing the name strings for curves
+		 * contained in this structure.
+		 */
+		public static IEnumerable Names
+		{
+			get { return new EnumerableProxy(objIds.Keys); }
+		}
+
+		public static DerObjectIdentifier GetOid(
+			short	curvesize,
+			bool	twisted)
+		{
+			return GetOid("brainpoolP" + curvesize + (twisted ? "t" : "r") + "1");
+		}
+	}
+}
diff --git a/Crypto/src/asn1/teletrust/TeleTrusTObjectIdentifiers.cs b/Crypto/src/asn1/teletrust/TeleTrusTObjectIdentifiers.cs
new file mode 100644
index 000000000..56e70842a
--- /dev/null
+++ b/Crypto/src/asn1/teletrust/TeleTrusTObjectIdentifiers.cs
@@ -0,0 +1,45 @@
+namespace Org.BouncyCastle.Asn1.TeleTrust
+{
+	public sealed class TeleTrusTObjectIdentifiers
+	{
+		private TeleTrusTObjectIdentifiers()
+		{
+		}
+
+		public static readonly DerObjectIdentifier TeleTrusTAlgorithm = new DerObjectIdentifier("1.3.36.3");
+
+		public static readonly DerObjectIdentifier RipeMD160 = new DerObjectIdentifier(TeleTrusTAlgorithm + ".2.1");
+		public static readonly DerObjectIdentifier RipeMD128 = new DerObjectIdentifier(TeleTrusTAlgorithm + ".2.2");
+		public static readonly DerObjectIdentifier RipeMD256 = new DerObjectIdentifier(TeleTrusTAlgorithm + ".2.3");
+
+		public static readonly DerObjectIdentifier TeleTrusTRsaSignatureAlgorithm = new DerObjectIdentifier(TeleTrusTAlgorithm + ".3.1");
+
+		public static readonly DerObjectIdentifier RsaSignatureWithRipeMD160 = new DerObjectIdentifier(TeleTrusTRsaSignatureAlgorithm + ".2");
+		public static readonly DerObjectIdentifier RsaSignatureWithRipeMD128 = new DerObjectIdentifier(TeleTrusTRsaSignatureAlgorithm + ".3");
+		public static readonly DerObjectIdentifier RsaSignatureWithRipeMD256 = new DerObjectIdentifier(TeleTrusTRsaSignatureAlgorithm + ".4");
+
+		public static readonly DerObjectIdentifier ECSign = new DerObjectIdentifier(TeleTrusTAlgorithm + ".3.2");
+
+		public static readonly DerObjectIdentifier ECSignWithSha1 = new DerObjectIdentifier(ECSign + ".1");
+		public static readonly DerObjectIdentifier ECSignWithRipeMD160 = new DerObjectIdentifier(ECSign + ".2");
+
+		public static readonly DerObjectIdentifier EccBrainpool = new DerObjectIdentifier(TeleTrusTAlgorithm + ".3.2.8");
+		public static readonly DerObjectIdentifier EllipticCurve = new DerObjectIdentifier(EccBrainpool + ".1");
+		public static readonly DerObjectIdentifier VersionOne = new DerObjectIdentifier(EllipticCurve + ".1");    
+
+		public static readonly DerObjectIdentifier BrainpoolP160R1 = new DerObjectIdentifier(VersionOne + ".1");
+		public static readonly DerObjectIdentifier BrainpoolP160T1 = new DerObjectIdentifier(VersionOne + ".2");
+		public static readonly DerObjectIdentifier BrainpoolP192R1 = new DerObjectIdentifier(VersionOne + ".3");
+		public static readonly DerObjectIdentifier BrainpoolP192T1 = new DerObjectIdentifier(VersionOne + ".4");
+		public static readonly DerObjectIdentifier BrainpoolP224R1 = new DerObjectIdentifier(VersionOne + ".5");
+		public static readonly DerObjectIdentifier BrainpoolP224T1 = new DerObjectIdentifier(VersionOne + ".6");
+		public static readonly DerObjectIdentifier BrainpoolP256R1 = new DerObjectIdentifier(VersionOne + ".7");
+		public static readonly DerObjectIdentifier BrainpoolP256T1 = new DerObjectIdentifier(VersionOne + ".8");
+		public static readonly DerObjectIdentifier BrainpoolP320R1 = new DerObjectIdentifier(VersionOne + ".9");
+		public static readonly DerObjectIdentifier BrainpoolP320T1 = new DerObjectIdentifier(VersionOne + ".10");
+		public static readonly DerObjectIdentifier BrainpoolP384R1 = new DerObjectIdentifier(VersionOne + ".11");
+		public static readonly DerObjectIdentifier BrainpoolP384T1 = new DerObjectIdentifier(VersionOne + ".12");
+		public static readonly DerObjectIdentifier BrainpoolP512R1 = new DerObjectIdentifier(VersionOne + ".13");
+		public static readonly DerObjectIdentifier BrainpoolP512T1 = new DerObjectIdentifier(VersionOne + ".14");
+	}
+}
diff --git a/Crypto/src/asn1/tsp/Accuracy.cs b/Crypto/src/asn1/tsp/Accuracy.cs
new file mode 100644
index 000000000..a193f52ff
--- /dev/null
+++ b/Crypto/src/asn1/tsp/Accuracy.cs
@@ -0,0 +1,149 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+	public class Accuracy
+		: Asn1Encodable
+	{
+		private readonly DerInteger seconds;
+		private readonly DerInteger millis;
+		private readonly DerInteger micros;
+
+		// constants
+		protected const int MinMillis = 1;
+		protected const int MaxMillis = 999;
+		protected const int MinMicros = 1;
+		protected const int MaxMicros = 999;
+
+		public Accuracy(
+			DerInteger seconds,
+			DerInteger millis,
+			DerInteger micros)
+		{
+			//Verifications
+			if (millis != null
+				&& (millis.Value.IntValue < MinMillis
+					|| millis.Value.IntValue > MaxMillis))
+			{
+				throw new ArgumentException(
+					"Invalid millis field : not in (1..999)");
+			}
+
+			if (micros != null
+				&& (micros.Value.IntValue < MinMicros
+					|| micros.Value.IntValue > MaxMicros))
+			{
+				throw new ArgumentException(
+					"Invalid micros field : not in (1..999)");
+			}
+
+			this.seconds = seconds;
+			this.millis = millis;
+			this.micros = micros;
+		}
+
+		private Accuracy(
+			Asn1Sequence seq)
+		{
+			for (int i = 0; i < seq.Count; ++i)
+			{
+				// seconds
+				if (seq[i] is DerInteger)
+				{
+					seconds = (DerInteger) seq[i];
+				}
+				else if (seq[i] is DerTaggedObject)
+				{
+					DerTaggedObject extra = (DerTaggedObject) seq[i];
+
+					switch (extra.TagNo)
+					{
+						case 0:
+							millis = DerInteger.GetInstance(extra, false);
+							if (millis.Value.IntValue < MinMillis
+								|| millis.Value.IntValue > MaxMillis)
+							{
+								throw new ArgumentException(
+									"Invalid millis field : not in (1..999).");
+							}
+							break;
+						case 1:
+							micros = DerInteger.GetInstance(extra, false);
+							if (micros.Value.IntValue < MinMicros
+								|| micros.Value.IntValue > MaxMicros)
+							{
+								throw new ArgumentException(
+									"Invalid micros field : not in (1..999).");
+							}
+							break;
+						default:
+							throw new ArgumentException("Invalig tag number");
+					}
+				}
+			}
+		}
+
+		public static Accuracy GetInstance(
+			object o)
+		{
+			if (o == null || o is Accuracy)
+			{
+				return (Accuracy) o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new Accuracy((Asn1Sequence) o);
+			}
+
+			throw new ArgumentException(
+				"Unknown object in 'Accuracy' factory: " + o.GetType().FullName);
+		}
+
+		public DerInteger Seconds
+		{
+			get { return seconds; }
+		}
+
+		public DerInteger Millis
+		{
+			get { return millis; }
+		}
+
+		public DerInteger Micros
+		{
+			get { return micros; }
+		}
+
+		/**
+		 * <pre>
+		 * Accuracy ::= SEQUENCE {
+		 *             seconds        INTEGER              OPTIONAL,
+		 *             millis     [0] INTEGER  (1..999)    OPTIONAL,
+		 *             micros     [1] INTEGER  (1..999)    OPTIONAL
+		 *             }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (seconds != null)
+			{
+				v.Add(seconds);
+			}
+
+			if (millis != null)
+			{
+				v.Add(new DerTaggedObject(false, 0, millis));
+			}
+
+			if (micros != null)
+			{
+				v.Add(new DerTaggedObject(false, 1, micros));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/tsp/MessageImprint.cs b/Crypto/src/asn1/tsp/MessageImprint.cs
new file mode 100644
index 000000000..0933bae21
--- /dev/null
+++ b/Crypto/src/asn1/tsp/MessageImprint.cs
@@ -0,0 +1,74 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+	public class MessageImprint
+		: Asn1Encodable
+	{
+		private readonly AlgorithmIdentifier	hashAlgorithm;
+		private readonly byte[]					hashedMessage;
+
+		/**
+		 * @param o
+		 * @return a MessageImprint object.
+		 */
+		public static MessageImprint GetInstance(
+			object o)
+		{
+			if (o == null || o is MessageImprint)
+			{
+				return (MessageImprint) o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new MessageImprint((Asn1Sequence) o);
+			}
+
+			throw new ArgumentException(
+				"Unknown object in 'MessageImprint' factory: " + o.GetType().FullName);
+		}
+
+		private MessageImprint(
+			Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]);
+			this.hashedMessage = Asn1OctetString.GetInstance(seq[1]).GetOctets();
+		}
+
+		public MessageImprint(
+			AlgorithmIdentifier	hashAlgorithm,
+			byte[]				hashedMessage)
+		{
+			this.hashAlgorithm = hashAlgorithm;
+			this.hashedMessage = hashedMessage;
+		}
+
+		public AlgorithmIdentifier HashAlgorithm
+		{
+			get { return hashAlgorithm; }
+		}
+
+		public byte[] GetHashedMessage()
+		{
+			return hashedMessage;
+		}
+
+		/**
+		 * <pre>
+		 *    MessageImprint ::= SEQUENCE  {
+		 *       hashAlgorithm                AlgorithmIdentifier,
+		 *       hashedMessage                OCTET STRING  }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(hashAlgorithm, new DerOctetString(hashedMessage));
+		}
+	}
+}
diff --git a/Crypto/src/asn1/tsp/TSTInfo.cs b/Crypto/src/asn1/tsp/TSTInfo.cs
new file mode 100644
index 000000000..61d5399c7
--- /dev/null
+++ b/Crypto/src/asn1/tsp/TSTInfo.cs
@@ -0,0 +1,249 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+	public class TstInfo
+		: Asn1Encodable
+	{
+		private readonly DerInteger				version;
+		private readonly DerObjectIdentifier	tsaPolicyId;
+		private readonly MessageImprint			messageImprint;
+		private readonly DerInteger				serialNumber;
+		private readonly DerGeneralizedTime		genTime;
+		private readonly Accuracy				accuracy;
+		private readonly DerBoolean				ordering;
+		private readonly DerInteger				nonce;
+		private readonly GeneralName			tsa;
+		private readonly X509Extensions			extensions;
+
+		public static TstInfo GetInstance(
+			object o)
+		{
+			if (o == null || o is TstInfo)
+			{
+				return (TstInfo) o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new TstInfo((Asn1Sequence) o);
+			}
+
+			if (o is Asn1OctetString)
+			{
+				try
+				{
+					byte[] octets = ((Asn1OctetString)o).GetOctets();
+					return GetInstance(Asn1Object.FromByteArray(octets));
+				}
+				catch (IOException)
+				{
+					throw new ArgumentException(
+						"Bad object format in 'TstInfo' factory.");
+				}
+			}
+
+			throw new ArgumentException(
+				"Unknown object in 'TstInfo' factory: " + o.GetType().FullName);
+		}
+
+		private TstInfo(
+			Asn1Sequence seq)
+		{
+			IEnumerator e = seq.GetEnumerator();
+
+			// version
+			e.MoveNext();
+			version = DerInteger.GetInstance(e.Current);
+
+			// tsaPolicy
+			e.MoveNext();
+			tsaPolicyId = DerObjectIdentifier.GetInstance(e.Current);
+
+			// messageImprint
+			e.MoveNext();
+			messageImprint = MessageImprint.GetInstance(e.Current);
+
+			// serialNumber
+			e.MoveNext();
+			serialNumber = DerInteger.GetInstance(e.Current);
+
+			// genTime
+			e.MoveNext();
+			genTime = DerGeneralizedTime.GetInstance(e.Current);
+
+			// default for ordering
+			ordering = DerBoolean.False;
+
+			while (e.MoveNext())
+			{
+				Asn1Object o = (Asn1Object) e.Current;
+
+				if (o is Asn1TaggedObject)
+				{
+					DerTaggedObject tagged = (DerTaggedObject) o;
+
+					switch (tagged.TagNo)
+					{
+						case 0:
+							tsa = GeneralName.GetInstance(tagged, true);
+							break;
+						case 1:
+							extensions = X509Extensions.GetInstance(tagged, false);
+							break;
+						default:
+							throw new ArgumentException("Unknown tag value " + tagged.TagNo);
+					}
+				}
+
+				if (o is DerSequence)
+				{
+					accuracy = Accuracy.GetInstance(o);
+				}
+
+				if (o is DerBoolean)
+				{
+					ordering = DerBoolean.GetInstance(o);
+				}
+
+				if (o is DerInteger)
+				{
+					nonce = DerInteger.GetInstance(o);
+				}
+			}
+		}
+
+		public TstInfo(
+			DerObjectIdentifier	tsaPolicyId,
+			MessageImprint		messageImprint,
+			DerInteger			serialNumber,
+			DerGeneralizedTime	genTime,
+			Accuracy			accuracy,
+			DerBoolean			ordering,
+			DerInteger			nonce,
+			GeneralName			tsa,
+			X509Extensions		extensions)
+		{
+			this.version = new DerInteger(1);
+			this.tsaPolicyId = tsaPolicyId;
+			this.messageImprint = messageImprint;
+			this.serialNumber = serialNumber;
+			this.genTime = genTime;
+			this.accuracy = accuracy;
+			this.ordering = ordering;
+			this.nonce = nonce;
+			this.tsa = tsa;
+			this.extensions = extensions;
+		}
+
+        public DerInteger Version
+        {
+            get { return version; }
+        }
+
+		public MessageImprint MessageImprint
+		{
+			get { return messageImprint; }
+		}
+
+		public DerObjectIdentifier Policy
+		{
+			get { return tsaPolicyId; }
+		}
+
+		public DerInteger SerialNumber
+		{
+			get { return serialNumber; }
+		}
+
+		public Accuracy Accuracy
+		{
+			get { return accuracy; }
+		}
+
+		public DerGeneralizedTime GenTime
+		{
+			get { return genTime; }
+		}
+
+		public DerBoolean Ordering
+		{
+			get { return ordering; }
+		}
+
+		public DerInteger Nonce
+		{
+			get { return nonce; }
+		}
+
+		public GeneralName Tsa
+		{
+			get { return tsa; }
+		}
+
+		public X509Extensions Extensions
+		{
+			get { return extensions; }
+		}
+
+		/**
+		 * <pre>
+		 *
+		 *     TstInfo ::= SEQUENCE  {
+		 *        version                      INTEGER  { v1(1) },
+		 *        policy                       TSAPolicyId,
+		 *        messageImprint               MessageImprint,
+		 *          -- MUST have the same value as the similar field in
+		 *          -- TimeStampReq
+		 *        serialNumber                 INTEGER,
+		 *         -- Time-Stamping users MUST be ready to accommodate integers
+		 *         -- up to 160 bits.
+		 *        genTime                      GeneralizedTime,
+		 *        accuracy                     Accuracy                 OPTIONAL,
+		 *        ordering                     BOOLEAN             DEFAULT FALSE,
+		 *        nonce                        INTEGER                  OPTIONAL,
+		 *          -- MUST be present if the similar field was present
+		 *          -- in TimeStampReq.  In that case it MUST have the same value.
+		 *        tsa                          [0] GeneralName          OPTIONAL,
+		 *        extensions                   [1] IMPLICIT Extensions   OPTIONAL  }
+		 *
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				version, tsaPolicyId, messageImprint, serialNumber, genTime);
+
+			if (accuracy != null)
+			{
+				v.Add(accuracy);
+			}
+
+			if (ordering != null && ordering.IsTrue)
+			{
+				v.Add(ordering);
+			}
+
+			if (nonce != null)
+			{
+				v.Add(nonce);
+			}
+
+			if (tsa != null)
+			{
+				v.Add(new DerTaggedObject(true, 0, tsa));
+			}
+
+			if (extensions != null)
+			{
+				v.Add(new DerTaggedObject(false, 1, extensions));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/tsp/TimeStampReq.cs b/Crypto/src/asn1/tsp/TimeStampReq.cs
new file mode 100644
index 000000000..55e973e76
--- /dev/null
+++ b/Crypto/src/asn1/tsp/TimeStampReq.cs
@@ -0,0 +1,164 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+	public class TimeStampReq
+		: Asn1Encodable
+	{
+		private readonly DerInteger				version;
+		private readonly MessageImprint			messageImprint;
+		private readonly DerObjectIdentifier	tsaPolicy;
+		private readonly DerInteger				nonce;
+		private readonly DerBoolean				certReq;
+		private readonly X509Extensions			extensions;
+
+		public static TimeStampReq GetInstance(
+			object o)
+		{
+			if (o == null || o is TimeStampReq)
+			{
+				return (TimeStampReq) o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new TimeStampReq((Asn1Sequence) o);
+			}
+
+			throw new ArgumentException(
+				"Unknown object in 'TimeStampReq' factory: " + o.GetType().FullName);
+		}
+
+		private TimeStampReq(
+			Asn1Sequence seq)
+		{
+			int nbObjects = seq.Count;
+			int seqStart = 0;
+
+			// version
+			version = DerInteger.GetInstance(seq[seqStart++]);
+
+			// messageImprint
+			messageImprint = MessageImprint.GetInstance(seq[seqStart++]);
+
+			for (int opt = seqStart; opt < nbObjects; opt++)
+			{
+				// tsaPolicy
+				if (seq[opt] is DerObjectIdentifier)
+				{
+					tsaPolicy = DerObjectIdentifier.GetInstance(seq[opt]);
+				}
+				// nonce
+				else if (seq[opt] is DerInteger)
+				{
+					nonce = DerInteger.GetInstance(seq[opt]);
+				}
+				// certReq
+				else if (seq[opt] is DerBoolean)
+				{
+					certReq = DerBoolean.GetInstance(seq[opt]);
+				}
+				// extensions
+				else if (seq[opt] is Asn1TaggedObject)
+				{
+					Asn1TaggedObject tagged = (Asn1TaggedObject) seq[opt];
+					if (tagged.TagNo == 0)
+					{
+						extensions = X509Extensions.GetInstance(tagged, false);
+					}
+				}
+			}
+		}
+
+		public TimeStampReq(
+			MessageImprint		messageImprint,
+			DerObjectIdentifier	tsaPolicy,
+			DerInteger			nonce,
+			DerBoolean			certReq,
+			X509Extensions		extensions)
+		{
+			// default
+			this.version = new DerInteger(1);
+
+			this.messageImprint = messageImprint;
+			this.tsaPolicy = tsaPolicy;
+			this.nonce = nonce;
+			this.certReq = certReq;
+			this.extensions = extensions;
+		}
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public MessageImprint MessageImprint
+		{
+			get { return messageImprint; }
+		}
+
+		public DerObjectIdentifier ReqPolicy
+		{
+			get { return tsaPolicy; }
+		}
+
+		public DerInteger Nonce
+		{
+			get { return nonce; }
+		}
+
+		public DerBoolean CertReq
+		{
+			get { return certReq; }
+		}
+
+		public X509Extensions Extensions
+		{
+			get { return extensions; }
+		}
+
+		/**
+		 * <pre>
+		 * TimeStampReq ::= SEQUENCE  {
+		 *  version                      INTEGER  { v1(1) },
+		 *  messageImprint               MessageImprint,
+		 *    --a hash algorithm OID and the hash value of the data to be
+		 *    --time-stamped
+		 *  reqPolicy             TSAPolicyId              OPTIONAL,
+		 *  nonce                 INTEGER                  OPTIONAL,
+		 *  certReq               BOOLEAN                  DEFAULT FALSE,
+		 *  extensions            [0] IMPLICIT Extensions  OPTIONAL
+		 * }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				version, messageImprint);
+
+			if (tsaPolicy != null)
+			{
+				v.Add(tsaPolicy);
+			}
+
+			if (nonce != null)
+			{
+				v.Add(nonce);
+			}
+
+			if (certReq != null && certReq.IsTrue)
+			{
+				v.Add(certReq);
+			}
+
+			if (extensions != null)
+			{
+				v.Add(new DerTaggedObject(false, 0, extensions));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/tsp/TimeStampResp.cs b/Crypto/src/asn1/tsp/TimeStampResp.cs
new file mode 100644
index 000000000..f26fb30bd
--- /dev/null
+++ b/Crypto/src/asn1/tsp/TimeStampResp.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Cms;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+	public class TimeStampResp
+		: Asn1Encodable
+	{
+		private readonly PkiStatusInfo	pkiStatusInfo;
+		private readonly ContentInfo	timeStampToken;
+
+		public static TimeStampResp GetInstance(
+			object o)
+		{
+			if (o == null || o is TimeStampResp)
+			{
+				return (TimeStampResp) o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new TimeStampResp((Asn1Sequence) o);
+			}
+
+			throw new ArgumentException(
+				"Unknown object in 'TimeStampResp' factory: " + o.GetType().FullName);
+		}
+
+		private TimeStampResp(
+			Asn1Sequence seq)
+		{
+			this.pkiStatusInfo = PkiStatusInfo.GetInstance(seq[0]);
+
+			if (seq.Count > 1)
+			{
+				this.timeStampToken = ContentInfo.GetInstance(seq[1]);
+			}
+		}
+
+		public TimeStampResp(
+			PkiStatusInfo	pkiStatusInfo,
+			ContentInfo		timeStampToken)
+		{
+			this.pkiStatusInfo = pkiStatusInfo;
+			this.timeStampToken = timeStampToken;
+		}
+
+		public PkiStatusInfo Status
+		{
+			get { return pkiStatusInfo; }
+		}
+
+		public ContentInfo TimeStampToken
+		{
+			get { return timeStampToken; }
+		}
+
+		/**
+		 * <pre>
+		 * TimeStampResp ::= SEQUENCE  {
+		 *   status                  PkiStatusInfo,
+		 *   timeStampToken          TimeStampToken     OPTIONAL  }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(pkiStatusInfo);
+
+			if (timeStampToken != null)
+			{
+				v.Add(timeStampToken);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/util/Asn1Dump.cs b/Crypto/src/asn1/util/Asn1Dump.cs
new file mode 100644
index 000000000..43d485500
--- /dev/null
+++ b/Crypto/src/asn1/util/Asn1Dump.cs
@@ -0,0 +1,378 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.Utilities
+{
+    public sealed class Asn1Dump
+    {
+		private static readonly string NewLine = Platform.NewLine;
+
+		private Asn1Dump()
+        {
+        }
+
+        private const string Tab = "    ";
+        private const int SampleSize = 32;
+
+        /**
+         * dump a Der object as a formatted string with indentation
+         *
+         * @param obj the Asn1Object to be dumped out.
+         */
+        private static void AsString(
+            string			indent,
+            bool			verbose,
+            Asn1Object		obj,
+			StringBuilder	buf)
+        {
+            if (obj is Asn1Sequence)
+            {
+				string tab = indent + Tab;
+				buf.Append(indent);
+                if (obj is BerSequence)
+                {
+                    buf.Append("BER Sequence");
+                }
+                else if (obj is DerSequence)
+                {
+                    buf.Append("DER Sequence");
+                }
+                else
+                {
+                    buf.Append("Sequence");
+                }
+
+                buf.Append(NewLine);
+
+				foreach (Asn1Encodable o in ((Asn1Sequence)obj))
+				{
+                    if (o == null || o is Asn1Null)
+                    {
+                        buf.Append(tab);
+                        buf.Append("NULL");
+                        buf.Append(NewLine);
+                    }
+                    else
+                    {
+                        AsString(tab, verbose, o.ToAsn1Object(), buf);
+                    }
+                }
+            }
+            else if (obj is DerTaggedObject)
+            {
+                string tab = indent + Tab;
+				buf.Append(indent);
+                if (obj is BerTaggedObject)
+                {
+                    buf.Append("BER Tagged [");
+                }
+                else
+                {
+                    buf.Append("Tagged [");
+                }
+
+				DerTaggedObject o = (DerTaggedObject)obj;
+
+				buf.Append(((int)o.TagNo).ToString());
+                buf.Append(']');
+
+				if (!o.IsExplicit())
+                {
+                    buf.Append(" IMPLICIT ");
+                }
+
+				buf.Append(NewLine);
+
+				if (o.IsEmpty())
+                {
+                    buf.Append(tab);
+                    buf.Append("EMPTY");
+                    buf.Append(NewLine);
+                }
+                else
+                {
+                    AsString(tab, verbose, o.GetObject(), buf);
+                }
+            }
+            else if (obj is BerSet)
+            {
+                string tab = indent + Tab;
+
+				buf.Append(indent);
+                buf.Append("BER Set");
+                buf.Append(NewLine);
+
+				foreach (Asn1Encodable o in ((Asn1Set)obj))
+				{
+                    if (o == null)
+                    {
+                        buf.Append(tab);
+                        buf.Append("NULL");
+                        buf.Append(NewLine);
+                    }
+                    else
+                    {
+                        AsString(tab, verbose, o.ToAsn1Object(), buf);
+                    }
+                }
+            }
+            else if (obj is DerSet)
+            {
+                string tab = indent + Tab;
+
+				buf.Append(indent);
+                buf.Append("DER Set");
+                buf.Append(NewLine);
+
+				foreach (Asn1Encodable o in ((Asn1Set)obj))
+				{
+                    if (o == null)
+                    {
+                        buf.Append(tab);
+                        buf.Append("NULL");
+                        buf.Append(NewLine);
+                    }
+                    else
+                    {
+                        AsString(tab, verbose, o.ToAsn1Object(), buf);
+                    }
+                }
+            }
+            else if (obj is DerObjectIdentifier)
+            {
+                buf.Append(indent + "ObjectIdentifier(" + ((DerObjectIdentifier)obj).Id + ")" + NewLine);
+            }
+            else if (obj is DerBoolean)
+            {
+                buf.Append(indent + "Boolean(" + ((DerBoolean)obj).IsTrue + ")" + NewLine);
+            }
+            else if (obj is DerInteger)
+            {
+                buf.Append(indent + "Integer(" + ((DerInteger)obj).Value + ")" + NewLine);
+            }
+			else if (obj is BerOctetString)
+			{
+				byte[] octets = ((Asn1OctetString)obj).GetOctets();
+				string extra = verbose ? dumpBinaryDataAsString(indent, octets) : "";
+				buf.Append(indent + "BER Octet String" + "[" + octets.Length + "] " + extra + NewLine);
+			}
+            else if (obj is DerOctetString)
+            {
+				byte[] octets = ((Asn1OctetString)obj).GetOctets();
+				string extra = verbose ? dumpBinaryDataAsString(indent, octets) : "";
+				buf.Append(indent + "DER Octet String" + "[" + octets.Length + "] " + extra + NewLine);
+			}
+			else if (obj is DerBitString)
+			{
+				DerBitString bt = (DerBitString)obj; 
+				byte[] bytes = bt.GetBytes();
+				string extra = verbose ? dumpBinaryDataAsString(indent, bytes) : "";
+				buf.Append(indent + "DER Bit String" + "[" + bytes.Length + ", " + bt.PadBits + "] " + extra + NewLine);
+			}
+            else if (obj is DerIA5String)
+            {
+                buf.Append(indent + "IA5String(" + ((DerIA5String)obj).GetString() + ") " + NewLine);
+            }
+			else if (obj is DerUtf8String)
+			{
+				buf.Append(indent + "UTF8String(" + ((DerUtf8String)obj).GetString() + ") " + NewLine);
+			}
+            else if (obj is DerPrintableString)
+            {
+                buf.Append(indent + "PrintableString(" + ((DerPrintableString)obj).GetString() + ") " + NewLine);
+            }
+            else if (obj is DerVisibleString)
+            {
+                buf.Append(indent + "VisibleString(" + ((DerVisibleString)obj).GetString() + ") " + NewLine);
+            }
+            else if (obj is DerBmpString)
+            {
+                buf.Append(indent + "BMPString(" + ((DerBmpString)obj).GetString() + ") " + NewLine);
+            }
+            else if (obj is DerT61String)
+            {
+                buf.Append(indent + "T61String(" + ((DerT61String)obj).GetString() + ") " + NewLine);
+            }
+            else if (obj is DerUtcTime)
+            {
+                buf.Append(indent + "UTCTime(" + ((DerUtcTime)obj).TimeString + ") " + NewLine);
+            }
+			else if (obj is DerGeneralizedTime)
+			{
+				buf.Append(indent + "GeneralizedTime(" + ((DerGeneralizedTime)obj).GetTime() + ") " + NewLine);
+			}
+            else if (obj is DerUnknownTag)
+            {
+				string hex = Hex.ToHexString(((DerUnknownTag)obj).GetData());
+                buf.Append(indent + "Unknown " + ((int)((DerUnknownTag)obj).Tag).ToString("X") + " " + hex + NewLine);
+            }
+            else if (obj is BerApplicationSpecific)
+            {
+                buf.Append(outputApplicationSpecific("BER", indent, verbose, (BerApplicationSpecific)obj));
+            }
+            else if (obj is DerApplicationSpecific)
+            {
+                buf.Append(outputApplicationSpecific("DER", indent, verbose, (DerApplicationSpecific)obj));
+            }
+			else if (obj is DerEnumerated)
+			{
+				DerEnumerated en = (DerEnumerated)obj;
+				buf.Append(indent + "DER Enumerated(" + en.Value + ")" + NewLine);
+			}
+			else if (obj is DerExternal)
+			{
+				DerExternal ext = (DerExternal)obj;
+				buf.Append(indent + "External " + NewLine);
+                string tab = indent + Tab;
+
+				if (ext.DirectReference != null)
+				{
+					buf.Append(tab + "Direct Reference: " + ext.DirectReference.Id + NewLine);
+				}
+				if (ext.IndirectReference != null)
+				{
+					buf.Append(tab + "Indirect Reference: " + ext.IndirectReference.ToString() + NewLine);
+				}
+				if (ext.DataValueDescriptor != null)
+				{
+					AsString(tab, verbose, ext.DataValueDescriptor, buf);
+				}
+				buf.Append(tab + "Encoding: " + ext.Encoding + NewLine);
+				AsString(tab, verbose, ext.ExternalContent, buf);
+			}
+            else
+            {
+                buf.Append(indent + obj.ToString() + NewLine);
+            }
+        }
+
+        private static string outputApplicationSpecific(
+            string					type,
+            string					indent,
+            bool					verbose,
+            DerApplicationSpecific	app)
+        {
+            StringBuilder buf = new StringBuilder();
+
+            if (app.IsConstructed())
+            {
+                try
+                {
+                    Asn1Sequence s = Asn1Sequence.GetInstance(app.GetObject(Asn1Tags.Sequence));
+                    buf.Append(indent + type + " ApplicationSpecific[" + app.ApplicationTag + "]" + NewLine);
+                    foreach (Asn1Encodable ae in s)
+                    {
+                    	AsString(indent + Tab, verbose, ae.ToAsn1Object(), buf);
+                    }
+                }
+                catch (IOException e)
+                {
+                    buf.Append(e);
+                }
+                return buf.ToString();
+            }
+
+            return indent + type + " ApplicationSpecific[" + app.ApplicationTag + "] ("
+                + Hex.ToHexString(app.GetContents()) + ")" + NewLine;
+        }
+
+		[Obsolete("Use version accepting Asn1Encodable")]
+		public static string DumpAsString(
+            object   obj)
+        {
+            if (obj is Asn1Encodable)
+            {
+				StringBuilder buf = new StringBuilder();
+                AsString("", false, ((Asn1Encodable)obj).ToAsn1Object(), buf);
+				return buf.ToString();
+            }
+
+            return "unknown object type " + obj.ToString();
+        }
+
+		/**
+		 * dump out a DER object as a formatted string, in non-verbose mode
+		 *
+		 * @param obj the Asn1Encodable to be dumped out.
+		 * @return  the resulting string.
+		 */
+		public static string DumpAsString(
+			Asn1Encodable obj)
+		{
+			return DumpAsString(obj, false);
+		}
+
+		/**
+		 * Dump out the object as a string
+		 *
+		 * @param obj the Asn1Encodable to be dumped out.
+		 * @param verbose  if true, dump out the contents of octet and bit strings.
+		 * @return  the resulting string.
+		 */
+		public static string DumpAsString(
+			Asn1Encodable	obj,
+			bool			verbose)
+		{
+			StringBuilder buf = new StringBuilder();
+			AsString("", verbose, obj.ToAsn1Object(), buf);
+			return buf.ToString();
+		}
+
+		private static string dumpBinaryDataAsString(string indent, byte[] bytes)
+		{
+			indent += Tab;
+
+			StringBuilder buf = new StringBuilder(NewLine);
+
+			for (int i = 0; i < bytes.Length; i += SampleSize)
+			{
+				if (bytes.Length - i > SampleSize)
+				{
+					buf.Append(indent);
+					buf.Append(Hex.ToHexString(bytes, i, SampleSize));
+					buf.Append(Tab);
+					buf.Append(calculateAscString(bytes, i, SampleSize));
+					buf.Append(NewLine);
+				}
+				else
+				{
+					buf.Append(indent);
+					buf.Append(Hex.ToHexString(bytes, i, bytes.Length - i));
+					for (int j = bytes.Length - i; j != SampleSize; j++)
+					{
+						buf.Append("  ");
+					}
+					buf.Append(Tab);
+					buf.Append(calculateAscString(bytes, i, bytes.Length - i));
+					buf.Append(NewLine);
+				}
+			}
+
+			return buf.ToString();
+		}
+
+		private static string calculateAscString(
+			byte[]	bytes,
+			int		off,
+			int		len)
+		{
+			StringBuilder buf = new StringBuilder();
+
+			for (int i = off; i != off + len; i++)
+			{
+				char c = (char)bytes[i]; 
+				if (c >= ' ' && c <= '~')
+				{
+					buf.Append(c);
+				}
+			}
+
+			return buf.ToString();
+		}
+    }
+}
diff --git a/Crypto/src/asn1/util/Dump.cs b/Crypto/src/asn1/util/Dump.cs
new file mode 100644
index 000000000..2712ca1b3
--- /dev/null
+++ b/Crypto/src/asn1/util/Dump.cs
@@ -0,0 +1,30 @@
+#if !PORTABLE
+using Org.BouncyCastle.Asn1;
+
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1.Utilities
+{
+    public sealed class Dump
+    {
+        private Dump()
+        {
+        }
+
+        public static void Main(string[] args)
+        {
+            FileStream fIn = File.OpenRead(args[0]);
+            Asn1InputStream bIn = new Asn1InputStream(fIn);
+
+			Asn1Object obj;
+			while ((obj = bIn.ReadObject()) != null)
+            {
+                Console.WriteLine(Asn1Dump.DumpAsString(obj));
+            }
+
+			bIn.Dispose();
+        }
+    }
+}
+#endif
\ No newline at end of file
diff --git a/Crypto/src/asn1/util/FilterStream.cs b/Crypto/src/asn1/util/FilterStream.cs
new file mode 100644
index 000000000..f277e33e6
--- /dev/null
+++ b/Crypto/src/asn1/util/FilterStream.cs
@@ -0,0 +1,72 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1.Utilities
+{
+    public class FilterStream : Stream
+    {
+        public FilterStream(Stream s)
+        {
+            this.s = s;
+        }
+        public override bool CanRead
+        {
+            get { return s.CanRead; }
+        }
+        public override bool CanSeek
+        {
+            get { return s.CanSeek; }
+        }
+        public override bool CanWrite
+        {
+            get { return s.CanWrite; }
+        }
+        public override long Length
+        {
+            get { return s.Length; }
+        }
+        public override long Position
+        {
+            get { return s.Position; }
+            set { s.Position = value; }
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                s.Dispose();
+            }
+        }
+
+        public override void Flush()
+        {
+            s.Flush();
+        }
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            return s.Seek(offset, origin);
+        }
+        public override void SetLength(long value)
+        {
+            s.SetLength(value);
+        }
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            return s.Read(buffer, offset, count);
+        }
+        public override int ReadByte()
+        {
+            return s.ReadByte();
+        }
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            s.Write(buffer, offset, count);
+        }
+        public override void WriteByte(byte value)
+        {
+            s.WriteByte(value);
+        }
+        protected readonly Stream s;
+    }
+}
diff --git a/Crypto/src/asn1/x500/DirectoryString.cs b/Crypto/src/asn1/x500/DirectoryString.cs
new file mode 100644
index 000000000..78ecc2663
--- /dev/null
+++ b/Crypto/src/asn1/x500/DirectoryString.cs
@@ -0,0 +1,75 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X500
+{
+	public class DirectoryString
+		: Asn1Encodable, IAsn1Choice, IAsn1String
+	{
+		private readonly DerStringBase str;
+
+		public static DirectoryString GetInstance(
+			object obj)
+		{
+			if (obj is DirectoryString)
+			{
+				return (DirectoryString) obj;
+			}
+
+			if (obj is DerStringBase)
+			{
+				if (obj is DerT61String
+					|| obj is DerPrintableString
+					|| obj is DerUniversalString
+					|| obj is DerUtf8String
+					|| obj is DerBmpString)
+				{
+					return new DirectoryString((DerStringBase) obj);
+				}
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public static DirectoryString GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			if (!isExplicit)
+				throw new ArgumentException("choice item must be explicitly tagged");
+
+			return GetInstance(obj.GetObject());
+		}
+
+		private DirectoryString(
+			DerStringBase str)
+		{
+			this.str = str;
+		}
+
+		public DirectoryString(
+			string str)
+		{
+			this.str = new DerUtf8String(str);
+		}
+
+		public string GetString()
+		{
+			return str.GetString();
+		}
+
+		/**
+		 * <pre>
+		 *  DirectoryString ::= CHOICE {
+		 *    teletexString               TeletexString (SIZE (1..MAX)),
+		 *    printableString             PrintableString (SIZE (1..MAX)),
+		 *    universalString             UniversalString (SIZE (1..MAX)),
+		 *    utf8String                  UTF8String (SIZE (1..MAX)),
+		 *    bmpString                   BMPString (SIZE (1..MAX))  }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return str.ToAsn1Object();
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/AccessDescription.cs b/Crypto/src/asn1/x509/AccessDescription.cs
new file mode 100644
index 000000000..09b5b5920
--- /dev/null
+++ b/Crypto/src/asn1/x509/AccessDescription.cs
@@ -0,0 +1,83 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * The AccessDescription object.
+	 * <pre>
+	 * AccessDescription  ::=  SEQUENCE {
+	 *       accessMethod          OBJECT IDENTIFIER,
+	 *       accessLocation        GeneralName  }
+	 * </pre>
+	 */
+	public class AccessDescription
+		: Asn1Encodable
+	{
+		public readonly static DerObjectIdentifier IdADCAIssuers = new DerObjectIdentifier("1.3.6.1.5.5.7.48.2");
+		public readonly static DerObjectIdentifier IdADOcsp = new DerObjectIdentifier("1.3.6.1.5.5.7.48.1");
+
+		private readonly DerObjectIdentifier accessMethod;
+		private readonly GeneralName accessLocation;
+
+		public static AccessDescription GetInstance(
+			object obj)
+		{
+			if (obj is AccessDescription)
+				return (AccessDescription) obj;
+
+			if (obj is Asn1Sequence)
+				return new AccessDescription((Asn1Sequence) obj);
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private AccessDescription(
+			Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("wrong number of elements in sequence");
+
+			accessMethod = DerObjectIdentifier.GetInstance(seq[0]);
+			accessLocation = GeneralName.GetInstance(seq[1]);
+		}
+
+		/**
+		 * create an AccessDescription with the oid and location provided.
+		 */
+		public AccessDescription(
+			DerObjectIdentifier	oid,
+			GeneralName			location)
+		{
+			accessMethod = oid;
+			accessLocation = location;
+		}
+
+		/**
+		 *
+		 * @return the access method.
+		 */
+		public DerObjectIdentifier AccessMethod
+		{
+			get { return accessMethod; }
+		}
+
+		/**
+		 *
+		 * @return the access location
+		 */
+		public GeneralName AccessLocation
+		{
+			get { return accessLocation; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(accessMethod, accessLocation);
+		}
+
+		public override string ToString()
+		{
+			return "AccessDescription: Oid(" + this.accessMethod.Id + ")";
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/AlgorithmIdentifier.cs b/Crypto/src/asn1/x509/AlgorithmIdentifier.cs
new file mode 100644
index 000000000..caf9e77c9
--- /dev/null
+++ b/Crypto/src/asn1/x509/AlgorithmIdentifier.cs
@@ -0,0 +1,110 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AlgorithmIdentifier
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	objectID;
+        private readonly Asn1Encodable			parameters;
+		private readonly bool					parametersDefined;
+
+		public static AlgorithmIdentifier GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static AlgorithmIdentifier GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is AlgorithmIdentifier)
+                return (AlgorithmIdentifier) obj;
+
+			if (obj is DerObjectIdentifier)
+                return new AlgorithmIdentifier((DerObjectIdentifier) obj);
+
+			if (obj is string)
+                return new AlgorithmIdentifier((string) obj);
+
+			if (obj is Asn1Sequence)
+                return new AlgorithmIdentifier((Asn1Sequence) obj);
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public AlgorithmIdentifier(
+            DerObjectIdentifier objectID)
+        {
+            this.objectID = objectID;
+        }
+
+		public AlgorithmIdentifier(
+            string objectID)
+        {
+            this.objectID = new DerObjectIdentifier(objectID);
+        }
+
+		public AlgorithmIdentifier(
+            DerObjectIdentifier	objectID,
+            Asn1Encodable		parameters)
+        {
+            this.objectID = objectID;
+            this.parameters = parameters;
+			this.parametersDefined = true;
+        }
+
+		internal AlgorithmIdentifier(
+            Asn1Sequence seq)
+        {
+			if (seq.Count < 1 || seq.Count > 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			this.objectID = DerObjectIdentifier.GetInstance(seq[0]);
+			this.parametersDefined = (seq.Count == 2);
+
+			if (parametersDefined)
+            {
+                this.parameters = seq[1];
+            }
+        }
+
+		public virtual DerObjectIdentifier ObjectID
+		{
+			get { return objectID; }
+		}
+
+		public Asn1Encodable Parameters
+		{
+			get { return parameters; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *      AlgorithmIdentifier ::= Sequence {
+         *                            algorithm OBJECT IDENTIFIER,
+         *                            parameters ANY DEFINED BY algorithm OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			Asn1EncodableVector v = new Asn1EncodableVector(objectID);
+
+			if (parametersDefined)
+			{
+				if (parameters != null)
+				{
+					v.Add(parameters);
+				}
+				else
+				{
+					v.Add(DerNull.Instance);
+				}
+			}
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/AttCertIssuer.cs b/Crypto/src/asn1/x509/AttCertIssuer.cs
new file mode 100644
index 000000000..e9314fa92
--- /dev/null
+++ b/Crypto/src/asn1/x509/AttCertIssuer.cs
@@ -0,0 +1,86 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AttCertIssuer
+        : Asn1Encodable, IAsn1Choice
+    {
+        internal readonly Asn1Encodable	obj;
+        internal readonly Asn1Object	choiceObj;
+
+		public static AttCertIssuer GetInstance(
+			object obj)
+		{
+			if (obj is AttCertIssuer)
+			{
+				return (AttCertIssuer)obj;
+			}
+			else if (obj is V2Form)
+			{
+				return new AttCertIssuer(V2Form.GetInstance(obj));
+			}
+			else if (obj is GeneralNames)
+			{
+				return new AttCertIssuer((GeneralNames)obj);
+			}
+			else if (obj is Asn1TaggedObject)
+			{
+				return new AttCertIssuer(V2Form.GetInstance((Asn1TaggedObject)obj, false));
+			}
+			else if (obj is Asn1Sequence)
+			{
+				return new AttCertIssuer(GeneralNames.GetInstance(obj));
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public static AttCertIssuer GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			return GetInstance(obj.GetObject()); // must be explictly tagged
+		}
+
+		/// <summary>
+		/// Don't use this one if you are trying to be RFC 3281 compliant.
+		/// Use it for v1 attribute certificates only.
+		/// </summary>
+		/// <param name="names">Our GeneralNames structure</param>
+		public AttCertIssuer(
+			GeneralNames names)
+		{
+			obj = names;
+			choiceObj = obj.ToAsn1Object();
+		}
+
+		public AttCertIssuer(
+            V2Form v2Form)
+        {
+            obj = v2Form;
+            choiceObj = new DerTaggedObject(false, 0, obj);
+        }
+
+		public Asn1Encodable Issuer
+		{
+			get { return obj; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  AttCertIssuer ::= CHOICE {
+         *       v1Form   GeneralNames,  -- MUST NOT be used in this
+         *                               -- profile
+         *       v2Form   [0] V2Form     -- v2 only
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return choiceObj;
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/AttCertValidityPeriod.cs b/Crypto/src/asn1/x509/AttCertValidityPeriod.cs
new file mode 100644
index 000000000..7f86cd0b8
--- /dev/null
+++ b/Crypto/src/asn1/x509/AttCertValidityPeriod.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AttCertValidityPeriod
+        : Asn1Encodable
+    {
+        private readonly DerGeneralizedTime	notBeforeTime;
+        private readonly DerGeneralizedTime	notAfterTime;
+
+		public static AttCertValidityPeriod GetInstance(
+            object obj)
+        {
+            if (obj is AttCertValidityPeriod || obj == null)
+            {
+                return (AttCertValidityPeriod) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new AttCertValidityPeriod((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public static AttCertValidityPeriod GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		private AttCertValidityPeriod(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			notBeforeTime = DerGeneralizedTime.GetInstance(seq[0]);
+			notAfterTime = DerGeneralizedTime.GetInstance(seq[1]);
+        }
+
+		public AttCertValidityPeriod(
+            DerGeneralizedTime	notBeforeTime,
+            DerGeneralizedTime	notAfterTime)
+        {
+            this.notBeforeTime = notBeforeTime;
+            this.notAfterTime = notAfterTime;
+        }
+
+		public DerGeneralizedTime NotBeforeTime
+		{
+			get { return notBeforeTime; }
+		}
+
+		public DerGeneralizedTime NotAfterTime
+		{
+			get { return notAfterTime; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  AttCertValidityPeriod  ::= Sequence {
+         *       notBeforeTime  GeneralizedTime,
+         *       notAfterTime   GeneralizedTime
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(notBeforeTime, notAfterTime);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/Attribute.cs b/Crypto/src/asn1/x509/Attribute.cs
new file mode 100644
index 000000000..d26db93e9
--- /dev/null
+++ b/Crypto/src/asn1/x509/Attribute.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AttributeX509
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	attrType;
+        private readonly Asn1Set				attrValues;
+
+		/**
+         * return an Attr object from the given object.
+         *
+         * @param o the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static AttributeX509 GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is AttributeX509)
+            {
+                return (AttributeX509) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new AttributeX509((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private AttributeX509(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			attrType = DerObjectIdentifier.GetInstance(seq[0]);
+			attrValues = Asn1Set.GetInstance(seq[1]);
+        }
+
+		public AttributeX509(
+            DerObjectIdentifier	attrType,
+            Asn1Set				attrValues)
+        {
+            this.attrType = attrType;
+            this.attrValues = attrValues;
+        }
+
+		public DerObjectIdentifier AttrType
+		{
+			get { return attrType; }
+		}
+
+		public Asn1Encodable[] GetAttributeValues()
+		{
+			return attrValues.ToArray();
+		}
+
+		public Asn1Set AttrValues
+		{
+			get { return attrValues; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * Attr ::= Sequence {
+         *     attrType OBJECT IDENTIFIER,
+         *     attrValues Set OF AttributeValue
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(attrType, attrValues);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/AttributeCertificate.cs b/Crypto/src/asn1/x509/AttributeCertificate.cs
new file mode 100644
index 000000000..5f85910da
--- /dev/null
+++ b/Crypto/src/asn1/x509/AttributeCertificate.cs
@@ -0,0 +1,81 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AttributeCertificate
+        : Asn1Encodable
+    {
+        private readonly AttributeCertificateInfo	acinfo;
+        private readonly AlgorithmIdentifier		signatureAlgorithm;
+        private readonly DerBitString				signatureValue;
+
+		/**
+         * @param obj
+         * @return
+         */
+        public static AttributeCertificate GetInstance(
+			object obj)
+        {
+            if (obj is AttributeCertificate)
+                return (AttributeCertificate) obj;
+
+			if (obj != null)
+				return new AttributeCertificate(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		public AttributeCertificate(
+            AttributeCertificateInfo	acinfo,
+            AlgorithmIdentifier			signatureAlgorithm,
+            DerBitString				signatureValue)
+        {
+            this.acinfo = acinfo;
+            this.signatureAlgorithm = signatureAlgorithm;
+            this.signatureValue = signatureValue;
+        }
+
+		private AttributeCertificate(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			this.acinfo = AttributeCertificateInfo.GetInstance(seq[0]);
+            this.signatureAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+            this.signatureValue = DerBitString.GetInstance(seq[2]);
+        }
+
+		public AttributeCertificateInfo ACInfo
+		{
+			get { return acinfo; }
+		}
+
+		public AlgorithmIdentifier SignatureAlgorithm
+		{
+			get { return signatureAlgorithm; }
+		}
+
+		public DerBitString SignatureValue
+		{
+			get { return signatureValue; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  AttributeCertificate ::= Sequence {
+         *       acinfo               AttributeCertificateInfo,
+         *       signatureAlgorithm   AlgorithmIdentifier,
+         *       signatureValue       BIT STRING
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(acinfo, signatureAlgorithm, signatureValue);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/AttributeCertificateInfo.cs b/Crypto/src/asn1/x509/AttributeCertificateInfo.cs
new file mode 100644
index 000000000..dcef3d472
--- /dev/null
+++ b/Crypto/src/asn1/x509/AttributeCertificateInfo.cs
@@ -0,0 +1,156 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AttributeCertificateInfo
+        : Asn1Encodable
+    {
+        internal readonly DerInteger			version;
+        internal readonly Holder				holder;
+        internal readonly AttCertIssuer			issuer;
+        internal readonly AlgorithmIdentifier	signature;
+        internal readonly DerInteger			serialNumber;
+        internal readonly AttCertValidityPeriod	attrCertValidityPeriod;
+        internal readonly Asn1Sequence			attributes;
+        internal readonly DerBitString			issuerUniqueID;
+        internal readonly X509Extensions		extensions;
+
+		public static AttributeCertificateInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+		public static AttributeCertificateInfo GetInstance(
+            object obj)
+        {
+            if (obj is AttributeCertificateInfo)
+            {
+                return (AttributeCertificateInfo) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new AttributeCertificateInfo((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private AttributeCertificateInfo(
+            Asn1Sequence seq)
+        {
+			if (seq.Count < 7 || seq.Count > 9)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			this.version = DerInteger.GetInstance(seq[0]);
+            this.holder = Holder.GetInstance(seq[1]);
+            this.issuer = AttCertIssuer.GetInstance(seq[2]);
+            this.signature = AlgorithmIdentifier.GetInstance(seq[3]);
+            this.serialNumber = DerInteger.GetInstance(seq[4]);
+            this.attrCertValidityPeriod = AttCertValidityPeriod.GetInstance(seq[5]);
+            this.attributes = Asn1Sequence.GetInstance(seq[6]);
+
+			for (int i = 7; i < seq.Count; i++)
+            {
+                Asn1Encodable obj = (Asn1Encodable) seq[i];
+
+				if (obj is DerBitString)
+                {
+                    this.issuerUniqueID = DerBitString.GetInstance(seq[i]);
+                }
+                else if (obj is Asn1Sequence || obj is X509Extensions)
+                {
+                    this.extensions = X509Extensions.GetInstance(seq[i]);
+                }
+            }
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public Holder Holder
+		{
+			get { return holder; }
+		}
+
+		public AttCertIssuer Issuer
+		{
+			get { return issuer; }
+		}
+
+		public AlgorithmIdentifier Signature
+		{
+			get { return signature; }
+		}
+
+		public DerInteger SerialNumber
+		{
+			get { return serialNumber; }
+		}
+
+		public AttCertValidityPeriod AttrCertValidityPeriod
+		{
+			get { return attrCertValidityPeriod; }
+		}
+
+		public Asn1Sequence Attributes
+		{
+			get { return attributes; }
+		}
+
+		public DerBitString IssuerUniqueID
+		{
+			get { return issuerUniqueID; }
+		}
+
+		public X509Extensions Extensions
+		{
+			get { return extensions; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  AttributeCertificateInfo ::= Sequence {
+         *       version              AttCertVersion -- version is v2,
+         *       holder               Holder,
+         *       issuer               AttCertIssuer,
+         *       signature            AlgorithmIdentifier,
+         *       serialNumber         CertificateSerialNumber,
+         *       attrCertValidityPeriod   AttCertValidityPeriod,
+         *       attributes           Sequence OF Attr,
+         *       issuerUniqueID       UniqueIdentifier OPTIONAL,
+         *       extensions           Extensions OPTIONAL
+         *  }
+         *
+         *  AttCertVersion ::= Integer { v2(1) }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				version, holder, issuer, signature, serialNumber,
+				attrCertValidityPeriod, attributes);
+
+			if (issuerUniqueID != null)
+            {
+                v.Add(issuerUniqueID);
+            }
+
+			if (extensions != null)
+            {
+                v.Add(extensions);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/AttributeTable.cs b/Crypto/src/asn1/x509/AttributeTable.cs
new file mode 100644
index 000000000..87b112f01
--- /dev/null
+++ b/Crypto/src/asn1/x509/AttributeTable.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AttributeTable
+    {
+        private readonly IDictionary attributes;
+
+        public AttributeTable(
+            IDictionary attrs)
+        {
+            this.attributes = Platform.CreateHashtable(attrs);
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete]
+        public AttributeTable(
+            Hashtable attrs)
+        {
+            this.attributes = Platform.CreateHashtable(attrs);
+        }
+#endif
+
+        public AttributeTable(
+            Asn1EncodableVector v)
+        {
+            this.attributes = Platform.CreateHashtable(v.Count);
+
+			for (int i = 0; i != v.Count; i++)
+            {
+                AttributeX509 a = AttributeX509.GetInstance(v[i]);
+
+				attributes.Add(a.AttrType, a);
+            }
+        }
+
+		public AttributeTable(
+            Asn1Set s)
+        {
+            this.attributes = Platform.CreateHashtable(s.Count);
+
+			for (int i = 0; i != s.Count; i++)
+            {
+                AttributeX509 a = AttributeX509.GetInstance(s[i]);
+
+				attributes.Add(a.AttrType, a);
+            }
+        }
+
+		public AttributeX509 Get(
+            DerObjectIdentifier oid)
+        {
+            return (AttributeX509) attributes[oid];
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete("Use 'ToDictionary' instead")]
+		public Hashtable ToHashtable()
+        {
+            return new Hashtable(attributes);
+        }
+#endif
+
+        public IDictionary ToDictionary()
+        {
+            return Platform.CreateHashtable(attributes);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/AuthorityInformationAccess.cs b/Crypto/src/asn1/x509/AuthorityInformationAccess.cs
new file mode 100644
index 000000000..3eeba8cd2
--- /dev/null
+++ b/Crypto/src/asn1/x509/AuthorityInformationAccess.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * The AuthorityInformationAccess object.
+	 * <pre>
+	 * id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
+	 *
+	 * AuthorityInfoAccessSyntax  ::=
+	 *      Sequence SIZE (1..MAX) OF AccessDescription
+	 * AccessDescription  ::=  Sequence {
+	 *       accessMethod          OBJECT IDENTIFIER,
+	 *       accessLocation        GeneralName  }
+	 *
+	 * id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
+	 * id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
+	 * id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
+	 * </pre>
+	 */
+	public class AuthorityInformationAccess
+		: Asn1Encodable
+	{
+		private readonly AccessDescription[] descriptions;
+
+		public static AuthorityInformationAccess GetInstance(
+			object obj)
+		{
+			if (obj is AuthorityInformationAccess)
+				return (AuthorityInformationAccess) obj;
+
+			if (obj is Asn1Sequence)
+				return new AuthorityInformationAccess((Asn1Sequence) obj);
+
+			if (obj is X509Extension)
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private AuthorityInformationAccess(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1)
+				throw new ArgumentException("sequence may not be empty");
+
+			this.descriptions = new AccessDescription[seq.Count];
+
+			for (int i = 0; i < seq.Count; ++i)
+			{
+				descriptions[i] = AccessDescription.GetInstance(seq[i]);
+			}
+		}
+
+		/**
+		 * create an AuthorityInformationAccess with the oid and location provided.
+		 */
+		[Obsolete("Use version taking an AccessDescription instead")]
+		public AuthorityInformationAccess(
+			DerObjectIdentifier	oid,
+			GeneralName			location)
+		{
+			this.descriptions = new AccessDescription[]{ new AccessDescription(oid, location) };
+		}
+
+		public AuthorityInformationAccess(
+			AccessDescription description)
+		{
+			this.descriptions = new AccessDescription[]{ description };
+		}
+
+		public AccessDescription[] GetAccessDescriptions()
+		{
+			return (AccessDescription[]) descriptions.Clone();
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(descriptions);
+		}
+
+		public override string ToString()
+		{
+			StringBuilder buf = new StringBuilder();
+			string sep = Platform.NewLine;
+
+			buf.Append("AuthorityInformationAccess:");
+			buf.Append(sep);
+
+			foreach (AccessDescription description in descriptions)
+			{
+				buf.Append("    ");
+				buf.Append(description);
+				buf.Append(sep);
+			}
+
+			return buf.ToString();
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/AuthorityKeyIdentifier.cs b/Crypto/src/asn1/x509/AuthorityKeyIdentifier.cs
new file mode 100644
index 000000000..12ccacfc7
--- /dev/null
+++ b/Crypto/src/asn1/x509/AuthorityKeyIdentifier.cs
@@ -0,0 +1,211 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The AuthorityKeyIdentifier object.
+     * <pre>
+     * id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 35 }
+     *
+     *   AuthorityKeyIdentifier ::= Sequence {
+     *      keyIdentifier             [0] IMPLICIT KeyIdentifier           OPTIONAL,
+     *      authorityCertIssuer       [1] IMPLICIT GeneralNames            OPTIONAL,
+     *      authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL  }
+     *
+     *   KeyIdentifier ::= OCTET STRING
+     * </pre>
+     *
+     */
+    public class AuthorityKeyIdentifier
+        : Asn1Encodable
+    {
+        internal readonly Asn1OctetString	keyidentifier;
+        internal readonly GeneralNames		certissuer;
+        internal readonly DerInteger		certserno;
+
+		public static AuthorityKeyIdentifier GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static AuthorityKeyIdentifier GetInstance(
+            object obj)
+        {
+            if (obj is AuthorityKeyIdentifier)
+            {
+                return (AuthorityKeyIdentifier) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new AuthorityKeyIdentifier((Asn1Sequence) obj);
+            }
+
+	        if (obj is X509Extension)
+			{
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		protected internal AuthorityKeyIdentifier(
+            Asn1Sequence seq)
+        {
+			foreach (Asn1TaggedObject o in seq)
+			{
+				switch (o.TagNo)
+                {
+					case 0:
+						this.keyidentifier = Asn1OctetString.GetInstance(o, false);
+						break;
+					case 1:
+						this.certissuer = GeneralNames.GetInstance(o, false);
+						break;
+					case 2:
+						this.certserno = DerInteger.GetInstance(o, false);
+						break;
+					default:
+						throw new ArgumentException("illegal tag");
+                }
+            }
+        }
+
+		/**
+         *
+         * Calulates the keyidentifier using a SHA1 hash over the BIT STRING
+         * from SubjectPublicKeyInfo as defined in RFC2459.
+         *
+         * Example of making a AuthorityKeyIdentifier:
+         * <pre>
+	     *   SubjectPublicKeyInfo apki = new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(
+		 *       publicKey.getEncoded()).readObject());
+         *   AuthorityKeyIdentifier aki = new AuthorityKeyIdentifier(apki);
+         * </pre>
+         *
+         **/
+        public AuthorityKeyIdentifier(
+            SubjectPublicKeyInfo spki)
+        {
+            IDigest digest = new Sha1Digest();
+            byte[] resBuf = new byte[digest.GetDigestSize()];
+
+			byte[] bytes = spki.PublicKeyData.GetBytes();
+            digest.BlockUpdate(bytes, 0, bytes.Length);
+            digest.DoFinal(resBuf, 0);
+            this.keyidentifier = new DerOctetString(resBuf);
+        }
+
+        /**
+         * create an AuthorityKeyIdentifier with the GeneralNames tag and
+         * the serial number provided as well.
+         */
+        public AuthorityKeyIdentifier(
+            SubjectPublicKeyInfo	spki,
+            GeneralNames			name,
+            BigInteger				serialNumber)
+        {
+            IDigest digest = new Sha1Digest();
+            byte[] resBuf = new byte[digest.GetDigestSize()];
+
+			byte[] bytes = spki.PublicKeyData.GetBytes();
+            digest.BlockUpdate(bytes, 0, bytes.Length);
+            digest.DoFinal(resBuf, 0);
+
+			this.keyidentifier = new DerOctetString(resBuf);
+            this.certissuer = name;
+            this.certserno = new DerInteger(serialNumber);
+        }
+
+		/**
+		 * create an AuthorityKeyIdentifier with the GeneralNames tag and
+		 * the serial number provided.
+		 */
+		public AuthorityKeyIdentifier(
+			GeneralNames	name,
+			BigInteger		serialNumber)
+		{
+			this.keyidentifier = null;
+			this.certissuer = GeneralNames.GetInstance(name.ToAsn1Object());
+			this.certserno = new DerInteger(serialNumber);
+		}
+
+		/**
+		 * create an AuthorityKeyIdentifier with a precomputed key identifier
+		 */
+		public AuthorityKeyIdentifier(
+			byte[] keyIdentifier)
+		{
+			this.keyidentifier = new DerOctetString(keyIdentifier);
+			this.certissuer = null;
+			this.certserno = null;
+		}
+
+		/**
+		 * create an AuthorityKeyIdentifier with a precomupted key identifier
+		 * and the GeneralNames tag and the serial number provided as well.
+		 */
+		public AuthorityKeyIdentifier(
+			byte[]			keyIdentifier,
+			GeneralNames	name,
+			BigInteger		serialNumber)
+		{
+			this.keyidentifier = new DerOctetString(keyIdentifier);
+			this.certissuer = GeneralNames.GetInstance(name.ToAsn1Object());
+			this.certserno = new DerInteger(serialNumber);
+		}
+
+		public byte[] GetKeyIdentifier()
+        {
+			return keyidentifier == null ? null : keyidentifier.GetOctets();
+        }
+
+		public GeneralNames AuthorityCertIssuer
+		{
+			get { return certissuer; }
+		}
+
+		public BigInteger AuthorityCertSerialNumber
+        {
+            get { return certserno == null ? null : certserno.Value; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (keyidentifier != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, keyidentifier));
+            }
+
+			if (certissuer != null)
+            {
+                v.Add(new DerTaggedObject(false, 1, certissuer));
+            }
+
+			if (certserno != null)
+            {
+                v.Add(new DerTaggedObject(false, 2, certserno));
+            }
+
+			return new DerSequence(v);
+        }
+
+		public override string ToString()
+        {
+            return ("AuthorityKeyIdentifier: KeyID(" + this.keyidentifier.GetOctets() + ")");
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/BasicConstraints.cs b/Crypto/src/asn1/x509/BasicConstraints.cs
new file mode 100644
index 000000000..522cb61cc
--- /dev/null
+++ b/Crypto/src/asn1/x509/BasicConstraints.cs
@@ -0,0 +1,133 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class BasicConstraints
+        : Asn1Encodable
+    {
+        private readonly DerBoolean	cA;
+        private readonly DerInteger	pathLenConstraint;
+
+		public static BasicConstraints GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static BasicConstraints GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is BasicConstraints)
+            {
+                return (BasicConstraints) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new BasicConstraints((Asn1Sequence) obj);
+            }
+
+			if (obj is X509Extension)
+			{
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private BasicConstraints(
+            Asn1Sequence seq)
+        {
+			if (seq.Count > 0)
+			{
+				if (seq[0] is DerBoolean)
+				{
+					this.cA = DerBoolean.GetInstance(seq[0]);
+				}
+				else
+				{
+					this.pathLenConstraint = DerInteger.GetInstance(seq[0]);
+				}
+
+				if (seq.Count > 1)
+				{
+					if (this.cA == null)
+						throw new ArgumentException("wrong sequence in constructor", "seq");
+
+					this.pathLenConstraint = DerInteger.GetInstance(seq[1]);
+				}
+			}
+        }
+
+		public BasicConstraints(
+            bool cA)
+        {
+			if (cA)
+			{
+				this.cA = DerBoolean.True;
+			}
+        }
+
+		/**
+         * create a cA=true object for the given path length constraint.
+         *
+         * @param pathLenConstraint
+         */
+        public BasicConstraints(
+            int pathLenConstraint)
+        {
+            this.cA = DerBoolean.True;
+            this.pathLenConstraint = new DerInteger(pathLenConstraint);
+        }
+
+		public bool IsCA()
+        {
+            return cA != null && cA.IsTrue;
+        }
+
+		public BigInteger PathLenConstraint
+        {
+            get { return pathLenConstraint == null ? null : pathLenConstraint.Value; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * BasicConstraints := Sequence {
+         *    cA                  Boolean DEFAULT FALSE,
+         *    pathLenConstraint   Integer (0..MAX) OPTIONAL
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (cA != null)
+			{
+				v.Add(cA);
+			}
+
+            if (pathLenConstraint != null)  // yes some people actually do this when cA is false...
+            {
+                v.Add(pathLenConstraint);
+            }
+
+			return new DerSequence(v);
+        }
+
+		public override string ToString()
+        {
+            if (pathLenConstraint == null)
+            {
+				return "BasicConstraints: isCa(" + this.IsCA() + ")";
+            }
+
+			return "BasicConstraints: isCa(" + this.IsCA() + "), pathLenConstraint = " + pathLenConstraint.Value;
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/CRLDistPoint.cs b/Crypto/src/asn1/x509/CRLDistPoint.cs
new file mode 100644
index 000000000..2b5c19798
--- /dev/null
+++ b/Crypto/src/asn1/x509/CRLDistPoint.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class CrlDistPoint
+        : Asn1Encodable
+    {
+        internal readonly Asn1Sequence seq;
+
+		public static CrlDistPoint GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static CrlDistPoint GetInstance(
+            object obj)
+        {
+            if (obj is CrlDistPoint || obj == null)
+            {
+                return (CrlDistPoint) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new CrlDistPoint((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private CrlDistPoint(
+            Asn1Sequence seq)
+        {
+            this.seq = seq;
+        }
+
+		public CrlDistPoint(
+            DistributionPoint[] points)
+        {
+			seq = new DerSequence(points);
+        }
+
+		/**
+         * Return the distribution points making up the sequence.
+         *
+         * @return DistributionPoint[]
+         */
+        public DistributionPoint[] GetDistributionPoints()
+        {
+            DistributionPoint[] dp = new DistributionPoint[seq.Count];
+
+			for (int i = 0; i != seq.Count; ++i)
+            {
+                dp[i] = DistributionPoint.GetInstance(seq[i]);
+            }
+
+			return dp;
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * CrlDistPoint ::= Sequence SIZE {1..MAX} OF DistributionPoint
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return seq;
+        }
+
+		public override string ToString()
+		{
+			StringBuilder buf = new StringBuilder();
+			string sep = Platform.NewLine;
+
+			buf.Append("CRLDistPoint:");
+			buf.Append(sep);
+			DistributionPoint[] dp = GetDistributionPoints();
+			for (int i = 0; i != dp.Length; i++)
+			{
+				buf.Append("    ");
+				buf.Append(dp[i]);
+				buf.Append(sep);
+			}
+			return buf.ToString();
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/CRLNumber.cs b/Crypto/src/asn1/x509/CRLNumber.cs
new file mode 100644
index 000000000..d744416a5
--- /dev/null
+++ b/Crypto/src/asn1/x509/CRLNumber.cs
@@ -0,0 +1,30 @@
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The CRLNumber object.
+     * <pre>
+     * CRLNumber::= Integer(0..MAX)
+     * </pre>
+     */
+    public class CrlNumber
+        : DerInteger
+    {
+        public CrlNumber(
+			BigInteger number)
+			: base(number)
+        {
+        }
+
+		public BigInteger Number
+		{
+			get { return PositiveValue; }
+		}
+
+		public override string ToString()
+		{
+			return "CRLNumber: " + Number;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/CRLReason.cs b/Crypto/src/asn1/x509/CRLReason.cs
new file mode 100644
index 000000000..e8eb53a59
--- /dev/null
+++ b/Crypto/src/asn1/x509/CRLReason.cs
@@ -0,0 +1,61 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The CRLReason enumeration.
+     * <pre>
+     * CRLReason ::= Enumerated {
+     *  unspecified             (0),
+     *  keyCompromise           (1),
+     *  cACompromise            (2),
+     *  affiliationChanged      (3),
+     *  superseded              (4),
+     *  cessationOfOperation    (5),
+     *  certificateHold         (6),
+     *  removeFromCRL           (8),
+     *  privilegeWithdrawn      (9),
+     *  aACompromise           (10)
+     * }
+     * </pre>
+     */
+    public class CrlReason
+        : DerEnumerated
+    {
+        public const int Unspecified = 0;
+        public const int KeyCompromise = 1;
+        public const int CACompromise = 2;
+        public const int AffiliationChanged = 3;
+        public const int Superseded = 4;
+        public const int CessationOfOperation  = 5;
+        public const int CertificateHold = 6;
+		// 7 -> Unknown
+        public const int RemoveFromCrl = 8;
+        public const int PrivilegeWithdrawn = 9;
+        public const int AACompromise = 10;
+
+		private static readonly string[] ReasonString = new string[]
+		{
+			"Unspecified", "KeyCompromise", "CACompromise", "AffiliationChanged",
+			"Superseded", "CessationOfOperation", "CertificateHold", "Unknown",
+			"RemoveFromCrl", "PrivilegeWithdrawn", "AACompromise"
+		};
+
+		public CrlReason(
+			int reason)
+			: base(reason)
+        {
+        }
+
+		public CrlReason(
+			DerEnumerated reason)
+			: base(reason.Value.IntValue)
+        {
+        }
+
+		public override string ToString()
+		{
+			int reason = Value.IntValue;
+			string str = (reason < 0 || reason > 10) ? "Invalid" : ReasonString[reason];
+			return "CrlReason: " + str;
+		}    
+	}
+}
diff --git a/Crypto/src/asn1/x509/CertPolicyId.cs b/Crypto/src/asn1/x509/CertPolicyId.cs
new file mode 100644
index 000000000..11cebcdd7
--- /dev/null
+++ b/Crypto/src/asn1/x509/CertPolicyId.cs
@@ -0,0 +1,20 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * CertPolicyId, used in the CertificatePolicies and PolicyMappings
+     * X509V3 Extensions.
+     *
+     * <pre>
+     *     CertPolicyId ::= OBJECT IDENTIFIER
+     * </pre>
+     */
+     public class CertPolicyID
+		 : DerObjectIdentifier
+    {
+       public CertPolicyID(
+		   string id)
+		   : base(id)
+       {
+       }
+    }
+}
diff --git a/Crypto/src/asn1/x509/CertificateList.cs b/Crypto/src/asn1/x509/CertificateList.cs
new file mode 100644
index 000000000..0412e0816
--- /dev/null
+++ b/Crypto/src/asn1/x509/CertificateList.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * PKIX RFC-2459
+     *
+     * The X.509 v2 CRL syntax is as follows.  For signature calculation,
+     * the data that is to be signed is ASN.1 Der encoded.
+     *
+     * <pre>
+     * CertificateList  ::=  Sequence  {
+     *      tbsCertList          TbsCertList,
+     *      signatureAlgorithm   AlgorithmIdentifier,
+     *      signatureValue       BIT STRING  }
+     * </pre>
+     */
+    public class CertificateList
+        : Asn1Encodable
+    {
+        private readonly TbsCertificateList	tbsCertList;
+        private readonly AlgorithmIdentifier sigAlgID;
+        private readonly DerBitString sig;
+
+		public static CertificateList GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static CertificateList GetInstance(
+            object obj)
+        {
+            if (obj is CertificateList)
+                return (CertificateList) obj;
+
+			if (obj != null)
+				return new CertificateList(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		private CertificateList(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 3)
+				throw new ArgumentException("sequence wrong size for CertificateList", "seq");
+
+			tbsCertList = TbsCertificateList.GetInstance(seq[0]);
+			sigAlgID = AlgorithmIdentifier.GetInstance(seq[1]);
+			sig = DerBitString.GetInstance(seq[2]);
+        }
+
+		public TbsCertificateList TbsCertList
+		{
+			get { return tbsCertList; }
+		}
+
+		public CrlEntry[] GetRevokedCertificates()
+        {
+            return tbsCertList.GetRevokedCertificates();
+        }
+
+		public IEnumerable GetRevokedCertificateEnumeration()
+		{
+			return tbsCertList.GetRevokedCertificateEnumeration();
+		}
+
+		public AlgorithmIdentifier SignatureAlgorithm
+		{
+			get { return sigAlgID; }
+		}
+
+		public DerBitString Signature
+		{
+			get { return sig; }
+		}
+
+		public int Version
+		{
+			get { return tbsCertList.Version; }
+		}
+
+		public X509Name Issuer
+		{
+			get { return tbsCertList.Issuer; }
+		}
+
+		public Time ThisUpdate
+		{
+			get { return tbsCertList.ThisUpdate; }
+		}
+
+		public Time NextUpdate
+		{
+			get { return tbsCertList.NextUpdate; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(tbsCertList, sigAlgID, sig);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/CertificatePair.cs b/Crypto/src/asn1/x509/CertificatePair.cs
new file mode 100644
index 000000000..8baa64719
--- /dev/null
+++ b/Crypto/src/asn1/x509/CertificatePair.cs
@@ -0,0 +1,160 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	* This class helps to support crossCerfificatePairs in a LDAP directory
+	* according RFC 2587
+	*
+	* <pre>
+	*     crossCertificatePairATTRIBUTE::={
+	*       WITH SYNTAX   CertificatePair
+	*       EQUALITY MATCHING RULE certificatePairExactMatch
+	*       ID joint-iso-ccitt(2) ds(5) attributeType(4) crossCertificatePair(40)}
+	* </pre>
+	*
+	* <blockquote> The forward elements of the crossCertificatePair attribute of a
+	* CA's directory entry shall be used to store all, except self-issued
+	* certificates issued to this CA. Optionally, the reverse elements of the
+	* crossCertificatePair attribute, of a CA's directory entry may contain a
+	* subset of certificates issued by this CA to other CAs. When both the forward
+	* and the reverse elements are present in a single attribute value, issuer name
+	* in one certificate shall match the subject name in the other and vice versa,
+	* and the subject public key in one certificate shall be capable of verifying
+	* the digital signature on the other certificate and vice versa.
+	*
+	* When a reverse element is present, the forward element value and the reverse
+	* element value need not be stored in the same attribute value; in other words,
+	* they can be stored in either a single attribute value or two attribute
+	* values. </blockquote>
+	*
+	* <pre>
+	*       CertificatePair ::= SEQUENCE {
+	*         forward		[0]	Certificate OPTIONAL,
+	*         reverse		[1]	Certificate OPTIONAL,
+	*         -- at least one of the pair shall be present -- }
+	* </pre>
+	*/
+	public class CertificatePair
+		: Asn1Encodable
+	{
+		private X509CertificateStructure forward, reverse;
+
+		public static CertificatePair GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CertificatePair)
+			{
+				return (CertificatePair) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new CertificatePair((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		* Constructor from Asn1Sequence.
+		* <p/>
+		* The sequence is of type CertificatePair:
+		* <p/>
+		* <pre>
+		*       CertificatePair ::= SEQUENCE {
+		*         forward		[0]	Certificate OPTIONAL,
+		*         reverse		[1]	Certificate OPTIONAL,
+		*         -- at least one of the pair shall be present -- }
+		* </pre>
+		*
+		* @param seq The ASN.1 sequence.
+		*/
+		private CertificatePair(
+			Asn1Sequence seq)
+		{
+			if (seq.Count != 1 && seq.Count != 2)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+			}
+
+			foreach (object obj in seq)
+			{
+				Asn1TaggedObject o = Asn1TaggedObject.GetInstance(obj);
+				if (o.TagNo == 0)
+				{
+					forward = X509CertificateStructure.GetInstance(o, true);
+				}
+				else if (o.TagNo == 1)
+				{
+					reverse = X509CertificateStructure.GetInstance(o, true);
+				}
+				else
+				{
+					throw new ArgumentException("Bad tag number: " + o.TagNo);
+				}
+			}
+		}
+
+		/**
+		* Constructor from a given details.
+		*
+		* @param forward Certificates issued to this CA.
+		* @param reverse Certificates issued by this CA to other CAs.
+		*/
+		public CertificatePair(
+			X509CertificateStructure	forward,
+			X509CertificateStructure	reverse)
+		{
+			this.forward = forward;
+			this.reverse = reverse;
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*       CertificatePair ::= SEQUENCE {
+		*         forward		[0]	Certificate OPTIONAL,
+		*         reverse		[1]	Certificate OPTIONAL,
+		*         -- at least one of the pair shall be present -- }
+		* </pre>
+		*
+		* @return a DERObject
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector vec = new Asn1EncodableVector();
+
+			if (forward != null)
+			{
+				vec.Add(new DerTaggedObject(0, forward));
+			}
+
+			if (reverse != null)
+			{
+				vec.Add(new DerTaggedObject(1, reverse));
+			}
+
+			return new DerSequence(vec);
+		}
+
+		/**
+		* @return Returns the forward.
+		*/
+		public X509CertificateStructure Forward
+		{
+			get { return forward; }
+		}
+
+		/**
+		* @return Returns the reverse.
+		*/
+		public X509CertificateStructure Reverse
+		{
+			get { return reverse; }
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/DSAParameter.cs b/Crypto/src/asn1/x509/DSAParameter.cs
new file mode 100644
index 000000000..b2b325f4d
--- /dev/null
+++ b/Crypto/src/asn1/x509/DSAParameter.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class DsaParameter
+        : Asn1Encodable
+    {
+        internal readonly DerInteger p, q, g;
+
+		public static DsaParameter GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static DsaParameter GetInstance(
+            object obj)
+        {
+            if(obj == null || obj is DsaParameter)
+            {
+                return (DsaParameter) obj;
+            }
+
+			if(obj is Asn1Sequence)
+            {
+                return new DsaParameter((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Invalid DsaParameter: " + obj.GetType().Name);
+        }
+
+		public DsaParameter(
+            BigInteger	p,
+            BigInteger	q,
+            BigInteger	g)
+        {
+            this.p = new DerInteger(p);
+            this.q = new DerInteger(q);
+            this.g = new DerInteger(g);
+        }
+
+		private DsaParameter(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.p = DerInteger.GetInstance(seq[0]);
+			this.q = DerInteger.GetInstance(seq[1]);
+			this.g = DerInteger.GetInstance(seq[2]);
+        }
+
+		public BigInteger P
+		{
+			get { return p.PositiveValue; }
+		}
+
+		public BigInteger Q
+		{
+			get { return q.PositiveValue; }
+		}
+
+		public BigInteger G
+		{
+			get { return g.PositiveValue; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(p, q, g);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/DigestInfo.cs b/Crypto/src/asn1/x509/DigestInfo.cs
new file mode 100644
index 000000000..1dec227fa
--- /dev/null
+++ b/Crypto/src/asn1/x509/DigestInfo.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The DigestInfo object.
+     * <pre>
+     * DigestInfo::=Sequence{
+     *          digestAlgorithm  AlgorithmIdentifier,
+     *          digest OCTET STRING }
+     * </pre>
+     */
+    public class DigestInfo
+        : Asn1Encodable
+    {
+        private readonly byte[] digest;
+        private readonly AlgorithmIdentifier algID;
+
+		public static DigestInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static DigestInfo GetInstance(
+            object obj)
+        {
+            if (obj is DigestInfo)
+            {
+                return (DigestInfo) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new DigestInfo((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public DigestInfo(
+            AlgorithmIdentifier	algID,
+            byte[]				digest)
+        {
+            this.digest = digest;
+            this.algID = algID;
+        }
+
+		private DigestInfo(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+            algID = AlgorithmIdentifier.GetInstance(seq[0]);
+			digest = Asn1OctetString.GetInstance(seq[1]).GetOctets();
+		}
+
+		public AlgorithmIdentifier AlgorithmID
+		{
+			get { return algID; }
+		}
+
+		public byte[] GetDigest()
+        {
+            return digest;
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(algID, new DerOctetString(digest));
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/DisplayText.cs b/Crypto/src/asn1/x509/DisplayText.cs
new file mode 100644
index 000000000..699f39031
--- /dev/null
+++ b/Crypto/src/asn1/x509/DisplayText.cs
@@ -0,0 +1,172 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * <code>DisplayText</code> class, used in
+	 * <code>CertificatePolicies</code> X509 V3 extensions (in policy qualifiers).
+	 *
+	 * <p>It stores a string in a chosen encoding.
+	 * <pre>
+	 * DisplayText ::= CHOICE {
+	 *      ia5String        IA5String      (SIZE (1..200)),
+	 *      visibleString    VisibleString  (SIZE (1..200)),
+	 *      bmpString        BMPString      (SIZE (1..200)),
+	 *      utf8String       UTF8String     (SIZE (1..200)) }
+	 * </pre></p>
+	 * @see PolicyQualifierInfo
+	 * @see PolicyInformation
+	 */
+	public class DisplayText
+		: Asn1Encodable, IAsn1Choice
+	{
+		/**
+		 * Constant corresponding to ia5String encoding.
+		 *
+		 */
+		public const int ContentTypeIA5String = 0;
+		/**
+		 * Constant corresponding to bmpString encoding.
+		 *
+		 */
+		public const int ContentTypeBmpString = 1;
+		/**
+		 * Constant corresponding to utf8String encoding.
+		 *
+		 */
+		public const int ContentTypeUtf8String = 2;
+		/**
+		 * Constant corresponding to visibleString encoding.
+		 *
+		 */
+		public const int ContentTypeVisibleString = 3;
+		/**
+		 * Describe constant <code>DisplayTextMaximumSize</code> here.
+		 *
+		 */
+		public const int DisplayTextMaximumSize = 200;
+
+		internal readonly int contentType;
+		internal readonly IAsn1String contents;
+
+		/**
+		 * Creates a new <code>DisplayText</code> instance.
+		 *
+		 * @param type the desired encoding type for the text.
+		 * @param text the text to store. Strings longer than 200
+		 * characters are truncated.
+		 */
+		public DisplayText(
+			int		type,
+			string	text)
+		{
+			if (text.Length > DisplayTextMaximumSize)
+			{
+				// RFC3280 limits these strings to 200 chars
+				// truncate the string
+				text = text.Substring(0, DisplayTextMaximumSize);
+			}
+
+			contentType = type;
+			switch (type)
+			{
+				case ContentTypeIA5String:
+					contents = (IAsn1String)new DerIA5String (text);
+					break;
+				case ContentTypeUtf8String:
+					contents = (IAsn1String)new DerUtf8String(text);
+					break;
+				case ContentTypeVisibleString:
+					contents = (IAsn1String)new DerVisibleString(text);
+					break;
+				case ContentTypeBmpString:
+					contents = (IAsn1String)new DerBmpString(text);
+					break;
+				default:
+					contents = (IAsn1String)new DerUtf8String(text);
+					break;
+			}
+		}
+
+//		/**
+//		 * return true if the passed in string can be represented without
+//		 * loss as a PrintableString, false otherwise.
+//		 */
+//		private bool CanBePrintable(
+//			string str)
+//		{
+//			for (int i = str.Length - 1; i >= 0; i--)
+//			{
+//				if (str[i] > 0x007f)
+//				{
+//					return false;
+//				}
+//			}
+//
+//			return true;
+//		}
+
+		/**
+		 * Creates a new <code>DisplayText</code> instance.
+		 *
+		 * @param text the text to encapsulate. Strings longer than 200
+		 * characters are truncated.
+		 */
+		public DisplayText(
+			string text)
+		{
+			// by default use UTF8String
+			if (text.Length > DisplayTextMaximumSize)
+			{
+				text = text.Substring(0, DisplayTextMaximumSize);
+			}
+
+			contentType = ContentTypeUtf8String;
+			contents = new DerUtf8String(text);
+		}
+
+		/**
+		 * Creates a new <code>DisplayText</code> instance.
+		 * <p>Useful when reading back a <code>DisplayText</code> class
+		 * from it's Asn1Encodable form.</p>
+		 *
+		 * @param contents an <code>Asn1Encodable</code> instance.
+		 */
+		public DisplayText(
+			IAsn1String contents)
+		{
+			this.contents = contents;
+		}
+
+		public static DisplayText GetInstance(
+			object obj)
+		{
+			if (obj is IAsn1String)
+			{
+				return new DisplayText((IAsn1String) obj);
+			}
+
+			if (obj is DisplayText)
+			{
+				return (DisplayText) obj;
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return (Asn1Object) contents;
+		}
+
+		/**
+		 * Returns the stored <code>string</code> object.
+		 *
+		 * @return the stored text as a <code>string</code>.
+		 */
+		public string GetString()
+		{
+			return contents.GetString();
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/DistributionPoint.cs b/Crypto/src/asn1/x509/DistributionPoint.cs
new file mode 100644
index 000000000..ad1d3989e
--- /dev/null
+++ b/Crypto/src/asn1/x509/DistributionPoint.cs
@@ -0,0 +1,161 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The DistributionPoint object.
+     * <pre>
+     * DistributionPoint ::= Sequence {
+     *      distributionPoint [0] DistributionPointName OPTIONAL,
+     *      reasons           [1] ReasonFlags OPTIONAL,
+     *      cRLIssuer         [2] GeneralNames OPTIONAL
+     * }
+     * </pre>
+     */
+    public class DistributionPoint
+        : Asn1Encodable
+    {
+        internal readonly DistributionPointName	distributionPoint;
+        internal readonly ReasonFlags			reasons;
+        internal readonly GeneralNames			cRLIssuer;
+
+		public static DistributionPoint GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static DistributionPoint GetInstance(
+            object obj)
+        {
+            if(obj == null || obj is DistributionPoint)
+            {
+                return (DistributionPoint) obj;
+            }
+
+			if(obj is Asn1Sequence)
+            {
+                return new DistributionPoint((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Invalid DistributionPoint: " + obj.GetType().Name);
+        }
+
+		private DistributionPoint(
+            Asn1Sequence seq)
+        {
+            for (int i = 0; i != seq.Count; i++)
+            {
+				Asn1TaggedObject t = Asn1TaggedObject.GetInstance(seq[i]);
+
+				switch (t.TagNo)
+                {
+                case 0:
+                    distributionPoint = DistributionPointName.GetInstance(t, true);
+                    break;
+                case 1:
+                    reasons = new ReasonFlags(DerBitString.GetInstance(t, false));
+                    break;
+                case 2:
+                    cRLIssuer = GeneralNames.GetInstance(t, false);
+                    break;
+                }
+            }
+        }
+
+		public DistributionPoint(
+            DistributionPointName	distributionPointName,
+            ReasonFlags				reasons,
+            GeneralNames			crlIssuer)
+        {
+            this.distributionPoint = distributionPointName;
+            this.reasons = reasons;
+            this.cRLIssuer = crlIssuer;
+        }
+
+		public DistributionPointName DistributionPointName
+        {
+			get { return distributionPoint; }
+        }
+
+		public ReasonFlags Reasons
+        {
+			get { return reasons; }
+        }
+
+		public GeneralNames CrlIssuer
+        {
+			get { return cRLIssuer; }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (distributionPoint != null)
+            {
+                //
+                // as this is a CHOICE it must be explicitly tagged
+                //
+                v.Add(new DerTaggedObject(0, distributionPoint));
+            }
+
+			if (reasons != null)
+            {
+                v.Add(new DerTaggedObject(false, 1, reasons));
+            }
+
+			if (cRLIssuer != null)
+            {
+                v.Add(new DerTaggedObject(false, 2, cRLIssuer));
+            }
+
+			return new DerSequence(v);
+        }
+
+		public override string ToString()
+		{
+			string sep = Platform.NewLine;
+			StringBuilder buf = new StringBuilder();
+			buf.Append("DistributionPoint: [");
+			buf.Append(sep);
+			if (distributionPoint != null)
+			{
+				appendObject(buf, sep, "distributionPoint", distributionPoint.ToString());
+			}
+			if (reasons != null)
+			{
+				appendObject(buf, sep, "reasons", reasons.ToString());
+			}
+			if (cRLIssuer != null)
+			{
+				appendObject(buf, sep, "cRLIssuer", cRLIssuer.ToString());
+			}
+			buf.Append("]");
+			buf.Append(sep);
+			return buf.ToString();
+		}
+
+		private void appendObject(
+			StringBuilder	buf,
+			string			sep,
+			string			name,
+			string			val)
+		{
+			string indent = "    ";
+
+			buf.Append(indent);
+			buf.Append(name);
+			buf.Append(":");
+			buf.Append(sep);
+			buf.Append(indent);
+			buf.Append(indent);
+			buf.Append(val);
+			buf.Append(sep);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/DistributionPointName.cs b/Crypto/src/asn1/x509/DistributionPointName.cs
new file mode 100644
index 000000000..1a9d24241
--- /dev/null
+++ b/Crypto/src/asn1/x509/DistributionPointName.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The DistributionPointName object.
+     * <pre>
+     * DistributionPointName ::= CHOICE {
+     *     fullName                 [0] GeneralNames,
+     *     nameRelativeToCRLIssuer  [1] RDN
+     * }
+     * </pre>
+     */
+    public class DistributionPointName
+        : Asn1Encodable, IAsn1Choice
+    {
+        internal readonly Asn1Encodable	name;
+        internal readonly int			type;
+
+		public const int FullName					= 0;
+        public const int NameRelativeToCrlIssuer	= 1;
+
+		public static DistributionPointName GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1TaggedObject.GetInstance(obj, true));
+        }
+
+		public static DistributionPointName GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DistributionPointName)
+            {
+                return (DistributionPointName) obj;
+            }
+
+			if (obj is Asn1TaggedObject)
+            {
+                return new DistributionPointName((Asn1TaggedObject) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+        public DistributionPointName(
+            int				type,
+            Asn1Encodable	name)
+        {
+            this.type = type;
+            this.name = name;
+        }
+
+		public DistributionPointName(
+			GeneralNames name)
+			:	this(FullName, name)
+		{
+		}
+
+		public int PointType
+        {
+			get { return type; }
+        }
+
+		public Asn1Encodable Name
+        {
+			get { return name; }
+        }
+
+		public DistributionPointName(
+            Asn1TaggedObject obj)
+        {
+            this.type = obj.TagNo;
+
+			if (type == FullName)
+            {
+                this.name = GeneralNames.GetInstance(obj, false);
+            }
+            else
+            {
+                this.name = Asn1Set.GetInstance(obj, false);
+            }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return new DerTaggedObject(false, type, name);
+        }
+
+		public override string ToString()
+		{
+			string sep = Platform.NewLine;
+			StringBuilder buf = new StringBuilder();
+			buf.Append("DistributionPointName: [");
+			buf.Append(sep);
+			if (type == FullName)
+			{
+				appendObject(buf, sep, "fullName", name.ToString());
+			}
+			else
+			{
+				appendObject(buf, sep, "nameRelativeToCRLIssuer", name.ToString());
+			}
+			buf.Append("]");
+			buf.Append(sep);
+			return buf.ToString();
+		}
+
+		private void appendObject(
+			StringBuilder	buf,
+			string			sep,
+			string			name,
+			string			val)
+		{
+			string indent = "    ";
+
+			buf.Append(indent);
+			buf.Append(name);
+			buf.Append(":");
+			buf.Append(sep);
+			buf.Append(indent);
+			buf.Append(indent);
+			buf.Append(val);
+			buf.Append(sep);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/ExtendedKeyUsage.cs b/Crypto/src/asn1/x509/ExtendedKeyUsage.cs
new file mode 100644
index 000000000..3bf79f392
--- /dev/null
+++ b/Crypto/src/asn1/x509/ExtendedKeyUsage.cs
@@ -0,0 +1,131 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The extendedKeyUsage object.
+     * <pre>
+     *      extendedKeyUsage ::= Sequence SIZE (1..MAX) OF KeyPurposeId
+     * </pre>
+     */
+    public class ExtendedKeyUsage
+        : Asn1Encodable
+    {
+        internal readonly IDictionary usageTable = Platform.CreateHashtable();
+        internal readonly Asn1Sequence seq;
+
+		public static ExtendedKeyUsage GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static ExtendedKeyUsage GetInstance(
+            object obj)
+        {
+            if (obj is ExtendedKeyUsage)
+            {
+                return (ExtendedKeyUsage) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new ExtendedKeyUsage((Asn1Sequence) obj);
+            }
+
+			if (obj is X509Extension)
+			{
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+			}
+
+			throw new ArgumentException("Invalid ExtendedKeyUsage: " + obj.GetType().Name);
+        }
+
+		private ExtendedKeyUsage(
+            Asn1Sequence seq)
+        {
+            this.seq = seq;
+
+			foreach (object o in seq)
+			{
+				if (!(o is DerObjectIdentifier))
+					throw new ArgumentException("Only DerObjectIdentifier instances allowed in ExtendedKeyUsage.");
+
+				this.usageTable.Add(o, o);
+            }
+        }
+
+		public ExtendedKeyUsage(
+			params KeyPurposeID[] usages)
+		{
+			this.seq = new DerSequence(usages);
+
+			foreach (KeyPurposeID usage in usages)
+			{
+				this.usageTable.Add(usage, usage);
+			}
+		}
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete]
+        public ExtendedKeyUsage(
+            ArrayList usages)
+            : this((IEnumerable)usages)
+        {
+        }
+#endif
+
+        public ExtendedKeyUsage(
+            IEnumerable usages)
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			foreach (Asn1Object o in usages)
+            {
+				v.Add(o);
+
+				this.usageTable.Add(o, o);
+            }
+
+			this.seq = new DerSequence(v);
+        }
+
+		public bool HasKeyPurposeId(
+            KeyPurposeID keyPurposeId)
+        {
+            return usageTable[keyPurposeId] != null;
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete("Use 'GetAllUsages'")]
+        public ArrayList GetUsages()
+        {
+            return new ArrayList(usageTable.Values);
+        }
+#endif
+
+        /**
+		 * Returns all extended key usages.
+		 * The returned ArrayList contains DerObjectIdentifier instances.
+		 * @return An ArrayList with all key purposes.
+		 */
+		public IList GetAllUsages()
+		{
+			return Platform.CreateArrayList(usageTable.Values);
+		}
+
+        public int Count
+		{
+			get { return usageTable.Count; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return seq;
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/GeneralName.cs b/Crypto/src/asn1/x509/GeneralName.cs
new file mode 100644
index 000000000..710ddc922
--- /dev/null
+++ b/Crypto/src/asn1/x509/GeneralName.cs
@@ -0,0 +1,418 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+using NetUtils = Org.BouncyCastle.Utilities.Net;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The GeneralName object.
+     * <pre>
+     * GeneralName ::= CHOICE {
+     *      otherName                       [0]     OtherName,
+     *      rfc822Name                      [1]     IA5String,
+     *      dNSName                         [2]     IA5String,
+     *      x400Address                     [3]     ORAddress,
+     *      directoryName                   [4]     Name,
+     *      ediPartyName                    [5]     EDIPartyName,
+     *      uniformResourceIdentifier       [6]     IA5String,
+     *      iPAddress                       [7]     OCTET STRING,
+     *      registeredID                    [8]     OBJECT IDENTIFIER}
+     *
+     * OtherName ::= Sequence {
+     *      type-id    OBJECT IDENTIFIER,
+     *      value      [0] EXPLICIT ANY DEFINED BY type-id }
+     *
+     * EDIPartyName ::= Sequence {
+     *      nameAssigner            [0]     DirectoryString OPTIONAL,
+     *      partyName               [1]     DirectoryString }
+     * </pre>
+     */
+    public class GeneralName
+        : Asn1Encodable, IAsn1Choice
+    {
+        public const int OtherName					= 0;
+        public const int Rfc822Name					= 1;
+        public const int DnsName					= 2;
+        public const int X400Address				= 3;
+        public const int DirectoryName				= 4;
+        public const int EdiPartyName				= 5;
+        public const int UniformResourceIdentifier	= 6;
+        public const int IPAddress					= 7;
+        public const int RegisteredID				= 8;
+
+		internal readonly Asn1Encodable	obj;
+        internal readonly int			tag;
+
+		public GeneralName(
+            X509Name directoryName)
+        {
+            this.obj = directoryName;
+            this.tag = 4;
+        }
+
+		/**
+         * When the subjectAltName extension contains an Internet mail address,
+         * the address MUST be included as an rfc822Name. The format of an
+         * rfc822Name is an "addr-spec" as defined in RFC 822 [RFC 822].
+         *
+         * When the subjectAltName extension contains a domain name service
+         * label, the domain name MUST be stored in the dNSName (an IA5String).
+         * The name MUST be in the "preferred name syntax," as specified by RFC
+         * 1034 [RFC 1034].
+         *
+         * When the subjectAltName extension contains a URI, the name MUST be
+         * stored in the uniformResourceIdentifier (an IA5String). The name MUST
+         * be a non-relative URL, and MUST follow the URL syntax and encoding
+         * rules specified in [RFC 1738].  The name must include both a scheme
+         * (e.g., "http" or "ftp") and a scheme-specific-part.  The scheme-
+         * specific-part must include a fully qualified domain name or IP
+         * address as the host.
+         *
+         * When the subjectAltName extension contains a iPAddress, the address
+         * MUST be stored in the octet string in "network byte order," as
+         * specified in RFC 791 [RFC 791]. The least significant bit (LSB) of
+         * each octet is the LSB of the corresponding byte in the network
+         * address. For IP Version 4, as specified in RFC 791, the octet string
+         * MUST contain exactly four octets.  For IP Version 6, as specified in
+         * RFC 1883, the octet string MUST contain exactly sixteen octets [RFC
+         * 1883].
+         */
+        public GeneralName(
+            Asn1Object	name,
+			int			tag)
+        {
+            this.obj = name;
+            this.tag = tag;
+        }
+
+		public GeneralName(
+            int				tag,
+            Asn1Encodable	name)
+        {
+            this.obj = name;
+            this.tag = tag;
+        }
+
+		/**
+		 * Create a GeneralName for the given tag from the passed in string.
+		 * <p>
+		 * This constructor can handle:
+		 * <ul>
+		 * <li>rfc822Name</li>
+		 * <li>iPAddress</li>
+		 * <li>directoryName</li>
+		 * <li>dNSName</li>
+		 * <li>uniformResourceIdentifier</li>
+		 * <li>registeredID</li>
+		 * </ul>
+		 * For x400Address, otherName and ediPartyName there is no common string
+		 * format defined.
+		 * </p><p>
+		 * Note: A directory name can be encoded in different ways into a byte
+		 * representation. Be aware of this if the byte representation is used for
+		 * comparing results.
+		 * </p>
+		 *
+		 * @param tag tag number
+		 * @param name string representation of name
+		 * @throws ArgumentException if the string encoding is not correct or
+		 *             not supported.
+		 */
+		public GeneralName(
+            int		tag,
+            string	name)
+        {
+			this.tag = tag;
+
+			if (tag == Rfc822Name || tag == DnsName || tag == UniformResourceIdentifier)
+			{
+				this.obj = new DerIA5String(name);
+			}
+			else if (tag == RegisteredID)
+			{
+				this.obj = new DerObjectIdentifier(name);
+			}
+			else if (tag == DirectoryName)
+			{
+				this.obj = new X509Name(name);
+			}
+			else if (tag == IPAddress)
+			{
+				byte[] enc = toGeneralNameEncoding(name);
+				if (enc == null)
+					throw new ArgumentException("IP Address is invalid", "name");
+
+				this.obj = new DerOctetString(enc);
+			}
+			else
+			{
+				throw new ArgumentException("can't process string for tag: " + tag, "tag");
+			}
+		}
+
+		public static GeneralName GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is GeneralName)
+            {
+                return (GeneralName) obj;
+            }
+
+            if (obj is Asn1TaggedObject)
+            {
+                Asn1TaggedObject	tagObj = (Asn1TaggedObject) obj;
+                int					tag = tagObj.TagNo;
+
+				switch (tag)
+				{
+					case OtherName:
+						return new GeneralName(tag, Asn1Sequence.GetInstance(tagObj, false));
+					case Rfc822Name:
+						return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false));
+					case DnsName:
+						return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false));
+					case X400Address:
+						throw new ArgumentException("unknown tag: " + tag);
+					case DirectoryName:
+						return new GeneralName(tag, X509Name.GetInstance(tagObj, true));
+					case EdiPartyName:
+						return new GeneralName(tag, Asn1Sequence.GetInstance(tagObj, false));
+					case UniformResourceIdentifier:
+						return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false));
+					case IPAddress:
+						return new GeneralName(tag, Asn1OctetString.GetInstance(tagObj, false));
+					case RegisteredID:
+						return new GeneralName(tag, DerObjectIdentifier.GetInstance(tagObj, false));
+				}
+	        }
+
+            if (obj is byte[])
+	        {
+	            try
+	            {
+	                return GetInstance(Asn1Object.FromByteArray((byte[])obj));
+	            }
+	            catch (IOException)
+	            {
+	                throw new ArgumentException("unable to parse encoded general name");
+	            }
+	        }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		public static GeneralName GetInstance(
+            Asn1TaggedObject	tagObj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1TaggedObject.GetInstance(tagObj, true));
+        }
+
+		public int TagNo
+		{
+			get { return tag; }
+		}
+
+		public Asn1Encodable Name
+		{
+			get { return obj; }
+		}
+
+		public override string ToString()
+		{
+			StringBuilder buf = new StringBuilder();
+			buf.Append(tag);
+			buf.Append(": ");
+
+			switch (tag)
+			{
+				case Rfc822Name:
+				case DnsName:
+				case UniformResourceIdentifier:
+					buf.Append(DerIA5String.GetInstance(obj).GetString());
+					break;
+				case DirectoryName:
+					buf.Append(X509Name.GetInstance(obj).ToString());
+					break;
+				default:
+					buf.Append(obj.ToString());
+					break;
+			}
+
+			return buf.ToString();
+		}
+
+		private byte[] toGeneralNameEncoding(
+			string ip)
+		{
+			if (NetUtils.IPAddress.IsValidIPv6WithNetmask(ip) || NetUtils.IPAddress.IsValidIPv6(ip))
+			{
+				int slashIndex = ip.IndexOf('/');
+
+				if (slashIndex < 0)
+				{
+					byte[] addr = new byte[16];
+					int[]  parsedIp = parseIPv6(ip);
+					copyInts(parsedIp, addr, 0);
+
+					return addr;
+				}
+				else
+				{
+					byte[] addr = new byte[32];
+					int[]  parsedIp = parseIPv6(ip.Substring(0, slashIndex));
+					copyInts(parsedIp, addr, 0);
+					string mask = ip.Substring(slashIndex + 1);
+					if (mask.IndexOf(':') > 0)
+					{
+						parsedIp = parseIPv6(mask);
+					}
+					else
+					{
+						parsedIp = parseMask(mask);
+					}
+					copyInts(parsedIp, addr, 16);
+
+					return addr;
+				}
+			}
+			else if (NetUtils.IPAddress.IsValidIPv4WithNetmask(ip) || NetUtils.IPAddress.IsValidIPv4(ip))
+			{
+				int slashIndex = ip.IndexOf('/');
+
+				if (slashIndex < 0)
+				{
+					byte[] addr = new byte[4];
+
+					parseIPv4(ip, addr, 0);
+
+					return addr;
+				}
+				else
+				{
+					byte[] addr = new byte[8];
+
+					parseIPv4(ip.Substring(0, slashIndex), addr, 0);
+
+					string mask = ip.Substring(slashIndex + 1);
+					if (mask.IndexOf('.') > 0)
+					{
+						parseIPv4(mask, addr, 4);
+					}
+					else
+					{
+						parseIPv4Mask(mask, addr, 4);
+					}
+
+					return addr;
+				}
+			}
+
+			return null;
+		}
+
+		private void parseIPv4Mask(string mask, byte[] addr, int offset)
+		{
+			int maskVal = Int32.Parse(mask);
+
+			for (int i = 0; i != maskVal; i++)
+			{
+				addr[(i / 8) + offset] |= (byte)(1 << (i % 8));
+			}
+		}
+
+		private void parseIPv4(string ip, byte[] addr, int offset)
+		{
+			foreach (string token in ip.Split('.', '/'))
+			{
+				addr[offset++] = (byte)Int32.Parse(token);
+			}
+		}
+
+		private int[] parseMask(string mask)
+		{
+			int[] res = new int[8];
+			int   maskVal = Int32.Parse(mask);
+
+			for (int i = 0; i != maskVal; i++)
+			{
+				res[i / 16] |= 1 << (i % 16);
+			}
+			return res;
+		}
+
+		private void copyInts(int[] parsedIp, byte[] addr, int offSet)
+		{
+			for (int i = 0; i != parsedIp.Length; i++)
+			{
+				addr[(i * 2) + offSet] = (byte)(parsedIp[i] >> 8);
+				addr[(i * 2 + 1) + offSet] = (byte)parsedIp[i];
+			}
+		}
+
+		private int[] parseIPv6(string ip)
+		{
+			if (ip.StartsWith("::"))
+			{
+				ip = ip.Substring(1);
+			}
+			else if (ip.EndsWith("::"))
+			{
+				ip = ip.Substring(0, ip.Length - 1);
+			}
+
+			IEnumerator sEnum = ip.Split(':').GetEnumerator();
+
+			int index = 0;
+			int[] val = new int[8];
+
+			int doubleColon = -1;
+
+			while (sEnum.MoveNext())
+			{
+				string e = (string) sEnum.Current;
+
+				if (e.Length == 0)
+				{
+					doubleColon = index;
+					val[index++] = 0;
+				}
+				else
+				{
+					if (e.IndexOf('.') < 0)
+					{
+						val[index++] = Int32.Parse(e, NumberStyles.AllowHexSpecifier);
+					}
+					else
+					{
+						string[] tokens = e.Split('.');
+
+						val[index++] = (Int32.Parse(tokens[0]) << 8) | Int32.Parse(tokens[1]);
+						val[index++] = (Int32.Parse(tokens[2]) << 8) | Int32.Parse(tokens[3]);
+					}
+				}
+			}
+
+			if (index != val.Length)
+			{
+				Array.Copy(val, doubleColon, val, val.Length - (index - doubleColon), index - doubleColon);
+				for (int i = doubleColon; i != val.Length - (index - doubleColon); i++)
+				{
+					val[i] = 0;
+				}
+			}
+
+			return val;
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			// Explicitly tagged if DirectoryName
+			return new DerTaggedObject(tag == DirectoryName, tag, obj);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/GeneralNames.cs b/Crypto/src/asn1/x509/GeneralNames.cs
new file mode 100644
index 000000000..6c5c8e690
--- /dev/null
+++ b/Crypto/src/asn1/x509/GeneralNames.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	public class GeneralNames
+		: Asn1Encodable
+	{
+		private readonly GeneralName[] names;
+
+		public static GeneralNames GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is GeneralNames)
+			{
+				return (GeneralNames) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new GeneralNames((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public static GeneralNames GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		/// <summary>Construct a GeneralNames object containing one GeneralName.</summary>
+		/// <param name="name">The name to be contained.</param>
+		public GeneralNames(
+			GeneralName name)
+		{
+			names = new GeneralName[]{ name };
+		}
+
+        public GeneralNames(
+            GeneralName[] names)
+        {
+            this.names = (GeneralName[])names.Clone();
+        }
+
+		private GeneralNames(
+			Asn1Sequence seq)
+		{
+			this.names = new GeneralName[seq.Count];
+
+			for (int i = 0; i != seq.Count; i++)
+			{
+				names[i] = GeneralName.GetInstance(seq[i]);
+			}
+		}
+
+		public GeneralName[] GetNames()
+		{
+			return (GeneralName[]) names.Clone();
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * <pre>
+		 * GeneralNames ::= Sequence SIZE {1..MAX} OF GeneralName
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(names);
+		}
+
+		public override string ToString()
+		{
+			StringBuilder buf = new StringBuilder();
+			string sep = Platform.NewLine;
+
+			buf.Append("GeneralNames:");
+			buf.Append(sep);
+
+			foreach (GeneralName name in names)
+			{
+				buf.Append("    ");
+				buf.Append(name);
+				buf.Append(sep);
+			}
+
+			return buf.ToString();
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/GeneralSubtree.cs b/Crypto/src/asn1/x509/GeneralSubtree.cs
new file mode 100644
index 000000000..e918a0277
--- /dev/null
+++ b/Crypto/src/asn1/x509/GeneralSubtree.cs
@@ -0,0 +1,189 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * Class for containing a restriction object subtrees in NameConstraints. See
+	 * RFC 3280.
+	 *
+	 * <pre>
+	 *
+	 *       GeneralSubtree ::= SEQUENCE
+	 *       {
+	 *         baseName                    GeneralName,
+	 *         minimum         [0]     BaseDistance DEFAULT 0,
+	 *         maximum         [1]     BaseDistance OPTIONAL
+	 *       }
+	 * </pre>
+	 *
+	 * @see org.bouncycastle.asn1.x509.NameConstraints
+	 *
+	 */
+	public class GeneralSubtree
+		: Asn1Encodable
+	{
+		private readonly GeneralName	baseName;
+		private readonly DerInteger		minimum;
+		private readonly DerInteger		maximum;
+
+		private GeneralSubtree(
+			Asn1Sequence seq)
+		{
+			baseName = GeneralName.GetInstance(seq[0]);
+
+			switch (seq.Count)
+			{
+				case 1:
+					break;
+				case 2:
+				{
+					Asn1TaggedObject o = Asn1TaggedObject.GetInstance(seq[1]);
+					switch (o.TagNo)
+					{
+						case 0:
+							minimum = DerInteger.GetInstance(o, false);
+							break;
+						case 1:
+							maximum = DerInteger.GetInstance(o, false);
+							break;
+						default:
+							throw new ArgumentException("Bad tag number: " + o.TagNo);
+					}
+					break;
+				}
+				case 3:
+				{
+					{
+						Asn1TaggedObject oMin = Asn1TaggedObject.GetInstance(seq[1]);
+						if (oMin.TagNo != 0)
+							throw new ArgumentException("Bad tag number for 'minimum': " + oMin.TagNo);
+						minimum = DerInteger.GetInstance(oMin, false);
+					}
+
+					{
+						Asn1TaggedObject oMax = Asn1TaggedObject.GetInstance(seq[2]);
+						if (oMax.TagNo != 1)
+							throw new ArgumentException("Bad tag number for 'maximum': " + oMax.TagNo);
+						maximum = DerInteger.GetInstance(oMax, false);
+					}
+
+					break;
+				}
+				default:
+					throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+		}
+
+		/**
+		 * Constructor from a given details.
+		 *
+		 * According RFC 3280, the minimum and maximum fields are not used with any
+		 * name forms, thus minimum MUST be zero, and maximum MUST be absent.
+		 * <p>
+		 * If minimum is <code>null</code>, zero is assumed, if
+		 * maximum is <code>null</code>, maximum is absent.</p>
+		 *
+		 * @param baseName
+		 *            A restriction.
+		 * @param minimum
+		 *            Minimum
+		 *
+		 * @param maximum
+		 *            Maximum
+		 */
+		public GeneralSubtree(
+			GeneralName	baseName,
+			BigInteger	minimum,
+			BigInteger	maximum)
+		{
+			this.baseName = baseName;
+			if (minimum != null)
+			{
+				this.minimum = new DerInteger(minimum);
+			}
+			if (maximum != null)
+			{
+				this.maximum = new DerInteger(maximum);
+			}
+		}
+
+		public GeneralSubtree(
+			GeneralName baseName)
+			: this(baseName, null, null)
+		{
+		}
+
+		public static GeneralSubtree GetInstance(
+			Asn1TaggedObject	o,
+			bool				isExplicit)
+		{
+			return new GeneralSubtree(Asn1Sequence.GetInstance(o, isExplicit));
+		}
+
+		public static GeneralSubtree GetInstance(
+			object obj)
+		{
+			if (obj == null)
+			{
+				return null;
+			}
+
+			if (obj is GeneralSubtree)
+			{
+				return (GeneralSubtree) obj;
+			}
+
+			return new GeneralSubtree(Asn1Sequence.GetInstance(obj));
+		}
+
+		public GeneralName Base
+		{
+			get { return baseName; }
+		}
+
+		public BigInteger Minimum
+		{
+			get { return minimum == null ? BigInteger.Zero : minimum.Value; }
+		}
+
+		public BigInteger Maximum
+		{
+			get { return maximum == null ? null : maximum.Value; }
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 *
+		 * Returns:
+		 *
+		 * <pre>
+		 *       GeneralSubtree ::= SEQUENCE
+		 *       {
+		 *         baseName                    GeneralName,
+		 *         minimum         [0]     BaseDistance DEFAULT 0,
+		 *         maximum         [1]     BaseDistance OPTIONAL
+		 *       }
+		 * </pre>
+		 *
+		 * @return a DERObject
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(baseName);
+
+			if (minimum != null && minimum.Value.SignValue != 0)
+			{
+				v.Add(new DerTaggedObject(false, 0, minimum));
+			}
+
+			if (maximum != null)
+			{
+				v.Add(new DerTaggedObject(false, 1, maximum));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/Holder.cs b/Crypto/src/asn1/x509/Holder.cs
new file mode 100644
index 000000000..d04f1cb60
--- /dev/null
+++ b/Crypto/src/asn1/x509/Holder.cs
@@ -0,0 +1,257 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * The Holder object.
+	 * <p>
+	 * For an v2 attribute certificate this is:
+	 * 
+	 * <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>
+	 * <p>
+	 * For an v1 attribute certificate this is:
+	 * 
+	 * <pre>
+	 *         subject CHOICE {
+	 *          baseCertificateID [0] IssuerSerial,
+	 *          -- associated with a Public Key Certificate
+	 *          subjectName [1] GeneralNames },
+	 *          -- associated with a name
+	 * </pre>
+	 * </p>
+	 */
+	public class Holder
+        : Asn1Encodable
+    {
+		internal readonly IssuerSerial		baseCertificateID;
+        internal readonly GeneralNames		entityName;
+        internal readonly ObjectDigestInfo	objectDigestInfo;
+		private readonly int version;
+
+		public static Holder GetInstance(
+            object obj)
+        {
+            if (obj is Holder)
+            {
+                return (Holder) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new Holder((Asn1Sequence) obj);
+            }
+
+			if (obj is Asn1TaggedObject)
+			{
+				return new Holder((Asn1TaggedObject) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		 * Constructor for a holder for an v1 attribute certificate.
+		 * 
+		 * @param tagObj The ASN.1 tagged holder object.
+		 */
+		public Holder(
+			Asn1TaggedObject tagObj)
+		{
+			switch (tagObj.TagNo)
+			{
+				case 0:
+					baseCertificateID = IssuerSerial.GetInstance(tagObj, false);
+					break;
+				case 1:
+					entityName = GeneralNames.GetInstance(tagObj, false);
+					break;
+				default:
+					throw new ArgumentException("unknown tag in Holder");
+			}
+
+			this.version = 0;
+		}
+
+		/**
+		 * Constructor for a holder for an v2 attribute certificate. *
+		 * 
+		 * @param seq The ASN.1 sequence.
+		 */
+		private Holder(
+            Asn1Sequence seq)
+        {
+			if (seq.Count > 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			for (int i = 0; i != seq.Count; i++)
+            {
+				Asn1TaggedObject tObj = Asn1TaggedObject.GetInstance(seq[i]);
+
+				switch (tObj.TagNo)
+                {
+                    case 0:
+                        baseCertificateID = IssuerSerial.GetInstance(tObj, false);
+                        break;
+                    case 1:
+                        entityName = GeneralNames.GetInstance(tObj, false);
+                        break;
+                    case 2:
+                        objectDigestInfo = ObjectDigestInfo.GetInstance(tObj, false);
+                        break;
+                    default:
+                        throw new ArgumentException("unknown tag in Holder");
+                }
+            }
+
+			this.version = 1;
+		}
+
+		public Holder(
+			IssuerSerial baseCertificateID)
+			: this(baseCertificateID, 1)
+		{
+		}
+
+		/**
+		 * Constructs a holder from a IssuerSerial.
+		 * @param baseCertificateID The IssuerSerial.
+		 * @param version The version of the attribute certificate. 
+		 */
+		public Holder(
+			IssuerSerial	baseCertificateID,
+			int				version)
+		{
+			this.baseCertificateID = baseCertificateID;
+			this.version = version;
+		}
+
+		/**
+		 * Returns 1 for v2 attribute certificates or 0 for v1 attribute
+		 * certificates. 
+		 * @return The version of the attribute certificate.
+		 */
+		public int Version
+		{
+			get { return version; }
+		}
+
+		/**
+		 * Constructs a holder with an entityName for v2 attribute certificates or
+		 * with a subjectName for v1 attribute certificates.
+		 * 
+		 * @param entityName The entity or subject name.
+		 */
+		public Holder(
+			GeneralNames entityName)
+			: this(entityName, 1)
+		{
+		}
+
+		/**
+		 * Constructs a holder with an entityName for v2 attribute certificates or
+		 * with a subjectName for v1 attribute certificates.
+		 * 
+		 * @param entityName The entity or subject name.
+		 * @param version The version of the attribute certificate. 
+		 */
+		public Holder(
+			GeneralNames	entityName,
+			int				version)
+		{
+			this.entityName = entityName;
+			this.version = version;
+		}
+
+		/**
+		 * Constructs a holder from an object digest info.
+		 * 
+		 * @param objectDigestInfo The object digest info object.
+		 */
+		public Holder(
+			ObjectDigestInfo objectDigestInfo)
+		{
+			this.objectDigestInfo = objectDigestInfo;
+			this.version = 1;
+		}
+
+		public IssuerSerial BaseCertificateID
+		{
+			get { return baseCertificateID; }
+		}
+
+		/**
+		 * Returns the entityName for an v2 attribute certificate or the subjectName
+		 * for an v1 attribute certificate.
+		 * 
+		 * @return The entityname or subjectname.
+		 */
+		public GeneralNames EntityName
+		{
+			get { return entityName; }
+		}
+
+		public ObjectDigestInfo ObjectDigestInfo
+		{
+			get { return objectDigestInfo; }
+		}
+
+		/**
+         * 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>
+         */
+		public override Asn1Object ToAsn1Object()
+		{
+			if (version == 1)
+			{
+				Asn1EncodableVector v = new Asn1EncodableVector();
+
+				if (baseCertificateID != null)
+				{
+					v.Add(new DerTaggedObject(false, 0, baseCertificateID));
+				}
+
+				if (entityName != null)
+				{
+					v.Add(new DerTaggedObject(false, 1, entityName));
+				}
+
+				if (objectDigestInfo != null)
+				{
+					v.Add(new DerTaggedObject(false, 2, objectDigestInfo));
+				}
+
+				return new DerSequence(v);
+			}
+
+			if (entityName != null)
+			{
+				return new DerTaggedObject(false, 1, entityName);
+			}
+
+			return new DerTaggedObject(false, 0, baseCertificateID);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/IetfAttrSyntax.cs b/Crypto/src/asn1/x509/IetfAttrSyntax.cs
new file mode 100644
index 000000000..e719865b3
--- /dev/null
+++ b/Crypto/src/asn1/x509/IetfAttrSyntax.cs
@@ -0,0 +1,161 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * Implementation of <code>IetfAttrSyntax</code> as specified by RFC3281.
+     */
+    public class IetfAttrSyntax
+        : Asn1Encodable
+    {
+        public const int ValueOctets	= 1;
+        public const int ValueOid		= 2;
+        public const int ValueUtf8		= 3;
+
+		internal readonly GeneralNames	policyAuthority;
+        internal readonly Asn1EncodableVector values = new Asn1EncodableVector();
+
+		internal int valueChoice = -1;
+
+		/**
+         *
+         */
+        public IetfAttrSyntax(
+			Asn1Sequence seq)
+        {
+            int i = 0;
+
+            if (seq[0] is Asn1TaggedObject)
+            {
+                policyAuthority = GeneralNames.GetInstance(((Asn1TaggedObject)seq[0]), false);
+                i++;
+            }
+            else if (seq.Count == 2)
+            { // VOMS fix
+                policyAuthority = GeneralNames.GetInstance(seq[0]);
+                i++;
+            }
+
+			if (!(seq[i] is Asn1Sequence))
+            {
+                throw new ArgumentException("Non-IetfAttrSyntax encoding");
+            }
+
+			seq = (Asn1Sequence) seq[i];
+
+			foreach (Asn1Object obj in seq)
+			{
+                int type;
+
+                if (obj is DerObjectIdentifier)
+                {
+                    type = ValueOid;
+                }
+                else if (obj is DerUtf8String)
+                {
+                    type = ValueUtf8;
+                }
+                else if (obj is DerOctetString)
+                {
+                    type = ValueOctets;
+                }
+                else
+                {
+                    throw new ArgumentException("Bad value type encoding IetfAttrSyntax");
+                }
+
+				if (valueChoice < 0)
+                {
+                    valueChoice = type;
+                }
+
+				if (type != valueChoice)
+                {
+                    throw new ArgumentException("Mix of value types in IetfAttrSyntax");
+                }
+
+				values.Add(obj);
+            }
+        }
+
+		public GeneralNames PolicyAuthority
+		{
+			get { return policyAuthority; }
+		}
+
+		public int ValueType
+		{
+			get { return valueChoice; }
+		}
+
+		public object[] GetValues()
+        {
+            if (this.ValueType == ValueOctets)
+            {
+                Asn1OctetString[] tmp = new Asn1OctetString[values.Count];
+
+				for (int i = 0; i != tmp.Length; i++)
+                {
+                    tmp[i] = (Asn1OctetString) values[i];
+                }
+
+				return tmp;
+            }
+
+			if (this.ValueType == ValueOid)
+            {
+                DerObjectIdentifier[] tmp = new DerObjectIdentifier[values.Count];
+
+                for (int i = 0; i != tmp.Length; i++)
+                {
+                    tmp[i] = (DerObjectIdentifier) values[i];
+                }
+
+				return tmp;
+            }
+
+			{
+				DerUtf8String[] tmp = new DerUtf8String[values.Count];
+
+				for (int i = 0; i != tmp.Length; i++)
+				{
+					tmp[i] = (DerUtf8String) values[i];
+				}
+
+				return tmp;
+			}
+        }
+
+		/**
+         *
+         * <pre>
+         *
+         *  IetfAttrSyntax ::= Sequence {
+         *    policyAuthority [0] GeneralNames OPTIONAL,
+         *    values Sequence OF CHOICE {
+         *      octets OCTET STRING,
+         *      oid OBJECT IDENTIFIER,
+         *      string UTF8String
+         *    }
+         *  }
+         *
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (policyAuthority != null)
+            {
+                v.Add(new DerTaggedObject(0, policyAuthority));
+            }
+
+			v.Add(new DerSequence(values));
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/IssuerSerial.cs b/Crypto/src/asn1/x509/IssuerSerial.cs
new file mode 100644
index 000000000..6a24e7333
--- /dev/null
+++ b/Crypto/src/asn1/x509/IssuerSerial.cs
@@ -0,0 +1,98 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class IssuerSerial
+        : Asn1Encodable
+    {
+        internal readonly GeneralNames	issuer;
+        internal readonly DerInteger	serial;
+        internal readonly DerBitString	issuerUid;
+
+		public static IssuerSerial GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is IssuerSerial)
+            {
+                return (IssuerSerial) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new IssuerSerial((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+        public static IssuerSerial GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		private IssuerSerial(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2 && seq.Count != 3)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			issuer = GeneralNames.GetInstance(seq[0]);
+			serial = DerInteger.GetInstance(seq[1]);
+
+			if (seq.Count == 3)
+            {
+				issuerUid = DerBitString.GetInstance(seq[2]);
+			}
+        }
+
+		public IssuerSerial(
+			GeneralNames	issuer,
+			DerInteger		serial)
+		{
+			this.issuer = issuer;
+			this.serial = serial;
+		}
+
+		public GeneralNames Issuer
+		{
+			get { return issuer; }
+		}
+
+		public DerInteger Serial
+		{
+			get { return serial; }
+		}
+
+		public DerBitString IssuerUid
+		{
+			get { return issuerUid; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  IssuerSerial  ::=  Sequence {
+         *       issuer         GeneralNames,
+         *       serial         CertificateSerialNumber,
+         *       issuerUid      UniqueIdentifier OPTIONAL
+         *  }
+         * </pre>
+         */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				issuer, serial);
+
+			if (issuerUid != null)
+			{
+				v.Add(issuerUid);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/IssuingDistributionPoint.cs b/Crypto/src/asn1/x509/IssuingDistributionPoint.cs
new file mode 100644
index 000000000..3af0d565f
--- /dev/null
+++ b/Crypto/src/asn1/x509/IssuingDistributionPoint.cs
@@ -0,0 +1,247 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * <pre>
+	 * IssuingDistributionPoint ::= SEQUENCE { 
+	 *   distributionPoint          [0] DistributionPointName OPTIONAL, 
+	 *   onlyContainsUserCerts      [1] BOOLEAN DEFAULT FALSE, 
+	 *   onlyContainsCACerts        [2] BOOLEAN DEFAULT FALSE, 
+	 *   onlySomeReasons            [3] ReasonFlags OPTIONAL, 
+	 *   indirectCRL                [4] BOOLEAN DEFAULT FALSE,
+	 *   onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }
+	 * </pre>
+	 */
+	public class IssuingDistributionPoint
+        : Asn1Encodable
+    {
+		private readonly DistributionPointName	_distributionPoint;
+		private readonly bool					_onlyContainsUserCerts;
+        private readonly bool					_onlyContainsCACerts;
+		private readonly ReasonFlags			_onlySomeReasons;
+		private readonly bool					_indirectCRL;
+        private readonly bool					_onlyContainsAttributeCerts;
+
+		private readonly Asn1Sequence seq;
+
+		public static IssuingDistributionPoint GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static IssuingDistributionPoint GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is IssuingDistributionPoint)
+            {
+                return (IssuingDistributionPoint) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new IssuingDistributionPoint((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		 * Constructor from given details.
+		 * 
+		 * @param distributionPoint
+		 *            May contain an URI as pointer to most current CRL.
+		 * @param onlyContainsUserCerts Covers revocation information for end certificates.
+		 * @param onlyContainsCACerts Covers revocation information for CA certificates.
+		 * 
+		 * @param onlySomeReasons
+		 *            Which revocation reasons does this point cover.
+		 * @param indirectCRL
+		 *            If <code>true</code> then the CRL contains revocation
+		 *            information about certificates ssued by other CAs.
+		 * @param onlyContainsAttributeCerts Covers revocation information for attribute certificates.
+		 */
+		public IssuingDistributionPoint(
+			DistributionPointName	distributionPoint,
+			bool					onlyContainsUserCerts,
+			bool					onlyContainsCACerts,
+			ReasonFlags				onlySomeReasons,
+			bool					indirectCRL,
+			bool					onlyContainsAttributeCerts)
+		{
+			this._distributionPoint = distributionPoint;
+			this._indirectCRL = indirectCRL;
+			this._onlyContainsAttributeCerts = onlyContainsAttributeCerts;
+			this._onlyContainsCACerts = onlyContainsCACerts;
+			this._onlyContainsUserCerts = onlyContainsUserCerts;
+			this._onlySomeReasons = onlySomeReasons;
+
+			Asn1EncodableVector vec = new Asn1EncodableVector();
+			if (distributionPoint != null)
+			{	// CHOICE item so explicitly tagged
+				vec.Add(new DerTaggedObject(true, 0, distributionPoint));
+			}
+			if (onlyContainsUserCerts)
+			{
+				vec.Add(new DerTaggedObject(false, 1, DerBoolean.True));
+			}
+			if (onlyContainsCACerts)
+			{
+				vec.Add(new DerTaggedObject(false, 2, DerBoolean.True));
+			}
+			if (onlySomeReasons != null)
+			{
+				vec.Add(new DerTaggedObject(false, 3, onlySomeReasons));
+			}
+			if (indirectCRL)
+			{
+				vec.Add(new DerTaggedObject(false, 4, DerBoolean.True));
+			}
+			if (onlyContainsAttributeCerts)
+			{
+				vec.Add(new DerTaggedObject(false, 5, DerBoolean.True));
+			}
+
+			seq = new DerSequence(vec);
+		}
+
+		/**
+         * Constructor from Asn1Sequence
+         */
+        private IssuingDistributionPoint(
+            Asn1Sequence seq)
+        {
+            this.seq = seq;
+
+			for (int i = 0; i != seq.Count; i++)
+            {
+				Asn1TaggedObject o = Asn1TaggedObject.GetInstance(seq[i]);
+
+				switch (o.TagNo)
+                {
+					case 0:
+						// CHOICE so explicit
+						_distributionPoint = DistributionPointName.GetInstance(o, true);
+						break;
+					case 1:
+						_onlyContainsUserCerts = DerBoolean.GetInstance(o, false).IsTrue;
+						break;
+					case 2:
+						_onlyContainsCACerts = DerBoolean.GetInstance(o, false).IsTrue;
+						break;
+					case 3:
+						_onlySomeReasons = new ReasonFlags(ReasonFlags.GetInstance(o, false));
+						break;
+					case 4:
+						_indirectCRL = DerBoolean.GetInstance(o, false).IsTrue;
+						break;
+					case 5:
+						_onlyContainsAttributeCerts = DerBoolean.GetInstance(o, false).IsTrue;
+						break;
+					default:
+						throw new ArgumentException("unknown tag in IssuingDistributionPoint");
+                }
+            }
+        }
+
+		public bool OnlyContainsUserCerts
+		{
+			get { return _onlyContainsUserCerts; }
+		}
+
+		public bool OnlyContainsCACerts
+		{
+			get { return _onlyContainsCACerts; }
+		}
+
+		public bool IsIndirectCrl
+		{
+			get { return _indirectCRL; }
+		}
+
+		public bool OnlyContainsAttributeCerts
+		{
+			get { return _onlyContainsAttributeCerts; }
+		}
+
+		/**
+		 * @return Returns the distributionPoint.
+		 */
+		public DistributionPointName DistributionPoint
+		{
+			get { return _distributionPoint; }
+		}
+
+		/**
+		 * @return Returns the onlySomeReasons.
+		 */
+		public ReasonFlags OnlySomeReasons
+		{
+			get { return _onlySomeReasons; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return seq;
+        }
+
+		public override string ToString()
+		{
+			string sep = Platform.NewLine;
+			StringBuilder buf = new StringBuilder();
+
+			buf.Append("IssuingDistributionPoint: [");
+			buf.Append(sep);
+			if (_distributionPoint != null)
+			{
+				appendObject(buf, sep, "distributionPoint", _distributionPoint.ToString());
+			}
+			if (_onlyContainsUserCerts)
+			{
+				appendObject(buf, sep, "onlyContainsUserCerts", _onlyContainsUserCerts.ToString());
+			}
+			if (_onlyContainsCACerts)
+			{
+				appendObject(buf, sep, "onlyContainsCACerts", _onlyContainsCACerts.ToString());
+			}
+			if (_onlySomeReasons != null)
+			{
+				appendObject(buf, sep, "onlySomeReasons", _onlySomeReasons.ToString());
+			}
+			if (_onlyContainsAttributeCerts)
+			{
+				appendObject(buf, sep, "onlyContainsAttributeCerts", _onlyContainsAttributeCerts.ToString());
+			}
+			if (_indirectCRL)
+			{
+				appendObject(buf, sep, "indirectCRL", _indirectCRL.ToString());
+			}
+			buf.Append("]");
+			buf.Append(sep);
+			return buf.ToString();
+		}
+
+		private void appendObject(
+			StringBuilder	buf,
+			string			sep,
+			string			name,
+			string			val)
+		{
+			string indent = "    ";
+
+			buf.Append(indent);
+			buf.Append(name);
+			buf.Append(":");
+			buf.Append(sep);
+			buf.Append(indent);
+			buf.Append(indent);
+			buf.Append(val);
+			buf.Append(sep);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/KeyPurposeId.cs b/Crypto/src/asn1/x509/KeyPurposeId.cs
new file mode 100644
index 000000000..4b48a9b51
--- /dev/null
+++ b/Crypto/src/asn1/x509/KeyPurposeId.cs
@@ -0,0 +1,36 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The KeyPurposeID object.
+     * <pre>
+     *     KeyPurposeID ::= OBJECT IDENTIFIER
+     * </pre>
+     */
+    public sealed class KeyPurposeID
+        : DerObjectIdentifier
+    {
+        private const string IdKP = "1.3.6.1.5.5.7.3";
+
+		private KeyPurposeID(
+			string id)
+			: base(id)
+        {
+        }
+
+		public static readonly KeyPurposeID AnyExtendedKeyUsage = new KeyPurposeID(X509Extensions.ExtendedKeyUsage.Id + ".0");
+        public static readonly KeyPurposeID IdKPServerAuth = new KeyPurposeID(IdKP + ".1");
+        public static readonly KeyPurposeID IdKPClientAuth = new KeyPurposeID(IdKP + ".2");
+        public static readonly KeyPurposeID IdKPCodeSigning = new KeyPurposeID(IdKP + ".3");
+        public static readonly KeyPurposeID IdKPEmailProtection = new KeyPurposeID(IdKP + ".4");
+        public static readonly KeyPurposeID IdKPIpsecEndSystem = new KeyPurposeID(IdKP + ".5");
+        public static readonly KeyPurposeID IdKPIpsecTunnel = new KeyPurposeID(IdKP + ".6");
+        public static readonly KeyPurposeID IdKPIpsecUser = new KeyPurposeID(IdKP + ".7");
+        public static readonly KeyPurposeID IdKPTimeStamping = new KeyPurposeID(IdKP + ".8");
+        public static readonly KeyPurposeID IdKPOcspSigning = new KeyPurposeID(IdKP + ".9");
+
+		//
+        // microsoft key purpose ids
+        //
+        public static readonly KeyPurposeID IdKPSmartCardLogon = new KeyPurposeID("1.3.6.1.4.1.311.20.2.2");
+    }
+}
diff --git a/Crypto/src/asn1/x509/KeyUsage.cs b/Crypto/src/asn1/x509/KeyUsage.cs
new file mode 100644
index 000000000..fef04e8b9
--- /dev/null
+++ b/Crypto/src/asn1/x509/KeyUsage.cs
@@ -0,0 +1,79 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The KeyUsage object.
+     * <pre>
+     *    id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }
+     *
+     *    KeyUsage ::= BIT STRING {
+     *         digitalSignature        (0),
+     *         nonRepudiation          (1),
+     *         keyEncipherment         (2),
+     *         dataEncipherment        (3),
+     *         keyAgreement            (4),
+     *         keyCertSign             (5),
+     *         cRLSign                 (6),
+     *         encipherOnly            (7),
+     *         decipherOnly            (8) }
+     * </pre>
+     */
+    public class KeyUsage
+        : DerBitString
+    {
+        public const int DigitalSignature = (1 << 7);
+        public const int NonRepudiation   = (1 << 6);
+        public const int KeyEncipherment  = (1 << 5);
+        public const int DataEncipherment = (1 << 4);
+        public const int KeyAgreement     = (1 << 3);
+        public const int KeyCertSign      = (1 << 2);
+        public const int CrlSign          = (1 << 1);
+        public const int EncipherOnly     = (1 << 0);
+        public const int DecipherOnly     = (1 << 15);
+
+		public static new KeyUsage GetInstance(
+			object obj)
+		{
+			if (obj is KeyUsage)
+			{
+				return (KeyUsage)obj;
+			}
+
+			if (obj is X509Extension)
+			{
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+			}
+
+			return new KeyUsage(DerBitString.GetInstance(obj));
+		}
+
+		/**
+         * Basic constructor.
+         *
+         * @param usage - the bitwise OR of the Key Usage flags giving the
+         * allowed uses for the key.
+         * e.g. (KeyUsage.keyEncipherment | KeyUsage.dataEncipherment)
+         */
+        public KeyUsage(
+			int usage)
+			: base(GetBytes(usage), GetPadBits(usage))
+        {
+        }
+
+		private KeyUsage(
+			DerBitString usage)
+			: base(usage.GetBytes(), usage.PadBits)
+        {
+        }
+
+		public override string ToString()
+        {
+			byte[] data = GetBytes();
+            if (data.Length == 1)
+            {
+				return "KeyUsage: 0x" + (data[0] & 0xff).ToString("X");
+            }
+
+			return "KeyUsage: 0x" + ((data[1] & 0xff) << 8 | (data[0] & 0xff)).ToString("X");
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/NameConstraints.cs b/Crypto/src/asn1/x509/NameConstraints.cs
new file mode 100644
index 000000000..c178f5b45
--- /dev/null
+++ b/Crypto/src/asn1/x509/NameConstraints.cs
@@ -0,0 +1,118 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	public class NameConstraints
+		: Asn1Encodable
+	{
+		private Asn1Sequence permitted, excluded;
+
+		public static NameConstraints GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is NameConstraints)
+			{
+				return (NameConstraints) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new NameConstraints((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public NameConstraints(
+			Asn1Sequence seq)
+		{
+			foreach (Asn1TaggedObject o in seq)
+			{
+				switch (o.TagNo)
+				{
+					case 0:
+						permitted = Asn1Sequence.GetInstance(o, false);
+						break;
+					case 1:
+						excluded = Asn1Sequence.GetInstance(o, false);
+						break;
+				}
+			}
+		}
+
+#if !(SILVERLIGHT || PORTABLE)
+        public NameConstraints(
+            ArrayList permitted,
+            ArrayList excluded)
+            : this((IList)permitted, (IList)excluded)
+        {
+        }
+#endif
+
+        /**
+		 * Constructor from a given details.
+		 *
+		 * <p>permitted and excluded are Vectors of GeneralSubtree objects.</p>
+		 *
+		 * @param permitted Permitted subtrees
+		 * @param excluded Excluded subtrees
+		 */
+		public NameConstraints(
+			IList   permitted,
+			IList   excluded)
+		{
+			if (permitted != null)
+			{
+				this.permitted = CreateSequence(permitted);
+			}
+
+			if (excluded != null)
+			{
+				this.excluded = CreateSequence(excluded);
+			}
+		}
+
+		private DerSequence CreateSequence(
+			IList subtrees)
+		{
+            GeneralSubtree[] gsts = new GeneralSubtree[subtrees.Count];
+            for (int i = 0; i < subtrees.Count; ++i)
+            {
+                gsts[i] = (GeneralSubtree)subtrees[i];
+            }
+            return new DerSequence(gsts);
+		}
+
+		public Asn1Sequence PermittedSubtrees
+		{
+			get { return permitted; }
+		}
+
+		public Asn1Sequence ExcludedSubtrees
+		{
+			get { return excluded; }
+		}
+
+		/*
+		 * NameConstraints ::= SEQUENCE { permittedSubtrees [0] GeneralSubtrees
+		 * OPTIONAL, excludedSubtrees [1] GeneralSubtrees OPTIONAL }
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (permitted != null)
+			{
+				v.Add(new DerTaggedObject(false, 0, permitted));
+			}
+
+			if (excluded != null)
+			{
+				v.Add(new DerTaggedObject(false, 1, excluded));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/NoticeReference.cs b/Crypto/src/asn1/x509/NoticeReference.cs
new file mode 100644
index 000000000..718fe92cf
--- /dev/null
+++ b/Crypto/src/asn1/x509/NoticeReference.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * <code>NoticeReference</code> class, used in
+	 * <code>CertificatePolicies</code> X509 V3 extensions
+	 * (in policy qualifiers).
+	 *
+	 * <pre>
+	 *  NoticeReference ::= Sequence {
+	 *      organization     DisplayText,
+	 *      noticeNumbers    Sequence OF Integer }
+	 *
+	 * </pre>
+	 *
+	 * @see PolicyQualifierInfo
+	 * @see PolicyInformation
+	 */
+	public class NoticeReference
+		: Asn1Encodable
+	{
+		internal readonly DisplayText organization;
+		internal readonly Asn1Sequence noticeNumbers;
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete]
+        public NoticeReference(
+            string orgName,
+            ArrayList numbers)
+            : this(orgName, (IList)numbers)
+        {
+        }
+#endif
+
+        /**
+		* Creates a new <code>NoticeReference</code> instance.
+		*
+		* @param orgName a <code>string</code> value
+		* @param numbers a <code>ArrayList</code> value
+		*/
+		public NoticeReference(
+			string  orgName,
+			IList   numbers)
+		{
+			organization = new DisplayText(orgName);
+
+			object o = numbers[0];
+
+			Asn1EncodableVector av = new Asn1EncodableVector();
+			if (o is int)
+			{
+				foreach (int nm in numbers)
+				{
+					av.Add(new DerInteger(nm));
+				}
+			}
+
+			noticeNumbers = new DerSequence(av);
+		}
+
+		/**
+		 * Creates a new <code>NoticeReference</code> instance.
+		 *
+		 * @param orgName a <code>string</code> value
+		 * @param numbers an <code>Asn1Sequence</code> value
+		 */
+		public NoticeReference(
+			string			orgName,
+			Asn1Sequence	numbers)
+		{
+			organization = new DisplayText(orgName);
+			noticeNumbers = numbers;
+		}
+
+		/**
+		 * Creates a new <code>NoticeReference</code> instance.
+		 *
+		 * @param displayTextType an <code>int</code> value
+		 * @param orgName a <code>string</code> value
+		 * @param numbers an <code>Asn1Sequence</code> value
+		 */
+		public NoticeReference(
+			int				displayTextType,
+			string			orgName,
+			Asn1Sequence	numbers)
+		{
+			organization = new DisplayText(displayTextType, orgName);
+			noticeNumbers = numbers;
+		}
+
+		/**
+		 * Creates a new <code>NoticeReference</code> instance.
+		 * <p>Useful for reconstructing a <code>NoticeReference</code>
+		 * instance from its encodable/encoded form.</p>
+		 *
+		 * @param as an <code>Asn1Sequence</code> value obtained from either
+		 * calling @{link ToAsn1Object()} for a <code>NoticeReference</code>
+		 * instance or from parsing it from a Der-encoded stream.
+		 */
+		private NoticeReference(
+			Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			organization = DisplayText.GetInstance(seq[0]);
+			noticeNumbers = Asn1Sequence.GetInstance(seq[1]);
+		}
+
+		public static NoticeReference GetInstance(
+			object obj)
+		{
+			if (obj is NoticeReference)
+			{
+				return (NoticeReference) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new NoticeReference((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		/**
+		 * Describe <code>ToAsn1Object</code> method here.
+		 *
+		 * @return a <code>Asn1Object</code> value
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(organization, noticeNumbers);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/ObjectDigestInfo.cs b/Crypto/src/asn1/x509/ObjectDigestInfo.cs
new file mode 100644
index 000000000..6d5b9c692
--- /dev/null
+++ b/Crypto/src/asn1/x509/ObjectDigestInfo.cs
@@ -0,0 +1,177 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * ObjectDigestInfo ASN.1 structure used in v2 attribute certificates.
+	 * 
+	 * <pre>
+	 *  
+	 *    ObjectDigestInfo ::= SEQUENCE {
+	 *         digestedObjectType  ENUMERATED {
+	 *                 publicKey            (0),
+	 *                 publicKeyCert        (1),
+	 *                 otherObjectTypes     (2) },
+	 *                         -- otherObjectTypes MUST NOT
+	 *                         -- be used in this profile
+	 *         otherObjectTypeID   OBJECT IDENTIFIER OPTIONAL,
+	 *         digestAlgorithm     AlgorithmIdentifier,
+	 *         objectDigest        BIT STRING
+	 *    }
+	 *   
+	 * </pre>
+	 * 
+	 */
+	public class ObjectDigestInfo
+        : Asn1Encodable
+    {
+		/**
+		 * The public key is hashed.
+		 */
+		public const int PublicKey = 0;
+
+		/**
+		 * The public key certificate is hashed.
+		 */
+		public const int PublicKeyCert = 1;
+
+		/**
+		 * An other object is hashed.
+		 */
+		public const int OtherObjectDigest = 2;
+
+		internal readonly DerEnumerated			digestedObjectType;
+        internal readonly DerObjectIdentifier	otherObjectTypeID;
+        internal readonly AlgorithmIdentifier	digestAlgorithm;
+        internal readonly DerBitString			objectDigest;
+
+		public static ObjectDigestInfo GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is ObjectDigestInfo)
+            {
+                return (ObjectDigestInfo) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new ObjectDigestInfo((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public static ObjectDigestInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+		/**
+		 * Constructor from given details.
+		 * <p>
+		 * If <code>digestedObjectType</code> is not {@link #publicKeyCert} or
+		 * {@link #publicKey} <code>otherObjectTypeID</code> must be given,
+		 * otherwise it is ignored.</p>
+		 * 
+		 * @param digestedObjectType The digest object type.
+		 * @param otherObjectTypeID The object type ID for
+		 *            <code>otherObjectDigest</code>.
+		 * @param digestAlgorithm The algorithm identifier for the hash.
+		 * @param objectDigest The hash value.
+		 */
+		public ObjectDigestInfo(
+			int					digestedObjectType,
+			string				otherObjectTypeID,
+			AlgorithmIdentifier	digestAlgorithm,
+			byte[]				objectDigest)
+		{
+			this.digestedObjectType = new DerEnumerated(digestedObjectType);
+
+			if (digestedObjectType == OtherObjectDigest)
+			{
+				this.otherObjectTypeID = new DerObjectIdentifier(otherObjectTypeID);
+			}
+
+			this.digestAlgorithm = digestAlgorithm; 
+
+			this.objectDigest = new DerBitString(objectDigest);
+		}
+
+		private ObjectDigestInfo(
+			Asn1Sequence seq)
+        {
+			if (seq.Count > 4 || seq.Count < 3)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			digestedObjectType = DerEnumerated.GetInstance(seq[0]);
+
+			int offset = 0;
+
+			if (seq.Count == 4)
+            {
+                otherObjectTypeID = DerObjectIdentifier.GetInstance(seq[1]);
+                offset++;
+            }
+
+			digestAlgorithm = AlgorithmIdentifier.GetInstance(seq[1 + offset]);
+			objectDigest = DerBitString.GetInstance(seq[2 + offset]);
+		}
+
+		public DerEnumerated DigestedObjectType
+		{
+			get { return digestedObjectType; }
+		}
+
+		public DerObjectIdentifier OtherObjectTypeID
+		{
+			get { return otherObjectTypeID; }
+		}
+
+		public AlgorithmIdentifier DigestAlgorithm
+		{
+			get { return digestAlgorithm; }
+		}
+
+		public DerBitString ObjectDigest
+		{
+			get { return objectDigest; }
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * 
+		 * <pre>
+		 *  
+		 *    ObjectDigestInfo ::= SEQUENCE {
+		 *         digestedObjectType  ENUMERATED {
+		 *                 publicKey            (0),
+		 *                 publicKeyCert        (1),
+		 *                 otherObjectTypes     (2) },
+		 *                         -- otherObjectTypes MUST NOT
+		 *                         -- be used in this profile
+		 *         otherObjectTypeID   OBJECT IDENTIFIER OPTIONAL,
+		 *         digestAlgorithm     AlgorithmIdentifier,
+		 *         objectDigest        BIT STRING
+		 *    }
+		 *   
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(digestedObjectType);
+
+			if (otherObjectTypeID != null)
+            {
+                v.Add(otherObjectTypeID);
+            }
+
+			v.Add(digestAlgorithm, objectDigest);
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/PolicyInformation.cs b/Crypto/src/asn1/x509/PolicyInformation.cs
new file mode 100644
index 000000000..29d245084
--- /dev/null
+++ b/Crypto/src/asn1/x509/PolicyInformation.cs
@@ -0,0 +1,80 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class PolicyInformation
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	policyIdentifier;
+        private readonly Asn1Sequence			policyQualifiers;
+
+		private PolicyInformation(
+            Asn1Sequence seq)
+        {
+			if (seq.Count < 1 || seq.Count > 2)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			policyIdentifier = DerObjectIdentifier.GetInstance(seq[0]);
+
+			if (seq.Count > 1)
+			{
+				policyQualifiers = Asn1Sequence.GetInstance(seq[1]);
+			}
+        }
+
+		public PolicyInformation(
+            DerObjectIdentifier policyIdentifier)
+        {
+            this.policyIdentifier = policyIdentifier;
+        }
+
+		public PolicyInformation(
+            DerObjectIdentifier	policyIdentifier,
+            Asn1Sequence		policyQualifiers)
+        {
+            this.policyIdentifier = policyIdentifier;
+            this.policyQualifiers = policyQualifiers;
+        }
+
+		public static PolicyInformation GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is PolicyInformation)
+            {
+                return (PolicyInformation) obj;
+            }
+
+			return new PolicyInformation(Asn1Sequence.GetInstance(obj));
+        }
+
+		public DerObjectIdentifier PolicyIdentifier
+		{
+			get { return policyIdentifier; }
+		}
+
+		public Asn1Sequence PolicyQualifiers
+		{
+			get { return policyQualifiers; }
+		}
+
+		/*
+         * PolicyInformation ::= Sequence {
+         *      policyIdentifier   CertPolicyId,
+         *      policyQualifiers   Sequence SIZE (1..MAX) OF
+         *              PolicyQualifierInfo OPTIONAL }
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(policyIdentifier);
+
+			if (policyQualifiers != null)
+            {
+                v.Add(policyQualifiers);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/PolicyMappings.cs b/Crypto/src/asn1/x509/PolicyMappings.cs
new file mode 100644
index 000000000..928ad134d
--- /dev/null
+++ b/Crypto/src/asn1/x509/PolicyMappings.cs
@@ -0,0 +1,70 @@
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * PolicyMappings V3 extension, described in RFC3280.
+	 * <pre>
+	 *    PolicyMappings ::= Sequence SIZE (1..MAX) OF Sequence {
+	 *      issuerDomainPolicy      CertPolicyId,
+	 *      subjectDomainPolicy     CertPolicyId }
+	 * </pre>
+	 *
+	 * @see <a href="http://www.faqs.org/rfc/rfc3280.txt">RFC 3280, section 4.2.1.6</a>
+	 */
+	public class PolicyMappings
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence seq;
+
+		/**
+		 * Creates a new <code>PolicyMappings</code> instance.
+		 *
+		 * @param seq an <code>Asn1Sequence</code> constructed as specified
+		 * in RFC 3280
+		 */
+		public PolicyMappings(
+			Asn1Sequence seq)
+		{
+			this.seq = seq;
+		}
+
+#if !(SILVERLIGHT || PORTABLE)
+        public PolicyMappings(
+            Hashtable mappings)
+            : this((IDictionary)mappings)
+        {
+        }
+#endif
+
+        /**
+		 * Creates a new <code>PolicyMappings</code> instance.
+		 *
+		 * @param mappings a <code>HashMap</code> value that maps
+		 * <code>string</code> oids
+		 * to other <code>string</code> oids.
+		 */
+		public PolicyMappings(
+			IDictionary mappings)
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			foreach (string idp in mappings.Keys)
+			{
+				string sdp = (string) mappings[idp];
+
+				v.Add(
+					new DerSequence(
+						new DerObjectIdentifier(idp),
+						new DerObjectIdentifier(sdp)));
+			}
+
+			seq = new DerSequence(v);
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return seq;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/PolicyQualifierId.cs b/Crypto/src/asn1/x509/PolicyQualifierId.cs
new file mode 100644
index 000000000..c858f0864
--- /dev/null
+++ b/Crypto/src/asn1/x509/PolicyQualifierId.cs
@@ -0,0 +1,28 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * PolicyQualifierId, used in the CertificatePolicies
+	 * X509V3 extension.
+	 *
+	 * <pre>
+	 *    id-qt          OBJECT IDENTIFIER ::=  { id-pkix 2 }
+	 *    id-qt-cps      OBJECT IDENTIFIER ::=  { id-qt 1 }
+	 *    id-qt-unotice  OBJECT IDENTIFIER ::=  { id-qt 2 }
+	 *  PolicyQualifierId ::=
+	 *       OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )
+	 * </pre>
+	 */
+	public sealed class PolicyQualifierID : DerObjectIdentifier
+	{
+		private const string IdQt = "1.3.6.1.5.5.7.2";
+
+		private PolicyQualifierID(
+			string id)
+			: base(id)
+		{
+		}
+
+		public static readonly PolicyQualifierID IdQtCps = new PolicyQualifierID(IdQt + ".1");
+		public static readonly PolicyQualifierID IdQtUnotice = new PolicyQualifierID(IdQt + ".2");
+	}
+}
diff --git a/Crypto/src/asn1/x509/PolicyQualifierInfo.cs b/Crypto/src/asn1/x509/PolicyQualifierInfo.cs
new file mode 100644
index 000000000..187f8d3bb
--- /dev/null
+++ b/Crypto/src/asn1/x509/PolicyQualifierInfo.cs
@@ -0,0 +1,91 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * Policy qualifiers, used in the X509V3 CertificatePolicies
+	 * extension.
+	 *
+	 * <pre>
+	 *   PolicyQualifierInfo ::= Sequence {
+	 *       policyQualifierId  PolicyQualifierId,
+	 *       qualifier          ANY DEFINED BY policyQualifierId }
+	 * </pre>
+	 */
+	public class PolicyQualifierInfo
+		: Asn1Encodable
+	{
+		internal readonly DerObjectIdentifier	policyQualifierId;
+		internal readonly Asn1Encodable			qualifier;
+
+		/**
+		 * Creates a new <code>PolicyQualifierInfo</code> instance.
+		 *
+		 * @param policyQualifierId a <code>PolicyQualifierId</code> value
+		 * @param qualifier the qualifier, defined by the above field.
+		 */
+		public PolicyQualifierInfo(
+			DerObjectIdentifier	policyQualifierId,
+			Asn1Encodable		qualifier)
+		{
+			this.policyQualifierId = policyQualifierId;
+			this.qualifier = qualifier;
+		}
+
+		/**
+		 * Creates a new <code>PolicyQualifierInfo</code> containing a
+		 * cPSuri qualifier.
+		 *
+		 * @param cps the CPS (certification practice statement) uri as a
+		 * <code>string</code>.
+		 */
+		public PolicyQualifierInfo(
+			string cps)
+		{
+			policyQualifierId = PolicyQualifierID.IdQtCps;
+			qualifier = new DerIA5String(cps);
+		}
+
+		/**
+		 * Creates a new <code>PolicyQualifierInfo</code> instance.
+		 *
+		 * @param as <code>PolicyQualifierInfo</code> X509 structure
+		 * encoded as an Asn1Sequence.
+		 */
+		private PolicyQualifierInfo(
+			Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			policyQualifierId = DerObjectIdentifier.GetInstance(seq[0]);
+			qualifier = seq[1];
+		}
+
+		public static PolicyQualifierInfo GetInstance(
+			object obj)
+		{
+			if (obj is PolicyQualifierInfo)
+			{
+				return (PolicyQualifierInfo) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new PolicyQualifierInfo((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		/**
+		 * Returns a Der-encodable representation of this instance.
+		 *
+		 * @return a <code>Asn1Object</code> value
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(policyQualifierId, qualifier);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs b/Crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs
new file mode 100644
index 000000000..ad2961eb0
--- /dev/null
+++ b/Crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs
@@ -0,0 +1,82 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/// <remarks>
+	/// <pre>
+	/// PrivateKeyUsagePeriod ::= SEQUENCE
+	/// {
+	/// notBefore       [0]     GeneralizedTime OPTIONAL,
+	/// notAfter        [1]     GeneralizedTime OPTIONAL }
+	/// </pre>
+	/// </remarks>
+	public class PrivateKeyUsagePeriod
+		: Asn1Encodable
+	{
+		public static PrivateKeyUsagePeriod GetInstance(
+			object obj)
+		{
+			if (obj is PrivateKeyUsagePeriod)
+			{
+				return (PrivateKeyUsagePeriod) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new PrivateKeyUsagePeriod((Asn1Sequence) obj);
+			}
+
+			if (obj is X509Extension)
+			{
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+			}
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		private DerGeneralizedTime _notBefore, _notAfter;
+
+		private PrivateKeyUsagePeriod(
+			Asn1Sequence seq)
+		{
+			foreach (Asn1TaggedObject tObj in seq)
+			{
+				if (tObj.TagNo == 0)
+				{
+					_notBefore = DerGeneralizedTime.GetInstance(tObj, false);
+				}
+				else if (tObj.TagNo == 1)
+				{
+					_notAfter = DerGeneralizedTime.GetInstance(tObj, false);
+				}
+			}
+		}
+
+		public DerGeneralizedTime NotBefore
+		{
+			get { return _notBefore; }
+		}
+
+		public DerGeneralizedTime NotAfter
+		{
+			get { return _notAfter; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (_notBefore != null)
+			{
+				v.Add(new DerTaggedObject(false, 0, _notBefore));
+			}
+
+			if (_notAfter != null)
+			{
+				v.Add(new DerTaggedObject(false, 1, _notAfter));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/RSAPublicKeyStructure.cs b/Crypto/src/asn1/x509/RSAPublicKeyStructure.cs
new file mode 100644
index 000000000..bdcba783e
--- /dev/null
+++ b/Crypto/src/asn1/x509/RSAPublicKeyStructure.cs
@@ -0,0 +1,92 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class RsaPublicKeyStructure
+        : Asn1Encodable
+    {
+        private BigInteger modulus;
+        private BigInteger publicExponent;
+
+		public static RsaPublicKeyStructure GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static RsaPublicKeyStructure GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is RsaPublicKeyStructure)
+            {
+                return (RsaPublicKeyStructure) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new RsaPublicKeyStructure((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Invalid RsaPublicKeyStructure: " + obj.GetType().Name);
+        }
+
+		public RsaPublicKeyStructure(
+            BigInteger	modulus,
+            BigInteger	publicExponent)
+        {
+			if (modulus == null)
+				throw new ArgumentNullException("modulus");
+			if (publicExponent == null)
+				throw new ArgumentNullException("publicExponent");
+			if (modulus.SignValue <= 0)
+				throw new ArgumentException("Not a valid RSA modulus", "modulus");
+			if (publicExponent.SignValue <= 0)
+				throw new ArgumentException("Not a valid RSA public exponent", "publicExponent");
+
+            this.modulus = modulus;
+            this.publicExponent = publicExponent;
+        }
+
+		private RsaPublicKeyStructure(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			// Note: we are accepting technically incorrect (i.e. negative) values here
+			modulus = DerInteger.GetInstance(seq[0]).PositiveValue;
+			publicExponent = DerInteger.GetInstance(seq[1]).PositiveValue;
+		}
+
+		public BigInteger Modulus
+        {
+            get { return modulus; }
+        }
+
+		public BigInteger PublicExponent
+        {
+            get { return publicExponent; }
+        }
+
+		/**
+         * This outputs the key in Pkcs1v2 format.
+         * <pre>
+         *      RSAPublicKey ::= Sequence {
+         *                          modulus Integer, -- n
+         *                          publicExponent Integer, -- e
+         *                      }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(
+				new DerInteger(Modulus),
+				new DerInteger(PublicExponent));
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/ReasonFlags.cs b/Crypto/src/asn1/x509/ReasonFlags.cs
new file mode 100644
index 000000000..f204c36aa
--- /dev/null
+++ b/Crypto/src/asn1/x509/ReasonFlags.cs
@@ -0,0 +1,46 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The ReasonFlags object.
+     * <pre>
+     * ReasonFlags ::= BIT STRING {
+     *    unused(0),
+     *    keyCompromise(1),
+     *    cACompromise(2),
+     *    affiliationChanged(3),
+     *    superseded(4),
+     *    cessationOfOperation(5),
+     *    certficateHold(6)
+     * }
+     * </pre>
+     */
+    public class ReasonFlags
+        : DerBitString
+    {
+        public const int Unused                 = (1 << 7);
+        public const int KeyCompromise          = (1 << 6);
+        public const int CACompromise           = (1 << 5);
+        public const int AffiliationChanged     = (1 << 4);
+        public const int Superseded             = (1 << 3);
+        public const int CessationOfOperation   = (1 << 2);
+        public const int CertificateHold        = (1 << 1);
+        public const int PrivilegeWithdrawn     = (1 << 0);
+        public const int AACompromise           = (1 << 15);
+
+		/**
+         * @param reasons - the bitwise OR of the Key Reason flags giving the
+         * allowed uses for the key.
+         */
+        public ReasonFlags(
+            int reasons)
+             : base(GetBytes(reasons), GetPadBits(reasons))
+        {
+        }
+
+		public ReasonFlags(
+            DerBitString reasons)
+             : base(reasons.GetBytes(), reasons.PadBits)
+        {
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/RoleSyntax.cs b/Crypto/src/asn1/x509/RoleSyntax.cs
new file mode 100644
index 000000000..48c3c6cae
--- /dev/null
+++ b/Crypto/src/asn1/x509/RoleSyntax.cs
@@ -0,0 +1,230 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	* Implementation of the RoleSyntax object as specified by the RFC3281.
+	*
+	* <pre>
+	* RoleSyntax ::= SEQUENCE {
+	*                 roleAuthority  [0] GeneralNames OPTIONAL,
+	*                 roleName       [1] GeneralName
+	*           }
+	* </pre>
+	*/
+	public class RoleSyntax
+		: Asn1Encodable
+	{
+		private readonly GeneralNames	roleAuthority;
+		private readonly GeneralName	roleName;
+
+		/**
+		 * RoleSyntax factory method.
+		 * @param obj the object used to construct an instance of <code>
+		 * RoleSyntax</code>. It must be an instance of <code>RoleSyntax
+		 * </code> or <code>Asn1Sequence</code>.
+		 * @return the instance of <code>RoleSyntax</code> built from the
+		 * supplied object.
+		 * @throws java.lang.ArgumentException if the object passed
+		 * to the factory is not an instance of <code>RoleSyntax</code> or
+		 * <code>Asn1Sequence</code>.
+		 */
+		public static RoleSyntax GetInstance(
+			object obj)
+		{
+			if (obj is RoleSyntax)
+				return (RoleSyntax)obj;
+
+			if (obj != null)
+				return new RoleSyntax(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		/**
+		* Constructor.
+		* @param roleAuthority the role authority of this RoleSyntax.
+		* @param roleName    the role name of this RoleSyntax.
+		*/
+		public RoleSyntax(
+			GeneralNames	roleAuthority,
+			GeneralName		roleName)
+		{
+			if (roleName == null
+				|| roleName.TagNo != GeneralName.UniformResourceIdentifier
+				|| ((IAsn1String) roleName.Name).GetString().Equals(""))
+			{
+				throw new ArgumentException("the role name MUST be non empty and MUST " +
+					"use the URI option of GeneralName");
+			}
+
+			this.roleAuthority = roleAuthority;
+			this.roleName = roleName;
+		}
+
+		/**
+		* Constructor. Invoking this constructor is the same as invoking
+		* <code>new RoleSyntax(null, roleName)</code>.
+		* @param roleName    the role name of this RoleSyntax.
+		*/
+		public RoleSyntax(
+			GeneralName roleName)
+			: this(null, roleName)
+		{
+		}
+
+		/**
+		* Utility constructor. Takes a <code>string</code> argument representing
+		* the role name, builds a <code>GeneralName</code> to hold the role name
+		* and calls the constructor that takes a <code>GeneralName</code>.
+		* @param roleName
+		*/
+		public RoleSyntax(
+			string roleName)
+			: this(new GeneralName(GeneralName.UniformResourceIdentifier,
+				(roleName == null)? "": roleName))
+		{
+		}
+
+		/**
+		* Constructor that builds an instance of <code>RoleSyntax</code> by
+		* extracting the encoded elements from the <code>Asn1Sequence</code>
+		* object supplied.
+		* @param seq    an instance of <code>Asn1Sequence</code> that holds
+		* the encoded elements used to build this <code>RoleSyntax</code>.
+		*/
+		private RoleSyntax(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1 || seq.Count > 2)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			for (int i = 0; i != seq.Count; i++)
+			{
+				Asn1TaggedObject taggedObject = Asn1TaggedObject.GetInstance(seq[i]);
+				switch (taggedObject.TagNo)
+				{
+					case 0:
+						roleAuthority = GeneralNames.GetInstance(taggedObject, false);
+						break;
+					case 1:
+						roleName = GeneralName.GetInstance(taggedObject, true);
+						break;
+					default:
+						throw new ArgumentException("Unknown tag in RoleSyntax");
+				}
+			}
+		}
+
+		/**
+		* Gets the role authority of this RoleSyntax.
+		* @return    an instance of <code>GeneralNames</code> holding the
+		* role authority of this RoleSyntax.
+		*/
+		public GeneralNames RoleAuthority
+		{
+			get { return this.roleAuthority; }
+		}
+
+		/**
+		* Gets the role name of this RoleSyntax.
+		* @return    an instance of <code>GeneralName</code> holding the
+		* role name of this RoleSyntax.
+		*/
+		public GeneralName RoleName
+		{
+			get { return this.roleName; }
+		}
+
+		/**
+		* Gets the role name as a <code>java.lang.string</code> object.
+		* @return    the role name of this RoleSyntax represented as a
+		* <code>string</code> object.
+		*/
+		public string GetRoleNameAsString()
+		{
+			return ((IAsn1String) this.roleName.Name).GetString();
+		}
+
+		/**
+		* Gets the role authority as a <code>string[]</code> object.
+		* @return the role authority of this RoleSyntax represented as a
+		* <code>string[]</code> array.
+		*/
+		public string[] GetRoleAuthorityAsString()
+		{
+			if (roleAuthority == null)
+			{
+				return new string[0];
+			}
+
+			GeneralName[] names = roleAuthority.GetNames();
+			string[] namesString = new string[names.Length];
+			for(int i = 0; i < names.Length; i++)
+			{
+				Asn1Encodable asn1Value = names[i].Name;
+				if (asn1Value is IAsn1String)
+				{
+					namesString[i] = ((IAsn1String) asn1Value).GetString();
+				}
+				else
+				{
+					namesString[i] = asn1Value.ToString();
+				}
+			}
+
+			return namesString;
+		}
+
+		/**
+		* Implementation of the method <code>ToAsn1Object</code> as
+		* required by the superclass <code>ASN1Encodable</code>.
+		*
+		* <pre>
+		* RoleSyntax ::= SEQUENCE {
+		*                 roleAuthority  [0] GeneralNames OPTIONAL,
+		*                 roleName       [1] GeneralName
+		*           }
+		* </pre>
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (this.roleAuthority != null)
+			{
+				v.Add(new DerTaggedObject(false, 0, roleAuthority));
+			}
+
+			v.Add(new DerTaggedObject(true, 1, roleName));
+
+			return new DerSequence(v);
+		}
+
+		public override string ToString()
+		{
+			StringBuilder buff = new StringBuilder("Name: " + this.GetRoleNameAsString() +
+				" - Auth: ");
+
+			if (this.roleAuthority == null || roleAuthority.GetNames().Length == 0)
+			{
+				buff.Append("N/A");
+			}
+			else
+			{
+				string[] names = this.GetRoleAuthorityAsString();
+				buff.Append('[').Append(names[0]);
+				for(int i = 1; i < names.Length; i++)
+				{
+					buff.Append(", ").Append(names[i]);
+				}
+				buff.Append(']');
+			}
+
+			return buff.ToString();
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/SubjectDirectoryAttributes.cs b/Crypto/src/asn1/x509/SubjectDirectoryAttributes.cs
new file mode 100644
index 000000000..c76d94d78
--- /dev/null
+++ b/Crypto/src/asn1/x509/SubjectDirectoryAttributes.cs
@@ -0,0 +1,142 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * This extension may contain further X.500 attributes of the subject. See also
+	 * RFC 3039.
+	 *
+	 * <pre>
+	 *     SubjectDirectoryAttributes ::= Attributes
+	 *     Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+	 *     Attribute ::= SEQUENCE
+	 *     {
+	 *       type AttributeType
+	 *       values SET OF AttributeValue
+	 *     }
+	 *
+	 *     AttributeType ::= OBJECT IDENTIFIER
+	 *     AttributeValue ::= ANY DEFINED BY AttributeType
+	 * </pre>
+	 *
+	 * @see org.bouncycastle.asn1.x509.X509Name for AttributeType ObjectIdentifiers.
+	 */
+	public class SubjectDirectoryAttributes
+		: Asn1Encodable
+	{
+		private readonly IList attributes;
+
+		public static SubjectDirectoryAttributes GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is SubjectDirectoryAttributes)
+			{
+				return (SubjectDirectoryAttributes) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new SubjectDirectoryAttributes((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		 * Constructor from Asn1Sequence.
+		 *
+		 * The sequence is of type SubjectDirectoryAttributes:
+		 *
+		 * <pre>
+		 *      SubjectDirectoryAttributes ::= Attributes
+		 *      Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+		 *      Attribute ::= SEQUENCE
+		 *      {
+		 *        type AttributeType
+		 *        values SET OF AttributeValue
+		 *      }
+		 *
+		 *      AttributeType ::= OBJECT IDENTIFIER
+		 *      AttributeValue ::= ANY DEFINED BY AttributeType
+		 * </pre>
+		 *
+		 * @param seq
+		 *            The ASN.1 sequence.
+		 */
+		private SubjectDirectoryAttributes(
+			Asn1Sequence seq)
+		{
+            this.attributes = Platform.CreateArrayList();
+            foreach (object o in seq)
+			{
+				Asn1Sequence s = Asn1Sequence.GetInstance(o);
+				attributes.Add(AttributeX509.GetInstance(s));
+			}
+		}
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete]
+        public SubjectDirectoryAttributes(
+            ArrayList attributes)
+            : this((IList)attributes)
+        {
+        }
+#endif
+
+        /**
+		 * Constructor from an ArrayList of attributes.
+		 *
+		 * The ArrayList consists of attributes of type {@link Attribute Attribute}
+		 *
+		 * @param attributes The attributes.
+		 *
+		 */
+		public SubjectDirectoryAttributes(
+			IList attributes)
+		{
+            this.attributes = Platform.CreateArrayList(attributes);
+        }
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 *
+		 * Returns:
+		 *
+		 * <pre>
+		 *      SubjectDirectoryAttributes ::= Attributes
+		 *      Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+		 *      Attribute ::= SEQUENCE
+		 *      {
+		 *        type AttributeType
+		 *        values SET OF AttributeValue
+		 *      }
+		 *
+		 *      AttributeType ::= OBJECT IDENTIFIER
+		 *      AttributeValue ::= ANY DEFINED BY AttributeType
+		 * </pre>
+		 *
+		 * @return a DERObject
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+            AttributeX509[] v = new AttributeX509[attributes.Count];
+            for (int i = 0; i < attributes.Count; ++i)
+            {
+                v[i] = (AttributeX509)attributes[i];
+            }
+            return new DerSequence(v);
+		}
+
+        /**
+		 * @return Returns the attributes.
+		 */
+		public IEnumerable Attributes
+		{
+			get { return new EnumerableProxy(attributes); }
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/SubjectKeyIdentifier.cs b/Crypto/src/asn1/x509/SubjectKeyIdentifier.cs
new file mode 100644
index 000000000..e640760f3
--- /dev/null
+++ b/Crypto/src/asn1/x509/SubjectKeyIdentifier.cs
@@ -0,0 +1,141 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The SubjectKeyIdentifier object.
+     * <pre>
+     * SubjectKeyIdentifier::= OCTET STRING
+     * </pre>
+     */
+    public class SubjectKeyIdentifier
+        : Asn1Encodable
+    {
+        private readonly byte[] keyIdentifier;
+
+		public static SubjectKeyIdentifier GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1OctetString.GetInstance(obj, explicitly));
+        }
+
+		public static SubjectKeyIdentifier GetInstance(
+            object obj)
+        {
+            if (obj is SubjectKeyIdentifier)
+            {
+                return (SubjectKeyIdentifier) obj;
+            }
+
+			if (obj is SubjectPublicKeyInfo)
+            {
+                return new SubjectKeyIdentifier((SubjectPublicKeyInfo) obj);
+            }
+
+			if (obj is Asn1OctetString)
+            {
+                return new SubjectKeyIdentifier((Asn1OctetString) obj);
+            }
+
+			if (obj is X509Extension)
+			{
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+			}
+
+			throw new ArgumentException("Invalid SubjectKeyIdentifier: " + obj.GetType().Name);
+        }
+
+		public SubjectKeyIdentifier(
+            byte[] keyID)
+        {
+			if (keyID == null)
+				throw new ArgumentNullException("keyID");
+
+			this.keyIdentifier = keyID;
+        }
+
+		public SubjectKeyIdentifier(
+            Asn1OctetString keyID)
+        {
+            this.keyIdentifier = keyID.GetOctets();
+        }
+
+		/**
+		 * Calculates the keyIdentifier using a SHA1 hash over the BIT STRING
+		 * from SubjectPublicKeyInfo as defined in RFC3280.
+		 *
+		 * @param spki the subject public key info.
+		 */
+		public SubjectKeyIdentifier(
+			SubjectPublicKeyInfo spki)
+		{
+			this.keyIdentifier = GetDigest(spki);
+		}
+
+		public byte[] GetKeyIdentifier()
+		{
+			return keyIdentifier;
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerOctetString(keyIdentifier);
+		}
+
+		/**
+		 * 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 keyInfo the key info object containing the subjectPublicKey field.
+		 * @return the key identifier.
+		 */
+		public static SubjectKeyIdentifier CreateSha1KeyIdentifier(
+			SubjectPublicKeyInfo keyInfo)
+		{
+			return new SubjectKeyIdentifier(keyInfo);
+		}
+
+		/**
+		 * 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 keyInfo the key info object containing the subjectPublicKey field.
+		 * @return the key identifier.
+		 */
+		public static SubjectKeyIdentifier CreateTruncatedSha1KeyIdentifier(
+			SubjectPublicKeyInfo keyInfo)
+		{
+			byte[] dig = GetDigest(keyInfo);
+			byte[] id = new byte[8];
+
+			Array.Copy(dig, dig.Length - 8, id, 0, id.Length);
+
+			id[0] &= 0x0f;
+			id[0] |= 0x40;
+
+			return new SubjectKeyIdentifier(id);
+		}
+
+		private static byte[] GetDigest(
+			SubjectPublicKeyInfo spki)
+		{
+            IDigest digest = new Sha1Digest();
+            byte[] resBuf = new byte[digest.GetDigestSize()];
+
+			byte[] bytes = spki.PublicKeyData.GetBytes();
+            digest.BlockUpdate(bytes, 0, bytes.Length);
+            digest.DoFinal(resBuf, 0);
+            return resBuf;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/SubjectPublicKeyInfo.cs b/Crypto/src/asn1/x509/SubjectPublicKeyInfo.cs
new file mode 100644
index 000000000..8ce4b2762
--- /dev/null
+++ b/Crypto/src/asn1/x509/SubjectPublicKeyInfo.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The object that contains the public key stored in a certficate.
+     * <p>
+     * The GetEncoded() method in the public keys in the JCE produces a DER
+     * encoded one of these.</p>
+     */
+    public class SubjectPublicKeyInfo
+        : Asn1Encodable
+    {
+        private readonly AlgorithmIdentifier	algID;
+        private readonly DerBitString			keyData;
+
+		public static SubjectPublicKeyInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static SubjectPublicKeyInfo GetInstance(
+            object obj)
+        {
+            if (obj is SubjectPublicKeyInfo)
+                return (SubjectPublicKeyInfo) obj;
+
+			if (obj != null)
+				return new SubjectPublicKeyInfo(Asn1Sequence.GetInstance(obj));
+
+			return null;
+        }
+
+		public SubjectPublicKeyInfo(
+            AlgorithmIdentifier	algID,
+            Asn1Encodable		publicKey)
+        {
+            this.keyData = new DerBitString(publicKey);
+            this.algID = algID;
+        }
+
+		public SubjectPublicKeyInfo(
+            AlgorithmIdentifier	algID,
+            byte[]				publicKey)
+        {
+            this.keyData = new DerBitString(publicKey);
+            this.algID = algID;
+        }
+
+		private SubjectPublicKeyInfo(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+            this.algID = AlgorithmIdentifier.GetInstance(seq[0]);
+			this.keyData = DerBitString.GetInstance(seq[1]);
+		}
+
+		public AlgorithmIdentifier AlgorithmID
+        {
+			get { return algID; }
+        }
+
+		/**
+         * for when the public key is an encoded object - if the bitstring
+         * can't be decoded this routine raises an IOException.
+         *
+         * @exception IOException - if the bit string doesn't represent a Der
+         * encoded object.
+         */
+        public Asn1Object GetPublicKey()
+        {
+			return Asn1Object.FromByteArray(keyData.GetBytes());
+        }
+
+		/**
+         * for when the public key is raw bits...
+         */
+        public DerBitString PublicKeyData
+        {
+			get { return keyData; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * SubjectPublicKeyInfo ::= Sequence {
+         *                          algorithm AlgorithmIdentifier,
+         *                          publicKey BIT STRING }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(algID, keyData);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/TBSCertList.cs b/Crypto/src/asn1/x509/TBSCertList.cs
new file mode 100644
index 000000000..b5934a230
--- /dev/null
+++ b/Crypto/src/asn1/x509/TBSCertList.cs
@@ -0,0 +1,274 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	public class CrlEntry
+		: Asn1Encodable
+	{
+		internal Asn1Sequence	seq;
+		internal DerInteger		userCertificate;
+		internal Time			revocationDate;
+		internal X509Extensions	crlEntryExtensions;
+
+		public CrlEntry(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 2 || seq.Count > 3)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			this.seq = seq;
+
+			userCertificate = DerInteger.GetInstance(seq[0]);
+			revocationDate = Time.GetInstance(seq[1]);
+		}
+
+		public DerInteger UserCertificate
+		{
+			get { return userCertificate; }
+		}
+
+		public Time RevocationDate
+		{
+			get { return revocationDate; }
+		}
+
+		public X509Extensions Extensions
+		{
+			get
+			{
+				if (crlEntryExtensions == null && seq.Count == 3)
+				{
+					crlEntryExtensions = X509Extensions.GetInstance(seq[2]);
+				}
+
+				return crlEntryExtensions;
+			}
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return seq;
+		}
+	}
+
+	/**
+     * PKIX RFC-2459 - TbsCertList object.
+     * <pre>
+     * TbsCertList  ::=  Sequence  {
+     *      version                 Version OPTIONAL,
+     *                                   -- if present, shall be v2
+     *      signature               AlgorithmIdentifier,
+     *      issuer                  Name,
+     *      thisUpdate              Time,
+     *      nextUpdate              Time OPTIONAL,
+     *      revokedCertificates     Sequence OF Sequence  {
+     *           userCertificate         CertificateSerialNumber,
+     *           revocationDate          Time,
+     *           crlEntryExtensions      Extensions OPTIONAL
+     *                                         -- if present, shall be v2
+     *                                }  OPTIONAL,
+     *      crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
+     *                                         -- if present, shall be v2
+     *                                }
+     * </pre>
+     */
+    public class TbsCertificateList
+        : Asn1Encodable
+    {
+		private class RevokedCertificatesEnumeration
+			: IEnumerable
+		{
+			private readonly IEnumerable en;
+
+			internal RevokedCertificatesEnumeration(
+				IEnumerable en)
+			{
+				this.en = en;
+			}
+
+			public IEnumerator GetEnumerator()
+			{
+				return new RevokedCertificatesEnumerator(en.GetEnumerator());
+			}
+
+			private class RevokedCertificatesEnumerator
+				: IEnumerator
+			{
+				private readonly IEnumerator e;
+
+				internal RevokedCertificatesEnumerator(
+					IEnumerator e)
+				{
+					this.e = e;
+				}
+
+				public bool MoveNext()
+				{
+					return e.MoveNext();
+				}
+
+				public void Reset()
+				{
+					e.Reset();
+				}
+
+				public object Current
+				{
+					get { return new CrlEntry(Asn1Sequence.GetInstance(e.Current)); }
+				}
+			}
+		}
+
+		internal Asn1Sequence			seq;
+		internal DerInteger				version;
+        internal AlgorithmIdentifier	signature;
+        internal X509Name				issuer;
+        internal Time					thisUpdate;
+        internal Time					nextUpdate;
+		internal Asn1Sequence			revokedCertificates;
+		internal X509Extensions			crlExtensions;
+
+		public static TbsCertificateList GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static TbsCertificateList GetInstance(
+            object obj)
+        {
+            TbsCertificateList list = obj as TbsCertificateList;
+
+			if (obj == null || list != null)
+            {
+                return list;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new TbsCertificateList((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        }
+
+		internal TbsCertificateList(
+            Asn1Sequence seq)
+        {
+			if (seq.Count < 3 || seq.Count > 7)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			int seqPos = 0;
+
+			this.seq = seq;
+
+			if (seq[seqPos] is DerInteger)
+            {
+				version = DerInteger.GetInstance(seq[seqPos++]);
+			}
+            else
+            {
+                version = new DerInteger(0);
+            }
+
+			signature = AlgorithmIdentifier.GetInstance(seq[seqPos++]);
+            issuer = X509Name.GetInstance(seq[seqPos++]);
+            thisUpdate = Time.GetInstance(seq[seqPos++]);
+
+			if (seqPos < seq.Count
+                && (seq[seqPos] is DerUtcTime
+                   || seq[seqPos] is DerGeneralizedTime
+                   || seq[seqPos] is Time))
+            {
+                nextUpdate = Time.GetInstance(seq[seqPos++]);
+            }
+
+			if (seqPos < seq.Count
+                && !(seq[seqPos] is DerTaggedObject))
+            {
+				revokedCertificates = Asn1Sequence.GetInstance(seq[seqPos++]);
+			}
+
+			if (seqPos < seq.Count
+                && seq[seqPos] is DerTaggedObject)
+            {
+				crlExtensions = X509Extensions.GetInstance(seq[seqPos]);
+			}
+        }
+
+		public int Version
+        {
+            get { return version.Value.IntValue + 1; }
+        }
+
+		public DerInteger VersionNumber
+        {
+            get { return version; }
+        }
+
+		public AlgorithmIdentifier Signature
+        {
+            get { return signature; }
+        }
+
+		public X509Name Issuer
+        {
+            get { return issuer; }
+        }
+
+		public Time ThisUpdate
+        {
+            get { return thisUpdate; }
+        }
+
+		public Time NextUpdate
+        {
+            get { return nextUpdate; }
+        }
+
+		public CrlEntry[] GetRevokedCertificates()
+        {
+			if (revokedCertificates == null)
+			{
+				return new CrlEntry[0];
+			}
+
+			CrlEntry[] entries = new CrlEntry[revokedCertificates.Count];
+
+			for (int i = 0; i < entries.Length; i++)
+			{
+				entries[i] = new CrlEntry(Asn1Sequence.GetInstance(revokedCertificates[i]));
+			}
+
+			return entries;
+		}
+
+		public IEnumerable GetRevokedCertificateEnumeration()
+		{
+			if (revokedCertificates == null)
+			{
+				return EmptyEnumerable.Instance;
+			}
+
+			return new RevokedCertificatesEnumeration(revokedCertificates);
+		}
+
+		public X509Extensions Extensions
+        {
+            get { return crlExtensions; }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return seq;
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/TBSCertificateStructure.cs b/Crypto/src/asn1/x509/TBSCertificateStructure.cs
new file mode 100644
index 000000000..fc7c39ba2
--- /dev/null
+++ b/Crypto/src/asn1/x509/TBSCertificateStructure.cs
@@ -0,0 +1,185 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The TbsCertificate object.
+     * <pre>
+     * TbsCertificate ::= Sequence {
+     *      version          [ 0 ]  Version DEFAULT v1(0),
+     *      serialNumber            CertificateSerialNumber,
+     *      signature               AlgorithmIdentifier,
+     *      issuer                  Name,
+     *      validity                Validity,
+     *      subject                 Name,
+     *      subjectPublicKeyInfo    SubjectPublicKeyInfo,
+     *      issuerUniqueID    [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
+     *      subjectUniqueID   [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
+     *      extensions        [ 3 ] Extensions OPTIONAL
+     *      }
+     * </pre>
+     * <p>
+     * Note: issuerUniqueID and subjectUniqueID are both deprecated by the IETF. This class
+     * will parse them, but you really shouldn't be creating new ones.</p>
+     */
+	public class TbsCertificateStructure
+		: Asn1Encodable
+	{
+		internal Asn1Sequence            seq;
+		internal DerInteger              version;
+		internal DerInteger              serialNumber;
+		internal AlgorithmIdentifier     signature;
+		internal X509Name                issuer;
+		internal Time                    startDate, endDate;
+		internal X509Name                subject;
+		internal SubjectPublicKeyInfo    subjectPublicKeyInfo;
+		internal DerBitString            issuerUniqueID;
+		internal DerBitString            subjectUniqueID;
+		internal X509Extensions          extensions;
+
+		public static TbsCertificateStructure GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static TbsCertificateStructure GetInstance(
+			object obj)
+		{
+			if (obj is TbsCertificateStructure)
+				return (TbsCertificateStructure) obj;
+
+			if (obj != null)
+				return new TbsCertificateStructure(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		internal TbsCertificateStructure(
+			Asn1Sequence seq)
+		{
+			int seqStart = 0;
+
+			this.seq = seq;
+
+			//
+			// some certficates don't include a version number - we assume v1
+			//
+			if (seq[0] is DerTaggedObject)
+			{
+				version = DerInteger.GetInstance((Asn1TaggedObject)seq[0], true);
+			}
+			else
+			{
+				seqStart = -1;          // field 0 is missing!
+				version = new DerInteger(0);
+			}
+
+			serialNumber = DerInteger.GetInstance(seq[seqStart + 1]);
+
+			signature = AlgorithmIdentifier.GetInstance(seq[seqStart + 2]);
+			issuer = X509Name.GetInstance(seq[seqStart + 3]);
+
+			//
+			// before and after dates
+			//
+			Asn1Sequence  dates = (Asn1Sequence)seq[seqStart + 4];
+
+			startDate = Time.GetInstance(dates[0]);
+			endDate = Time.GetInstance(dates[1]);
+
+			subject = X509Name.GetInstance(seq[seqStart + 5]);
+
+			//
+			// public key info.
+			//
+			subjectPublicKeyInfo = SubjectPublicKeyInfo.GetInstance(seq[seqStart + 6]);
+
+			for (int extras = seq.Count - (seqStart + 6) - 1; extras > 0; extras--)
+			{
+				DerTaggedObject extra = (DerTaggedObject) seq[seqStart + 6 + extras];
+
+				switch (extra.TagNo)
+				{
+					case 1:
+						issuerUniqueID = DerBitString.GetInstance(extra, false);
+						break;
+					case 2:
+						subjectUniqueID = DerBitString.GetInstance(extra, false);
+						break;
+					case 3:
+						extensions = X509Extensions.GetInstance(extra);
+						break;
+				}
+			}
+		}
+
+		public int Version
+		{
+			get { return version.Value.IntValue + 1; }
+		}
+
+		public DerInteger VersionNumber
+		{
+			get { return version; }
+		}
+
+		public DerInteger SerialNumber
+		{
+			get { return serialNumber; }
+		}
+
+		public AlgorithmIdentifier Signature
+		{
+			get { return signature; }
+		}
+
+		public X509Name Issuer
+		{
+			get { return issuer; }
+		}
+
+		public Time StartDate
+		{
+			get { return startDate; }
+		}
+
+		public Time EndDate
+		{
+			get { return endDate; }
+		}
+
+		public X509Name Subject
+		{
+			get { return subject; }
+		}
+
+		public SubjectPublicKeyInfo SubjectPublicKeyInfo
+		{
+			get { return subjectPublicKeyInfo; }
+		}
+
+		public DerBitString IssuerUniqueID
+		{
+			get { return issuerUniqueID; }
+        }
+
+		public DerBitString SubjectUniqueID
+        {
+			get { return subjectUniqueID; }
+        }
+
+		public X509Extensions Extensions
+        {
+			get { return extensions; }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return seq;
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/Target.cs b/Crypto/src/asn1/x509/Target.cs
new file mode 100644
index 000000000..309b28c95
--- /dev/null
+++ b/Crypto/src/asn1/x509/Target.cs
@@ -0,0 +1,139 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * Target structure used in target information extension for attribute
+	 * certificates from RFC 3281.
+	 * 
+	 * <pre>
+	 *     Target  ::= CHOICE {
+	 *       targetName          [0] GeneralName,
+	 *       targetGroup         [1] GeneralName,
+	 *       targetCert          [2] TargetCert
+	 *     }
+	 * </pre>
+	 * 
+	 * <p>
+	 * The targetCert field is currently not supported and must not be used
+	 * according to RFC 3281.</p>
+	 */
+	public class Target
+		: Asn1Encodable, IAsn1Choice
+	{
+		public enum Choice
+		{
+			Name = 0,
+			Group = 1
+		};
+
+		private readonly GeneralName targetName;
+		private readonly GeneralName targetGroup;
+
+		/**
+		* Creates an instance of a Target from the given object.
+		* <p>
+		* <code>obj</code> can be a Target or a {@link Asn1TaggedObject}</p>
+		* 
+		* @param obj The object.
+		* @return A Target instance.
+		* @throws ArgumentException if the given object cannot be
+		*             interpreted as Target.
+		*/
+		public static Target GetInstance(
+			object obj)
+		{
+			if (obj is Target)
+			{
+				return (Target) obj;
+			}
+
+			if (obj is Asn1TaggedObject)
+			{
+				return new Target((Asn1TaggedObject) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		 * Constructor from Asn1TaggedObject.
+		 * 
+		 * @param tagObj The tagged object.
+		 * @throws ArgumentException if the encoding is wrong.
+		 */
+		private Target(
+			Asn1TaggedObject tagObj)
+		{
+			switch ((Choice) tagObj.TagNo)
+			{
+				case Choice.Name:	// GeneralName is already a choice so explicit
+					targetName = GeneralName.GetInstance(tagObj, true);
+					break;
+				case Choice.Group:
+					targetGroup = GeneralName.GetInstance(tagObj, true);
+					break;
+				default:
+					throw new ArgumentException("unknown tag: " + tagObj.TagNo);
+			}
+		}
+
+		/**
+		 * Constructor from given details.
+		 * <p>
+		 * Exactly one of the parameters must be not <code>null</code>.</p>
+		 *
+		 * @param type the choice type to apply to the name.
+		 * @param name the general name.
+		 * @throws ArgumentException if type is invalid.
+		 */
+		public Target(
+			Choice		type,
+			GeneralName	name)
+			: this(new DerTaggedObject((int) type, name))
+		{
+		}
+
+		/**
+		 * @return Returns the targetGroup.
+		 */
+		public virtual GeneralName TargetGroup
+		{
+			get { return targetGroup; }
+		}
+
+		/**
+		 * @return Returns the targetName.
+		 */
+		public virtual GeneralName TargetName
+		{
+			get { return targetName; }
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * 
+		 * Returns:
+		 * 
+		 * <pre>
+		 *     Target  ::= CHOICE {
+		 *       targetName          [0] GeneralName,
+		 *       targetGroup         [1] GeneralName,
+		 *       targetCert          [2] TargetCert
+		 *     }
+		 * </pre>
+		 * 
+		 * @return an Asn1Object
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			// GeneralName is a choice already so most be explicitly tagged
+			if (targetName != null)
+			{
+				return new DerTaggedObject(true, 0, targetName);
+			}
+
+			return new DerTaggedObject(true, 1, targetGroup);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/TargetInformation.cs b/Crypto/src/asn1/x509/TargetInformation.cs
new file mode 100644
index 000000000..75b18c0c9
--- /dev/null
+++ b/Crypto/src/asn1/x509/TargetInformation.cs
@@ -0,0 +1,123 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * Target information extension for attributes certificates according to RFC
+	 * 3281.
+	 * 
+	 * <pre>
+	 *           SEQUENCE OF Targets
+	 * </pre>
+	 * 
+	 */
+	public class TargetInformation
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence targets;
+
+		/**
+		 * Creates an instance of a TargetInformation from the given object.
+		 * <p>
+		 * <code>obj</code> can be a TargetInformation or a {@link Asn1Sequence}</p>
+		 * 
+		 * @param obj The object.
+		 * @return A TargetInformation instance.
+		 * @throws ArgumentException if the given object cannot be interpreted as TargetInformation.
+		 */
+		public static TargetInformation GetInstance(
+			object obj)
+		{
+			if (obj is TargetInformation)
+			{
+				return (TargetInformation) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new TargetInformation((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		 * Constructor from a Asn1Sequence.
+		 * 
+		 * @param seq The Asn1Sequence.
+		 * @throws ArgumentException if the sequence does not contain
+		 *             correctly encoded Targets elements.
+		 */
+		private TargetInformation(
+			Asn1Sequence targets)
+		{
+			this.targets = targets;
+		}
+
+		/**
+		 * Returns the targets in this target information extension.
+		 * <p>
+		 * The ArrayList is cloned before it is returned.</p>
+		 * 
+		 * @return Returns the targets.
+		 */
+		public virtual Targets[] GetTargetsObjects()
+		{
+			Targets[] result = new Targets[targets.Count];
+
+			for (int i = 0; i < targets.Count; ++i)
+			{
+				result[i] = Targets.GetInstance(targets[i]);
+			}
+
+			return result;
+		}
+
+		/**
+		 * Constructs a target information from a single targets element. 
+		 * According to RFC 3281 only one targets element must be produced.
+		 * 
+		 * @param targets A Targets instance.
+		 */
+		public TargetInformation(
+			Targets targets)
+		{
+			this.targets = new DerSequence(targets);
+		}
+
+		/**
+		 * According to RFC 3281 only one targets element must be produced. If
+		 * multiple targets are given they must be merged in
+		 * into one targets element.
+		 *
+		 * @param targets An array with {@link Targets}.
+		 */
+		public TargetInformation(
+			Target[] targets)
+			: this(new Targets(targets))
+		{
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * 
+		 * Returns:
+		 * 
+		 * <pre>
+		 *          SEQUENCE OF Targets
+		 * </pre>
+		 * 
+		 * <p>
+		 * According to RFC 3281 only one targets element must be produced. If
+		 * multiple targets are given in the constructor they are merged into one
+		 * targets element. If this was produced from a
+		 * {@link Org.BouncyCastle.Asn1.Asn1Sequence} the encoding is kept.</p>
+		 * 
+		 * @return an Asn1Object
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return targets;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/Targets.cs b/Crypto/src/asn1/x509/Targets.cs
new file mode 100644
index 000000000..3e436d8d8
--- /dev/null
+++ b/Crypto/src/asn1/x509/Targets.cs
@@ -0,0 +1,121 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * Targets structure used in target information extension for attribute
+	 * certificates from RFC 3281.
+	 * 
+	 * <pre>
+	 *            Targets ::= SEQUENCE OF Target
+	 *           
+	 *            Target  ::= CHOICE {
+	 *              targetName          [0] GeneralName,
+	 *              targetGroup         [1] GeneralName,
+	 *              targetCert          [2] TargetCert
+	 *            }
+	 *           
+	 *            TargetCert  ::= SEQUENCE {
+	 *              targetCertificate    IssuerSerial,
+	 *              targetName           GeneralName OPTIONAL,
+	 *              certDigestInfo       ObjectDigestInfo OPTIONAL
+	 *            }
+	 * </pre>
+	 * 
+	 * @see org.bouncycastle.asn1.x509.Target
+	 * @see org.bouncycastle.asn1.x509.TargetInformation
+	 */
+	public class Targets
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence targets;
+
+		/**
+		 * Creates an instance of a Targets from the given object.
+		 * <p>
+		 * <code>obj</code> can be a Targets or a {@link Asn1Sequence}</p>
+		 * 
+		 * @param obj The object.
+		 * @return A Targets instance.
+		 * @throws ArgumentException if the given object cannot be interpreted as Target.
+		 */
+		public static Targets GetInstance(
+			object obj)
+		{
+			if (obj is Targets)
+			{
+				return (Targets) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new Targets((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		 * Constructor from Asn1Sequence.
+		 * 
+		 * @param targets The ASN.1 SEQUENCE.
+		 * @throws ArgumentException if the contents of the sequence are
+		 *             invalid.
+		 */
+		private Targets(
+			Asn1Sequence targets)
+		{
+			this.targets = targets;
+		}
+
+		/**
+		 * Constructor from given targets.
+		 * <p>
+		 * The ArrayList is copied.</p>
+		 * 
+		 * @param targets An <code>ArrayList</code> of {@link Target}s.
+		 * @see Target
+		 * @throws ArgumentException if the ArrayList contains not only Targets.
+		 */
+		public Targets(
+			Target[] targets)
+		{
+			this.targets = new DerSequence(targets);
+		}
+
+		/**
+		 * Returns the targets in an <code>ArrayList</code>.
+		 * <p>
+		 * The ArrayList is cloned before it is returned.</p>
+		 * 
+		 * @return Returns the targets.
+		 */
+		public virtual Target[] GetTargets()
+		{
+			Target[] result = new Target[targets.Count];
+
+			for (int i = 0; i < targets.Count; ++i)
+			{
+				result[i] = Target.GetInstance(targets[i]);
+			}
+
+			return result;
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * 
+		 * Returns:
+		 * 
+		 * <pre>
+		 *            Targets ::= SEQUENCE OF Target
+		 * </pre>
+		 * 
+		 * @return an Asn1Object
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return targets;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/Time.cs b/Crypto/src/asn1/x509/Time.cs
new file mode 100644
index 000000000..ca4e99ac7
--- /dev/null
+++ b/Crypto/src/asn1/x509/Time.cs
@@ -0,0 +1,120 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class Time
+        : Asn1Encodable, IAsn1Choice
+    {
+        internal Asn1Object time;
+
+		public static Time GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(obj.GetObject());
+        }
+
+		public Time(
+            Asn1Object time)
+        {
+			if (time == null)
+				throw new ArgumentNullException("time");
+
+			if (!(time is DerUtcTime) && !(time is DerGeneralizedTime))
+            {
+                throw new ArgumentException("unknown object passed to Time");
+            }
+
+			this.time = time;
+        }
+
+		/**
+         * creates a time object from a given date - if the date is between 1950
+         * and 2049 a UTCTime object is Generated, otherwise a GeneralizedTime
+         * is used.
+         */
+        public Time(
+            DateTime date)
+        {
+            string d = date.ToString("yyyyMMddHHmmss") + "Z";
+
+			int year = Int32.Parse(d.Substring(0, 4));
+
+			if (year < 1950 || year > 2049)
+            {
+                time = new DerGeneralizedTime(d);
+            }
+            else
+            {
+                time = new DerUtcTime(d.Substring(2));
+            }
+        }
+
+		public static Time GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is Time)
+                return (Time) obj;
+
+			if (obj is DerUtcTime)
+                return new Time((DerUtcTime) obj);
+
+			if (obj is DerGeneralizedTime)
+                return new Time((DerGeneralizedTime) obj);
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        }
+
+		public string GetTime()
+        {
+            if (time is DerUtcTime)
+            {
+                return ((DerUtcTime) time).AdjustedTimeString;
+            }
+
+			return ((DerGeneralizedTime) time).GetTime();
+        }
+
+		/// <summary>
+        /// Return our time as DateTime.
+        /// </summary>
+        /// <returns>A date time.</returns>
+        public DateTime ToDateTime()
+        {
+			try
+			{
+				if (time is DerUtcTime)
+				{
+					return ((DerUtcTime)time).ToAdjustedDateTime();
+				}
+				else
+				{
+					return ((DerGeneralizedTime)time).ToDateTime();
+				}
+			}
+			catch (FormatException e)
+			{
+				// this should never happen
+				throw new InvalidOperationException("invalid date string: " + e.Message);
+			}
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * Time ::= CHOICE {
+         *             utcTime        UTCTime,
+         *             generalTime    GeneralizedTime }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return time;
+        }
+
+		public override string ToString()
+		{
+			return GetTime();
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/UserNotice.cs b/Crypto/src/asn1/x509/UserNotice.cs
new file mode 100644
index 000000000..2878a180f
--- /dev/null
+++ b/Crypto/src/asn1/x509/UserNotice.cs
@@ -0,0 +1,104 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * <code>UserNotice</code> class, used in
+     * <code>CertificatePolicies</code> X509 extensions (in policy
+     * qualifiers).
+     * <pre>
+     * UserNotice ::= Sequence {
+     *      noticeRef        NoticeReference OPTIONAL,
+     *      explicitText     DisplayText OPTIONAL}
+     *
+     * </pre>
+     *
+     * @see PolicyQualifierId
+     * @see PolicyInformation
+     */
+    public class UserNotice
+        : Asn1Encodable
+    {
+        internal NoticeReference	noticeRef;
+        internal DisplayText		explicitText;
+
+		/**
+         * Creates a new <code>UserNotice</code> instance.
+         *
+         * @param noticeRef a <code>NoticeReference</code> value
+         * @param explicitText a <code>DisplayText</code> value
+         */
+        public UserNotice(
+            NoticeReference	noticeRef,
+            DisplayText		explicitText)
+        {
+            this.noticeRef = noticeRef;
+            this.explicitText = explicitText;
+        }
+
+		/**
+         * Creates a new <code>UserNotice</code> instance.
+         *
+         * @param noticeRef a <code>NoticeReference</code> value
+         * @param str the explicitText field as a string.
+         */
+        public UserNotice(
+            NoticeReference	noticeRef,
+            string			str)
+        {
+            this.noticeRef = noticeRef;
+            this.explicitText = new DisplayText(str);
+        }
+
+		/**
+		 * Creates a new <code>UserNotice</code> instance.
+		 * <p>Useful from reconstructing a <code>UserNotice</code> instance
+		 * from its encodable/encoded form.
+		 *
+		 * @param as an <code>ASN1Sequence</code> value obtained from either
+		 * calling @{link toASN1Object()} for a <code>UserNotice</code>
+		 * instance or from parsing it from a DER-encoded stream.</p>
+		 */
+		public UserNotice(
+			Asn1Sequence seq)
+		{
+			if (seq.Count == 2)
+			{
+				noticeRef = NoticeReference.GetInstance(seq[0]);
+				explicitText = DisplayText.GetInstance(seq[1]);
+			}
+			else if (seq.Count == 1)
+			{
+				if (seq[0].ToAsn1Object() is Asn1Sequence)
+				{
+					noticeRef = NoticeReference.GetInstance(seq[0]);
+				}
+				else
+				{
+					explicitText = DisplayText.GetInstance(seq[0]);
+				}
+			}
+			else
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector av = new Asn1EncodableVector();
+
+			if (noticeRef != null)
+            {
+                av.Add(noticeRef);
+            }
+
+			if (explicitText != null)
+            {
+                av.Add(explicitText);
+            }
+
+			return new DerSequence(av);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/V1TBSCertificateGenerator.cs b/Crypto/src/asn1/x509/V1TBSCertificateGenerator.cs
new file mode 100644
index 000000000..20b525a48
--- /dev/null
+++ b/Crypto/src/asn1/x509/V1TBSCertificateGenerator.cs
@@ -0,0 +1,108 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * Generator for Version 1 TbsCertificateStructures.
+     * <pre>
+     * TbsCertificate ::= Sequence {
+     *      version          [ 0 ]  Version DEFAULT v1(0),
+     *      serialNumber            CertificateSerialNumber,
+     *      signature               AlgorithmIdentifier,
+     *      issuer                  Name,
+     *      validity                Validity,
+     *      subject                 Name,
+     *      subjectPublicKeyInfo    SubjectPublicKeyInfo,
+     *      }
+     * </pre>
+     *
+     */
+    public class V1TbsCertificateGenerator
+    {
+        internal DerTaggedObject		version = new DerTaggedObject(0, new DerInteger(0));
+        internal DerInteger				serialNumber;
+        internal AlgorithmIdentifier	signature;
+        internal X509Name				issuer;
+        internal Time					startDate, endDate;
+        internal X509Name				subject;
+        internal SubjectPublicKeyInfo	subjectPublicKeyInfo;
+
+		public V1TbsCertificateGenerator()
+        {
+        }
+
+		public void SetSerialNumber(
+            DerInteger serialNumber)
+        {
+            this.serialNumber = serialNumber;
+        }
+
+		public void SetSignature(
+            AlgorithmIdentifier signature)
+        {
+            this.signature = signature;
+        }
+
+		public void SetIssuer(
+            X509Name issuer)
+        {
+            this.issuer = issuer;
+        }
+
+		public void SetStartDate(
+            Time startDate)
+        {
+            this.startDate = startDate;
+        }
+
+		public void SetStartDate(
+            DerUtcTime startDate)
+        {
+            this.startDate = new Time(startDate);
+        }
+
+		public void SetEndDate(
+            Time endDate)
+        {
+            this.endDate = endDate;
+        }
+
+		public void SetEndDate(
+            DerUtcTime endDate)
+        {
+            this.endDate = new Time(endDate);
+        }
+
+		public void SetSubject(
+            X509Name subject)
+        {
+            this.subject = subject;
+        }
+
+		public void SetSubjectPublicKeyInfo(
+            SubjectPublicKeyInfo pubKeyInfo)
+        {
+            this.subjectPublicKeyInfo = pubKeyInfo;
+        }
+
+		public TbsCertificateStructure GenerateTbsCertificate()
+        {
+            if ((serialNumber == null) || (signature == null)
+                || (issuer == null) || (startDate == null) || (endDate == null)
+                || (subject == null) || (subjectPublicKeyInfo == null))
+            {
+                throw new InvalidOperationException("not all mandatory fields set in V1 TBScertificate generator");
+            }
+
+			return new TbsCertificateStructure(
+				new DerSequence(
+					//version, - not required as default value
+					serialNumber,
+					signature,
+					issuer,
+					new DerSequence(startDate, endDate), // before and after dates
+					subject,
+					subjectPublicKeyInfo));
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs b/Crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs
new file mode 100644
index 000000000..02580b5b8
--- /dev/null
+++ b/Crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs
@@ -0,0 +1,137 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * Generator for Version 2 AttributeCertificateInfo
+     * <pre>
+     * AttributeCertificateInfo ::= Sequence {
+     *       version              AttCertVersion -- version is v2,
+     *       holder               Holder,
+     *       issuer               AttCertIssuer,
+     *       signature            AlgorithmIdentifier,
+     *       serialNumber         CertificateSerialNumber,
+     *       attrCertValidityPeriod   AttCertValidityPeriod,
+     *       attributes           Sequence OF Attr,
+     *       issuerUniqueID       UniqueIdentifier OPTIONAL,
+     *       extensions           Extensions OPTIONAL
+     * }
+     * </pre>
+     *
+     */
+    public class V2AttributeCertificateInfoGenerator
+    {
+        internal DerInteger				version;
+        internal Holder					holder;
+        internal AttCertIssuer			issuer;
+        internal AlgorithmIdentifier	signature;
+        internal DerInteger				serialNumber;
+//        internal AttCertValidityPeriod	attrCertValidityPeriod;
+        internal Asn1EncodableVector	attributes;
+        internal DerBitString			issuerUniqueID;
+        internal X509Extensions			extensions;
+        internal DerGeneralizedTime		startDate, endDate;
+
+		public V2AttributeCertificateInfoGenerator()
+        {
+            this.version = new DerInteger(1);
+            attributes = new Asn1EncodableVector();
+        }
+
+		public void SetHolder(
+			Holder holder)
+        {
+            this.holder = holder;
+        }
+
+		public void AddAttribute(
+			string			oid,
+			Asn1Encodable	value)
+        {
+            attributes.Add(new AttributeX509(new DerObjectIdentifier(oid), new DerSet(value)));
+        }
+
+		/**
+         * @param attribute
+         */
+        public void AddAttribute(AttributeX509 attribute)
+        {
+            attributes.Add(attribute);
+        }
+
+		public void SetSerialNumber(
+            DerInteger serialNumber)
+        {
+            this.serialNumber = serialNumber;
+        }
+
+		public void SetSignature(
+            AlgorithmIdentifier signature)
+        {
+            this.signature = signature;
+        }
+
+		public void SetIssuer(
+            AttCertIssuer issuer)
+        {
+            this.issuer = issuer;
+        }
+
+		public void SetStartDate(
+            DerGeneralizedTime startDate)
+        {
+            this.startDate = startDate;
+        }
+
+		public void SetEndDate(
+            DerGeneralizedTime endDate)
+        {
+            this.endDate = endDate;
+        }
+
+		public void SetIssuerUniqueID(
+            DerBitString issuerUniqueID)
+        {
+            this.issuerUniqueID = issuerUniqueID;
+        }
+
+		public void SetExtensions(
+            X509Extensions extensions)
+        {
+            this.extensions = extensions;
+        }
+
+		public AttributeCertificateInfo GenerateAttributeCertificateInfo()
+        {
+            if ((serialNumber == null) || (signature == null)
+                || (issuer == null) || (startDate == null) || (endDate == null)
+                || (holder == null) || (attributes == null))
+            {
+                throw new InvalidOperationException("not all mandatory fields set in V2 AttributeCertificateInfo generator");
+            }
+
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				version, holder, issuer, signature, serialNumber);
+
+			//
+            // before and after dates => AttCertValidityPeriod
+            //
+            v.Add(new AttCertValidityPeriod(startDate, endDate));
+
+			// Attributes
+            v.Add(new DerSequence(attributes));
+
+			if (issuerUniqueID != null)
+            {
+                v.Add(issuerUniqueID);
+            }
+
+			if (extensions != null)
+            {
+                v.Add(extensions);
+            }
+
+			return AttributeCertificateInfo.GetInstance(new DerSequence(v));
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/V2Form.cs b/Crypto/src/asn1/x509/V2Form.cs
new file mode 100644
index 000000000..a9c43357c
--- /dev/null
+++ b/Crypto/src/asn1/x509/V2Form.cs
@@ -0,0 +1,125 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class V2Form
+        : Asn1Encodable
+    {
+        internal GeneralNames        issuerName;
+        internal IssuerSerial        baseCertificateID;
+        internal ObjectDigestInfo    objectDigestInfo;
+
+		public static V2Form GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static V2Form GetInstance(
+            object obj)
+        {
+            if (obj is V2Form)
+            {
+                return (V2Form) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new V2Form((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        }
+
+		public V2Form(
+            GeneralNames issuerName)
+        {
+            this.issuerName = issuerName;
+        }
+
+		private V2Form(
+            Asn1Sequence seq)
+        {
+			if (seq.Count > 3)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			int index = 0;
+
+			if (!(seq[0] is Asn1TaggedObject))
+            {
+                index++;
+                this.issuerName = GeneralNames.GetInstance(seq[0]);
+            }
+
+			for (int i = index; i != seq.Count; i++)
+            {
+				Asn1TaggedObject o = Asn1TaggedObject.GetInstance(seq[i]);
+				if (o.TagNo == 0)
+                {
+                    baseCertificateID = IssuerSerial.GetInstance(o, false);
+                }
+                else if (o.TagNo == 1)
+                {
+                    objectDigestInfo = ObjectDigestInfo.GetInstance(o, false);
+                }
+				else
+				{
+					throw new ArgumentException("Bad tag number: " + o.TagNo);
+				}
+			}
+        }
+
+		public GeneralNames IssuerName
+        {
+            get { return issuerName; }
+        }
+
+		public IssuerSerial BaseCertificateID
+        {
+            get { return baseCertificateID; }
+        }
+
+		public ObjectDigestInfo ObjectDigestInfo
+        {
+            get { return objectDigestInfo; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  V2Form ::= Sequence {
+         *       issuerName            GeneralNames  OPTIONAL,
+         *       baseCertificateID     [0] IssuerSerial  OPTIONAL,
+         *       objectDigestInfo      [1] ObjectDigestInfo  OPTIONAL
+         *         -- issuerName MUST be present in this profile
+         *         -- baseCertificateID and objectDigestInfo MUST NOT
+         *         -- be present in this profile
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (issuerName != null)
+            {
+                v.Add(issuerName);
+            }
+
+			if (baseCertificateID != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, baseCertificateID));
+            }
+
+			if (objectDigestInfo != null)
+            {
+                v.Add(new DerTaggedObject(false, 1, objectDigestInfo));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/V2TBSCertListGenerator.cs b/Crypto/src/asn1/x509/V2TBSCertListGenerator.cs
new file mode 100644
index 000000000..2c929188f
--- /dev/null
+++ b/Crypto/src/asn1/x509/V2TBSCertListGenerator.cs
@@ -0,0 +1,201 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * Generator for Version 2 TbsCertList structures.
+     * <pre>
+     *  TbsCertList  ::=  Sequence  {
+     *       version                 Version OPTIONAL,
+     *                                    -- if present, shall be v2
+     *       signature               AlgorithmIdentifier,
+     *       issuer                  Name,
+     *       thisUpdate              Time,
+     *       nextUpdate              Time OPTIONAL,
+     *       revokedCertificates     Sequence OF Sequence  {
+     *            userCertificate         CertificateSerialNumber,
+     *            revocationDate          Time,
+     *            crlEntryExtensions      Extensions OPTIONAL
+     *                                          -- if present, shall be v2
+     *                                 }  OPTIONAL,
+     *       crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
+     *                                          -- if present, shall be v2
+     *                                 }
+     * </pre>
+     *
+     * <b>Note: This class may be subject to change</b>
+     */
+    public class V2TbsCertListGenerator
+    {
+        private DerInteger			version = new DerInteger(1);
+        private AlgorithmIdentifier	signature;
+        private X509Name			issuer;
+        private Time				thisUpdate, nextUpdate;
+        private X509Extensions		extensions;
+        private IList			    crlEntries;
+
+		public V2TbsCertListGenerator()
+        {
+        }
+
+		public void SetSignature(
+            AlgorithmIdentifier signature)
+        {
+            this.signature = signature;
+        }
+
+		public void SetIssuer(
+            X509Name issuer)
+        {
+            this.issuer = issuer;
+        }
+
+		public void SetThisUpdate(
+            DerUtcTime thisUpdate)
+        {
+            this.thisUpdate = new Time(thisUpdate);
+        }
+
+		public void SetNextUpdate(
+            DerUtcTime nextUpdate)
+        {
+            this.nextUpdate = (nextUpdate != null)
+				?	new Time(nextUpdate)
+				:	null;
+        }
+
+		public void SetThisUpdate(
+            Time thisUpdate)
+        {
+            this.thisUpdate = thisUpdate;
+        }
+
+		public void SetNextUpdate(
+            Time nextUpdate)
+        {
+            this.nextUpdate = nextUpdate;
+        }
+
+		public void AddCrlEntry(
+			Asn1Sequence crlEntry)
+		{
+			if (crlEntries == null)
+			{
+				crlEntries = Platform.CreateArrayList();
+			}
+
+			crlEntries.Add(crlEntry);
+		}
+
+		public void AddCrlEntry(DerInteger userCertificate, DerUtcTime revocationDate, int reason)
+		{
+			AddCrlEntry(userCertificate, new Time(revocationDate), reason);
+		}
+
+		public void AddCrlEntry(DerInteger userCertificate, Time revocationDate, int reason)
+		{
+			AddCrlEntry(userCertificate, revocationDate, reason, null);
+		}
+
+		public void AddCrlEntry(DerInteger userCertificate, Time revocationDate, int reason,
+			DerGeneralizedTime invalidityDate)
+		{
+            IList extOids = Platform.CreateArrayList();
+            IList extValues = Platform.CreateArrayList();
+
+			if (reason != 0)
+			{
+				CrlReason crlReason = new CrlReason(reason);
+
+				try
+				{
+					extOids.Add(X509Extensions.ReasonCode);
+					extValues.Add(new X509Extension(false, new DerOctetString(crlReason.GetEncoded())));
+				}
+				catch (IOException e)
+				{
+					throw new ArgumentException("error encoding reason: " + e);
+				}
+			}
+
+			if (invalidityDate != null)
+			{
+				try
+				{
+					extOids.Add(X509Extensions.InvalidityDate);
+					extValues.Add(new X509Extension(false, new DerOctetString(invalidityDate.GetEncoded())));
+				}
+				catch (IOException e)
+				{
+					throw new ArgumentException("error encoding invalidityDate: " + e);
+				}
+			}
+
+			if (extOids.Count != 0)
+			{
+				AddCrlEntry(userCertificate, revocationDate, new X509Extensions(extOids, extValues));
+			}
+			else
+			{
+				AddCrlEntry(userCertificate, revocationDate, null);
+			}
+		}
+
+		public void AddCrlEntry(DerInteger userCertificate, Time revocationDate, X509Extensions extensions)
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				userCertificate, revocationDate);
+
+			if (extensions != null)
+			{
+				v.Add(extensions);
+			}
+
+			AddCrlEntry(new DerSequence(v));
+		}
+
+		public void SetExtensions(
+            X509Extensions extensions)
+        {
+            this.extensions = extensions;
+        }
+
+		public TbsCertificateList GenerateTbsCertList()
+        {
+            if ((signature == null) || (issuer == null) || (thisUpdate == null))
+            {
+                throw new InvalidOperationException("Not all mandatory fields set in V2 TbsCertList generator.");
+            }
+
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				version, signature, issuer, thisUpdate);
+
+			if (nextUpdate != null)
+            {
+                v.Add(nextUpdate);
+            }
+
+			// Add CRLEntries if they exist
+            if (crlEntries != null)
+            {
+                Asn1Sequence[] certs = new Asn1Sequence[crlEntries.Count];
+                for (int i = 0; i < crlEntries.Count; ++i)
+                {
+                    certs[i] = (Asn1Sequence)crlEntries[i];
+                }
+				v.Add(new DerSequence(certs));
+            }
+
+			if (extensions != null)
+            {
+                v.Add(new DerTaggedObject(0, extensions));
+            }
+
+			return new TbsCertificateList(new DerSequence(v));
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/V3TBSCertificateGenerator.cs b/Crypto/src/asn1/x509/V3TBSCertificateGenerator.cs
new file mode 100644
index 000000000..beb469a0d
--- /dev/null
+++ b/Crypto/src/asn1/x509/V3TBSCertificateGenerator.cs
@@ -0,0 +1,168 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * Generator for Version 3 TbsCertificateStructures.
+     * <pre>
+     * TbsCertificate ::= Sequence {
+     *      version          [ 0 ]  Version DEFAULT v1(0),
+     *      serialNumber            CertificateSerialNumber,
+     *      signature               AlgorithmIdentifier,
+     *      issuer                  Name,
+     *      validity                Validity,
+     *      subject                 Name,
+     *      subjectPublicKeyInfo    SubjectPublicKeyInfo,
+     *      issuerUniqueID    [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
+     *      subjectUniqueID   [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
+     *      extensions        [ 3 ] Extensions OPTIONAL
+     *      }
+     * </pre>
+     *
+     */
+    public class V3TbsCertificateGenerator
+    {
+        internal DerTaggedObject         version = new DerTaggedObject(0, new DerInteger(2));
+        internal DerInteger              serialNumber;
+        internal AlgorithmIdentifier     signature;
+        internal X509Name                issuer;
+        internal Time                    startDate, endDate;
+        internal X509Name                subject;
+        internal SubjectPublicKeyInfo    subjectPublicKeyInfo;
+        internal X509Extensions          extensions;
+
+		private bool altNamePresentAndCritical;
+		private DerBitString issuerUniqueID;
+		private DerBitString subjectUniqueID;
+
+		public V3TbsCertificateGenerator()
+        {
+        }
+
+		public void SetSerialNumber(
+            DerInteger serialNumber)
+        {
+            this.serialNumber = serialNumber;
+        }
+
+		public void SetSignature(
+            AlgorithmIdentifier signature)
+        {
+            this.signature = signature;
+        }
+
+		public void SetIssuer(
+            X509Name issuer)
+        {
+            this.issuer = issuer;
+        }
+
+		public void SetStartDate(
+            DerUtcTime startDate)
+        {
+            this.startDate = new Time(startDate);
+        }
+
+		public void SetStartDate(
+            Time startDate)
+        {
+            this.startDate = startDate;
+        }
+
+		public void SetEndDate(
+            DerUtcTime endDate)
+        {
+            this.endDate = new Time(endDate);
+        }
+
+		public void SetEndDate(
+            Time endDate)
+        {
+            this.endDate = endDate;
+        }
+
+		public void SetSubject(
+            X509Name subject)
+        {
+            this.subject = subject;
+        }
+
+		public void SetIssuerUniqueID(
+			DerBitString uniqueID)
+		{
+			this.issuerUniqueID = uniqueID;
+		}
+
+		public void SetSubjectUniqueID(
+			DerBitString uniqueID)
+		{
+			this.subjectUniqueID = uniqueID;
+		}
+
+		public void SetSubjectPublicKeyInfo(
+            SubjectPublicKeyInfo pubKeyInfo)
+        {
+            this.subjectPublicKeyInfo = pubKeyInfo;
+        }
+
+		public void SetExtensions(
+            X509Extensions extensions)
+        {
+            this.extensions = extensions;
+
+			if (extensions != null)
+			{
+				X509Extension altName = extensions.GetExtension(X509Extensions.SubjectAlternativeName);
+
+				if (altName != null && altName.IsCritical)
+				{
+					altNamePresentAndCritical = true;
+				}
+			}
+		}
+
+		public TbsCertificateStructure GenerateTbsCertificate()
+        {
+            if ((serialNumber == null) || (signature == null)
+                || (issuer == null) || (startDate == null) || (endDate == null)
+				|| (subject == null && !altNamePresentAndCritical)
+				|| (subjectPublicKeyInfo == null))
+            {
+                throw new InvalidOperationException("not all mandatory fields set in V3 TBScertificate generator");
+            }
+
+			DerSequence validity = new DerSequence(startDate, endDate); // before and after dates
+
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				version, serialNumber, signature, issuer, validity);
+
+			if (subject != null)
+			{
+				v.Add(subject);
+			}
+			else
+			{
+				v.Add(DerSequence.Empty);
+			}
+
+			v.Add(subjectPublicKeyInfo);
+
+			if (issuerUniqueID != null)
+			{
+				v.Add(new DerTaggedObject(false, 1, issuerUniqueID));
+			}
+
+			if (subjectUniqueID != null)
+			{
+				v.Add(new DerTaggedObject(false, 2, subjectUniqueID));
+			}
+
+			if (extensions != null)
+            {
+                v.Add(new DerTaggedObject(3, extensions));
+            }
+
+			return new TbsCertificateStructure(new DerSequence(v));
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/X509Attributes.cs b/Crypto/src/asn1/x509/X509Attributes.cs
new file mode 100644
index 000000000..291329a62
--- /dev/null
+++ b/Crypto/src/asn1/x509/X509Attributes.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	public class X509Attributes
+	{
+		public static readonly DerObjectIdentifier RoleSyntax = new DerObjectIdentifier("2.5.4.72");
+	}
+}
diff --git a/Crypto/src/asn1/x509/X509CertificateStructure.cs b/Crypto/src/asn1/x509/X509CertificateStructure.cs
new file mode 100644
index 000000000..e50d3563b
--- /dev/null
+++ b/Crypto/src/asn1/x509/X509CertificateStructure.cs
@@ -0,0 +1,129 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * an X509Certificate structure.
+     * <pre>
+     *  Certificate ::= Sequence {
+     *      tbsCertificate          TbsCertificate,
+     *      signatureAlgorithm      AlgorithmIdentifier,
+     *      signature               BIT STRING
+     *  }
+     * </pre>
+     */
+    public class X509CertificateStructure
+        : Asn1Encodable
+    {
+        private readonly TbsCertificateStructure	tbsCert;
+        private readonly AlgorithmIdentifier		sigAlgID;
+        private readonly DerBitString				sig;
+
+		public static X509CertificateStructure GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static X509CertificateStructure GetInstance(
+            object obj)
+        {
+            if (obj is X509CertificateStructure)
+                return (X509CertificateStructure)obj;
+
+			if (obj != null)
+				return new X509CertificateStructure(Asn1Sequence.GetInstance(obj));
+
+			return null;
+        }
+
+		public X509CertificateStructure(
+			TbsCertificateStructure	tbsCert,
+			AlgorithmIdentifier		sigAlgID,
+			DerBitString			sig)
+		{
+			if (tbsCert == null)
+				throw new ArgumentNullException("tbsCert");
+			if (sigAlgID == null)
+				throw new ArgumentNullException("sigAlgID");
+			if (sig == null)
+				throw new ArgumentNullException("sig");
+
+			this.tbsCert = tbsCert;
+			this.sigAlgID = sigAlgID;
+			this.sig = sig;
+		}
+
+		private X509CertificateStructure(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 3)
+				throw new ArgumentException("sequence wrong size for a certificate", "seq");
+
+			//
+            // correct x509 certficate
+            //
+			tbsCert = TbsCertificateStructure.GetInstance(seq[0]);
+			sigAlgID = AlgorithmIdentifier.GetInstance(seq[1]);
+			sig = DerBitString.GetInstance(seq[2]);
+        }
+
+		public TbsCertificateStructure TbsCertificate
+        {
+			get { return tbsCert; }
+        }
+
+		public int Version
+        {
+            get { return tbsCert.Version; }
+        }
+
+		public DerInteger SerialNumber
+        {
+            get { return tbsCert.SerialNumber; }
+        }
+
+		public X509Name Issuer
+        {
+            get { return tbsCert.Issuer; }
+        }
+
+		public Time StartDate
+        {
+            get { return tbsCert.StartDate; }
+        }
+
+		public Time EndDate
+        {
+            get { return tbsCert.EndDate; }
+        }
+
+		public X509Name Subject
+        {
+            get { return tbsCert.Subject; }
+        }
+
+		public SubjectPublicKeyInfo SubjectPublicKeyInfo
+        {
+            get { return tbsCert.SubjectPublicKeyInfo; }
+        }
+
+		public AlgorithmIdentifier SignatureAlgorithm
+        {
+            get { return sigAlgID; }
+        }
+
+		public DerBitString Signature
+        {
+            get { return sig; }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(tbsCert, sigAlgID, sig);
+        }
+	}
+}
diff --git a/Crypto/src/asn1/x509/X509DefaultEntryConverter.cs b/Crypto/src/asn1/x509/X509DefaultEntryConverter.cs
new file mode 100644
index 000000000..7282ead26
--- /dev/null
+++ b/Crypto/src/asn1/x509/X509DefaultEntryConverter.cs
@@ -0,0 +1,63 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The default converter for X509 DN entries when going from their
+     * string value to ASN.1 strings.
+     */
+    public class X509DefaultEntryConverter
+        : X509NameEntryConverter
+    {
+        /**
+         * Apply default conversion for the given value depending on the oid
+         * and the character range of the value.
+         *
+         * @param oid the object identifier for the DN entry
+         * @param value the value associated with it
+         * @return the ASN.1 equivalent for the string value.
+         */
+        public override Asn1Object GetConvertedValue(
+            DerObjectIdentifier	oid,
+            string				value)
+        {
+            if (value.Length != 0 && value[0] == '#')
+            {
+				try
+				{
+					return ConvertHexEncoded(value, 1);
+				}
+				catch (IOException)
+				{
+					throw new Exception("can't recode value for oid " + oid.Id);
+				}
+			}
+
+			if (value.Length != 0 && value[0] == '\\')
+			{
+				value = value.Substring(1);
+			}
+
+			if (oid.Equals(X509Name.EmailAddress) || oid.Equals(X509Name.DC))
+            {
+                return new DerIA5String(value);
+            }
+
+			if (oid.Equals(X509Name.DateOfBirth)) // accept time string as well as # (for compatibility)
+			{
+				return new DerGeneralizedTime(value);
+			}
+
+			if (oid.Equals(X509Name.C)
+				|| oid.Equals(X509Name.SerialNumber)
+				|| oid.Equals(X509Name.DnQualifier)
+				|| oid.Equals(X509Name.TelephoneNumber))
+			{
+				return new DerPrintableString(value);
+			}
+
+			return new DerUtf8String(value);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/X509Extension.cs b/Crypto/src/asn1/x509/X509Extension.cs
new file mode 100644
index 000000000..430ce4447
--- /dev/null
+++ b/Crypto/src/asn1/x509/X509Extension.cs
@@ -0,0 +1,79 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * an object for the elements in the X.509 V3 extension block.
+     */
+    public class X509Extension
+    {
+        internal bool				critical;
+        internal Asn1OctetString	value;
+
+		public X509Extension(
+            DerBoolean		critical,
+            Asn1OctetString	value)
+        {
+            if (critical == null)
+            {
+                throw new ArgumentNullException("critical");
+            }
+
+			this.critical = critical.IsTrue;
+            this.value = value;
+        }
+
+		public X509Extension(
+            bool			critical,
+            Asn1OctetString	value)
+        {
+            this.critical = critical;
+            this.value = value;
+        }
+
+		public bool IsCritical { get { return critical; } }
+
+		public Asn1OctetString Value { get { return value; } }
+
+		public Asn1Encodable GetParsedValue()
+		{
+			return ConvertValueToObject(this);
+		}
+
+		public override int GetHashCode()
+        {
+			int vh = this.Value.GetHashCode();
+
+			return IsCritical ? vh : ~vh;
+        }
+
+		public override bool Equals(
+            object obj)
+        {
+            X509Extension other = obj as X509Extension;
+            if (other == null)
+            {
+                return false;
+            }
+
+			return Value.Equals(other.Value) && IsCritical == other.IsCritical;
+        }
+
+		/// <sumary>Convert the value of the passed in extension to an object.</sumary>
+		/// <param name="ext">The extension to parse.</param>
+		/// <returns>The object the value string contains.</returns>
+		/// <exception cref="ArgumentException">If conversion is not possible.</exception>
+		public static Asn1Object ConvertValueToObject(
+			X509Extension ext)
+		{
+			try
+			{
+				return Asn1Object.FromByteArray(ext.Value.GetOctets());
+			}
+			catch (Exception e)
+			{
+				throw new ArgumentException("can't convert extension", e);
+			}
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/X509Extensions.cs b/Crypto/src/asn1/x509/X509Extensions.cs
new file mode 100644
index 000000000..1896450f5
--- /dev/null
+++ b/Crypto/src/asn1/x509/X509Extensions.cs
@@ -0,0 +1,451 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class X509Extensions
+        : Asn1Encodable
+    {
+		/**
+		 * Subject Directory Attributes
+		 */
+		public static readonly DerObjectIdentifier SubjectDirectoryAttributes = new DerObjectIdentifier("2.5.29.9");
+
+		/**
+         * Subject Key Identifier
+         */
+        public static readonly DerObjectIdentifier SubjectKeyIdentifier = new DerObjectIdentifier("2.5.29.14");
+
+		/**
+         * Key Usage
+         */
+        public static readonly DerObjectIdentifier KeyUsage = new DerObjectIdentifier("2.5.29.15");
+
+		/**
+         * Private Key Usage Period
+         */
+        public static readonly DerObjectIdentifier PrivateKeyUsagePeriod = new DerObjectIdentifier("2.5.29.16");
+
+		/**
+         * Subject Alternative Name
+         */
+        public static readonly DerObjectIdentifier SubjectAlternativeName = new DerObjectIdentifier("2.5.29.17");
+
+		/**
+         * Issuer Alternative Name
+         */
+        public static readonly DerObjectIdentifier IssuerAlternativeName = new DerObjectIdentifier("2.5.29.18");
+
+		/**
+         * Basic Constraints
+         */
+        public static readonly DerObjectIdentifier BasicConstraints = new DerObjectIdentifier("2.5.29.19");
+
+		/**
+         * CRL Number
+         */
+        public static readonly DerObjectIdentifier CrlNumber = new DerObjectIdentifier("2.5.29.20");
+
+		/**
+         * Reason code
+         */
+        public static readonly DerObjectIdentifier ReasonCode = new DerObjectIdentifier("2.5.29.21");
+
+		/**
+         * Hold Instruction Code
+         */
+        public static readonly DerObjectIdentifier InstructionCode = new DerObjectIdentifier("2.5.29.23");
+
+		/**
+         * Invalidity Date
+         */
+        public static readonly DerObjectIdentifier InvalidityDate = new DerObjectIdentifier("2.5.29.24");
+
+		/**
+         * Delta CRL indicator
+         */
+        public static readonly DerObjectIdentifier DeltaCrlIndicator = new DerObjectIdentifier("2.5.29.27");
+
+		/**
+         * Issuing Distribution Point
+         */
+        public static readonly DerObjectIdentifier IssuingDistributionPoint = new DerObjectIdentifier("2.5.29.28");
+
+		/**
+         * Certificate Issuer
+         */
+        public static readonly DerObjectIdentifier CertificateIssuer = new DerObjectIdentifier("2.5.29.29");
+
+		/**
+         * Name Constraints
+         */
+        public static readonly DerObjectIdentifier NameConstraints = new DerObjectIdentifier("2.5.29.30");
+
+		/**
+         * CRL Distribution Points
+         */
+        public static readonly DerObjectIdentifier CrlDistributionPoints = new DerObjectIdentifier("2.5.29.31");
+
+		/**
+         * Certificate Policies
+         */
+        public static readonly DerObjectIdentifier CertificatePolicies = new DerObjectIdentifier("2.5.29.32");
+
+		/**
+         * Policy Mappings
+         */
+        public static readonly DerObjectIdentifier PolicyMappings = new DerObjectIdentifier("2.5.29.33");
+
+		/**
+         * Authority Key Identifier
+         */
+        public static readonly DerObjectIdentifier AuthorityKeyIdentifier = new DerObjectIdentifier("2.5.29.35");
+
+		/**
+         * Policy Constraints
+         */
+        public static readonly DerObjectIdentifier PolicyConstraints = new DerObjectIdentifier("2.5.29.36");
+
+		/**
+         * Extended Key Usage
+         */
+        public static readonly DerObjectIdentifier ExtendedKeyUsage = new DerObjectIdentifier("2.5.29.37");
+
+		/**
+		 * Freshest CRL
+		 */
+		public static readonly DerObjectIdentifier FreshestCrl = new DerObjectIdentifier("2.5.29.46");
+
+		/**
+         * Inhibit Any Policy
+         */
+        public static readonly DerObjectIdentifier InhibitAnyPolicy = new DerObjectIdentifier("2.5.29.54");
+
+		/**
+         * Authority Info Access
+         */
+		public static readonly DerObjectIdentifier AuthorityInfoAccess = new DerObjectIdentifier("1.3.6.1.5.5.7.1.1");
+
+		/**
+		 * Subject Info Access
+		 */
+		public static readonly DerObjectIdentifier SubjectInfoAccess = new DerObjectIdentifier("1.3.6.1.5.5.7.1.11");
+
+		/**
+		 * Logo Type
+		 */
+		public static readonly DerObjectIdentifier LogoType = new DerObjectIdentifier("1.3.6.1.5.5.7.1.12");
+
+		/**
+		 * BiometricInfo
+		 */
+		public static readonly DerObjectIdentifier BiometricInfo = new DerObjectIdentifier("1.3.6.1.5.5.7.1.2");
+
+		/**
+		 * QCStatements
+		 */
+		public static readonly DerObjectIdentifier QCStatements = new DerObjectIdentifier("1.3.6.1.5.5.7.1.3");
+
+		/**
+		 * Audit identity extension in attribute certificates.
+		 */
+		public static readonly DerObjectIdentifier AuditIdentity = new DerObjectIdentifier("1.3.6.1.5.5.7.1.4");
+
+		/**
+		 * NoRevAvail extension in attribute certificates.
+		 */
+		public static readonly DerObjectIdentifier NoRevAvail = new DerObjectIdentifier("2.5.29.56");
+
+		/**
+		 * TargetInformation extension in attribute certificates.
+		 */
+		public static readonly DerObjectIdentifier TargetInformation = new DerObjectIdentifier("2.5.29.55");
+
+        private readonly IDictionary extensions = Platform.CreateHashtable();
+        private readonly IList ordering;
+
+		public static X509Extensions GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static X509Extensions GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is X509Extensions)
+            {
+                return (X509Extensions) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new X509Extensions((Asn1Sequence) obj);
+            }
+
+			if (obj is Asn1TaggedObject)
+            {
+                return GetInstance(((Asn1TaggedObject) obj).GetObject());
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+         * Constructor from Asn1Sequence.
+         *
+         * the extensions are a list of constructed sequences, either with (Oid, OctetString) or (Oid, Boolean, OctetString)
+         */
+        private X509Extensions(
+            Asn1Sequence seq)
+        {
+            this.ordering = Platform.CreateArrayList();
+
+			foreach (Asn1Encodable ae in seq)
+			{
+				Asn1Sequence s = Asn1Sequence.GetInstance(ae.ToAsn1Object());
+
+				if (s.Count < 2 || s.Count > 3)
+					throw new ArgumentException("Bad sequence size: " + s.Count);
+
+				DerObjectIdentifier oid = DerObjectIdentifier.GetInstance(s[0].ToAsn1Object());
+
+				bool isCritical = s.Count == 3
+					&& DerBoolean.GetInstance(s[1].ToAsn1Object()).IsTrue;
+
+				Asn1OctetString octets = Asn1OctetString.GetInstance(s[s.Count - 1].ToAsn1Object());
+
+				extensions.Add(oid, new X509Extension(isCritical, octets));
+				ordering.Add(oid);
+			}
+        }
+
+        /**
+         * constructor from a table of extensions.
+         * <p>
+         * it's is assumed the table contains Oid/string pairs.</p>
+         */
+        public X509Extensions(
+            IDictionary extensions)
+            : this(null, extensions)
+        {
+        }
+
+        /**
+         * Constructor from a table of extensions with ordering.
+         * <p>
+         * It's is assumed the table contains Oid/string pairs.</p>
+         */
+        public X509Extensions(
+            IList       ordering,
+            IDictionary extensions)
+        {
+            if (ordering == null)
+            {
+                this.ordering = Platform.CreateArrayList(extensions.Keys);
+            }
+            else
+            {
+                this.ordering = Platform.CreateArrayList(ordering);
+            }
+
+            foreach (DerObjectIdentifier oid in this.ordering)
+            {
+                this.extensions.Add(oid, (X509Extension)extensions[oid]);
+            }
+        }
+
+        /**
+         * Constructor from two vectors
+         *
+         * @param objectIDs an ArrayList of the object identifiers.
+         * @param values an ArrayList of the extension values.
+         */
+        public X509Extensions(
+            IList oids,
+            IList values)
+        {
+            this.ordering = Platform.CreateArrayList(oids);
+
+            int count = 0;
+            foreach (DerObjectIdentifier oid in this.ordering)
+            {
+                this.extensions.Add(oid, (X509Extension)values[count++]);
+            }
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+		/**
+         * constructor from a table of extensions.
+         * <p>
+         * it's is assumed the table contains Oid/string pairs.</p>
+         */
+        [Obsolete]
+        public X509Extensions(
+            Hashtable extensions)
+             : this(null, extensions)
+        {
+        }
+
+		/**
+         * Constructor from a table of extensions with ordering.
+         * <p>
+         * It's is assumed the table contains Oid/string pairs.</p>
+         */
+        [Obsolete]
+        public X509Extensions(
+            ArrayList	ordering,
+            Hashtable	extensions)
+        {
+            if (ordering == null)
+            {
+                this.ordering = Platform.CreateArrayList(extensions.Keys);
+            }
+            else
+            {
+                this.ordering = Platform.CreateArrayList(ordering);
+            }
+
+            foreach (DerObjectIdentifier oid in this.ordering)
+			{
+				this.extensions.Add(oid, (X509Extension) extensions[oid]);
+			}
+        }
+
+		/**
+		 * Constructor from two vectors
+		 *
+		 * @param objectIDs an ArrayList of the object identifiers.
+		 * @param values an ArrayList of the extension values.
+		 */
+        [Obsolete]
+		public X509Extensions(
+			ArrayList	oids,
+			ArrayList	values)
+		{
+            this.ordering = Platform.CreateArrayList(oids);
+
+            int count = 0;
+			foreach (DerObjectIdentifier oid in this.ordering)
+			{
+				this.extensions.Add(oid, (X509Extension) values[count++]);
+			}
+		}
+#endif
+
+        [Obsolete("Use ExtensionOids IEnumerable property")]
+		public IEnumerator Oids()
+		{
+			return ExtensionOids.GetEnumerator();
+		}
+
+		/**
+		 * return an Enumeration of the extension field's object ids.
+		 */
+		public IEnumerable ExtensionOids
+        {
+			get { return new EnumerableProxy(ordering); }
+        }
+
+		/**
+         * return the extension represented by the object identifier
+         * passed in.
+         *
+         * @return the extension if it's present, null otherwise.
+         */
+        public X509Extension GetExtension(
+            DerObjectIdentifier oid)
+        {
+             return (X509Extension) extensions[oid];
+        }
+
+		/**
+		 * <pre>
+		 *     Extensions        ::=   SEQUENCE SIZE (1..MAX) OF Extension
+		 *
+		 *     Extension         ::=   SEQUENCE {
+		 *        extnId            EXTENSION.&amp;id ({ExtensionSet}),
+		 *        critical          BOOLEAN DEFAULT FALSE,
+		 *        extnValue         OCTET STRING }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector	vec = new Asn1EncodableVector();
+
+			foreach (DerObjectIdentifier oid in ordering)
+			{
+                X509Extension ext = (X509Extension) extensions[oid];
+                Asn1EncodableVector	v = new Asn1EncodableVector(oid);
+
+				if (ext.IsCritical)
+                {
+                    v.Add(DerBoolean.True);
+                }
+
+				v.Add(ext.Value);
+
+				vec.Add(new DerSequence(v));
+            }
+
+			return new DerSequence(vec);
+        }
+
+		public bool Equivalent(
+			X509Extensions other)
+		{
+			if (extensions.Count != other.extensions.Count)
+				return false;
+
+			foreach (DerObjectIdentifier oid in extensions.Keys)
+			{
+				if (!extensions[oid].Equals(other.extensions[oid]))
+					return false;
+			}
+
+			return true;
+		}
+
+		public DerObjectIdentifier[] GetExtensionOids()
+		{
+			return ToOidArray(ordering);
+		}
+
+		public DerObjectIdentifier[] GetNonCriticalExtensionOids()
+		{
+			return GetExtensionOids(false);
+		}
+
+		public DerObjectIdentifier[] GetCriticalExtensionOids()
+		{
+			return GetExtensionOids(true);
+		}
+
+		private DerObjectIdentifier[] GetExtensionOids(bool isCritical)
+		{
+			IList oids = Platform.CreateArrayList();
+
+			foreach (DerObjectIdentifier oid in this.ordering)
+            {
+				X509Extension ext = (X509Extension)extensions[oid];
+				if (ext.IsCritical == isCritical)
+				{
+					oids.Add(oid);
+				}
+            }
+
+			return ToOidArray(oids);
+		}
+
+		private static DerObjectIdentifier[] ToOidArray(IList oids)
+		{
+			DerObjectIdentifier[] oidArray = new DerObjectIdentifier[oids.Count];
+			oids.CopyTo(oidArray, 0);
+			return oidArray;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/X509ExtensionsGenerator.cs b/Crypto/src/asn1/x509/X509ExtensionsGenerator.cs
new file mode 100644
index 000000000..d6f567b22
--- /dev/null
+++ b/Crypto/src/asn1/x509/X509ExtensionsGenerator.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/// <remarks>Generator for X.509 extensions</remarks>
+	public class X509ExtensionsGenerator
+	{
+		private IDictionary extensions = Platform.CreateHashtable();
+        private IList extOrdering = Platform.CreateArrayList();
+
+		/// <summary>Reset the generator</summary>
+		public void Reset()
+		{
+            extensions = Platform.CreateHashtable();
+            extOrdering = Platform.CreateArrayList();
+		}
+
+		/// <summary>
+		/// Add an extension with the given oid and the passed in value to be included
+		/// in the OCTET STRING associated with the extension.
+		/// </summary>
+		/// <param name="oid">OID for the extension.</param>
+		/// <param name="critical">True if critical, false otherwise.</param>
+		/// <param name="extValue">The ASN.1 object to be included in the extension.</param>
+		public void AddExtension(
+			DerObjectIdentifier	oid,
+			bool				critical,
+			Asn1Encodable		extValue)
+		{
+			byte[] encoded;
+			try
+			{
+				encoded = extValue.GetDerEncoded();
+			}
+			catch (Exception e)
+			{
+				throw new ArgumentException("error encoding value: " + e);
+			}
+
+			this.AddExtension(oid, critical, encoded);
+		}
+
+		/// <summary>
+		/// Add an extension with the given oid and the passed in byte array to be wrapped
+		/// in the OCTET STRING associated with the extension.
+		/// </summary>
+		/// <param name="oid">OID for the extension.</param>
+		/// <param name="critical">True if critical, false otherwise.</param>
+		/// <param name="extValue">The byte array to be wrapped.</param>
+		public void AddExtension(
+			DerObjectIdentifier	oid,
+			bool				critical,
+			byte[]				extValue)
+		{
+			if (extensions.Contains(oid))
+			{
+				throw new ArgumentException("extension " + oid + " already added");
+			}
+
+			extOrdering.Add(oid);
+			extensions.Add(oid, new X509Extension(critical, new DerOctetString(extValue)));
+		}
+
+		/// <summary>Return true if there are no extension present in this generator.</summary>
+		/// <returns>True if empty, false otherwise</returns>
+		public bool IsEmpty
+		{
+			get { return extOrdering.Count < 1; }
+		}
+
+		/// <summary>Generate an X509Extensions object based on the current state of the generator.</summary>
+		/// <returns>An <c>X509Extensions</c> object</returns>
+		public X509Extensions Generate()
+		{
+			return new X509Extensions(extOrdering, extensions);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/X509Name.cs b/Crypto/src/asn1/x509/X509Name.cs
new file mode 100644
index 000000000..b459cbe1b
--- /dev/null
+++ b/Crypto/src/asn1/x509/X509Name.cs
@@ -0,0 +1,1189 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+#if (SILVERLIGHT || PORTABLE)
+using System.Collections.Generic;
+#endif
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+    * <pre>
+    *     RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+    *
+    *     RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
+    *
+    *     AttributeTypeAndValue ::= SEQUENCE {
+    *                                   type  OBJECT IDENTIFIER,
+    *                                   value ANY }
+    * </pre>
+    */
+    public class X509Name
+        : Asn1Encodable
+    {
+        /**
+        * country code - StringType(SIZE(2))
+        */
+        public static readonly DerObjectIdentifier C = new DerObjectIdentifier("2.5.4.6");
+
+        /**
+        * organization - StringType(SIZE(1..64))
+        */
+        public static readonly DerObjectIdentifier O = new DerObjectIdentifier("2.5.4.10");
+
+        /**
+        * organizational unit name - StringType(SIZE(1..64))
+        */
+        public static readonly DerObjectIdentifier OU = new DerObjectIdentifier("2.5.4.11");
+
+        /**
+        * Title
+        */
+        public static readonly DerObjectIdentifier T = new DerObjectIdentifier("2.5.4.12");
+
+        /**
+        * common name - StringType(SIZE(1..64))
+        */
+        public static readonly DerObjectIdentifier CN = new DerObjectIdentifier("2.5.4.3");
+
+		/**
+		* street - StringType(SIZE(1..64))
+		*/
+		public static readonly DerObjectIdentifier Street = new DerObjectIdentifier("2.5.4.9");
+
+		/**
+		* device serial number name - StringType(SIZE(1..64))
+		*/
+		public static readonly DerObjectIdentifier SerialNumber = new DerObjectIdentifier("2.5.4.5");
+
+		/**
+        * locality name - StringType(SIZE(1..64))
+        */
+        public static readonly DerObjectIdentifier L = new DerObjectIdentifier("2.5.4.7");
+
+        /**
+        * state, or province name - StringType(SIZE(1..64))
+        */
+        public static readonly DerObjectIdentifier ST = new DerObjectIdentifier("2.5.4.8");
+
+        /**
+        * Naming attributes of type X520name
+        */
+        public static readonly DerObjectIdentifier Surname = new DerObjectIdentifier("2.5.4.4");
+        public static readonly DerObjectIdentifier GivenName = new DerObjectIdentifier("2.5.4.42");
+        public static readonly DerObjectIdentifier Initials = new DerObjectIdentifier("2.5.4.43");
+        public static readonly DerObjectIdentifier Generation = new DerObjectIdentifier("2.5.4.44");
+        public static readonly DerObjectIdentifier UniqueIdentifier = new DerObjectIdentifier("2.5.4.45");
+
+		/**
+		 * businessCategory - DirectoryString(SIZE(1..128)
+		 */
+		public static readonly DerObjectIdentifier BusinessCategory = new DerObjectIdentifier(
+																	   "2.5.4.15");
+
+		/**
+		 * postalCode - DirectoryString(SIZE(1..40)
+		 */
+		public static readonly DerObjectIdentifier PostalCode = new DerObjectIdentifier(
+																 "2.5.4.17");
+
+		/**
+		 * dnQualifier - DirectoryString(SIZE(1..64)
+		 */
+		public static readonly DerObjectIdentifier DnQualifier = new DerObjectIdentifier(
+														 "2.5.4.46");
+
+		/**
+		 * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64)
+		 */
+		public static readonly DerObjectIdentifier Pseudonym = new DerObjectIdentifier(
+																"2.5.4.65");
+
+		/**
+		 * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z
+		 */
+		public static readonly DerObjectIdentifier DateOfBirth = new DerObjectIdentifier(
+																  "1.3.6.1.5.5.7.9.1");
+
+		/**
+		 * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128)
+		 */
+		public static readonly DerObjectIdentifier PlaceOfBirth = new DerObjectIdentifier(
+																   "1.3.6.1.5.5.7.9.2");
+
+		/**
+		 * RFC 3039 DateOfBirth - PrintableString (SIZE(1)) -- "M", "F", "m" or "f"
+		 */
+		public static readonly DerObjectIdentifier Gender = new DerObjectIdentifier(
+																   "1.3.6.1.5.5.7.9.3");
+
+		/**
+		 * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
+		 * codes only
+		 */
+		public static readonly DerObjectIdentifier CountryOfCitizenship = new DerObjectIdentifier(
+																		   "1.3.6.1.5.5.7.9.4");
+
+		/**
+		 * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
+		 * codes only
+		 */
+		public static readonly DerObjectIdentifier CountryOfResidence = new DerObjectIdentifier(
+																		 "1.3.6.1.5.5.7.9.5");
+
+		/**
+		 * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64)
+		 */
+		public static readonly DerObjectIdentifier NameAtBirth =  new DerObjectIdentifier("1.3.36.8.3.14");
+
+		/**
+		 * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF
+		 * DirectoryString(SIZE(1..30))
+		 */
+		public static readonly DerObjectIdentifier PostalAddress = new DerObjectIdentifier("2.5.4.16");
+
+		/**
+		 * RFC 2256 dmdName
+		 */
+		public static readonly DerObjectIdentifier DmdName = new DerObjectIdentifier("2.5.4.54");
+
+		/**
+		 * id-at-telephoneNumber
+		 */
+		public static readonly DerObjectIdentifier TelephoneNumber = X509ObjectIdentifiers.id_at_telephoneNumber;
+
+		/**
+		 * id-at-name
+		 */
+		public static readonly DerObjectIdentifier Name = X509ObjectIdentifiers.id_at_name;
+
+		/**
+        * Email address (RSA PKCS#9 extension) - IA5String.
+        * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.</p>
+        */
+        public static readonly DerObjectIdentifier EmailAddress = PkcsObjectIdentifiers.Pkcs9AtEmailAddress;
+
+        /**
+        * more from PKCS#9
+        */
+        public static readonly DerObjectIdentifier UnstructuredName = PkcsObjectIdentifiers.Pkcs9AtUnstructuredName;
+        public static readonly DerObjectIdentifier UnstructuredAddress = PkcsObjectIdentifiers.Pkcs9AtUnstructuredAddress;
+
+        /**
+        * email address in Verisign certificates
+        */
+        public static readonly DerObjectIdentifier E = EmailAddress;
+
+        /*
+        * others...
+        */
+        public static readonly DerObjectIdentifier DC = new DerObjectIdentifier("0.9.2342.19200300.100.1.25");
+
+        /**
+        * LDAP User id.
+        */
+        public static readonly DerObjectIdentifier UID = new DerObjectIdentifier("0.9.2342.19200300.100.1.1");
+
+        /**
+        * determines whether or not strings should be processed and printed
+        * from back to front.
+        */
+//        public static bool DefaultReverse = false;
+		public static bool DefaultReverse
+		{
+			get { return defaultReverse[0]; }
+			set { defaultReverse[0] = value; }
+		}
+
+		private static readonly bool[] defaultReverse = { false };
+
+#if (SILVERLIGHT || PORTABLE)
+        /**
+		* default look up table translating OID values into their common symbols following
+		* the convention in RFC 2253 with a few extras
+		*/
+		public static readonly IDictionary DefaultSymbols = Platform.CreateHashtable();
+
+		/**
+		 * look up table translating OID values into their common symbols following the convention in RFC 2253
+		 */
+		public static readonly IDictionary RFC2253Symbols = Platform.CreateHashtable();
+
+		/**
+		 * look up table translating OID values into their common symbols following the convention in RFC 1779
+		 *
+		 */
+		public static readonly IDictionary RFC1779Symbols = Platform.CreateHashtable();
+
+        /**
+        * look up table translating common symbols into their OIDS.
+        */
+        public static readonly IDictionary DefaultLookup = Platform.CreateHashtable();
+#else
+        /**
+		* default look up table translating OID values into their common symbols following
+		* the convention in RFC 2253 with a few extras
+		*/
+		public static readonly Hashtable DefaultSymbols = new Hashtable();
+
+		/**
+		 * look up table translating OID values into their common symbols following the convention in RFC 2253
+		 */
+		public static readonly Hashtable RFC2253Symbols = new Hashtable();
+
+		/**
+		 * look up table translating OID values into their common symbols following the convention in RFC 1779
+		 *
+		 */
+		public static readonly Hashtable RFC1779Symbols = new Hashtable();
+
+        /**
+        * look up table translating common symbols into their OIDS.
+        */
+        public static readonly Hashtable DefaultLookup = new Hashtable();
+#endif
+
+        static X509Name()
+        {
+            DefaultSymbols.Add(C, "C");
+            DefaultSymbols.Add(O, "O");
+            DefaultSymbols.Add(T, "T");
+            DefaultSymbols.Add(OU, "OU");
+            DefaultSymbols.Add(CN, "CN");
+            DefaultSymbols.Add(L, "L");
+            DefaultSymbols.Add(ST, "ST");
+            DefaultSymbols.Add(SerialNumber, "SERIALNUMBER");
+            DefaultSymbols.Add(EmailAddress, "E");
+            DefaultSymbols.Add(DC, "DC");
+            DefaultSymbols.Add(UID, "UID");
+			DefaultSymbols.Add(Street, "STREET");
+            DefaultSymbols.Add(Surname, "SURNAME");
+            DefaultSymbols.Add(GivenName, "GIVENNAME");
+            DefaultSymbols.Add(Initials, "INITIALS");
+            DefaultSymbols.Add(Generation, "GENERATION");
+            DefaultSymbols.Add(UnstructuredAddress, "unstructuredAddress");
+            DefaultSymbols.Add(UnstructuredName, "unstructuredName");
+			DefaultSymbols.Add(UniqueIdentifier, "UniqueIdentifier");
+			DefaultSymbols.Add(DnQualifier, "DN");
+			DefaultSymbols.Add(Pseudonym, "Pseudonym");
+			DefaultSymbols.Add(PostalAddress, "PostalAddress");
+			DefaultSymbols.Add(NameAtBirth, "NameAtBirth");
+			DefaultSymbols.Add(CountryOfCitizenship, "CountryOfCitizenship");
+			DefaultSymbols.Add(CountryOfResidence, "CountryOfResidence");
+			DefaultSymbols.Add(Gender, "Gender");
+			DefaultSymbols.Add(PlaceOfBirth, "PlaceOfBirth");
+			DefaultSymbols.Add(DateOfBirth, "DateOfBirth");
+			DefaultSymbols.Add(PostalCode, "PostalCode");
+			DefaultSymbols.Add(BusinessCategory, "BusinessCategory");
+			DefaultSymbols.Add(TelephoneNumber, "TelephoneNumber");
+
+            RFC2253Symbols.Add(C, "C");
+            RFC2253Symbols.Add(O, "O");
+            RFC2253Symbols.Add(OU, "OU");
+            RFC2253Symbols.Add(CN, "CN");
+            RFC2253Symbols.Add(L, "L");
+            RFC2253Symbols.Add(ST, "ST");
+			RFC2253Symbols.Add(Street, "STREET");
+			RFC2253Symbols.Add(DC, "DC");
+            RFC2253Symbols.Add(UID, "UID");
+
+			RFC1779Symbols.Add(C, "C");
+			RFC1779Symbols.Add(O, "O");
+			RFC1779Symbols.Add(OU, "OU");
+			RFC1779Symbols.Add(CN, "CN");
+			RFC1779Symbols.Add(L, "L");
+			RFC1779Symbols.Add(ST, "ST");
+			RFC1779Symbols.Add(Street, "STREET");
+
+			DefaultLookup.Add("c", C);
+            DefaultLookup.Add("o", O);
+            DefaultLookup.Add("t", T);
+            DefaultLookup.Add("ou", OU);
+            DefaultLookup.Add("cn", CN);
+            DefaultLookup.Add("l", L);
+            DefaultLookup.Add("st", ST);
+			DefaultLookup.Add("serialnumber", SerialNumber);
+			DefaultLookup.Add("street", Street);
+			DefaultLookup.Add("emailaddress", E);
+            DefaultLookup.Add("dc", DC);
+            DefaultLookup.Add("e", E);
+            DefaultLookup.Add("uid", UID);
+            DefaultLookup.Add("surname", Surname);
+            DefaultLookup.Add("givenname", GivenName);
+            DefaultLookup.Add("initials", Initials);
+            DefaultLookup.Add("generation", Generation);
+            DefaultLookup.Add("unstructuredaddress", UnstructuredAddress);
+            DefaultLookup.Add("unstructuredname", UnstructuredName);
+			DefaultLookup.Add("uniqueidentifier", UniqueIdentifier);
+			DefaultLookup.Add("dn", DnQualifier);
+			DefaultLookup.Add("pseudonym", Pseudonym);
+			DefaultLookup.Add("postaladdress", PostalAddress);
+			DefaultLookup.Add("nameofbirth", NameAtBirth);
+			DefaultLookup.Add("countryofcitizenship", CountryOfCitizenship);
+			DefaultLookup.Add("countryofresidence", CountryOfResidence);
+			DefaultLookup.Add("gender", Gender);
+			DefaultLookup.Add("placeofbirth", PlaceOfBirth);
+			DefaultLookup.Add("dateofbirth", DateOfBirth);
+			DefaultLookup.Add("postalcode", PostalCode);
+			DefaultLookup.Add("businesscategory", BusinessCategory);
+			DefaultLookup.Add("telephonenumber", TelephoneNumber);
+		}
+
+        private readonly IList ordering = Platform.CreateArrayList();
+		private readonly X509NameEntryConverter converter;
+
+		private IList		    values = Platform.CreateArrayList();
+        private IList           added = Platform.CreateArrayList();
+        private Asn1Sequence	seq;
+
+		/**
+        * Return a X509Name based on the passed in tagged object.
+        *
+        * @param obj tag object holding name.
+        * @param explicitly true if explicitly tagged false otherwise.
+        * @return the X509Name
+        */
+        public static X509Name GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static X509Name GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is X509Name)
+                return (X509Name)obj;
+
+			if (obj != null)
+				return new X509Name(Asn1Sequence.GetInstance(obj));
+
+			throw new ArgumentException("null object in factory", "obj");
+        }
+
+		protected X509Name()
+		{
+		}
+
+		/**
+        * Constructor from Asn1Sequence
+        *
+        * the principal will be a list of constructed sets, each containing an (OID, string) pair.
+        */
+        protected X509Name(
+            Asn1Sequence seq)
+        {
+            this.seq = seq;
+
+			foreach (Asn1Encodable asn1Obj in seq)
+			{
+				Asn1Set asn1Set = Asn1Set.GetInstance(asn1Obj.ToAsn1Object());
+
+				for (int i = 0; i < asn1Set.Count; i++)
+                {
+					Asn1Sequence s = Asn1Sequence.GetInstance(asn1Set[i].ToAsn1Object());
+
+					if (s.Count != 2)
+						throw new ArgumentException("badly sized pair");
+
+					ordering.Add(DerObjectIdentifier.GetInstance(s[0].ToAsn1Object()));
+
+					Asn1Object derValue = s[1].ToAsn1Object();
+					if (derValue is IAsn1String && !(derValue is DerUniversalString))
+					{
+						string v = ((IAsn1String)derValue).GetString();
+						if (v.StartsWith("#"))
+						{
+							v = "\\" + v;
+						}
+
+						values.Add(v);
+					}
+                    else
+                    {
+						values.Add("#" + Hex.ToHexString(derValue.GetEncoded()));
+                    }
+
+					added.Add(i != 0);
+                }
+            }
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete]
+        public X509Name(
+            ArrayList ordering,
+            Hashtable attributes)
+            : this(ordering, attributes, new X509DefaultEntryConverter())
+        {
+        }
+#endif
+
+        /**
+        * Constructor from a table of attributes with ordering.
+        * <p>
+        * it's is assumed the table contains OID/string pairs, and the contents
+        * of the table are copied into an internal table as part of the
+        * construction process. The ordering ArrayList should contain the OIDs
+        * in the order they are meant to be encoded or printed in ToString.</p>
+        */
+        public X509Name(
+            IList       ordering,
+            IDictionary attributes)
+            : this(ordering, attributes, new X509DefaultEntryConverter())
+        {
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete]
+        public X509Name(
+            ArrayList				ordering,
+            Hashtable				attributes,
+            X509NameEntryConverter	converter)
+            : this((IList)ordering, (IDictionary)attributes, converter)
+        {
+        }
+#endif
+
+        /**
+        * Constructor from a table of attributes with ordering.
+        * <p>
+        * it's is assumed the table contains OID/string pairs, and the contents
+        * of the table are copied into an internal table as part of the
+        * construction process. The ordering ArrayList should contain the OIDs
+        * in the order they are meant to be encoded or printed in ToString.</p>
+        * <p>
+        * The passed in converter will be used to convert the strings into their
+        * ASN.1 counterparts.</p>
+        */
+        public X509Name(
+            IList                   ordering,
+            IDictionary             attributes,
+            X509NameEntryConverter	converter)
+        {
+			this.converter = converter;
+
+			foreach (DerObjectIdentifier oid in ordering)
+			{
+				object attribute = attributes[oid];
+				if (attribute == null)
+				{
+					throw new ArgumentException("No attribute for object id - " + oid + " - passed to distinguished name");
+				}
+
+				this.ordering.Add(oid);
+				this.added.Add(false);
+				this.values.Add(attribute); // copy the hash table
+			}
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete]
+        public X509Name(
+            ArrayList oids,
+            ArrayList values)
+            : this(oids, values, new X509DefaultEntryConverter())
+        {
+        }
+#endif
+
+        /**
+        * Takes two vectors one of the oids and the other of the values.
+        */
+        public X509Name(
+            IList   oids,
+            IList   values)
+            : this(oids, values, new X509DefaultEntryConverter())
+        {
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete]
+        public X509Name(
+            ArrayList				oids,
+            ArrayList				values,
+            X509NameEntryConverter	converter)
+            : this((IList)oids, (IList)values, converter)
+        {
+        }
+#endif
+
+        /**
+        * Takes two vectors one of the oids and the other of the values.
+        * <p>
+        * The passed in converter will be used to convert the strings into their
+        * ASN.1 counterparts.</p>
+        */
+        public X509Name(
+            IList			    	oids,
+            IList		    		values,
+            X509NameEntryConverter	converter)
+        {
+            this.converter = converter;
+
+			if (oids.Count != values.Count)
+            {
+                throw new ArgumentException("'oids' must be same length as 'values'.");
+            }
+
+			for (int i = 0; i < oids.Count; i++)
+            {
+                this.ordering.Add(oids[i]);
+                this.values.Add(values[i]);
+                this.added.Add(false);
+            }
+        }
+
+//		private static bool IsEncoded(
+//			string s)
+//		{
+//			return s.StartsWith("#");
+//		}
+
+		/**
+        * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+        * some such, converting it into an ordered set of name attributes.
+        */
+        public X509Name(
+            string dirName)
+            : this(DefaultReverse, (IDictionary)DefaultLookup, dirName)
+        {
+        }
+
+		/**
+        * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+        * some such, converting it into an ordered set of name attributes with each
+        * string value being converted to its associated ASN.1 type using the passed
+        * in converter.
+        */
+        public X509Name(
+            string					dirName,
+            X509NameEntryConverter	converter)
+            : this(DefaultReverse, DefaultLookup, dirName, converter)
+        {
+        }
+
+		/**
+        * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+        * some such, converting it into an ordered set of name attributes. If reverse
+        * is true, create the encoded version of the sequence starting from the
+        * last element in the string.
+        */
+        public X509Name(
+            bool	reverse,
+            string	dirName)
+            : this(reverse, (IDictionary)DefaultLookup, dirName)
+        {
+        }
+
+		/**
+        * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+        * some such, converting it into an ordered set of name attributes with each
+        * string value being converted to its associated ASN.1 type using the passed
+        * in converter. If reverse is true the ASN.1 sequence representing the DN will
+        * be built by starting at the end of the string, rather than the start.
+        */
+        public X509Name(
+            bool					reverse,
+            string					dirName,
+            X509NameEntryConverter	converter)
+            : this(reverse, DefaultLookup, dirName, converter)
+        {
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete]
+        public X509Name(
+            bool reverse,
+            Hashtable lookUp,
+            string dirName)
+            : this(reverse, lookUp, dirName, new X509DefaultEntryConverter())
+        {
+        }
+#endif
+
+        /**
+        * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+        * some such, converting it into an ordered set of name attributes. lookUp
+        * should provide a table of lookups, indexed by lowercase only strings and
+        * yielding a DerObjectIdentifier, other than that OID. and numeric oids
+        * will be processed automatically.
+        * <br/>
+        * If reverse is true, create the encoded version of the sequence
+        * starting from the last element in the string.
+        * @param reverse true if we should start scanning from the end (RFC 2553).
+        * @param lookUp table of names and their oids.
+        * @param dirName the X.500 string to be parsed.
+        */
+        public X509Name(
+            bool		reverse,
+            IDictionary lookUp,
+            string		dirName)
+            : this(reverse, lookUp, dirName, new X509DefaultEntryConverter())
+        {
+        }
+
+		private DerObjectIdentifier DecodeOid(
+            string		name,
+            IDictionary lookUp)
+        {
+            if (name.ToUpperInvariant().StartsWith("OID."))
+            {
+                return new DerObjectIdentifier(name.Substring(4));
+            }
+            else if (name[0] >= '0' && name[0] <= '9')
+            {
+                return new DerObjectIdentifier(name);
+            }
+
+			DerObjectIdentifier oid = (DerObjectIdentifier)lookUp[name.ToLowerInvariant()];
+            if (oid == null)
+            {
+                throw new ArgumentException("Unknown object id - " + name + " - passed to distinguished name");
+            }
+
+			return oid;
+        }
+
+		/**
+        * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+        * some such, converting it into an ordered set of name attributes. lookUp
+        * should provide a table of lookups, indexed by lowercase only strings and
+        * yielding a DerObjectIdentifier, other than that OID. and numeric oids
+        * will be processed automatically. The passed in converter is used to convert the
+        * string values to the right of each equals sign to their ASN.1 counterparts.
+        * <br/>
+        * @param reverse true if we should start scanning from the end, false otherwise.
+        * @param lookUp table of names and oids.
+        * @param dirName the string dirName
+        * @param converter the converter to convert string values into their ASN.1 equivalents
+        */
+        public X509Name(
+            bool					reverse,
+            IDictionary				lookUp,
+            string					dirName,
+            X509NameEntryConverter	converter)
+        {
+            this.converter = converter;
+            X509NameTokenizer nTok = new X509NameTokenizer(dirName);
+
+			while (nTok.HasMoreTokens())
+            {
+                string token = nTok.NextToken();
+                int index = token.IndexOf('=');
+
+				if (index == -1)
+                {
+                    throw new ArgumentException("badly formated directory string");
+                }
+
+				string name = token.Substring(0, index);
+                string value = token.Substring(index + 1);
+                DerObjectIdentifier	oid = DecodeOid(name, lookUp);
+
+				if (value.IndexOf('+') > 0)
+                {
+                    X509NameTokenizer vTok = new X509NameTokenizer(value, '+');
+					string v = vTok.NextToken();
+
+					this.ordering.Add(oid);
+                    this.values.Add(v);
+                    this.added.Add(false);
+
+					while (vTok.HasMoreTokens())
+                    {
+                        string sv = vTok.NextToken();
+                        int ndx = sv.IndexOf('=');
+
+                        string nm = sv.Substring(0, ndx);
+                        string vl = sv.Substring(ndx + 1);
+                        this.ordering.Add(DecodeOid(nm, lookUp));
+                        this.values.Add(vl);
+                        this.added.Add(true);
+                    }
+                }
+                else
+                {
+                    this.ordering.Add(oid);
+                    this.values.Add(value);
+                    this.added.Add(false);
+                }
+            }
+
+			if (reverse)
+            {
+//				this.ordering.Reverse();
+//				this.values.Reverse();
+//				this.added.Reverse();
+				IList o = Platform.CreateArrayList();
+                IList v = Platform.CreateArrayList();
+                IList a = Platform.CreateArrayList();
+				int count = 1;
+
+				for (int i = 0; i < this.ordering.Count; i++)
+				{
+					if (!((bool) this.added[i]))
+					{
+						count = 0;
+					}
+
+					int index = count++;
+
+					o.Insert(index, this.ordering[i]);
+					v.Insert(index, this.values[i]);
+					a.Insert(index, this.added[i]);
+				}
+
+				this.ordering = o;
+				this.values = v;
+				this.added = a;
+			}
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+		/**
+		* return an ArrayList of the oids in the name, in the order they were found.
+		*/
+        [Obsolete("Use 'GetOidList' instead")]
+        public ArrayList GetOids()
+        {
+            return new ArrayList(ordering);
+        }
+#endif
+
+        /**
+        * return an IList of the oids in the name, in the order they were found.
+        */
+        public IList GetOidList()
+        {
+            return Platform.CreateArrayList(ordering);
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+		/**
+		* return an ArrayList of the values found in the name, in the order they
+		* were found.
+		*/
+        [Obsolete("Use 'GetValueList' instead")]
+		public ArrayList GetValues()
+		{
+            return new ArrayList(values);
+		}
+#endif
+
+        /**
+        * return an IList of the values found in the name, in the order they
+        * were found.
+        */
+        public IList GetValueList()
+        {
+            return Platform.CreateArrayList(values);
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+		/**
+		 * return an ArrayList of the values found in the name, in the order they
+		 * were found, with the DN label corresponding to passed in oid.
+		 */
+		public ArrayList GetValues(
+			DerObjectIdentifier oid)
+		{
+			ArrayList v = new ArrayList();
+            DoGetValueList(oid, v);
+			return v;
+		}
+#endif
+
+        /**
+		 * return an IList of the values found in the name, in the order they
+		 * were found, with the DN label corresponding to passed in oid.
+		 */
+        public IList GetValueList(DerObjectIdentifier oid)
+        {
+            IList v = Platform.CreateArrayList();
+            DoGetValueList(oid, v);
+            return v;
+        }
+
+        private void DoGetValueList(DerObjectIdentifier oid, IList v)
+        {
+            for (int i = 0; i != values.Count; i++)
+            {
+                if (ordering[i].Equals(oid))
+                {
+                    string val = (string)values[i];
+
+                    if (val.StartsWith("\\#"))
+                    {
+                        val = val.Substring(1);
+                    }
+
+                    v.Add(val);
+                }
+            }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            if (seq == null)
+            {
+                Asn1EncodableVector vec = new Asn1EncodableVector();
+                Asn1EncodableVector sVec = new Asn1EncodableVector();
+                DerObjectIdentifier lstOid = null;
+
+				for (int i = 0; i != ordering.Count; i++)
+                {
+                    DerObjectIdentifier oid = (DerObjectIdentifier)ordering[i];
+					string str = (string)values[i];
+
+					if (lstOid == null
+                        || ((bool)this.added[i]))
+                    {
+                    }
+                    else
+                    {
+                        vec.Add(new DerSet(sVec));
+                        sVec = new Asn1EncodableVector();
+                    }
+
+					sVec.Add(
+						new DerSequence(
+							oid,
+							converter.GetConvertedValue(oid, str)));
+
+					lstOid = oid;
+                }
+
+				vec.Add(new DerSet(sVec));
+
+				seq = new DerSequence(vec);
+            }
+
+            return seq;
+        }
+
+        /// <param name="other">The X509Name object to test equivalency against.</param>
+		/// <param name="inOrder">If true, the order of elements must be the same,
+		/// as well as the values associated with each element.</param>
+		public bool Equivalent(
+			X509Name	other,
+			bool		inOrder)
+		{
+			if (!inOrder)
+				return this.Equivalent(other);
+
+			if (other == null)
+				return false;
+
+			if (other == this)
+				return true;
+
+			int orderingSize = ordering.Count;
+
+			if (orderingSize != other.ordering.Count)
+				return false;
+
+			for (int i = 0; i < orderingSize; i++)
+			{
+				DerObjectIdentifier oid = (DerObjectIdentifier) ordering[i];
+				DerObjectIdentifier oOid = (DerObjectIdentifier) other.ordering[i];
+
+				if (!oid.Equals(oOid))
+					return false;
+
+				string val = (string) values[i];
+				string oVal = (string) other.values[i];
+
+				if (!equivalentStrings(val, oVal))
+					return false;
+			}
+
+			return true;
+		}
+
+        /**
+		 * test for equivalence - note: case is ignored.
+		 */
+		public bool Equivalent(
+			X509Name other)
+		{
+			if (other == null)
+				return false;
+
+			if (other == this)
+				return true;
+
+			int orderingSize = ordering.Count;
+
+			if (orderingSize != other.ordering.Count)
+			{
+				return false;
+			}
+
+			bool[] indexes = new bool[orderingSize];
+			int start, end, delta;
+
+			if (ordering[0].Equals(other.ordering[0]))   // guess forward
+			{
+				start = 0;
+				end = orderingSize;
+				delta = 1;
+			}
+			else  // guess reversed - most common problem
+			{
+				start = orderingSize - 1;
+				end = -1;
+				delta = -1;
+			}
+
+			for (int i = start; i != end; i += delta)
+			{
+				bool found = false;
+				DerObjectIdentifier  oid = (DerObjectIdentifier)ordering[i];
+				string value = (string)values[i];
+
+				for (int j = 0; j < orderingSize; j++)
+				{
+					if (indexes[j])
+					{
+						continue;
+					}
+
+					DerObjectIdentifier oOid = (DerObjectIdentifier)other.ordering[j];
+
+					if (oid.Equals(oOid))
+					{
+						string oValue = (string)other.values[j];
+
+						if (equivalentStrings(value, oValue))
+						{
+							indexes[j] = true;
+							found      = true;
+							break;
+						}
+					}
+				}
+
+				if (!found)
+				{
+					return false;
+				}
+			}
+
+			return true;
+		}
+
+		private static bool equivalentStrings(
+			string	s1,
+			string	s2)
+		{
+			string v1 = canonicalize(s1);
+			string v2 = canonicalize(s2);
+
+			if (!v1.Equals(v2))
+			{
+				v1 = stripInternalSpaces(v1);
+				v2 = stripInternalSpaces(v2);
+
+				if (!v1.Equals(v2))
+				{
+					return false;
+				}
+			}
+
+			return true;
+		}
+
+		private static string canonicalize(
+			string s)
+		{
+			string v = s.ToLowerInvariant().Trim();
+
+			if (v.StartsWith("#"))
+			{
+				Asn1Object obj = decodeObject(v);
+
+				if (obj is IAsn1String)
+				{
+					v = ((IAsn1String)obj).GetString().ToLowerInvariant().Trim();
+				}
+			}
+
+			return v;
+		}
+
+		private static Asn1Object decodeObject(
+			string v)
+		{
+			try
+			{
+				return Asn1Object.FromByteArray(Hex.Decode(v.Substring(1)));
+			}
+			catch (IOException e)
+			{
+				throw new InvalidOperationException("unknown encoding in name: " + e.Message, e);
+			}
+		}
+
+		private static string stripInternalSpaces(
+			string str)
+		{
+			StringBuilder res = new StringBuilder();
+
+			if (str.Length != 0)
+			{
+				char c1 = str[0];
+
+				res.Append(c1);
+
+				for (int k = 1; k < str.Length; k++)
+				{
+					char c2 = str[k];
+					if (!(c1 == ' ' && c2 == ' '))
+					{
+						res.Append(c2);
+					}
+					c1 = c2;
+				}
+			}
+
+			return res.ToString();
+		}
+
+		private void AppendValue(
+            StringBuilder		buf,
+            IDictionary         oidSymbols,
+            DerObjectIdentifier	oid,
+            string				val)
+        {
+            string sym = (string)oidSymbols[oid];
+
+            if (sym != null)
+            {
+                buf.Append(sym);
+            }
+            else
+            {
+                buf.Append(oid.Id);
+            }
+
+            buf.Append('=');
+
+            int index = buf.Length;
+
+            buf.Append(val);
+
+            int end = buf.Length;
+
+			if (val.StartsWith("\\#"))
+			{
+				index += 2;
+			}
+
+			while (index != end)
+            {
+                if ((buf[index] == ',')
+                || (buf[index] == '"')
+                || (buf[index] == '\\')
+                || (buf[index] == '+')
+				|| (buf[index] == '=')
+                || (buf[index] == '<')
+                || (buf[index] == '>')
+                || (buf[index] == ';'))
+                {
+                    buf.Insert(index++, "\\");
+                    end++;
+                }
+
+                index++;
+            }
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete]
+        public string ToString(
+            bool        reverse,
+            Hashtable   oidSymbols)
+        {
+            return ToString(reverse, (IDictionary)oidSymbols);
+        }
+#endif
+
+        /**
+        * convert the structure to a string - if reverse is true the
+        * oids and values are listed out starting with the last element
+        * in the sequence (ala RFC 2253), otherwise the string will begin
+        * with the first element of the structure. If no string definition
+        * for the oid is found in oidSymbols the string value of the oid is
+        * added. Two standard symbol tables are provided DefaultSymbols, and
+        * RFC2253Symbols as part of this class.
+        *
+        * @param reverse if true start at the end of the sequence and work back.
+        * @param oidSymbols look up table strings for oids.
+        */
+        public string ToString(
+            bool		reverse,
+            IDictionary oidSymbols)
+        {
+#if (SILVERLIGHT || PORTABLE)
+            List<object> components = new List<object>();
+#else
+			ArrayList components = new ArrayList();
+#endif
+
+            StringBuilder ava = null;
+
+			for (int i = 0; i < ordering.Count; i++)
+			{
+				if ((bool) added[i])
+				{
+					ava.Append('+');
+					AppendValue(ava, oidSymbols,
+						(DerObjectIdentifier)ordering[i],
+						(string)values[i]);
+				}
+				else
+				{
+					ava = new StringBuilder();
+					AppendValue(ava, oidSymbols,
+						(DerObjectIdentifier)ordering[i],
+						(string)values[i]);
+					components.Add(ava);
+				}
+			}
+
+			if (reverse)
+			{
+				components.Reverse();
+			}
+
+			StringBuilder buf = new StringBuilder();
+
+			if (components.Count > 0)
+			{
+				buf.Append(components[0].ToString());
+
+				for (int i = 1; i < components.Count; ++i)
+				{
+					buf.Append(',');
+					buf.Append(components[i].ToString());
+				}
+			}
+
+			return buf.ToString();
+		}
+
+		public override string ToString()
+        {
+            return ToString(DefaultReverse, (IDictionary)DefaultSymbols);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/X509NameEntryConverter.cs b/Crypto/src/asn1/x509/X509NameEntryConverter.cs
new file mode 100644
index 000000000..5872656a9
--- /dev/null
+++ b/Crypto/src/asn1/x509/X509NameEntryConverter.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * It turns out that the number of standard ways the fields in a DN should be
+     * encoded into their ASN.1 counterparts is rapidly approaching the
+     * number of machines on the internet. By default the X509Name class
+     * will produce UTF8Strings in line with the current recommendations (RFC 3280).
+     * <p>
+     * An example of an encoder look like below:
+     * <pre>
+     * public class X509DirEntryConverter
+     *     : X509NameEntryConverter
+     * {
+     *     public Asn1Object GetConvertedValue(
+     *         DerObjectIdentifier  oid,
+     *         string               value)
+     *     {
+     *         if (str.Length() != 0 &amp;&amp; str.charAt(0) == '#')
+     *         {
+     *             return ConvertHexEncoded(str, 1);
+     *         }
+     *         if (oid.Equals(EmailAddress))
+     *         {
+     *             return new DerIA5String(str);
+     *         }
+     *         else if (CanBePrintable(str))
+     *         {
+     *             return new DerPrintableString(str);
+     *         }
+     *         else if (CanBeUTF8(str))
+     *         {
+     *             return new DerUtf8String(str);
+     *         }
+     *         else
+     *         {
+     *             return new DerBmpString(str);
+     *         }
+     *     }
+     * }
+	 * </pre>
+	 * </p>
+     */
+    public abstract class X509NameEntryConverter
+    {
+        /**
+         * Convert an inline encoded hex string rendition of an ASN.1
+         * object back into its corresponding ASN.1 object.
+         *
+         * @param str the hex encoded object
+         * @param off the index at which the encoding starts
+         * @return the decoded object
+         */
+        protected Asn1Object ConvertHexEncoded(
+            string	hexString,
+            int		offset)
+        {
+			string str = hexString.Substring(offset);
+
+			return Asn1Object.FromByteArray(Hex.Decode(str));
+        }
+
+		/**
+         * return true if the passed in string can be represented without
+         * loss as a PrintableString, false otherwise.
+         */
+        protected bool CanBePrintable(
+            string str)
+        {
+			return DerPrintableString.IsPrintableString(str);
+        }
+
+		/**
+         * Convert the passed in string value into the appropriate ASN.1
+         * encoded object.
+         *
+         * @param oid the oid associated with the value in the DN.
+         * @param value the value of the particular DN component.
+         * @return the ASN.1 equivalent for the value.
+         */
+        public abstract Asn1Object GetConvertedValue(DerObjectIdentifier oid, string value);
+    }
+}
diff --git a/Crypto/src/asn1/x509/X509NameTokenizer.cs b/Crypto/src/asn1/x509/X509NameTokenizer.cs
new file mode 100644
index 000000000..ab5529535
--- /dev/null
+++ b/Crypto/src/asn1/x509/X509NameTokenizer.cs
@@ -0,0 +1,104 @@
+using System.Text;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * class for breaking up an X500 Name into it's component tokens, ala
+     * java.util.StringTokenizer. We need this class as some of the
+     * lightweight Java environment don't support classes like
+     * StringTokenizer.
+     */
+    public class X509NameTokenizer
+    {
+        private string			value;
+        private int				index;
+        private char			separator;
+        private StringBuilder	buffer = new StringBuilder();
+
+		public X509NameTokenizer(
+            string oid)
+            : this(oid, ',')
+        {
+        }
+
+		public X509NameTokenizer(
+            string	oid,
+            char	separator)
+        {
+            this.value = oid;
+            this.index = -1;
+            this.separator = separator;
+        }
+
+		public bool HasMoreTokens()
+        {
+            return index != value.Length;
+        }
+
+		public string NextToken()
+        {
+            if (index == value.Length)
+            {
+                return null;
+            }
+
+            int end = index + 1;
+            bool quoted = false;
+            bool escaped = false;
+
+			buffer.Remove(0, buffer.Length);
+
+			while (end != value.Length)
+            {
+                char c = value[end];
+
+				if (c == '"')
+                {
+                    if (!escaped)
+                    {
+                        quoted = !quoted;
+                    }
+                    else
+                    {
+                        buffer.Append(c);
+						escaped = false;
+                    }
+                }
+                else
+                {
+                    if (escaped || quoted)
+                    {
+						if (c == '#' && buffer[buffer.Length - 1] == '=')
+						{
+							buffer.Append('\\');
+						}
+						else if (c == '+' && separator != '+')
+						{
+							buffer.Append('\\');
+						}
+						buffer.Append(c);
+                        escaped = false;
+                    }
+                    else if (c == '\\')
+                    {
+                        escaped = true;
+                    }
+                    else if (c == separator)
+                    {
+                        break;
+                    }
+                    else
+                    {
+                        buffer.Append(c);
+                    }
+                }
+
+				end++;
+            }
+
+			index = end;
+
+			return buffer.ToString().Trim();
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/X509ObjectIdentifiers.cs b/Crypto/src/asn1/x509/X509ObjectIdentifiers.cs
new file mode 100644
index 000000000..f00e31475
--- /dev/null
+++ b/Crypto/src/asn1/x509/X509ObjectIdentifiers.cs
@@ -0,0 +1,59 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public abstract class X509ObjectIdentifiers
+    {
+        //
+        // base id
+        //
+        internal const string ID = "2.5.4";
+
+		public static readonly DerObjectIdentifier CommonName              = new DerObjectIdentifier(ID + ".3");
+        public static readonly DerObjectIdentifier CountryName             = new DerObjectIdentifier(ID + ".6");
+        public static readonly DerObjectIdentifier LocalityName            = new DerObjectIdentifier(ID + ".7");
+        public static readonly DerObjectIdentifier StateOrProvinceName     = new DerObjectIdentifier(ID + ".8");
+        public static readonly DerObjectIdentifier Organization            = new DerObjectIdentifier(ID + ".10");
+        public static readonly DerObjectIdentifier OrganizationalUnitName  = new DerObjectIdentifier(ID + ".11");
+
+		public static readonly DerObjectIdentifier id_at_telephoneNumber   = new DerObjectIdentifier(ID + ".20");
+		public static readonly DerObjectIdentifier id_at_name              = new DerObjectIdentifier(ID + ".41");
+
+		// id-SHA1 OBJECT IDENTIFIER ::=
+        //   {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 }    //
+        public static readonly DerObjectIdentifier IdSha1 = new DerObjectIdentifier("1.3.14.3.2.26");
+
+		//
+        // ripemd160 OBJECT IDENTIFIER ::=
+        //      {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) hashAlgorithm(2) RipeMD-160(1)}
+        //
+        public static readonly DerObjectIdentifier RipeMD160 = new DerObjectIdentifier("1.3.36.3.2.1");
+
+		//
+        // ripemd160WithRSAEncryption OBJECT IDENTIFIER ::=
+        //      {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) signatureAlgorithm(3) rsaSignature(1) rsaSignatureWithripemd160(2) }
+        //
+        public static readonly DerObjectIdentifier RipeMD160WithRsaEncryption = new DerObjectIdentifier("1.3.36.3.3.1.2");
+
+		public static readonly DerObjectIdentifier IdEARsa = new DerObjectIdentifier("2.5.8.1.1");
+
+		// id-pkix
+		public static readonly DerObjectIdentifier IdPkix = new DerObjectIdentifier("1.3.6.1.5.5.7");
+
+		//
+		// private internet extensions
+		//
+		public static readonly DerObjectIdentifier IdPE = new DerObjectIdentifier(IdPkix + ".1");
+
+		//
+		// authority information access
+		//
+		public static readonly DerObjectIdentifier IdAD = new DerObjectIdentifier(IdPkix + ".48");
+		public static readonly DerObjectIdentifier IdADCAIssuers = new DerObjectIdentifier(IdAD + ".2");
+		public static readonly DerObjectIdentifier IdADOcsp = new DerObjectIdentifier(IdAD + ".1");
+
+		//
+		// OID for ocsp and crl uri in AuthorityInformationAccess extension
+		//
+		public static readonly DerObjectIdentifier OcspAccessMethod = IdADOcsp;
+		public static readonly DerObjectIdentifier CrlAccessMethod = IdADCAIssuers;
+    }
+}
diff --git a/Crypto/src/asn1/x509/qualified/BiometricData.cs b/Crypto/src/asn1/x509/qualified/BiometricData.cs
new file mode 100644
index 000000000..61d7c99cb
--- /dev/null
+++ b/Crypto/src/asn1/x509/qualified/BiometricData.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    /**
+    * The BiometricData object.
+    * <pre>
+    * BiometricData  ::=  SEQUENCE {
+    *       typeOfBiometricData  TypeOfBiometricData,
+    *       hashAlgorithm        AlgorithmIdentifier,
+    *       biometricDataHash    OCTET STRING,
+    *       sourceDataUri        IA5String OPTIONAL  }
+    * </pre>
+    */
+    public class BiometricData
+        : Asn1Encodable
+    {
+        private readonly TypeOfBiometricData typeOfBiometricData;
+        private readonly AlgorithmIdentifier hashAlgorithm;
+        private readonly Asn1OctetString     biometricDataHash;
+        private readonly DerIA5String        sourceDataUri;
+
+        public static BiometricData GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is BiometricData)
+            {
+                return (BiometricData)obj;
+            }
+
+            if (obj is Asn1Sequence)
+            {
+				return new BiometricData(Asn1Sequence.GetInstance(obj));
+            }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		private BiometricData(
+			Asn1Sequence seq)
+        {
+			typeOfBiometricData = TypeOfBiometricData.GetInstance(seq[0]);
+			hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+			biometricDataHash = Asn1OctetString.GetInstance(seq[2]);
+
+			if (seq.Count > 3)
+			{
+				sourceDataUri = DerIA5String.GetInstance(seq[3]);
+			}
+        }
+
+		public BiometricData(
+            TypeOfBiometricData	typeOfBiometricData,
+            AlgorithmIdentifier	hashAlgorithm,
+            Asn1OctetString		biometricDataHash,
+            DerIA5String		sourceDataUri)
+        {
+            this.typeOfBiometricData = typeOfBiometricData;
+            this.hashAlgorithm = hashAlgorithm;
+            this.biometricDataHash = biometricDataHash;
+            this.sourceDataUri = sourceDataUri;
+        }
+
+        public BiometricData(
+            TypeOfBiometricData	typeOfBiometricData,
+            AlgorithmIdentifier	hashAlgorithm,
+            Asn1OctetString		biometricDataHash)
+        {
+            this.typeOfBiometricData = typeOfBiometricData;
+            this.hashAlgorithm = hashAlgorithm;
+            this.biometricDataHash = biometricDataHash;
+            this.sourceDataUri = null;
+        }
+
+        public TypeOfBiometricData TypeOfBiometricData
+        {
+			get { return typeOfBiometricData; }
+        }
+
+		public AlgorithmIdentifier HashAlgorithm
+		{
+			get { return hashAlgorithm; }
+		}
+
+		public Asn1OctetString BiometricDataHash
+		{
+			get { return biometricDataHash; }
+		}
+
+		public DerIA5String SourceDataUri
+		{
+			get { return sourceDataUri; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector seq = new Asn1EncodableVector(
+				typeOfBiometricData, hashAlgorithm, biometricDataHash);
+
+			if (sourceDataUri != null)
+            {
+                seq.Add(sourceDataUri);
+            }
+
+			return new DerSequence(seq);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs b/Crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs
new file mode 100644
index 000000000..86a4eee0a
--- /dev/null
+++ b/Crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs
@@ -0,0 +1,19 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+	public abstract class EtsiQCObjectIdentifiers
+	{
+		//
+		// base id
+		//
+		public static readonly DerObjectIdentifier IdEtsiQcs                 = new DerObjectIdentifier("0.4.0.1862.1");
+
+		public static readonly DerObjectIdentifier IdEtsiQcsQcCompliance     = new DerObjectIdentifier(IdEtsiQcs+".1");
+		public static readonly DerObjectIdentifier IdEtsiQcsLimitValue       = new DerObjectIdentifier(IdEtsiQcs+".2");
+		public static readonly DerObjectIdentifier IdEtsiQcsRetentionPeriod  = new DerObjectIdentifier(IdEtsiQcs+".3");
+		public static readonly DerObjectIdentifier IdEtsiQcsQcSscd           = new DerObjectIdentifier(IdEtsiQcs+".4");
+	}
+}
diff --git a/Crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs b/Crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs
new file mode 100644
index 000000000..3300562c8
--- /dev/null
+++ b/Crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs
@@ -0,0 +1,84 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    /**
+    * The Iso4217CurrencyCode object.
+    * <pre>
+    * Iso4217CurrencyCode  ::=  CHOICE {
+    *       alphabetic              PrintableString (SIZE 3), --Recommended
+    *       numeric              INTEGER (1..999) }
+    * -- Alphabetic or numeric currency code as defined in ISO 4217
+    * -- It is recommended that the Alphabetic form is used
+    * </pre>
+    */
+    public class Iso4217CurrencyCode
+        : Asn1Encodable, IAsn1Choice
+    {
+        internal const int AlphabeticMaxSize = 3;
+        internal const int NumericMinSize = 1;
+        internal const int NumericMaxSize = 999;
+
+		internal Asn1Encodable	obj;
+//        internal int			numeric;
+
+		public static Iso4217CurrencyCode GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is Iso4217CurrencyCode)
+            {
+                return (Iso4217CurrencyCode) obj;
+            }
+
+			if (obj is DerInteger)
+            {
+                DerInteger numericobj = DerInteger.GetInstance(obj);
+                int numeric = numericobj.Value.IntValue;
+                return new Iso4217CurrencyCode(numeric);
+            }
+
+			if (obj is DerPrintableString)
+            {
+                DerPrintableString alphabetic = DerPrintableString.GetInstance(obj);
+                return new Iso4217CurrencyCode(alphabetic.GetString());
+            }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+        }
+
+		public Iso4217CurrencyCode(
+            int numeric)
+        {
+            if (numeric > NumericMaxSize || numeric < NumericMinSize)
+            {
+                throw new ArgumentException("wrong size in numeric code : not in (" +NumericMinSize +".."+ NumericMaxSize +")");
+            }
+
+			obj = new DerInteger(numeric);
+        }
+
+		public Iso4217CurrencyCode(
+            string alphabetic)
+        {
+            if (alphabetic.Length > AlphabeticMaxSize)
+            {
+                throw new ArgumentException("wrong size in alphabetic code : max size is " + AlphabeticMaxSize);
+            }
+
+			obj = new DerPrintableString(alphabetic);
+        }
+
+		public bool IsAlphabetic { get { return obj is DerPrintableString; } }
+
+		public string Alphabetic { get { return ((DerPrintableString) obj).GetString(); } }
+
+		public int Numeric { get { return ((DerInteger)obj).Value.IntValue; } }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return obj.ToAsn1Object();
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/qualified/MonetaryValue.cs b/Crypto/src/asn1/x509/qualified/MonetaryValue.cs
new file mode 100644
index 000000000..45e113671
--- /dev/null
+++ b/Crypto/src/asn1/x509/qualified/MonetaryValue.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    /**
+    * The MonetaryValue object.
+    * <pre>
+    * MonetaryValue  ::=  SEQUENCE {
+    *       currency              Iso4217CurrencyCode,
+    *       amount               INTEGER,
+    *       exponent             INTEGER }
+    * -- value = amount * 10^exponent
+    * </pre>
+    */
+    public class MonetaryValue
+        : Asn1Encodable
+    {
+        internal Iso4217CurrencyCode	currency;
+        internal DerInteger				amount;
+        internal DerInteger				exponent;
+
+		public static MonetaryValue GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is MonetaryValue)
+            {
+                return (MonetaryValue) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new MonetaryValue(Asn1Sequence.GetInstance(obj));
+            }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		private MonetaryValue(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+            currency = Iso4217CurrencyCode.GetInstance(seq[0]);
+            amount = DerInteger.GetInstance(seq[1]);
+            exponent = DerInteger.GetInstance(seq[2]);
+        }
+
+		public MonetaryValue(
+            Iso4217CurrencyCode	currency,
+            int					amount,
+            int					exponent)
+        {
+            this.currency = currency;
+            this.amount = new DerInteger(amount);
+            this.exponent = new DerInteger(exponent);
+        }
+
+		public Iso4217CurrencyCode Currency
+		{
+			get { return currency; }
+		}
+
+		public BigInteger Amount
+		{
+			get { return amount.Value; }
+		}
+
+		public BigInteger Exponent
+		{
+			get { return exponent.Value; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(currency, amount, exponent);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/qualified/QCStatement.cs b/Crypto/src/asn1/x509/qualified/QCStatement.cs
new file mode 100644
index 000000000..317f03447
--- /dev/null
+++ b/Crypto/src/asn1/x509/qualified/QCStatement.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    /**
+    * The QCStatement object.
+    * <pre>
+    * QCStatement ::= SEQUENCE {
+    *   statementId        OBJECT IDENTIFIER,
+    *   statementInfo      ANY DEFINED BY statementId OPTIONAL}
+    * </pre>
+    */
+    public class QCStatement
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	qcStatementId;
+        private readonly Asn1Encodable			qcStatementInfo;
+
+		public static QCStatement GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is QCStatement)
+            {
+                return (QCStatement) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+				return new QCStatement(Asn1Sequence.GetInstance(obj));
+            }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		private QCStatement(
+            Asn1Sequence seq)
+        {
+			qcStatementId = DerObjectIdentifier.GetInstance(seq[0]);
+
+			if (seq.Count > 1)
+			{
+				qcStatementInfo = seq[1];
+			}
+        }
+
+		public QCStatement(
+            DerObjectIdentifier qcStatementId)
+        {
+            this.qcStatementId = qcStatementId;
+        }
+
+        public QCStatement(
+            DerObjectIdentifier qcStatementId,
+            Asn1Encodable       qcStatementInfo)
+        {
+            this.qcStatementId = qcStatementId;
+            this.qcStatementInfo = qcStatementInfo;
+        }
+
+		public DerObjectIdentifier StatementId
+		{
+			get { return qcStatementId; }
+		}
+
+		public Asn1Encodable StatementInfo
+		{
+			get { return qcStatementInfo; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector seq = new Asn1EncodableVector(qcStatementId);
+
+			if (qcStatementInfo != null)
+            {
+                seq.Add(qcStatementInfo);
+            }
+
+			return new DerSequence(seq);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs b/Crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs
new file mode 100644
index 000000000..8ebd69edb
--- /dev/null
+++ b/Crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs
@@ -0,0 +1,21 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    public sealed class Rfc3739QCObjectIdentifiers
+    {
+		private Rfc3739QCObjectIdentifiers()
+		{
+		}
+
+		//
+        // base id
+        //
+        public static readonly DerObjectIdentifier IdQcs = new DerObjectIdentifier("1.3.6.1.5.5.7.11");
+
+        public static readonly DerObjectIdentifier IdQcsPkixQCSyntaxV1 = new DerObjectIdentifier(IdQcs+".1");
+        public static readonly DerObjectIdentifier IdQcsPkixQCSyntaxV2 = new DerObjectIdentifier(IdQcs+".2");
+    }
+}
diff --git a/Crypto/src/asn1/x509/qualified/SemanticsInformation.cs b/Crypto/src/asn1/x509/qualified/SemanticsInformation.cs
new file mode 100644
index 000000000..72e7cd0e1
--- /dev/null
+++ b/Crypto/src/asn1/x509/qualified/SemanticsInformation.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    /**
+    * The SemanticsInformation object.
+    * <pre>
+    *       SemanticsInformation ::= SEQUENCE {
+    *         semanticsIdentifier        OBJECT IDENTIFIER   OPTIONAL,
+    *         nameRegistrationAuthorities NameRegistrationAuthorities
+    *                                                         OPTIONAL }
+    *         (WITH COMPONENTS {..., semanticsIdentifier PRESENT}|
+    *          WITH COMPONENTS {..., nameRegistrationAuthorities PRESENT})
+    *
+    *     NameRegistrationAuthorities ::=  SEQUENCE SIZE (1..MAX) OF
+    *         GeneralName
+    * </pre>
+    */
+    public class SemanticsInformation
+		: Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	semanticsIdentifier;
+        private readonly GeneralName[]			nameRegistrationAuthorities;
+
+		public static SemanticsInformation GetInstance(
+			object obj)
+        {
+            if (obj == null || obj is SemanticsInformation)
+            {
+                return (SemanticsInformation) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new SemanticsInformation(Asn1Sequence.GetInstance(obj));
+            }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		public SemanticsInformation(
+			Asn1Sequence seq)
+        {
+            if (seq.Count < 1)
+            {
+                throw new ArgumentException("no objects in SemanticsInformation");
+            }
+
+			IEnumerator e = seq.GetEnumerator();
+			e.MoveNext();
+            object obj = e.Current;
+            if (obj is DerObjectIdentifier)
+            {
+                semanticsIdentifier = DerObjectIdentifier.GetInstance(obj);
+                if (e.MoveNext())
+                {
+                    obj  = e.Current;
+                }
+                else
+                {
+                    obj  = null;
+                }
+            }
+
+			if (obj  != null)
+            {
+                Asn1Sequence generalNameSeq = Asn1Sequence.GetInstance(obj );
+                nameRegistrationAuthorities = new GeneralName[generalNameSeq.Count];
+                for (int i= 0; i < generalNameSeq.Count; i++)
+                {
+                    nameRegistrationAuthorities[i] = GeneralName.GetInstance(generalNameSeq[i]);
+                }
+            }
+        }
+
+		public SemanticsInformation(
+            DerObjectIdentifier semanticsIdentifier,
+            GeneralName[] generalNames)
+        {
+            this.semanticsIdentifier = semanticsIdentifier;
+            this.nameRegistrationAuthorities = generalNames;
+        }
+
+		public SemanticsInformation(
+			DerObjectIdentifier semanticsIdentifier)
+        {
+            this.semanticsIdentifier = semanticsIdentifier;
+        }
+
+        public SemanticsInformation(
+			GeneralName[] generalNames)
+        {
+            this.nameRegistrationAuthorities = generalNames;
+        }
+
+		public DerObjectIdentifier SemanticsIdentifier { get { return semanticsIdentifier; } }
+
+		public GeneralName[] GetNameRegistrationAuthorities()
+        {
+            return nameRegistrationAuthorities;
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector seq = new Asn1EncodableVector();
+
+            if (this.semanticsIdentifier != null)
+            {
+                seq.Add(semanticsIdentifier);
+            }
+
+			if (this.nameRegistrationAuthorities != null)
+            {
+                seq.Add(new DerSequence(nameRegistrationAuthorities));
+            }
+
+			return new DerSequence(seq);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs b/Crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs
new file mode 100644
index 000000000..a77e54acb
--- /dev/null
+++ b/Crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs
@@ -0,0 +1,91 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    /**
+    * The TypeOfBiometricData object.
+    * <pre>
+    * TypeOfBiometricData ::= CHOICE {
+    *   predefinedBiometricType   PredefinedBiometricType,
+    *   biometricDataOid          OBJECT IDENTIFIER }
+    *
+    * PredefinedBiometricType ::= INTEGER {
+    *   picture(0),handwritten-signature(1)}
+    *   (picture|handwritten-signature)
+    * </pre>
+    */
+    public class TypeOfBiometricData
+        : Asn1Encodable, IAsn1Choice
+    {
+        public const int Picture				= 0;
+        public const int HandwrittenSignature	= 1;
+
+		internal Asn1Encodable obj;
+
+		public static TypeOfBiometricData GetInstance(
+			object obj)
+        {
+            if (obj == null || obj is TypeOfBiometricData)
+            {
+                return (TypeOfBiometricData) obj;
+            }
+
+			if (obj is DerInteger)
+            {
+                DerInteger predefinedBiometricTypeObj = DerInteger.GetInstance(obj);
+                int predefinedBiometricType = predefinedBiometricTypeObj.Value.IntValue;
+
+				return new TypeOfBiometricData(predefinedBiometricType);
+            }
+
+			if (obj is DerObjectIdentifier)
+            {
+                DerObjectIdentifier BiometricDataOid = DerObjectIdentifier.GetInstance(obj);
+                return new TypeOfBiometricData(BiometricDataOid);
+            }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		public TypeOfBiometricData(
+			int predefinedBiometricType)
+        {
+            if (predefinedBiometricType == Picture || predefinedBiometricType == HandwrittenSignature)
+            {
+                obj = new DerInteger(predefinedBiometricType);
+            }
+            else
+            {
+                throw new ArgumentException("unknow PredefinedBiometricType : " + predefinedBiometricType);
+            }
+        }
+
+		public TypeOfBiometricData(
+			DerObjectIdentifier biometricDataOid)
+        {
+            obj = biometricDataOid;
+        }
+
+		public bool IsPredefined
+		{
+			get { return obj is DerInteger; }
+		}
+
+		public int PredefinedBiometricType
+		{
+			get { return ((DerInteger) obj).Value.IntValue; }
+		}
+
+		public DerObjectIdentifier BiometricDataOid
+		{
+			get { return (DerObjectIdentifier) obj; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return obj.ToAsn1Object();
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/sigi/NameOrPseudonym.cs b/Crypto/src/asn1/x509/sigi/NameOrPseudonym.cs
new file mode 100644
index 000000000..222895cf1
--- /dev/null
+++ b/Crypto/src/asn1/x509/sigi/NameOrPseudonym.cs
@@ -0,0 +1,177 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X500;
+
+namespace Org.BouncyCastle.Asn1.X509.SigI
+{
+	/**
+	* Structure for a name or pseudonym.
+	* 
+	* <pre>
+	*       NameOrPseudonym ::= CHOICE {
+	*     	   surAndGivenName SEQUENCE {
+	*     	     surName DirectoryString,
+	*     	     givenName SEQUENCE OF DirectoryString 
+	*         },
+	*     	   pseudonym DirectoryString 
+	*       }
+	* </pre>
+	* 
+	* @see org.bouncycastle.asn1.x509.sigi.PersonalData
+	* 
+	*/
+	public class NameOrPseudonym
+		: Asn1Encodable, IAsn1Choice
+	{
+		private readonly DirectoryString	pseudonym;
+		private readonly DirectoryString	surname;
+		private readonly Asn1Sequence		givenName;
+
+		public static NameOrPseudonym GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is NameOrPseudonym)
+			{
+				return (NameOrPseudonym)obj;
+			}
+
+			if (obj is IAsn1String)
+			{
+				return new NameOrPseudonym(DirectoryString.GetInstance(obj));
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new NameOrPseudonym((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		* Constructor from DERString.
+		* <p/>
+		* The sequence is of type NameOrPseudonym:
+		* <p/>
+		* <pre>
+		*       NameOrPseudonym ::= CHOICE {
+		*     	   surAndGivenName SEQUENCE {
+		*     	     surName DirectoryString,
+		*     	     givenName SEQUENCE OF DirectoryString
+		*         },
+		*     	   pseudonym DirectoryString
+		*       }
+		* </pre>
+		* @param pseudonym pseudonym value to use.
+		*/
+		public NameOrPseudonym(
+			DirectoryString pseudonym)
+		{
+			this.pseudonym = pseudonym;
+		}
+
+		/**
+		* Constructor from Asn1Sequence.
+		* <p/>
+		* The sequence is of type NameOrPseudonym:
+		* <p/>
+		* <pre>
+		*       NameOrPseudonym ::= CHOICE {
+		*     	   surAndGivenName SEQUENCE {
+		*     	     surName DirectoryString,
+		*     	     givenName SEQUENCE OF DirectoryString
+		*         },
+		*     	   pseudonym DirectoryString
+		*       }
+		* </pre>
+		*
+		* @param seq The ASN.1 sequence.
+		*/
+		private NameOrPseudonym(
+			Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			if (!(seq[0] is IAsn1String))
+				throw new ArgumentException("Bad object encountered: " + seq[0].GetType().Name);
+
+			surname = DirectoryString.GetInstance(seq[0]);
+			givenName = Asn1Sequence.GetInstance(seq[1]);
+		}
+
+		/**
+		* Constructor from a given details.
+		*
+		* @param pseudonym The pseudonym.
+		*/
+		public NameOrPseudonym(
+			string pseudonym)
+			: this(new DirectoryString(pseudonym))
+		{
+		}
+
+		/**
+		 * Constructor from a given details.
+		 *
+		 * @param surname   The surname.
+		 * @param givenName A sequence of directory strings making up the givenName
+		 */
+		public NameOrPseudonym(
+			DirectoryString	surname,
+			Asn1Sequence	givenName)
+		{
+			this.surname = surname;
+			this.givenName = givenName;
+		}
+
+		public DirectoryString Pseudonym
+		{
+			get { return pseudonym; }
+		}
+
+		public DirectoryString Surname
+		{
+			get { return surname; }
+		}
+
+		public DirectoryString[] GetGivenName()
+		{
+			DirectoryString[] items = new DirectoryString[givenName.Count];
+			int count = 0;
+			foreach (object o in givenName)
+			{
+				items[count++] = DirectoryString.GetInstance(o);
+			}
+			return items;
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*       NameOrPseudonym ::= CHOICE {
+		*     	   surAndGivenName SEQUENCE {
+		*     	     surName DirectoryString,
+		*     	     givenName SEQUENCE OF DirectoryString
+		*         },
+		*     	   pseudonym DirectoryString
+		*       }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			if (pseudonym != null)
+			{
+				return pseudonym.ToAsn1Object();
+			}
+
+			return new DerSequence(surname, givenName);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/sigi/PersonalData.cs b/Crypto/src/asn1/x509/sigi/PersonalData.cs
new file mode 100644
index 000000000..6acdc7308
--- /dev/null
+++ b/Crypto/src/asn1/x509/sigi/PersonalData.cs
@@ -0,0 +1,210 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509.SigI
+{
+	/**
+	* Contains personal data for the otherName field in the subjectAltNames
+	* extension.
+	* <p/>
+	* <pre>
+	*     PersonalData ::= SEQUENCE {
+	*       nameOrPseudonym NameOrPseudonym,
+	*       nameDistinguisher [0] INTEGER OPTIONAL,
+	*       dateOfBirth [1] GeneralizedTime OPTIONAL,
+	*       placeOfBirth [2] DirectoryString OPTIONAL,
+	*       gender [3] PrintableString OPTIONAL,
+	*       postalAddress [4] DirectoryString OPTIONAL
+	*       }
+	* </pre>
+	*
+	* @see org.bouncycastle.asn1.x509.sigi.NameOrPseudonym
+	* @see org.bouncycastle.asn1.x509.sigi.SigIObjectIdentifiers
+	*/
+	public class PersonalData
+		: Asn1Encodable
+	{
+		private readonly NameOrPseudonym	nameOrPseudonym;
+		private readonly BigInteger			nameDistinguisher;
+		private readonly DerGeneralizedTime	dateOfBirth;
+		private readonly DirectoryString	placeOfBirth;
+		private readonly string				gender;
+		private readonly DirectoryString	postalAddress;
+
+		public static PersonalData GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is PersonalData)
+			{
+				return (PersonalData) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new PersonalData((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		* Constructor from Asn1Sequence.
+		* <p/>
+		* The sequence is of type NameOrPseudonym:
+		* <p/>
+		* <pre>
+		*     PersonalData ::= SEQUENCE {
+		*       nameOrPseudonym NameOrPseudonym,
+		*       nameDistinguisher [0] INTEGER OPTIONAL,
+		*       dateOfBirth [1] GeneralizedTime OPTIONAL,
+		*       placeOfBirth [2] DirectoryString OPTIONAL,
+		*       gender [3] PrintableString OPTIONAL,
+		*       postalAddress [4] DirectoryString OPTIONAL
+		*       }
+		* </pre>
+		*
+		* @param seq The ASN.1 sequence.
+		*/
+		private PersonalData(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			IEnumerator e = seq.GetEnumerator();
+			e.MoveNext();
+
+			nameOrPseudonym = NameOrPseudonym.GetInstance(e.Current);
+
+			while (e.MoveNext())
+			{
+				Asn1TaggedObject o = Asn1TaggedObject.GetInstance(e.Current);
+				int tag = o.TagNo;
+				switch (tag)
+				{
+					case 0:
+						nameDistinguisher = DerInteger.GetInstance(o, false).Value;
+						break;
+					case 1:
+						dateOfBirth = DerGeneralizedTime.GetInstance(o, false);
+						break;
+					case 2:
+						placeOfBirth = DirectoryString.GetInstance(o, true);
+						break;
+					case 3:
+						gender = DerPrintableString.GetInstance(o, false).GetString();
+						break;
+					case 4:
+						postalAddress = DirectoryString.GetInstance(o, true);
+						break;
+					default:
+						throw new ArgumentException("Bad tag number: " + o.TagNo);
+				}
+			}
+		}
+
+		/**
+		* Constructor from a given details.
+		*
+		* @param nameOrPseudonym  Name or pseudonym.
+		* @param nameDistinguisher Name distinguisher.
+		* @param dateOfBirth      Date of birth.
+		* @param placeOfBirth     Place of birth.
+		* @param gender           Gender.
+		* @param postalAddress    Postal Address.
+		*/
+		public PersonalData(
+			NameOrPseudonym		nameOrPseudonym,
+			BigInteger			nameDistinguisher,
+			DerGeneralizedTime	dateOfBirth,
+			DirectoryString		placeOfBirth,
+			string				gender,
+			DirectoryString		postalAddress)
+		{
+			this.nameOrPseudonym = nameOrPseudonym;
+			this.dateOfBirth = dateOfBirth;
+			this.gender = gender;
+			this.nameDistinguisher = nameDistinguisher;
+			this.postalAddress = postalAddress;
+			this.placeOfBirth = placeOfBirth;
+		}
+
+		public NameOrPseudonym NameOrPseudonym
+		{
+			get { return nameOrPseudonym; }
+		}
+
+		public BigInteger NameDistinguisher
+		{
+			get { return nameDistinguisher; }
+		}
+
+		public DerGeneralizedTime DateOfBirth
+		{
+			get { return dateOfBirth; }
+		}
+
+		public DirectoryString PlaceOfBirth
+		{
+			get { return placeOfBirth; }
+		}
+
+		public string Gender
+		{
+			get { return gender; }
+		}
+
+		public DirectoryString PostalAddress
+		{
+			get { return postalAddress; }
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*     PersonalData ::= SEQUENCE {
+		*       nameOrPseudonym NameOrPseudonym,
+		*       nameDistinguisher [0] INTEGER OPTIONAL,
+		*       dateOfBirth [1] GeneralizedTime OPTIONAL,
+		*       placeOfBirth [2] DirectoryString OPTIONAL,
+		*       gender [3] PrintableString OPTIONAL,
+		*       postalAddress [4] DirectoryString OPTIONAL
+		*       }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector vec = new Asn1EncodableVector();
+			vec.Add(nameOrPseudonym);
+			if (nameDistinguisher != null)
+			{
+				vec.Add(new DerTaggedObject(false, 0, new DerInteger(nameDistinguisher)));
+			}
+			if (dateOfBirth != null)
+			{
+				vec.Add(new DerTaggedObject(false, 1, dateOfBirth));
+			}
+			if (placeOfBirth != null)
+			{
+				vec.Add(new DerTaggedObject(true, 2, placeOfBirth));
+			}
+			if (gender != null)
+			{
+				vec.Add(new DerTaggedObject(false, 3, new DerPrintableString(gender, true)));
+			}
+			if (postalAddress != null)
+			{
+				vec.Add(new DerTaggedObject(true, 4, postalAddress));
+			}
+			return new DerSequence(vec);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/sigi/SigIObjectIdentifiers.cs b/Crypto/src/asn1/x509/sigi/SigIObjectIdentifiers.cs
new file mode 100644
index 000000000..682311adc
--- /dev/null
+++ b/Crypto/src/asn1/x509/sigi/SigIObjectIdentifiers.cs
@@ -0,0 +1,49 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509.SigI
+{
+	/**
+	 * Object Identifiers of SigI specifciation (German Signature Law
+	 * Interoperability specification).
+	 */
+	public sealed class SigIObjectIdentifiers
+	{
+		private SigIObjectIdentifiers()
+		{
+		}
+
+		public readonly static DerObjectIdentifier IdSigI = new DerObjectIdentifier("1.3.36.8");
+
+		/**
+		* Key purpose IDs for German SigI (Signature Interoperability
+		* Specification)
+		*/
+		public readonly static DerObjectIdentifier IdSigIKP = new DerObjectIdentifier(IdSigI + ".2");
+
+		/**
+		* Certificate policy IDs for German SigI (Signature Interoperability
+		* Specification)
+		*/
+		public readonly static DerObjectIdentifier IdSigICP = new DerObjectIdentifier(IdSigI + ".1");
+
+		/**
+		* Other Name IDs for German SigI (Signature Interoperability Specification)
+		*/
+		public readonly static DerObjectIdentifier IdSigION = new DerObjectIdentifier(IdSigI + ".4");
+
+		/**
+		* To be used for for the generation of directory service certificates.
+		*/
+		public static readonly DerObjectIdentifier IdSigIKPDirectoryService = new DerObjectIdentifier(IdSigIKP + ".1");
+
+		/**
+		* ID for PersonalData
+		*/
+		public static readonly DerObjectIdentifier IdSigIONPersonalData = new DerObjectIdentifier(IdSigION + ".1");
+
+		/**
+		* Certificate is conform to german signature law.
+		*/
+		public static readonly DerObjectIdentifier IdSigICPSigConform = new DerObjectIdentifier(IdSigICP + ".1");
+	}
+}
diff --git a/Crypto/src/asn1/x9/DHDomainParameters.cs b/Crypto/src/asn1/x9/DHDomainParameters.cs
new file mode 100644
index 000000000..8de869694
--- /dev/null
+++ b/Crypto/src/asn1/x9/DHDomainParameters.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+	public class DHDomainParameters
+		: Asn1Encodable
+	{
+		private readonly DerInteger p, g, q, j;
+		private readonly DHValidationParms validationParms;
+
+		public static DHDomainParameters GetInstance(Asn1TaggedObject obj, bool isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+
+		public static DHDomainParameters GetInstance(object obj)
+		{
+			if (obj == null || obj is DHDomainParameters)
+				return (DHDomainParameters)obj;
+
+			if (obj is Asn1Sequence)
+				return new DHDomainParameters((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid DHDomainParameters: " + obj.GetType().FullName, "obj");
+		}
+
+		public DHDomainParameters(DerInteger p, DerInteger g, DerInteger q, DerInteger j,
+			DHValidationParms validationParms)
+		{
+			if (p == null)
+				throw new ArgumentNullException("p");
+			if (g == null)
+				throw new ArgumentNullException("g");
+			if (q == null)
+				throw new ArgumentNullException("q");
+
+			this.p = p;
+			this.g = g;
+			this.q = q;
+			this.j = j;
+			this.validationParms = validationParms;
+		}
+
+		private DHDomainParameters(Asn1Sequence seq)
+		{
+			if (seq.Count < 3 || seq.Count > 5)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			IEnumerator e = seq.GetEnumerator();
+			this.p = DerInteger.GetInstance(GetNext(e));
+			this.g = DerInteger.GetInstance(GetNext(e));
+			this.q = DerInteger.GetInstance(GetNext(e));
+
+			Asn1Encodable next = GetNext(e);
+
+			if (next != null && next is DerInteger)
+			{
+				this.j = DerInteger.GetInstance(next);
+				next = GetNext(e);
+			}
+
+			if (next != null)
+			{
+				this.validationParms = DHValidationParms.GetInstance(next.ToAsn1Object());
+			}
+		}
+
+		private static Asn1Encodable GetNext(IEnumerator e)
+		{
+			return e.MoveNext() ? (Asn1Encodable)e.Current : null;
+		}
+
+		public DerInteger P
+		{
+			get { return this.p; }
+		}
+
+		public DerInteger G
+		{
+			get { return this.g; }
+		}
+
+		public DerInteger Q
+		{
+			get { return this.q; }
+		}
+
+		public DerInteger J
+		{
+			get { return this.j; }
+		}
+
+		public DHValidationParms ValidationParms
+		{
+			get { return this.validationParms; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(p, g, q);
+
+			if (this.j != null)
+			{
+				v.Add(this.j);
+			}
+
+			if (this.validationParms != null)
+			{
+				v.Add(this.validationParms);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x9/DHPublicKey.cs b/Crypto/src/asn1/x9/DHPublicKey.cs
new file mode 100644
index 000000000..1a20a8a16
--- /dev/null
+++ b/Crypto/src/asn1/x9/DHPublicKey.cs
@@ -0,0 +1,44 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+	public class DHPublicKey
+		: Asn1Encodable
+	{
+		private readonly DerInteger y;
+
+		public static DHPublicKey GetInstance(Asn1TaggedObject obj, bool isExplicit)
+		{
+			return GetInstance(DerInteger.GetInstance(obj, isExplicit));
+		}
+
+		public static DHPublicKey GetInstance(object obj)
+		{
+			if (obj == null || obj is DHPublicKey)
+				return (DHPublicKey)obj;
+
+			if (obj is DerInteger)
+				return new DHPublicKey((DerInteger)obj);
+
+			throw new ArgumentException("Invalid DHPublicKey: " + obj.GetType().FullName, "obj");
+		}
+
+		public DHPublicKey(DerInteger y)
+		{
+			if (y == null)
+				throw new ArgumentNullException("y");
+
+			this.y = y;
+		}
+
+		public DerInteger Y
+		{
+			get { return this.y; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return this.y;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x9/DHValidationParms.cs b/Crypto/src/asn1/x9/DHValidationParms.cs
new file mode 100644
index 000000000..a37964cfb
--- /dev/null
+++ b/Crypto/src/asn1/x9/DHValidationParms.cs
@@ -0,0 +1,62 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+	public class DHValidationParms
+		: Asn1Encodable
+	{
+		private readonly DerBitString seed;
+		private readonly DerInteger pgenCounter;
+
+		public static DHValidationParms GetInstance(Asn1TaggedObject obj, bool isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+
+		public static DHValidationParms GetInstance(object obj)
+		{
+			if (obj == null || obj is DHDomainParameters)
+				return (DHValidationParms)obj;
+
+			if (obj is Asn1Sequence)
+				return new DHValidationParms((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid DHValidationParms: " + obj.GetType().FullName, "obj");
+		}
+		
+		public DHValidationParms(DerBitString seed, DerInteger pgenCounter)
+		{
+			if (seed == null)
+				throw new ArgumentNullException("seed");
+			if (pgenCounter == null)
+				throw new ArgumentNullException("pgenCounter");
+
+			this.seed = seed;
+			this.pgenCounter = pgenCounter;
+		}
+
+		private DHValidationParms(Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.seed = DerBitString.GetInstance(seq[0]);
+			this.pgenCounter = DerInteger.GetInstance(seq[1]);
+		}
+
+		public DerBitString Seed
+		{
+			get { return this.seed; }
+		}
+
+		public DerInteger PgenCounter
+		{
+			get { return this.pgenCounter; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(seed, pgenCounter);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x9/KeySpecificInfo.cs b/Crypto/src/asn1/x9/KeySpecificInfo.cs
new file mode 100644
index 000000000..46298646b
--- /dev/null
+++ b/Crypto/src/asn1/x9/KeySpecificInfo.cs
@@ -0,0 +1,58 @@
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+    /**
+     * ASN.1 def for Diffie-Hellman key exchange KeySpecificInfo structure. See
+     * RFC 2631, or X9.42, for further details.
+     */
+    public class KeySpecificInfo
+        : Asn1Encodable
+    {
+        private DerObjectIdentifier	algorithm;
+        private Asn1OctetString		counter;
+
+		public KeySpecificInfo(
+            DerObjectIdentifier	algorithm,
+            Asn1OctetString		counter)
+        {
+            this.algorithm = algorithm;
+            this.counter = counter;
+        }
+
+		public KeySpecificInfo(
+            Asn1Sequence seq)
+        {
+            IEnumerator e = seq.GetEnumerator();
+
+			e.MoveNext();
+            algorithm = (DerObjectIdentifier)e.Current;
+            e.MoveNext();
+            counter = (Asn1OctetString)e.Current;
+        }
+
+		public DerObjectIdentifier Algorithm
+        {
+            get { return algorithm; }
+        }
+
+		public Asn1OctetString Counter
+        {
+            get { return counter; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  KeySpecificInfo ::= Sequence {
+         *      algorithm OBJECT IDENTIFIER,
+         *      counter OCTET STRING SIZE (4..4)
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(algorithm, counter);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x9/OtherInfo.cs b/Crypto/src/asn1/x9/OtherInfo.cs
new file mode 100644
index 000000000..21863bd17
--- /dev/null
+++ b/Crypto/src/asn1/x9/OtherInfo.cs
@@ -0,0 +1,88 @@
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+    /**
+     * ANS.1 def for Diffie-Hellman key exchange OtherInfo structure. See
+     * RFC 2631, or X9.42, for further details.
+     */
+    public class OtherInfo
+        : Asn1Encodable
+    {
+        private KeySpecificInfo	keyInfo;
+        private Asn1OctetString	partyAInfo;
+        private Asn1OctetString	suppPubInfo;
+
+		public OtherInfo(
+            KeySpecificInfo	keyInfo,
+            Asn1OctetString	partyAInfo,
+            Asn1OctetString	suppPubInfo)
+        {
+            this.keyInfo = keyInfo;
+            this.partyAInfo = partyAInfo;
+            this.suppPubInfo = suppPubInfo;
+        }
+
+		public OtherInfo(
+            Asn1Sequence seq)
+        {
+            IEnumerator e = seq.GetEnumerator();
+
+			e.MoveNext();
+            keyInfo = new KeySpecificInfo((Asn1Sequence) e.Current);
+
+			while (e.MoveNext())
+            {
+                DerTaggedObject o = (DerTaggedObject) e.Current;
+
+				if (o.TagNo == 0)
+                {
+                    partyAInfo = (Asn1OctetString) o.GetObject();
+                }
+                else if ((int) o.TagNo == 2)
+                {
+                    suppPubInfo = (Asn1OctetString) o.GetObject();
+                }
+            }
+        }
+
+		public KeySpecificInfo KeyInfo
+        {
+			get { return keyInfo; }
+        }
+
+		public Asn1OctetString PartyAInfo
+        {
+			get { return partyAInfo; }
+        }
+
+		public Asn1OctetString SuppPubInfo
+        {
+            get { return suppPubInfo; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  OtherInfo ::= Sequence {
+         *      keyInfo KeySpecificInfo,
+         *      partyAInfo [0] OCTET STRING OPTIONAL,
+         *      suppPubInfo [2] OCTET STRING
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(keyInfo);
+
+			if (partyAInfo != null)
+            {
+                v.Add(new DerTaggedObject(0, partyAInfo));
+            }
+
+			v.Add(new DerTaggedObject(2, suppPubInfo));
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x9/X962NamedCurves.cs b/Crypto/src/asn1/x9/X962NamedCurves.cs
new file mode 100644
index 000000000..de80ca280
--- /dev/null
+++ b/Crypto/src/asn1/x9/X962NamedCurves.cs
@@ -0,0 +1,733 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+	/**
+	 * table of the current named curves defined in X.962 EC-DSA.
+	 */
+	public sealed class X962NamedCurves
+	{
+		private X962NamedCurves()
+		{
+		}
+
+		internal class Prime192v1Holder
+			: X9ECParametersHolder
+		{
+			private Prime192v1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Prime192v1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve cFp192v1 = new FpCurve(
+					new BigInteger("6277101735386680763835789423207666416083908700390324961279"),
+					new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
+					new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16));
+
+				return new X9ECParameters(
+					cFp192v1,
+					cFp192v1.DecodePoint(
+						Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")),
+					new BigInteger("ffffffffffffffffffffffff99def836146bc9b1b4d22831", 16),
+					BigInteger.One,
+					Hex.Decode("3045AE6FC8422f64ED579528D38120EAE12196D5"));
+			}
+		}
+
+		internal class Prime192v2Holder
+			: X9ECParametersHolder
+		{
+			private Prime192v2Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Prime192v2Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve cFp192v2 = new FpCurve(
+					new BigInteger("6277101735386680763835789423207666416083908700390324961279"),
+					new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
+					new BigInteger("cc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953", 16));
+
+				return new X9ECParameters(
+					cFp192v2,
+					cFp192v2.DecodePoint(
+						Hex.Decode("03eea2bae7e1497842f2de7769cfe9c989c072ad696f48034a")),
+					new BigInteger("fffffffffffffffffffffffe5fb1a724dc80418648d8dd31", 16),
+					BigInteger.One,
+					Hex.Decode("31a92ee2029fd10d901b113e990710f0d21ac6b6"));
+			}
+		}
+
+		internal class Prime192v3Holder
+			: X9ECParametersHolder
+		{
+			private Prime192v3Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Prime192v3Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve cFp192v3 = new FpCurve(
+					new BigInteger("6277101735386680763835789423207666416083908700390324961279"),
+					new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
+					new BigInteger("22123dc2395a05caa7423daeccc94760a7d462256bd56916", 16));
+
+				return new X9ECParameters(
+					cFp192v3,
+					cFp192v3.DecodePoint(
+						Hex.Decode("027d29778100c65a1da1783716588dce2b8b4aee8e228f1896")),
+					new BigInteger("ffffffffffffffffffffffff7a62d031c83f4294f640ec13", 16),
+					BigInteger.One,
+					Hex.Decode("c469684435deb378c4b65ca9591e2a5763059a2e"));
+			}
+		}
+
+		internal class Prime239v1Holder
+			: X9ECParametersHolder
+		{
+			private Prime239v1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Prime239v1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve cFp239v1 = new FpCurve(
+					new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
+					new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16),
+					new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16));
+
+				return new X9ECParameters(
+					cFp239v1,
+					cFp239v1.DecodePoint(
+						Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")),
+					new BigInteger("7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b", 16),
+					BigInteger.One,
+					Hex.Decode("e43bb460f0b80cc0c0b075798e948060f8321b7d"));
+			}
+		}
+
+		internal class Prime239v2Holder
+			: X9ECParametersHolder
+		{
+			private Prime239v2Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Prime239v2Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve cFp239v2 = new FpCurve(
+					new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
+					new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16),
+					new BigInteger("617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c", 16));
+
+				return new X9ECParameters(
+					cFp239v2,
+					cFp239v2.DecodePoint(
+						Hex.Decode("0238af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7")),
+					new BigInteger("7fffffffffffffffffffffff800000cfa7e8594377d414c03821bc582063", 16),
+					BigInteger.One,
+					Hex.Decode("e8b4011604095303ca3b8099982be09fcb9ae616"));
+			}
+		}
+
+		internal class Prime239v3Holder
+			: X9ECParametersHolder
+		{
+			private Prime239v3Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Prime239v3Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve cFp239v3 = new FpCurve(
+					new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
+					new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16),
+					new BigInteger("255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e", 16));
+
+				return new X9ECParameters(
+					cFp239v3,
+					cFp239v3.DecodePoint(
+						Hex.Decode("036768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a")),
+					new BigInteger("7fffffffffffffffffffffff7fffff975deb41b3a6057c3c432146526551", 16),
+					BigInteger.One,
+					Hex.Decode("7d7374168ffe3471b60a857686a19475d3bfa2ff"));
+			}
+		}
+
+		internal class Prime256v1Holder
+			: X9ECParametersHolder
+		{
+			private Prime256v1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new Prime256v1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				ECCurve cFp256v1 = new FpCurve(
+					new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951"),
+					new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+					new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16));
+
+				return new X9ECParameters(
+					cFp256v1,
+					cFp256v1.DecodePoint(
+						Hex.Decode("036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296")),
+					new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16),
+					BigInteger.One,
+					Hex.Decode("c49d360886e704936a6678e1139d26b7819f7e90"));
+			}
+		}
+
+		/*
+		 * F2m Curves
+		 */
+		internal class C2pnb163v1Holder
+			: X9ECParametersHolder
+		{
+			private C2pnb163v1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new C2pnb163v1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger n = new BigInteger("0400000000000000000001E60FC8821CC74DAEAFC1", 16);
+				BigInteger h = BigInteger.ValueOf(2);
+
+				ECCurve c2m163v1 = new F2mCurve(
+					163,
+					1, 2, 8,
+					new BigInteger("072546B5435234A422E0789675F432C89435DE5242", 16),
+					new BigInteger("00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9", 16),
+					n, h);
+
+				return new X9ECParameters(
+					c2m163v1,
+					c2m163v1.DecodePoint(
+						Hex.Decode("0307AF69989546103D79329FCC3D74880F33BBE803CB")),
+					n, h,
+					Hex.Decode("D2COFB15760860DEF1EEF4D696E6768756151754"));
+			}
+		}
+
+		internal class C2pnb163v2Holder
+			: X9ECParametersHolder
+		{
+			private C2pnb163v2Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new C2pnb163v2Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger n = new BigInteger("03FFFFFFFFFFFFFFFFFFFDF64DE1151ADBB78F10A7", 16);
+				BigInteger h = BigInteger.ValueOf(2);
+
+				ECCurve c2m163v2 = new F2mCurve(
+					163,
+					1, 2, 8,
+					new BigInteger("0108B39E77C4B108BED981ED0E890E117C511CF072", 16),
+					new BigInteger("0667ACEB38AF4E488C407433FFAE4F1C811638DF20", 16),
+					n, h);
+
+				return new X9ECParameters(
+					c2m163v2,
+					c2m163v2.DecodePoint(
+						Hex.Decode("030024266E4EB5106D0A964D92C4860E2671DB9B6CC5")),
+					n, h,
+					null);
+			}
+		}
+
+		internal class C2pnb163v3Holder
+			: X9ECParametersHolder
+		{
+			private C2pnb163v3Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new C2pnb163v3Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger n = new BigInteger("03FFFFFFFFFFFFFFFFFFFE1AEE140F110AFF961309", 16);
+				BigInteger h = BigInteger.ValueOf(2);
+
+				ECCurve c2m163v3 = new F2mCurve(
+					163,
+					1, 2, 8,
+					new BigInteger("07A526C63D3E25A256A007699F5447E32AE456B50E", 16),
+					new BigInteger("03F7061798EB99E238FD6F1BF95B48FEEB4854252B", 16),
+					n, h);
+
+				return new X9ECParameters(
+					c2m163v3,
+					c2m163v3.DecodePoint(Hex.Decode("0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB")),
+					n, h,
+					null);
+			}
+		}
+
+		internal class C2pnb176w1Holder
+			: X9ECParametersHolder
+		{
+			private C2pnb176w1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new C2pnb176w1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger n = new BigInteger("010092537397ECA4F6145799D62B0A19CE06FE26AD", 16);
+				BigInteger h = BigInteger.ValueOf(0xFF6E);
+
+				ECCurve c2m176w1 = new F2mCurve(
+					176,
+					1, 2, 43,
+					new BigInteger("00E4E6DB2995065C407D9D39B8D0967B96704BA8E9C90B", 16),
+					new BigInteger("005DDA470ABE6414DE8EC133AE28E9BBD7FCEC0AE0FFF2", 16),
+					n, h);
+
+				return new X9ECParameters(
+					c2m176w1,
+					c2m176w1.DecodePoint(
+						Hex.Decode("038D16C2866798B600F9F08BB4A8E860F3298CE04A5798")),
+					n, h,
+					null);
+			}
+		}
+
+		internal class C2tnb191v1Holder
+			: X9ECParametersHolder
+		{
+			private C2tnb191v1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new C2tnb191v1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger n = new BigInteger("40000000000000000000000004A20E90C39067C893BBB9A5", 16);
+				BigInteger h = BigInteger.ValueOf(2);
+
+				ECCurve c2m191v1 = new F2mCurve(
+					191,
+					9,
+					new BigInteger("2866537B676752636A68F56554E12640276B649EF7526267", 16),
+					new BigInteger("2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC", 16),
+					n, h);
+
+				return new X9ECParameters(
+					c2m191v1,
+					c2m191v1.DecodePoint(
+						Hex.Decode("0236B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D")),
+					n, h,
+					Hex.Decode("4E13CA542744D696E67687561517552F279A8C84"));
+			}
+		}
+
+		internal class C2tnb191v2Holder
+			: X9ECParametersHolder
+		{
+			private C2tnb191v2Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new C2tnb191v2Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger n = new BigInteger("20000000000000000000000050508CB89F652824E06B8173", 16);
+				BigInteger h = BigInteger.ValueOf(4);
+
+				ECCurve c2m191v2 = new F2mCurve(
+					191,
+					9,
+					new BigInteger("401028774D7777C7B7666D1366EA432071274F89FF01E718", 16),
+					new BigInteger("0620048D28BCBD03B6249C99182B7C8CD19700C362C46A01", 16),
+					n, h);
+
+				return new X9ECParameters(
+					c2m191v2,
+					c2m191v2.DecodePoint(
+						Hex.Decode("023809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10")),
+					n, h,
+					null);
+			}
+		}
+
+		internal class C2tnb191v3Holder
+			: X9ECParametersHolder
+		{
+			private C2tnb191v3Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new C2tnb191v3Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger n = new BigInteger("155555555555555555555555610C0B196812BFB6288A3EA3", 16);
+				BigInteger h = BigInteger.ValueOf(6);
+
+				ECCurve c2m191v3 = new F2mCurve(
+					191,
+					9,
+					new BigInteger("6C01074756099122221056911C77D77E77A777E7E7E77FCB", 16),
+					new BigInteger("71FE1AF926CF847989EFEF8DB459F66394D90F32AD3F15E8", 16),
+					n, h);
+
+				return new X9ECParameters(
+					c2m191v3,
+					c2m191v3.DecodePoint(
+						Hex.Decode("03375D4CE24FDE434489DE8746E71786015009E66E38A926DD")),
+					n, h,
+					null);
+			}
+		}
+
+		internal class C2pnb208w1Holder
+			: X9ECParametersHolder
+		{
+			private C2pnb208w1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new C2pnb208w1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger n = new BigInteger("0101BAF95C9723C57B6C21DA2EFF2D5ED588BDD5717E212F9D", 16);
+				BigInteger h = BigInteger.ValueOf(0xFE48);
+
+				ECCurve c2m208w1 = new F2mCurve(
+					208,
+					1, 2, 83,
+					new BigInteger("0", 16),
+					new BigInteger("00C8619ED45A62E6212E1160349E2BFA844439FAFC2A3FD1638F9E", 16),
+					n, h);
+
+				return new X9ECParameters(
+					c2m208w1,
+					c2m208w1.DecodePoint(
+						Hex.Decode("0289FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A")),
+					n, h,
+					null);
+			}
+		}
+
+		internal class C2tnb239v1Holder
+			: X9ECParametersHolder
+		{
+			private C2tnb239v1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new C2tnb239v1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger n = new BigInteger("2000000000000000000000000000000F4D42FFE1492A4993F1CAD666E447", 16);
+				BigInteger h = BigInteger.ValueOf(4);
+
+				ECCurve c2m239v1 = new F2mCurve(
+					239,
+					36,
+					new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16),
+					new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16),
+					n, h);
+
+				return new X9ECParameters(
+					c2m239v1,
+					c2m239v1.DecodePoint(
+						Hex.Decode("0257927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D")),
+					n, h,
+					null);
+			}
+		}
+
+		internal class C2tnb239v2Holder
+			: X9ECParametersHolder
+		{
+			private C2tnb239v2Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new C2tnb239v2Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger n = new BigInteger("1555555555555555555555555555553C6F2885259C31E3FCDF154624522D", 16);
+				BigInteger h = BigInteger.ValueOf(6);
+
+				ECCurve c2m239v2 = new F2mCurve(
+					239,
+					36,
+					new BigInteger("4230017757A767FAE42398569B746325D45313AF0766266479B75654E65F", 16),
+					new BigInteger("5037EA654196CFF0CD82B2C14A2FCF2E3FF8775285B545722F03EACDB74B", 16),
+					n, h);
+
+				return new X9ECParameters(
+					c2m239v2,
+					c2m239v2.DecodePoint(
+						Hex.Decode("0228F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205")),
+					n, h,
+					null);
+			}
+		}
+
+		internal class C2tnb239v3Holder
+			: X9ECParametersHolder
+		{
+			private C2tnb239v3Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new C2tnb239v3Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger n = new BigInteger("0CCCCCCCCCCCCCCCCCCCCCCCCCCCCCAC4912D2D9DF903EF9888B8A0E4CFF", 16);
+				BigInteger h = BigInteger.ValueOf(10);
+
+				ECCurve c2m239v3 = new F2mCurve(
+					239,
+					36,
+					new BigInteger("01238774666A67766D6676F778E676B66999176666E687666D8766C66A9F", 16),
+					new BigInteger("6A941977BA9F6A435199ACFC51067ED587F519C5ECB541B8E44111DE1D40", 16),
+					n, h);
+
+				return new X9ECParameters(
+					c2m239v3,
+					c2m239v3.DecodePoint(
+						Hex.Decode("0370F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92")),
+					n, h,
+					null);
+			}
+		}
+
+		internal class C2pnb272w1Holder
+			: X9ECParametersHolder
+		{
+			private C2pnb272w1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new C2pnb272w1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger n = new BigInteger("0100FAF51354E0E39E4892DF6E319C72C8161603FA45AA7B998A167B8F1E629521", 16);
+				BigInteger h = BigInteger.ValueOf(0xFF06);
+
+				ECCurve c2m272w1 = new F2mCurve(
+					272,
+					1, 3, 56,
+					new BigInteger("0091A091F03B5FBA4AB2CCF49C4EDD220FB028712D42BE752B2C40094DBACDB586FB20", 16),
+					new BigInteger("7167EFC92BB2E3CE7C8AAAFF34E12A9C557003D7C73A6FAF003F99F6CC8482E540F7", 16),
+					n, h);
+
+				return new X9ECParameters(
+					c2m272w1,
+					c2m272w1.DecodePoint(
+						Hex.Decode("026108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D")),
+					n, h,
+					null);
+			}
+		}
+
+		internal class C2pnb304w1Holder
+			: X9ECParametersHolder
+		{
+			private C2pnb304w1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new C2pnb304w1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger n = new BigInteger("0101D556572AABAC800101D556572AABAC8001022D5C91DD173F8FB561DA6899164443051D", 16);
+				BigInteger h = BigInteger.ValueOf(0xFE2E);
+
+				ECCurve c2m304w1 = new F2mCurve(
+					304,
+					1, 2, 11,
+					new BigInteger("00FD0D693149A118F651E6DCE6802085377E5F882D1B510B44160074C1288078365A0396C8E681", 16),
+					new BigInteger("00BDDB97E555A50A908E43B01C798EA5DAA6788F1EA2794EFCF57166B8C14039601E55827340BE", 16),
+					n, h);
+
+				return new X9ECParameters(
+					c2m304w1,
+					c2m304w1.DecodePoint(
+						Hex.Decode("02197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614")),
+					n, h,
+					null);
+			}
+		}
+
+		internal class C2tnb359v1Holder
+			: X9ECParametersHolder
+		{
+			private C2tnb359v1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new C2tnb359v1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger n = new BigInteger("01AF286BCA1AF286BCA1AF286BCA1AF286BCA1AF286BC9FB8F6B85C556892C20A7EB964FE7719E74F490758D3B", 16);
+				BigInteger h = BigInteger.ValueOf(0x4C);
+
+				ECCurve c2m359v1 = new F2mCurve(
+					359,
+					68,
+					new BigInteger("5667676A654B20754F356EA92017D946567C46675556F19556A04616B567D223A5E05656FB549016A96656A557", 16),
+					new BigInteger("2472E2D0197C49363F1FE7F5B6DB075D52B6947D135D8CA445805D39BC345626089687742B6329E70680231988", 16),
+					n, h);
+
+				return new X9ECParameters(
+					c2m359v1,
+					c2m359v1.DecodePoint(
+						Hex.Decode("033C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097")),
+					n, h,
+					null);
+			}
+		}
+
+		internal class C2pnb368w1Holder
+			: X9ECParametersHolder
+		{
+			private C2pnb368w1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new C2pnb368w1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger n = new BigInteger("010090512DA9AF72B08349D98A5DD4C7B0532ECA51CE03E2D10F3B7AC579BD87E909AE40A6F131E9CFCE5BD967", 16);
+				BigInteger h = BigInteger.ValueOf(0xFF70);
+
+				ECCurve c2m368w1 = new F2mCurve(
+					368,
+					1, 2, 85,
+					new BigInteger("00E0D2EE25095206F5E2A4F9ED229F1F256E79A0E2B455970D8D0D865BD94778C576D62F0AB7519CCD2A1A906AE30D", 16),
+					new BigInteger("00FC1217D4320A90452C760A58EDCD30C8DD069B3C34453837A34ED50CB54917E1C2112D84D164F444F8F74786046A", 16),
+					n, h);
+
+				return new X9ECParameters(
+					c2m368w1,
+					c2m368w1.DecodePoint(
+						Hex.Decode("021085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F")),
+					n, h,
+					null);
+			}
+		}
+
+		internal class C2tnb431r1Holder
+			: X9ECParametersHolder
+		{
+			private C2tnb431r1Holder() {}
+
+			internal static readonly X9ECParametersHolder Instance = new C2tnb431r1Holder();
+
+			protected override X9ECParameters CreateParameters()
+			{
+				BigInteger n = new BigInteger("0340340340340340340340340340340340340340340340340340340323C313FAB50589703B5EC68D3587FEC60D161CC149C1AD4A91", 16);
+				BigInteger h = BigInteger.ValueOf(0x2760);
+
+				ECCurve c2m431r1 = new F2mCurve(
+					431,
+					120,
+					new BigInteger("1A827EF00DD6FC0E234CAF046C6A5D8A85395B236CC4AD2CF32A0CADBDC9DDF620B0EB9906D0957F6C6FEACD615468DF104DE296CD8F", 16),
+					new BigInteger("10D9B4A3D9047D8B154359ABFB1B7F5485B04CEB868237DDC9DEDA982A679A5A919B626D4E50A8DD731B107A9962381FB5D807BF2618", 16),
+					n, h);
+
+				return new X9ECParameters(
+					c2m431r1,
+					c2m431r1.DecodePoint(
+						Hex.Decode("02120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7")),
+					n, h,
+					null);
+			}
+		}
+
+		private static readonly IDictionary objIds = Platform.CreateHashtable();
+        private static readonly IDictionary curves = Platform.CreateHashtable();
+        private static readonly IDictionary names = Platform.CreateHashtable();
+
+		private static void DefineCurve(
+			string					name,
+			DerObjectIdentifier		oid,
+			X9ECParametersHolder	holder)
+		{
+			objIds.Add(name, oid);
+			names.Add(oid, name);
+			curves.Add(oid, holder);
+		}
+
+		static X962NamedCurves()
+		{
+			DefineCurve("prime192v1", X9ObjectIdentifiers.Prime192v1, Prime192v1Holder.Instance);
+			DefineCurve("prime192v2", X9ObjectIdentifiers.Prime192v2, Prime192v2Holder.Instance);
+			DefineCurve("prime192v3", X9ObjectIdentifiers.Prime192v3, Prime192v3Holder.Instance);
+			DefineCurve("prime239v1", X9ObjectIdentifiers.Prime239v1, Prime239v1Holder.Instance);
+			DefineCurve("prime239v2", X9ObjectIdentifiers.Prime239v2, Prime239v2Holder.Instance);
+			DefineCurve("prime239v3", X9ObjectIdentifiers.Prime239v3, Prime239v3Holder.Instance);
+			DefineCurve("prime256v1", X9ObjectIdentifiers.Prime256v1, Prime256v1Holder.Instance);
+			DefineCurve("c2pnb163v1", X9ObjectIdentifiers.C2Pnb163v1, C2pnb163v1Holder.Instance);
+			DefineCurve("c2pnb163v2", X9ObjectIdentifiers.C2Pnb163v2, C2pnb163v2Holder.Instance);
+			DefineCurve("c2pnb163v3", X9ObjectIdentifiers.C2Pnb163v3, C2pnb163v3Holder.Instance);
+			DefineCurve("c2pnb176w1", X9ObjectIdentifiers.C2Pnb176w1, C2pnb176w1Holder.Instance);
+			DefineCurve("c2tnb191v1", X9ObjectIdentifiers.C2Tnb191v1, C2tnb191v1Holder.Instance);
+			DefineCurve("c2tnb191v2", X9ObjectIdentifiers.C2Tnb191v2, C2tnb191v2Holder.Instance);
+			DefineCurve("c2tnb191v3", X9ObjectIdentifiers.C2Tnb191v3, C2tnb191v3Holder.Instance);
+			DefineCurve("c2pnb208w1", X9ObjectIdentifiers.C2Pnb208w1, C2pnb208w1Holder.Instance);
+			DefineCurve("c2tnb239v1", X9ObjectIdentifiers.C2Tnb239v1, C2tnb239v1Holder.Instance);
+			DefineCurve("c2tnb239v2", X9ObjectIdentifiers.C2Tnb239v2, C2tnb239v2Holder.Instance);
+			DefineCurve("c2tnb239v3", X9ObjectIdentifiers.C2Tnb239v3, C2tnb239v3Holder.Instance);
+			DefineCurve("c2pnb272w1", X9ObjectIdentifiers.C2Pnb272w1, C2pnb272w1Holder.Instance);
+			DefineCurve("c2pnb304w1", X9ObjectIdentifiers.C2Pnb304w1, C2pnb304w1Holder.Instance);
+			DefineCurve("c2tnb359v1", X9ObjectIdentifiers.C2Tnb359v1, C2tnb359v1Holder.Instance);
+			DefineCurve("c2pnb368w1", X9ObjectIdentifiers.C2Pnb368w1, C2pnb368w1Holder.Instance);
+			DefineCurve("c2tnb431r1", X9ObjectIdentifiers.C2Tnb431r1, C2tnb431r1Holder.Instance);
+		}
+
+		public static X9ECParameters GetByName(
+			string name)
+		{
+			DerObjectIdentifier oid = (DerObjectIdentifier) objIds[name.ToLowerInvariant()];
+
+			return oid == null ? null : GetByOid(oid);
+		}
+
+		/**
+		 * return the X9ECParameters object for the named curve represented by
+		 * the passed in object identifier. Null if the curve isn't present.
+		 *
+		 * @param oid an object identifier representing a named curve, if present.
+		 */
+		public static X9ECParameters GetByOid(
+			DerObjectIdentifier oid)
+		{
+			X9ECParametersHolder holder = (X9ECParametersHolder) curves[oid];
+
+			return holder == null ? null : holder.Parameters;
+		}
+
+		/**
+		 * return the object identifier signified by the passed in name. Null
+		 * if there is no object identifier associated with name.
+		 *
+		 * @return the object identifier associated with name, if present.
+		 */
+		public static DerObjectIdentifier GetOid(
+			string name)
+		{
+			return (DerObjectIdentifier) objIds[name.ToLowerInvariant()];
+		}
+
+		/**
+		 * return the named curve name represented by the given object identifier.
+		 */
+		public static string GetName(
+			DerObjectIdentifier oid)
+		{
+			return (string) names[oid];
+		}
+
+		/**
+		 * returns an enumeration containing the name strings for curves
+		 * contained in this structure.
+		 */
+		public static IEnumerable Names
+		{
+			get { return new EnumerableProxy(objIds.Keys); }
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x9/X962Parameters.cs b/Crypto/src/asn1/x9/X962Parameters.cs
new file mode 100644
index 000000000..5b7eaa1de
--- /dev/null
+++ b/Crypto/src/asn1/x9/X962Parameters.cs
@@ -0,0 +1,53 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+    public class X962Parameters
+        : Asn1Encodable, IAsn1Choice
+    {
+        private readonly Asn1Object _params;
+
+		public X962Parameters(
+            X9ECParameters ecParameters)
+        {
+            this._params = ecParameters.ToAsn1Object();
+        }
+
+		public X962Parameters(
+            DerObjectIdentifier namedCurve)
+        {
+            this._params = namedCurve;
+        }
+
+		public X962Parameters(
+            Asn1Object obj)
+        {
+            this._params = obj;
+        }
+
+		public bool IsNamedCurve
+        {
+			get { return (_params is DerObjectIdentifier); }
+        }
+
+		public Asn1Object Parameters
+        {
+            get { return _params; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * Parameters ::= CHOICE {
+         *    ecParameters ECParameters,
+         *    namedCurve   CURVES.&amp;id({CurveNames}),
+         *    implicitlyCA Null
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return _params;
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x9/X9Curve.cs b/Crypto/src/asn1/x9/X9Curve.cs
new file mode 100644
index 000000000..b92e7b3b5
--- /dev/null
+++ b/Crypto/src/asn1/x9/X9Curve.cs
@@ -0,0 +1,147 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+    /**
+     * ASN.1 def for Elliptic-Curve Curve structure. See
+     * X9.62, for further details.
+     */
+    public class X9Curve
+        : Asn1Encodable
+    {
+        private readonly ECCurve curve;
+        private readonly byte[] seed;
+		private readonly DerObjectIdentifier fieldIdentifier;
+
+		public X9Curve(
+            ECCurve curve)
+			: this(curve, null)
+        {
+            this.curve = curve;
+        }
+
+		public X9Curve(
+            ECCurve	curve,
+            byte[]	seed)
+        {
+			if (curve == null)
+				throw new ArgumentNullException("curve");
+
+			this.curve = curve;
+            this.seed = Arrays.Clone(seed);
+
+			if (curve is FpCurve)
+			{
+				this.fieldIdentifier = X9ObjectIdentifiers.PrimeField;
+			}
+			else if (curve is F2mCurve)
+			{
+				this.fieldIdentifier = X9ObjectIdentifiers.CharacteristicTwoField;
+			}
+			else
+			{
+				throw new ArgumentException("This type of ECCurve is not implemented");
+			}
+		}
+
+		public X9Curve(
+            X9FieldID		fieldID,
+            Asn1Sequence	seq)
+        {
+			if (fieldID == null)
+				throw new ArgumentNullException("fieldID");
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+
+			this.fieldIdentifier = fieldID.Identifier;
+
+			if (fieldIdentifier.Equals(X9ObjectIdentifiers.PrimeField))
+            {
+                BigInteger q = ((DerInteger) fieldID.Parameters).Value;
+                X9FieldElement x9A = new X9FieldElement(q, (Asn1OctetString) seq[0]);
+                X9FieldElement x9B = new X9FieldElement(q, (Asn1OctetString) seq[1]);
+                curve = new FpCurve(q, x9A.Value.ToBigInteger(), x9B.Value.ToBigInteger());
+            }
+            else
+            {
+				if (fieldIdentifier.Equals(X9ObjectIdentifiers.CharacteristicTwoField)) 
+				{
+					// Characteristic two field
+					DerSequence parameters = (DerSequence)fieldID.Parameters;
+					int m = ((DerInteger)parameters[0]).Value.IntValue;
+					DerObjectIdentifier representation
+						= (DerObjectIdentifier)parameters[1];
+
+					int k1 = 0;
+					int k2 = 0;
+					int k3 = 0;
+					if (representation.Equals(X9ObjectIdentifiers.TPBasis)) 
+					{
+						// Trinomial basis representation
+						k1 = ((DerInteger)parameters[2]).Value.IntValue;
+					}
+					else 
+					{
+						// Pentanomial basis representation
+						DerSequence pentanomial = (DerSequence) parameters[2];
+						k1 = ((DerInteger) pentanomial[0]).Value.IntValue;
+						k2 = ((DerInteger) pentanomial[1]).Value.IntValue;
+						k3 = ((DerInteger) pentanomial[2]).Value.IntValue;
+					}
+					X9FieldElement x9A = new X9FieldElement(m, k1, k2, k3, (Asn1OctetString)seq[0]);
+					X9FieldElement x9B = new X9FieldElement(m, k1, k2, k3, (Asn1OctetString)seq[1]);
+					// TODO Is it possible to get the order (n) and cofactor(h) too?
+					curve = new F2mCurve(m, k1, k2, k3, x9A.Value.ToBigInteger(), x9B.Value.ToBigInteger());
+				}
+			}
+
+			if (seq.Count == 3)
+            {
+                seed = ((DerBitString) seq[2]).GetBytes();
+            }
+        }
+
+		public ECCurve Curve
+        {
+			get { return curve; }
+        }
+
+		public byte[] GetSeed()
+        {
+            return Arrays.Clone(seed);
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  Curve ::= Sequence {
+         *      a               FieldElement,
+         *      b               FieldElement,
+         *      seed            BIT STRING      OPTIONAL
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (fieldIdentifier.Equals(X9ObjectIdentifiers.PrimeField)
+				|| fieldIdentifier.Equals(X9ObjectIdentifiers.CharacteristicTwoField)) 
+			{ 
+				v.Add(new X9FieldElement(curve.A).ToAsn1Object());
+				v.Add(new X9FieldElement(curve.B).ToAsn1Object());
+			} 
+
+			if (seed != null)
+			{
+				v.Add(new DerBitString(seed));
+			}
+
+			return new DerSequence(v);
+		}
+    }
+}
diff --git a/Crypto/src/asn1/x9/X9ECParameters.cs b/Crypto/src/asn1/x9/X9ECParameters.cs
new file mode 100644
index 000000000..d025b36ce
--- /dev/null
+++ b/Crypto/src/asn1/x9/X9ECParameters.cs
@@ -0,0 +1,170 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+    /**
+     * ASN.1 def for Elliptic-Curve ECParameters structure. See
+     * X9.62, for further details.
+     */
+    public class X9ECParameters
+        : Asn1Encodable
+    {
+        private X9FieldID	fieldID;
+        private ECCurve		curve;
+        private ECPoint		g;
+        private BigInteger	n;
+        private BigInteger	h;
+        private byte[]		seed;
+
+		public X9ECParameters(
+            Asn1Sequence seq)
+        {
+            if (!(seq[0] is DerInteger)
+               || !((DerInteger) seq[0]).Value.Equals(BigInteger.One))
+            {
+                throw new ArgumentException("bad version in X9ECParameters");
+            }
+
+			X9Curve x9c = null;
+            if (seq[2] is X9Curve)
+            {
+                x9c = (X9Curve) seq[2];
+            }
+            else
+            {
+                x9c = new X9Curve(
+					new X9FieldID(
+						(Asn1Sequence) seq[1]),
+						(Asn1Sequence) seq[2]);
+            }
+
+			this.curve = x9c.Curve;
+
+			if (seq[3] is X9ECPoint)
+            {
+                this.g = ((X9ECPoint) seq[3]).Point;
+            }
+            else
+            {
+                this.g = new X9ECPoint(curve, (Asn1OctetString) seq[3]).Point;
+            }
+
+			this.n = ((DerInteger) seq[4]).Value;
+            this.seed = x9c.GetSeed();
+
+			if (seq.Count == 6)
+            {
+                this.h = ((DerInteger) seq[5]).Value;
+            }
+        }
+
+		public X9ECParameters(
+            ECCurve		curve,
+            ECPoint		g,
+            BigInteger	n)
+            : this(curve, g, n, BigInteger.One, null)
+        {
+        }
+
+		public X9ECParameters(
+            ECCurve		curve,
+            ECPoint		g,
+            BigInteger	n,
+            BigInteger	h)
+            : this(curve, g, n, h, null)
+        {
+        }
+
+		public X9ECParameters(
+            ECCurve		curve,
+            ECPoint		g,
+            BigInteger	n,
+            BigInteger	h,
+            byte[]		seed)
+        {
+            this.curve = curve;
+            this.g = g;
+            this.n = n;
+            this.h = h;
+            this.seed = seed;
+
+			if (curve is FpCurve)
+			{
+				this.fieldID = new X9FieldID(((FpCurve) curve).Q);
+			}
+			else if (curve is F2mCurve)
+			{
+				F2mCurve curveF2m = (F2mCurve) curve;
+				this.fieldID = new X9FieldID(curveF2m.M, curveF2m.K1,
+					curveF2m.K2, curveF2m.K3);
+			}
+        }
+
+		public ECCurve Curve
+        {
+			get { return curve; }
+        }
+
+		public ECPoint G
+        {
+            get { return g; }
+        }
+
+		public BigInteger N
+        {
+            get { return n; }
+        }
+
+		public BigInteger H
+        {
+            get
+			{
+				if (h == null)
+				{
+					// TODO - this should be calculated, it will cause issues with custom curves.
+					return BigInteger.One;
+				}
+
+				return h;
+			}
+        }
+
+		public byte[] GetSeed()
+        {
+            return seed;
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  ECParameters ::= Sequence {
+         *      version         Integer { ecpVer1(1) } (ecpVer1),
+         *      fieldID         FieldID {{FieldTypes}},
+         *      curve           X9Curve,
+         *      base            X9ECPoint,
+         *      order           Integer,
+         *      cofactor        Integer OPTIONAL
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				new DerInteger(1),
+				fieldID,
+				new X9Curve(curve, seed),
+				new X9ECPoint(g),
+				new DerInteger(n));
+
+			if (h != null)
+            {
+                v.Add(new DerInteger(h));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x9/X9ECParametersHolder.cs b/Crypto/src/asn1/x9/X9ECParametersHolder.cs
new file mode 100644
index 000000000..b3455709c
--- /dev/null
+++ b/Crypto/src/asn1/x9/X9ECParametersHolder.cs
@@ -0,0 +1,22 @@
+namespace Org.BouncyCastle.Asn1.X9
+{
+	public abstract class X9ECParametersHolder
+	{
+		private X9ECParameters parameters;
+
+		public X9ECParameters Parameters
+		{
+			get
+			{
+				if (parameters == null)
+				{
+					parameters = CreateParameters();
+				}
+
+				return parameters;
+			}
+		}
+
+		protected abstract X9ECParameters CreateParameters();
+	}
+}
diff --git a/Crypto/src/asn1/x9/X9ECPoint.cs b/Crypto/src/asn1/x9/X9ECPoint.cs
new file mode 100644
index 000000000..ba2b2bcbf
--- /dev/null
+++ b/Crypto/src/asn1/x9/X9ECPoint.cs
@@ -0,0 +1,44 @@
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+    /**
+     * class for describing an ECPoint as a Der object.
+     */
+    public class X9ECPoint
+        : Asn1Encodable
+    {
+        private readonly ECPoint p;
+
+		public X9ECPoint(
+            ECPoint p)
+        {
+            this.p = p;
+        }
+
+		public X9ECPoint(
+            ECCurve			c,
+            Asn1OctetString	s)
+        {
+            this.p = c.DecodePoint(s.GetOctets());
+        }
+
+		public ECPoint Point
+        {
+			get { return p; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  ECPoint ::= OCTET STRING
+         * </pre>
+         * <p>
+         * Octet string produced using ECPoint.GetEncoded().</p>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerOctetString(p.GetEncoded());
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x9/X9FieldElement.cs b/Crypto/src/asn1/x9/X9FieldElement.cs
new file mode 100644
index 000000000..06fa0e3dc
--- /dev/null
+++ b/Crypto/src/asn1/x9/X9FieldElement.cs
@@ -0,0 +1,69 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+    /**
+     * Class for processing an ECFieldElement as a DER object.
+     */
+    public class X9FieldElement
+        : Asn1Encodable
+    {
+		private ECFieldElement f;
+
+		public X9FieldElement(
+			ECFieldElement f)
+		{
+			this.f = f;
+		}
+
+		public X9FieldElement(
+			BigInteger		p,
+			Asn1OctetString	s)
+			: this(new FpFieldElement(p, new BigInteger(1, s.GetOctets())))
+		{
+		}
+
+		public X9FieldElement(
+			int				m,
+			int				k1,
+			int				k2,
+			int				k3,
+			Asn1OctetString	s)
+			: this(new F2mFieldElement(m, k1, k2, k3, new BigInteger(1, s.GetOctets())))
+		{
+		}
+
+		public ECFieldElement Value
+        {
+            get { return f; }
+        }
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * <pre>
+		 *  FieldElement ::= OCTET STRING
+		 * </pre>
+		 * <p>
+		 * <ol>
+		 * <li> if <i>q</i> is an odd prime then the field element is
+		 * processed as an Integer and converted to an octet string
+		 * according to x 9.62 4.3.1.</li>
+		 * <li> if <i>q</i> is 2<sup>m</sup> then the bit string
+		 * contained in the field element is converted into an octet
+		 * string with the same ordering padded at the front if necessary.
+		 * </li>
+		 * </ol>
+		 * </p>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			int byteCount = X9IntegerConverter.GetByteLength(f);
+			byte[] paddedBigInteger = X9IntegerConverter.IntegerToBytes(f.ToBigInteger(), byteCount);
+
+			return new DerOctetString(paddedBigInteger);
+		}
+    }
+}
diff --git a/Crypto/src/asn1/x9/X9FieldID.cs b/Crypto/src/asn1/x9/X9FieldID.cs
new file mode 100644
index 000000000..c51cc4df2
--- /dev/null
+++ b/Crypto/src/asn1/x9/X9FieldID.cs
@@ -0,0 +1,102 @@
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+    /**
+     * ASN.1 def for Elliptic-Curve Field ID structure. See
+     * X9.62, for further details.
+     */
+    public class X9FieldID
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	id;
+        private readonly Asn1Object parameters;
+
+		/**
+		 * Constructor for elliptic curves over prime fields
+		 * <code>F<sub>2</sub></code>.
+		 * @param primeP The prime <code>p</code> defining the prime field.
+		 */
+		public X9FieldID(
+			BigInteger primeP)
+		{
+			this.id = X9ObjectIdentifiers.PrimeField;
+			this.parameters = new DerInteger(primeP);
+		}
+
+		/**
+		 * Constructor for elliptic curves over binary fields
+		 * <code>F<sub>2<sup>m</sup></sub></code>.
+		 * @param m  The exponent <code>m</code> of
+		 * <code>F<sub>2<sup>m</sup></sub></code>.
+		 * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
+		 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+		 * represents the reduction polynomial <code>f(z)</code>.
+		 * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
+		 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+		 * represents the reduction polynomial <code>f(z)</code>.
+		 * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
+		 * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+		 * represents the reduction polynomial <code>f(z)</code>..
+		 */
+		public X9FieldID(
+			int m,
+			int k1,
+			int k2,
+			int k3)
+		{
+			this.id = X9ObjectIdentifiers.CharacteristicTwoField;
+
+			Asn1EncodableVector fieldIdParams = new Asn1EncodableVector(new DerInteger(m));
+
+			if (k2 == 0)
+			{
+				fieldIdParams.Add(
+					X9ObjectIdentifiers.TPBasis,
+					new DerInteger(k1));
+			}
+			else
+			{
+				fieldIdParams.Add(
+					X9ObjectIdentifiers.PPBasis,
+					new DerSequence(
+						new DerInteger(k1),
+						new DerInteger(k2),
+						new DerInteger(k3)));
+			}
+
+			this.parameters = new DerSequence(fieldIdParams);
+		}
+
+		internal X9FieldID(
+			Asn1Sequence seq)
+		{
+			this.id = (DerObjectIdentifier) seq[0];
+			this.parameters = (Asn1Object) seq[1];
+		}
+
+		public DerObjectIdentifier Identifier
+        {
+            get { return id; }
+        }
+
+		public Asn1Object Parameters
+        {
+            get { return parameters; }
+        }
+
+		/**
+         * Produce a Der encoding of the following structure.
+         * <pre>
+         *  FieldID ::= Sequence {
+         *      fieldType       FIELD-ID.&amp;id({IOSet}),
+         *      parameters      FIELD-ID.&amp;Type({IOSet}{&#64;fieldType})
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(id, parameters);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x9/X9IntegerConverter.cs b/Crypto/src/asn1/x9/X9IntegerConverter.cs
new file mode 100644
index 000000000..2bce20488
--- /dev/null
+++ b/Crypto/src/asn1/x9/X9IntegerConverter.cs
@@ -0,0 +1,48 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+    public sealed class X9IntegerConverter
+    {
+		private X9IntegerConverter()
+		{
+		}
+
+		public static int GetByteLength(
+            ECFieldElement fe)
+        {
+			return (fe.FieldSize + 7) / 8;
+        }
+
+		public static int GetByteLength(
+			ECCurve c)
+		{
+			return (c.FieldSize + 7) / 8;
+		}
+
+		public static byte[] IntegerToBytes(
+			BigInteger	s,
+			int			qLength)
+		{
+			byte[] bytes = s.ToByteArrayUnsigned();
+
+			if (qLength < bytes.Length)
+			{
+				byte[] tmp = new byte[qLength];
+				Array.Copy(bytes, bytes.Length - tmp.Length, tmp, 0, tmp.Length);
+				return tmp;
+			}
+			else if (qLength > bytes.Length)
+			{
+				byte[] tmp = new byte[qLength];
+				Array.Copy(bytes, 0, tmp, tmp.Length - bytes.Length, bytes.Length);
+				return tmp;
+			}
+
+			return bytes;
+		}
+    }
+}
diff --git a/Crypto/src/asn1/x9/X9ObjectIdentifiers.cs b/Crypto/src/asn1/x9/X9ObjectIdentifiers.cs
new file mode 100644
index 000000000..5b2fdbd2d
--- /dev/null
+++ b/Crypto/src/asn1/x9/X9ObjectIdentifiers.cs
@@ -0,0 +1,135 @@
+namespace Org.BouncyCastle.Asn1.X9
+{
+    public abstract class X9ObjectIdentifiers
+    {
+        //
+        // X9.62
+        //
+        // ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+        //            us(840) ansi-x962(10045) }
+        //
+        internal const string AnsiX962 = "1.2.840.10045";
+        internal const string IdFieldType = AnsiX962 + ".1";
+
+		public static readonly DerObjectIdentifier PrimeField
+                        = new DerObjectIdentifier(IdFieldType + ".1");
+
+		public static readonly DerObjectIdentifier CharacteristicTwoField
+                        = new DerObjectIdentifier(IdFieldType + ".2");
+
+		public static readonly DerObjectIdentifier GNBasis
+                        = new DerObjectIdentifier(IdFieldType + ".2.3.1");
+
+		public static readonly DerObjectIdentifier TPBasis
+                        = new DerObjectIdentifier(IdFieldType + ".2.3.2");
+
+		public static readonly DerObjectIdentifier PPBasis
+                        = new DerObjectIdentifier(IdFieldType + ".2.3.3");
+
+		public const string IdECSigType = AnsiX962 + ".4";
+
+		public static readonly DerObjectIdentifier ECDsaWithSha1
+                        = new DerObjectIdentifier(IdECSigType + ".1");
+
+		public const string IdPublicKeyType = AnsiX962 + ".2";
+
+		public static readonly DerObjectIdentifier IdECPublicKey
+                        = new DerObjectIdentifier(IdPublicKeyType + ".1");
+
+		public static readonly DerObjectIdentifier ECDsaWithSha2 = new DerObjectIdentifier(IdECSigType + ".3");
+		public static readonly DerObjectIdentifier ECDsaWithSha224 = new DerObjectIdentifier(ECDsaWithSha2 + ".1");
+		public static readonly DerObjectIdentifier ECDsaWithSha256 = new DerObjectIdentifier(ECDsaWithSha2 + ".2");
+		public static readonly DerObjectIdentifier ECDsaWithSha384 = new DerObjectIdentifier(ECDsaWithSha2 + ".3");
+		public static readonly DerObjectIdentifier ECDsaWithSha512 = new DerObjectIdentifier(ECDsaWithSha2 + ".4");
+
+
+		//
+        // named curves
+        //
+        public static readonly DerObjectIdentifier EllipticCurve = new DerObjectIdentifier(AnsiX962 + ".3");
+
+		//
+        // Two Curves
+        //
+        public static readonly DerObjectIdentifier CTwoCurve = new DerObjectIdentifier(EllipticCurve + ".0");
+
+		public static readonly DerObjectIdentifier C2Pnb163v1 = new DerObjectIdentifier(CTwoCurve + ".1");
+        public static readonly DerObjectIdentifier C2Pnb163v2 = new DerObjectIdentifier(CTwoCurve + ".2");
+        public static readonly DerObjectIdentifier C2Pnb163v3 = new DerObjectIdentifier(CTwoCurve + ".3");
+        public static readonly DerObjectIdentifier C2Pnb176w1 = new DerObjectIdentifier(CTwoCurve + ".4");
+        public static readonly DerObjectIdentifier C2Tnb191v1 = new DerObjectIdentifier(CTwoCurve + ".5");
+        public static readonly DerObjectIdentifier C2Tnb191v2 = new DerObjectIdentifier(CTwoCurve + ".6");
+        public static readonly DerObjectIdentifier C2Tnb191v3 = new DerObjectIdentifier(CTwoCurve + ".7");
+        public static readonly DerObjectIdentifier C2Onb191v4 = new DerObjectIdentifier(CTwoCurve + ".8");
+        public static readonly DerObjectIdentifier C2Onb191v5 = new DerObjectIdentifier(CTwoCurve + ".9");
+        public static readonly DerObjectIdentifier C2Pnb208w1 = new DerObjectIdentifier(CTwoCurve + ".10");
+        public static readonly DerObjectIdentifier C2Tnb239v1 = new DerObjectIdentifier(CTwoCurve + ".11");
+        public static readonly DerObjectIdentifier C2Tnb239v2 = new DerObjectIdentifier(CTwoCurve + ".12");
+        public static readonly DerObjectIdentifier C2Tnb239v3 = new DerObjectIdentifier(CTwoCurve + ".13");
+        public static readonly DerObjectIdentifier C2Onb239v4 = new DerObjectIdentifier(CTwoCurve + ".14");
+        public static readonly DerObjectIdentifier C2Onb239v5 = new DerObjectIdentifier(CTwoCurve + ".15");
+        public static readonly DerObjectIdentifier C2Pnb272w1 = new DerObjectIdentifier(CTwoCurve + ".16");
+		public static readonly DerObjectIdentifier C2Pnb304w1 = new DerObjectIdentifier(CTwoCurve + ".17");
+		public static readonly DerObjectIdentifier C2Tnb359v1 = new DerObjectIdentifier(CTwoCurve + ".18");
+        public static readonly DerObjectIdentifier C2Pnb368w1 = new DerObjectIdentifier(CTwoCurve + ".19");
+        public static readonly DerObjectIdentifier C2Tnb431r1 = new DerObjectIdentifier(CTwoCurve + ".20");
+
+		//
+        // Prime
+        //
+        public static readonly DerObjectIdentifier PrimeCurve = new DerObjectIdentifier(EllipticCurve + ".1");
+
+		public static readonly DerObjectIdentifier Prime192v1 = new DerObjectIdentifier(PrimeCurve + ".1");
+        public static readonly DerObjectIdentifier Prime192v2 = new DerObjectIdentifier(PrimeCurve + ".2");
+        public static readonly DerObjectIdentifier Prime192v3 = new DerObjectIdentifier(PrimeCurve + ".3");
+        public static readonly DerObjectIdentifier Prime239v1 = new DerObjectIdentifier(PrimeCurve + ".4");
+        public static readonly DerObjectIdentifier Prime239v2 = new DerObjectIdentifier(PrimeCurve + ".5");
+        public static readonly DerObjectIdentifier Prime239v3 = new DerObjectIdentifier(PrimeCurve + ".6");
+        public static readonly DerObjectIdentifier Prime256v1 = new DerObjectIdentifier(PrimeCurve + ".7");
+
+		//
+        // DSA
+        //
+        // dsapublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+        //            us(840) ansi-x957(10040) number-type(4) 1 }
+        public static readonly DerObjectIdentifier IdDsa = new DerObjectIdentifier("1.2.840.10040.4.1");
+
+		/**
+         *   id-dsa-with-sha1 OBJECT IDENTIFIER ::=  { iso(1) member-body(2)
+         *         us(840) x9-57 (10040) x9cm(4) 3 }
+         */
+        public static readonly DerObjectIdentifier IdDsaWithSha1 = new DerObjectIdentifier("1.2.840.10040.4.3");
+
+		/**
+		 * X9.63
+		 */
+		public static readonly DerObjectIdentifier X9x63Scheme = new DerObjectIdentifier("1.3.133.16.840.63.0");
+		public static readonly DerObjectIdentifier DHSinglePassStdDHSha1KdfScheme = new DerObjectIdentifier(X9x63Scheme + ".2");
+		public static readonly DerObjectIdentifier DHSinglePassCofactorDHSha1KdfScheme = new DerObjectIdentifier(X9x63Scheme + ".3");
+		public static readonly DerObjectIdentifier MqvSinglePassSha1KdfScheme = new DerObjectIdentifier(X9x63Scheme + ".16");
+
+		/**
+		 * X9.42
+		 */
+
+		internal const string AnsiX942 = "1.2.840.10046";
+
+		//
+        // Diffie-Hellman
+        //
+        // dhpublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+        //            us(840) ansi-x942(10046) number-type(2) 1 }
+        //
+        public static readonly DerObjectIdentifier DHPublicNumber = new DerObjectIdentifier(AnsiX942 + ".2.1");
+
+		public static readonly DerObjectIdentifier X9x42Schemes = new DerObjectIdentifier(AnsiX942 + ".3");
+		public static readonly DerObjectIdentifier DHStatic = new DerObjectIdentifier(X9x42Schemes + ".1");
+		public static readonly DerObjectIdentifier DHEphem = new DerObjectIdentifier(X9x42Schemes + ".2");
+		public static readonly DerObjectIdentifier DHOneFlow = new DerObjectIdentifier(X9x42Schemes + ".3");
+		public static readonly DerObjectIdentifier DHHybrid1 = new DerObjectIdentifier(X9x42Schemes + ".4");
+		public static readonly DerObjectIdentifier DHHybrid2 = new DerObjectIdentifier(X9x42Schemes + ".5");
+		public static readonly DerObjectIdentifier DHHybridOneFlow = new DerObjectIdentifier(X9x42Schemes + ".6");
+		public static readonly DerObjectIdentifier Mqv2 = new DerObjectIdentifier(X9x42Schemes + ".7");
+		public static readonly DerObjectIdentifier Mqv1 = new DerObjectIdentifier(X9x42Schemes + ".8");
+	}
+}