1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.location.cts.asn1.base; 18 19 import java.nio.BufferOverflowException; 20 import java.nio.ByteBuffer; 21 import java.nio.ReadOnlyBufferException; 22 import java.util.Collection; 23 24 import javax.annotation.Nullable; 25 26 /** 27 * Specifies ASN.1 functionality needed for all ASN.1 objects. 28 * 29 */ 30 public abstract class Asn1Object { 31 /** 32 * Returns the tags that can decode to this type. Subclasses are expected to "fauxverride". 33 */ getPossibleFirstTags()34 public static Collection<Asn1Tag> getPossibleFirstTags() { 35 throw new UnsupportedOperationException("No first tags defined"); 36 } 37 38 /** 39 * Returns the universal tag defined for the base type. 40 */ getDefaultTag()41 abstract Asn1Tag getDefaultTag(); 42 43 /** 44 * Returns the declared tag for this type. Tagged subclasses must override, the 45 * default implementation returns null. 46 */ getTag()47 @Nullable protected Asn1Tag getTag() { 48 return null; 49 } 50 51 /** 52 * Returns true if implicit tagging is to be applied to the type. Tagged subclasses must 53 * override, the default implementation throws. 54 */ isTagImplicit()55 protected boolean isTagImplicit() { 56 throw new IllegalStateException("Not a tagged subclass"); 57 } 58 59 /** 60 * Returns true if this object is "constructed", that is, it's composed of further TLVs 61 * (as opposed to being primitive). 62 */ isConstructed()63 boolean isConstructed() { 64 return false; 65 } 66 67 /** 68 * Returns the number of octets in the BER encoding of this object. Called by 69 * {@link #encodeBer()} to allocate a buffer of the correct size before starting 70 * the encoding. 71 */ getBerLength()72 int getBerLength() { 73 int valueLen = getBerValueLength(); 74 Asn1Tag tag = getTag(); 75 if (tag == null) { 76 tag = getDefaultTag(); 77 } else if (!isTagImplicit()) { 78 valueLen = getDefaultTag().getTaggedLength(valueLen); 79 } 80 return tag.getTaggedLength(valueLen); 81 } 82 83 /** 84 * Returns the number of octets required to encoded the value of this {@link Asn1Object}. 85 */ getBerValueLength()86 abstract int getBerValueLength(); 87 88 /** 89 * Returns the BER encoding of this object. 90 */ encodeBer()91 public byte[] encodeBer() { 92 ByteBuffer buf = ByteBuffer.allocate(getBerLength()); 93 encodeBer(buf); 94 return buf.array(); 95 } 96 encodeBer(ByteBuffer buf)97 void encodeBer(ByteBuffer buf) { 98 int valueLen = getBerValueLength(); 99 Asn1Tag tag = getTag(); 100 if (tag == null) { 101 tag = getDefaultTag(); 102 } else { 103 if (!isTagImplicit()) { 104 int innerValueLen = getDefaultTag().getTaggedLength(valueLen); 105 tag.writeTagAndLength(buf, true, innerValueLen); 106 tag = getDefaultTag(); 107 } 108 } 109 tag.writeTagAndLength(buf, isConstructed(), valueLen); 110 encodeBerValue(buf); 111 } 112 113 /** 114 * Writes the BER encoded value of this {@link Asn1Object} into the specified buffer. 115 * 116 * @param buf the byte buffer to write to 117 * @throws BufferOverflowException If there is insufficient space in the buffer 118 * @throws ReadOnlyBufferException If the buffer is read-only 119 */ encodeBerValue(ByteBuffer buf)120 abstract void encodeBerValue(ByteBuffer buf); 121 122 /** 123 * BER decodes the provided buffer. Should only be called on newly created instances as subclasses 124 * may not write optional fields not explicitly present in the input. 125 * 126 * @param data the BER encoded input 127 * @throws IllegalArgumentException in case of parsing failure 128 */ decodeBer(byte[] data)129 public void decodeBer(byte[] data) { 130 decodeBer(ByteBuffer.wrap(data)); 131 } 132 decodeBer(ByteBuffer buf)133 void decodeBer(ByteBuffer buf) { 134 Asn1Tag tag = Asn1Tag.readTag(buf); 135 int valueLen = Asn1Tag.readLength(buf); 136 137 if (valueLen != buf.remaining()) { 138 throw new IllegalArgumentException("Length mismatch: expected=" + buf.remaining() 139 + ", actual=" + valueLen); 140 } 141 142 if (getTag() != null) { 143 checkTag(tag, getTag()); 144 if (!isTagImplicit()) { 145 // read inner tag and length 146 Asn1Tag innerTag = Asn1Tag.readTag(buf); 147 int innerValueLen = Asn1Tag.readLength(buf); 148 if (innerValueLen != buf.remaining()) { 149 throw new IllegalArgumentException("Length mismatch: expected=" + buf.remaining() 150 + ", actual=" + innerValueLen); 151 } 152 checkTag(innerTag, getDefaultTag()); 153 } 154 } 155 156 decodeBerValue(buf); 157 158 if (buf.hasRemaining()) { 159 throw new IllegalArgumentException("BER encoded input not fully read"); 160 } 161 } 162 checkTag(Asn1Tag actual, Asn1Tag expected)163 void checkTag(Asn1Tag actual, Asn1Tag expected) { 164 if (!expected.equals(actual)) { 165 throw new IllegalArgumentException("Invalid tag: expected=" + expected 166 + ", actual=" + actual); 167 } 168 } 169 170 /** 171 * Decodes the BER encoded value of this {@link Asn1Object}. On return from this method the 172 * provided buffer should be empty. 173 */ decodeBerValue(ByteBuffer buf)174 abstract void decodeBerValue(ByteBuffer buf); 175 176 /** 177 * Returns remaining bytes in the {@link ByteBuffer} in a newly allocated byte array of exactly 178 * the right size. The ByteBuffer will be empty upon return. 179 */ getRemaining(ByteBuffer buf)180 static byte[] getRemaining(ByteBuffer buf) { 181 byte[] bytes = new byte[buf.remaining()]; 182 buf.get(bytes); 183 return bytes; 184 } 185 encodePerAligned()186 public abstract Iterable<BitStream> encodePerAligned(); 187 encodePerUnaligned()188 public abstract Iterable<BitStream> encodePerUnaligned(); 189 190 /** 191 * This method should only be called on a newly created instance to avoid 192 * having residue state in it. 193 */ decodePerUnaligned(BitStreamReader reader)194 public abstract void decodePerUnaligned(BitStreamReader reader); 195 196 197 /** 198 * This method should only be called on a newly created instance to avoid 199 * having residue state in it. 200 */ decodePerAligned(BitStreamReader reader)201 public abstract void decodePerAligned(BitStreamReader reader); 202 toIndentedString(String indent)203 public String toIndentedString(String indent) { 204 return indent + toString(); 205 } 206 } 207