/// <summary> /// Create a new instance of FieldMetaData with a given MemberInfo. /// </summary> /// <param name="outRef">Indicates the reference of the out object that hold this constraint.</param> /// <param name="info"></param> /// <remarks> /// AttachedTag, Constraint will be set automatically by reflection. /// </remarks> protected Asn1ConstraintedFieldMetadata(Asn1Object outRef, MemberInfo info) { OutReference = outRef; MemberInfo = info; //Get AttachedTag AttachedTag = null; var attrs = MemberInfo.GetCustomAttributes(typeof(Asn1Tag), true); if (attrs.Length != 0) { //Only the first tag is valid. Asn1Tag tag = attrs[0] as Asn1Tag; if (tag.TagType != Asn1TagType.Context && tag.TagType != Asn1TagType.Application) { throw new Asn1UserDefinedTypeInconsistent(ExceptionMessages.UserDefinedTypeInconsistent + " Only Context-Specific tag and Application tag are allowed."); } AttachedTag = tag; } //Get Constraint Constraint = GetConstraints(); }
/// <summary> /// Encodes a tag to the buffer. /// </summary> /// <param name="buffer"></param> /// <param name="tag"></param> /// <returns>The length of the encoding result.</returns> /// <remarks>Override this method in a user-defined class only if the procedure is not applicable in some special scenarios.</remarks> protected virtual int TagBerEncode(IAsn1BerEncodingBuffer buffer, Asn1Tag tag) { return Asn1StandardProcedure.TagBerEncode(buffer, tag); }
/// <summary> /// Decodes a tag from the buffer. /// </summary> /// <param name="buffer"></param> /// <param name="tag"></param> /// <returns>The number of the bytes consumed in the buffer to decode the tag.</returns> /// <remarks>Override this method in a user-defined class only if the procedure is not applicable in some special scenarios.</remarks> protected virtual int TagBerDecode(IAsn1DecodingBuffer buffer, out Asn1Tag tag) { return Asn1StandardProcedure.TagBerDecode(buffer, out tag); }
/// <summary> /// Encodes a tag to the buffer. /// </summary> /// <param name="buffer"></param> /// <param name="tag"></param> /// <returns>The length of the encoding result.</returns> public static int TagBerEncode(IAsn1BerEncodingBuffer buffer, Asn1Tag tag) { //Ref. X.690: 8.1.2.2, there are four kinds of tags byte prefix = 0; switch (tag.TagType) { case Asn1TagType.Universal: { prefix = 0;//00 } break; case Asn1TagType.Application: { prefix = 1;//01 } break; case Asn1TagType.Context: { prefix = 2;//10 } break; case Asn1TagType.Private: { prefix = 3;//11 //Ref. X.680: G.2.12.4 throw new Asn1UnreachableExcpetion(ExceptionMessages.Unreachable); }; } prefix <<= 6; if (tag.EncodingWay == EncodingWay.Constructed) { prefix |= (1 << 5);//Set the sixth bit to 1 if it is encoded in constructed way. Ref. X.690: 8.1.2.3 } if (tag.TagValue <= 30)//Use one byte to store the encoding result //Ref. X.690: 8.1.2.3 { prefix |= (byte)tag.TagValue; buffer.WriteByte(prefix); return 1; } else//Use more than one bytes to store. { //Ref. X.690: 8.1.2.4.3 throw new NotImplementedException("Case tag > 30 is not implemented. Check X.690: 8.1.2.4.3."); } }
/// <summary> /// Decodes a tag from the buffer. /// </summary> /// <param name="buffer"></param> /// <param name="tag"></param> /// <returns>The number of the bytes consumed in the buffer to decode the tag.</returns> public static int TagBerDecode(IAsn1DecodingBuffer buffer, out Asn1Tag tag) { byte prefix = buffer.ReadByte(); int firstTwoBits = (prefix >> 6); Asn1TagType tagType = Asn1TagType.Private; long tagValue; switch (firstTwoBits) { case 0: { tagType = Asn1TagType.Universal; } break; case 1: { tagType = Asn1TagType.Application; } break; case 2: { tagType = Asn1TagType.Context; } break; case 3: { throw new NotImplementedException(ExceptionMessages.Unreachable); }; } tagValue = prefix & ((byte)(1 << 5) - 1); if (tagValue <= 30) { tag = new Asn1Tag(tagType, tagValue); if ((prefix & (1 << 5)) != 0) { tag.EncodingWay = EncodingWay.Constructed; } else { tag.EncodingWay = EncodingWay.Primitive; } return 1; } else { throw new NotImplementedException("Case tag > 30 is not implemented. Check X.690: 8.1.2.4.3."); } }
/// <summary> /// Decodes the data from the buffer and stores the data in this object. /// </summary> /// <param name="buffer">A buffer that stores a BER encoding result.</param> /// <param name="length">The length of the encoding result of the data in the given buffer.</param> /// <returns>The number of the bytes consumed in the buffer to decode the data.</returns> /// <remarks> /// For the TLV (Tag, Length, Value) triple in the encoding result, /// this method provides the functionality of decoding Value. /// The decoding for Tag and Length will be done in Asn1Object::BerDecode method. /// </remarks> protected override int ValueBerDecode(IAsn1DecodingBuffer buffer, int length) { int consumedLen = 0; Asn1Tag tag = null; //The current decoded tag. int tagLen = 0; //The consumed length of the bytes in the buffer when decoding the current tag. bool tagUsed = true; int curFieldIndex = 0;//The index of the field that currently is trying to decode. Asn1Object[] tempFields = GetFieldsTypeInstances(); while (consumedLen < length) { if (curFieldIndex >= tempFields.Length) { throw new Asn1DecodingUnexpectedData(ExceptionMessages.DecodingUnexpectedData); } if (tagUsed) { tagLen = TagBerDecode(buffer, out tag); //The decoded tag may be context , application or universal tag. } if (fieldOptionalFlags[curFieldIndex] == false) { //Current field is mandatory. if (attachedTags[curFieldIndex] != null) { //Current field has a context class tag. //The decoded tag must be the context class tag of the field. if (tag.Equals(attachedTags[curFieldIndex])) { consumedLen += tagLen; int lengthAfterCtxTag; consumedLen += LengthBerDecode(buffer, out lengthAfterCtxTag); //Decodes this field by Asn1Object::BerDecode when the if-else statement for fieldOptionalFlags ends. } else { throw new Asn1DecodingUnexpectedData(ExceptionMessages.DecodingUnexpectedData + " Context Tag Decode fail."); } } else { //Current field doesn't have a context class tag. //The decoded tag must be the application or universal class tag of the field. //Retreat the buffer since the decoding of application or universal class is part of Asn1Object::BerDecode. buffer.SeekBytePosition(-tagLen); //Decode this field by Asn1Object::BerDecode when the if-else statement for fieldOptionalFlags ends. } } else { //Current field is optional. if (attachedTags[curFieldIndex] != null) { //Current field has a context class tag. //Check whether it is the encoding result of this field by the context-specific class tag. if (tag.Equals(attachedTags[curFieldIndex])) { //Yes consumedLen += tagLen; int lengthAfterCtxTag; consumedLen += LengthBerDecode(buffer, out lengthAfterCtxTag); //Decode this field by Asn1Object::BerDecode when the if-else statement for OptionalFlags ends. } else { //No tagUsed = false; tempFields[curFieldIndex] = null; curFieldIndex++; //Check the next field. continue; } } else { //Current field doesn't have a context class tag. //Check whether it is the encoding result of this field by the top most class tag. if (tag.Equals(tempFields[curFieldIndex].TopTag)) { //Yes buffer.SeekBytePosition(-tagLen); //Decode this field by Asn1Object::BerDecode when the if-else statement for OptionalFlags ends. } else { //No tagUsed = false; tempFields[curFieldIndex] = null; curFieldIndex++; //Check the next field. continue; } } } consumedLen += tempFields[curFieldIndex].BerDecode(buffer); tagUsed = true; curFieldIndex++; } //Ensure consumedLen equals to length. if (consumedLen > length) { throw new Asn1DecodingUnexpectedData(ExceptionMessages.DecodingUnexpectedData); } //Stores the decoded fields in this object. if (tempFields.Length != fieldsMemberInfo.Length) { throw new Asn1DecodingUnexpectedData(ExceptionMessages.DecodingUnexpectedData); } for (int i = 0; i < curFieldIndex; i++) { if (fieldsMemberInfo[i].MemberType == MemberTypes.Property) { (fieldsMemberInfo[i] as PropertyInfo).SetValue(this, tempFields[i], null); } else if (fieldsMemberInfo[i].MemberType == MemberTypes.Field) { (fieldsMemberInfo[i] as FieldInfo).SetValue(this, tempFields[i]); } else { //Unreachable. Ensured by the AttributeUsage of Asn1Field. throw new Asn1UserDefinedTypeInconsistent(ExceptionMessages.UserDefinedTypeInconsistent + " Asn1Field property could only be used in properties or fields."); } } return(consumedLen); }
public override int BerEncode(IAsn1BerEncodingBuffer buffer, bool explicitTag = true) { int allLen = 0; Asn1Tag contextTag; switch (SelectedChoice) { case 0: allLen += field0.BerEncodeWithoutUnisersalTag(buffer); contextTag = new Asn1Tag(Asn1TagType.Context, 0) { EncodingWay = EncodingWay.Primitive }; allLen += TagBerEncode(buffer, contextTag); break; case 1: allLen += field1.BerEncodeWithoutUnisersalTag(buffer); contextTag = new Asn1Tag(Asn1TagType.Context, 3) { EncodingWay = EncodingWay.Constructed }; allLen += TagBerEncode(buffer, contextTag); break; case 2: allLen += field2.BerEncodeWithoutUnisersalTag(buffer); contextTag = new Asn1Tag(Asn1TagType.Context, 9) { EncodingWay = EncodingWay.Primitive }; allLen += TagBerEncode(buffer, contextTag); break; case 3: allLen += field3.BerEncodeWithoutUnisersalTag(buffer); contextTag = new Asn1Tag(Asn1TagType.Context, 10) { EncodingWay = EncodingWay.Primitive }; allLen += TagBerEncode(buffer, contextTag); break; case 4: allLen += field4.BerEncodeWithoutUnisersalTag(buffer); contextTag = new Asn1Tag(Asn1TagType.Context, 11) { EncodingWay = EncodingWay.Primitive }; allLen += TagBerEncode(buffer, contextTag); break; default: throw new Asn1ConstraintsNotSatisfied(ExceptionMessages.InvalidChoiceIndex + " AuthenticationChoice"); } return allLen; }