Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (C) 2020 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package okhttp3.tls.internal.der
import java.math.BigInteger
import java.net.ProtocolException
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Date
import java.util.TimeZone
import kotlin.reflect.KClass
import okio.ByteString
/**
* Built-in adapters for reading standard ASN.1 types.
*/
internal object Adapters {
val BOOLEAN = BasicDerAdapter(
name = "BOOLEAN",
tagClass = DerHeader.TAG_CLASS_UNIVERSAL,
tag = 1L,
codec = object : BasicDerAdapter.Codec {
override fun decode(reader: DerReader) = reader.readBoolean()
override fun encode(writer: DerWriter, value: Boolean) = writer.writeBoolean(value)
}
)
val INTEGER_AS_LONG = BasicDerAdapter(
name = "INTEGER",
tagClass = DerHeader.TAG_CLASS_UNIVERSAL,
tag = 2L,
codec = object : BasicDerAdapter.Codec {
override fun decode(reader: DerReader) = reader.readLong()
override fun encode(writer: DerWriter, value: Long) = writer.writeLong(value)
}
)
val INTEGER_AS_BIG_INTEGER = BasicDerAdapter(
name = "INTEGER",
tagClass = DerHeader.TAG_CLASS_UNIVERSAL,
tag = 2L,
codec = object : BasicDerAdapter.Codec {
override fun decode(reader: DerReader) = reader.readBigInteger()
override fun encode(writer: DerWriter, value: BigInteger) = writer.writeBigInteger(value)
}
)
val BIT_STRING = BasicDerAdapter(
name = "BIT STRING",
tagClass = DerHeader.TAG_CLASS_UNIVERSAL,
tag = 3L,
codec = object : BasicDerAdapter.Codec {
override fun decode(reader: DerReader) = reader.readBitString()
override fun encode(writer: DerWriter, value: BitString) = writer.writeBitString(value)
}
)
val OCTET_STRING = BasicDerAdapter(
name = "OCTET STRING",
tagClass = DerHeader.TAG_CLASS_UNIVERSAL,
tag = 4L,
codec = object : BasicDerAdapter.Codec {
override fun decode(reader: DerReader) = reader.readOctetString()
override fun encode(writer: DerWriter, value: ByteString) = writer.writeOctetString(value)
}
)
val NULL = BasicDerAdapter(
name = "NULL",
tagClass = DerHeader.TAG_CLASS_UNIVERSAL,
tag = 5L,
codec = object : BasicDerAdapter.Codec {
override fun decode(reader: DerReader) = null
override fun encode(writer: DerWriter, value: Unit?) {
}
}
)
val OBJECT_IDENTIFIER = BasicDerAdapter(
name = "OBJECT IDENTIFIER",
tagClass = DerHeader.TAG_CLASS_UNIVERSAL,
tag = 6L,
codec = object : BasicDerAdapter.Codec {
override fun decode(reader: DerReader) = reader.readObjectIdentifier()
override fun encode(writer: DerWriter, value: String) = writer.writeObjectIdentifier(value)
}
)
val UTF8_STRING = BasicDerAdapter(
name = "UTF8",
tagClass = DerHeader.TAG_CLASS_UNIVERSAL,
tag = 12L,
codec = object : BasicDerAdapter.Codec {
override fun decode(reader: DerReader) = reader.readUtf8String()
override fun encode(writer: DerWriter, value: String) = writer.writeUtf8(value)
}
)
/**
* Permits alphanumerics, spaces, and these:
*
* ```
* ' () + , - . / : = ?
* ```
*/
// TODO(jwilson): constrain to printable string characters.
val PRINTABLE_STRING = BasicDerAdapter(
name = "PRINTABLE STRING",
tagClass = DerHeader.TAG_CLASS_UNIVERSAL,
tag = 19L,
codec = object : BasicDerAdapter.Codec {
override fun decode(reader: DerReader) = reader.readUtf8String()
override fun encode(writer: DerWriter, value: String) = writer.writeUtf8(value)
}
)
/**
* Based on International Alphabet No. 5. Note that there are bytes that IA5 and US-ASCII
* disagree on interpretation.
*/
// TODO(jwilson): constrain to IA5 characters.
val IA5_STRING = BasicDerAdapter(
name = "IA5 STRING",
tagClass = DerHeader.TAG_CLASS_UNIVERSAL,
tag = 22L,
codec = object : BasicDerAdapter.Codec {
override fun decode(reader: DerReader) = reader.readUtf8String()
override fun encode(writer: DerWriter, value: String) = writer.writeUtf8(value)
}
)
/**
* A timestamp like "191216030210Z" or "191215190210-0800" for 2019-12-15T19:02:10-08:00. The
* cutoff of the 2-digit year is 1950-01-01T00:00:00Z.
*/
val UTC_TIME = BasicDerAdapter(
name = "UTC TIME",
tagClass = DerHeader.TAG_CLASS_UNIVERSAL,
tag = 23L,
codec = object : BasicDerAdapter.Codec {
override fun decode(reader: DerReader): Long {
val string = reader.readUtf8String()
return parseUtcTime(string)
}
override fun encode(writer: DerWriter, value: Long) {
val string = formatUtcTime(value)
return writer.writeUtf8(string)
}
}
)
internal fun parseUtcTime(string: String): Long {
val utc = TimeZone.getTimeZone("GMT")
val dateFormat = SimpleDateFormat("yyMMddHHmmss'Z'").apply {
timeZone = utc
set2DigitYearStart(Date(-631152000000L)) // 1950-01-01T00:00:00Z.
}
try {
val parsed = dateFormat.parse(string)
return parsed.time
} catch (e: ParseException) {
throw ProtocolException("Failed to parse UTCTime $string")
}
}
internal fun formatUtcTime(date: Long): String {
val utc = TimeZone.getTimeZone("GMT")
val dateFormat = SimpleDateFormat("yyMMddHHmmss'Z'").apply {
timeZone = utc
set2DigitYearStart(Date(-631152000000L)) // 1950-01-01T00:00:00Z.
}
return dateFormat.format(date)
}
/**
* A timestamp like "191216030210Z" or "20191215190210-0800" for 2019-12-15T19:02:10-08:00. This
* is the same as [UTC_TIME] with the exception of the 4-digit year.
*/
val GENERALIZED_TIME = BasicDerAdapter(
name = "GENERALIZED TIME",
tagClass = DerHeader.TAG_CLASS_UNIVERSAL,
tag = 24L,
codec = object : BasicDerAdapter.Codec {
override fun decode(reader: DerReader): Long {
val string = reader.readUtf8String()
return parseGeneralizedTime(string)
}
override fun encode(writer: DerWriter, value: Long) {
val string = formatGeneralizedTime(value)
return writer.writeUtf8(string)
}
}
)
/** Decodes any value without interpretation as [AnyValue]. */
val ANY_VALUE = object : DerAdapter {
override fun matches(header: DerHeader) = true
override fun fromDer(reader: DerReader): AnyValue {
reader.read("ANY") { header ->
val bytes = reader.readUnknown()
return AnyValue(
tagClass = header.tagClass,
tag = header.tag,
constructed = header.constructed,
length = header.length,
bytes = bytes
)
}
}
override fun toDer(writer: DerWriter, value: AnyValue) {
writer.write("ANY", value.tagClass, value.tag) {
writer.writeOctetString(value.bytes)
writer.constructed = value.constructed
}
}
}
internal fun parseGeneralizedTime(string: String): Long {
val utc = TimeZone.getTimeZone("GMT")
val dateFormat = SimpleDateFormat("yyyyMMddHHmmss'Z'").apply {
timeZone = utc
}
try {
val parsed = dateFormat.parse(string)
return parsed.time
} catch (e: ParseException) {
throw ProtocolException("Failed to parse GeneralizedTime $string")
}
}
internal fun formatGeneralizedTime(date: Long): String {
val utc = TimeZone.getTimeZone("GMT")
val dateFormat = SimpleDateFormat("yyyyMMddHHmmss'Z'").apply {
timeZone = utc
}
return dateFormat.format(date)
}
/**
* Returns a composite adapter for a struct or data class. This may be used for both SEQUENCE and
* SET types.
*
* The fields are specified as a list of member adapters. When decoding, a value for each
* non-optional member but be included in sequence.
*
* TODO: for sets, sort by tag when encoding.
* TODO: for set ofs, sort by encoded value when encoding.
*/
fun sequence(
name: String,
vararg members: DerAdapter<*>,
decompose: (T) -> List<*>,
construct: (List<*>) -> T
): BasicDerAdapter {
val codec = object : BasicDerAdapter.Codec {
override fun decode(reader: DerReader): T {
return reader.withTypeHint {
val list = mutableListOf()
while (list.size < members.size) {
val member = members[list.size]
list += member.fromDer(reader)
}
if (reader.hasNext()) {
throw ProtocolException("unexpected ${reader.peekHeader()} at $reader")
}
return@withTypeHint construct(list)
}
}
override fun encode(writer: DerWriter, value: T) {
val list = decompose(value)
writer.withTypeHint {
for (i in list.indices) {
val adapter = members[i] as DerAdapter
adapter.toDer(writer, list[i])
}
}
}
}
return BasicDerAdapter(
name = name,
tagClass = DerHeader.TAG_CLASS_UNIVERSAL,
tag = 16L,
codec = codec
)
}
/** Returns an adapter that decodes as the first of a list of available types. */
fun choice(vararg choices: DerAdapter<*>): DerAdapter, Any?>> {
return object : DerAdapter, Any?>> {
override fun matches(header: DerHeader): Boolean = true
override fun fromDer(reader: DerReader): Pair, Any?> {
val peekedHeader = reader.peekHeader()
?: throw ProtocolException("expected a value at $reader")
val choice = choices.firstOrNull { it.matches(peekedHeader) }
?: throw ProtocolException(
"expected a matching choice but was $peekedHeader at $reader")
return choice to choice.fromDer(reader)
}
override fun toDer(writer: DerWriter, value: Pair, Any?>) {
val (adapter, v) = value
(adapter as DerAdapter).toDer(writer, v)
}
override fun toString() = choices.joinToString(separator = " OR ")
}
}
/**
* This decodes a value into its contents using a preceding member of the same SEQUENCE. For
* example, extensions type IDs specify what types to use for the corresponding values.
*
* If the hint is unknown [chooser] should return null which will cause the value to be decoded as
* an opaque byte string.
*
* This may optionally wrap the contents in a tag.
*/
fun usingTypeHint(
chooser: (Any?) -> DerAdapter<*>?
): DerAdapter {
return object : DerAdapter {
override fun matches(header: DerHeader) = true
override fun toDer(writer: DerWriter, value: Any?) {
// If we don't understand this hint, encode the body as a byte string. The byte string
// will include a tag and length header as a prefix.
val adapter = chooser(writer.typeHint) as DerAdapter?
when {
adapter != null -> adapter.toDer(writer, value)
else -> writer.writeOctetString(value as ByteString)
}
}
override fun fromDer(reader: DerReader): Any? {
val adapter = chooser(reader.typeHint) as DerAdapter?
return when {
adapter != null -> adapter.fromDer(reader)
else -> reader.readUnknown()
}
}
}
}
/**
* Object class to adapter type. This approach limits us to one adapter per Kotlin class, which
* might be too few for values like UTF_STRING and OBJECT_IDENTIFIER that share a Kotlin class but
* have very different ASN.1 interpretations.
*/
private val defaultAnyChoices = listOf(
Boolean::class to BOOLEAN,
BigInteger::class to INTEGER_AS_BIG_INTEGER,
BitString::class to BIT_STRING,
ByteString::class to OCTET_STRING,
Unit::class to NULL,
Nothing::class to OBJECT_IDENTIFIER,
Nothing::class to UTF8_STRING,
String::class to PRINTABLE_STRING,
Nothing::class to IA5_STRING,
Nothing::class to UTC_TIME,
Long::class to GENERALIZED_TIME,
AnyValue::class to ANY_VALUE
)
fun any(
vararg choices: Pair, DerAdapter<*>> = defaultAnyChoices.toTypedArray(),
isOptional: Boolean = false,
optionalValue: Any? = null
): DerAdapter {
return object : DerAdapter {
override fun matches(header: DerHeader): Boolean = true
override fun toDer(writer: DerWriter, value: Any?) {
when {
isOptional && value == optionalValue -> {
// Write nothing.
}
else -> {
for ((type, adapter) in choices) {
if (type.isInstance(value) || (value == null && type == Unit::class)) {
(adapter as DerAdapter).toDer(writer, value)
return
}
}
}
}
}
override fun fromDer(reader: DerReader): Any? {
if (isOptional && !reader.hasNext()) return optionalValue
val peekedHeader = reader.peekHeader()
?: throw ProtocolException("expected a value at $reader")
for ((_, adapter) in choices) {
if (adapter.matches(peekedHeader)) {
return adapter.fromDer(reader)
}
}
throw ProtocolException("expected any but was $peekedHeader at $reader")
}
}
}
}