All Downloads are FREE. Search and download functionalities are using the official Maven repository.

main.okhttp3.tls.internal.der.DerAdapter.kt Maven / Gradle / Ivy

The newest version!
/*
 * 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 okio.Buffer
import okio.ByteString

/**
 * Encode and decode a model object like a [Long] or [Certificate] as DER bytes.
 */
internal interface DerAdapter {
  /** Returns true if this adapter can read [header] in a choice. */
  fun matches(header: DerHeader): Boolean

  /**
   * Returns a value from this adapter.
   *
   * This must always return a value, though it doesn't necessarily need to consume data from
   * [reader]. For example, if the reader's peeked tag isn't readable by this adapter, it may return
   * a default value.
   *
   * If this does read a value, it starts with the tag and length, and reads an entire value,
   * including any potential composed values.
   *
   * If there's nothing to read and no default value, this will throw an exception.
   */
  fun fromDer(reader: DerReader): T

  fun fromDer(byteString: ByteString): T {
    val buffer = Buffer().write(byteString)
    val reader = DerReader(buffer)
    return fromDer(reader)
  }

  /**
   * Writes [value] to this adapter, unless it is the default value and can be safely omitted.
   *
   * If this does write a value, it will write a tag and a length and a full value.
   */
  fun toDer(
    writer: DerWriter,
    value: T,
  )

  fun toDer(value: T): ByteString {
    val buffer = Buffer()
    val writer = DerWriter(buffer)
    toDer(writer, value)
    return buffer.readByteString()
  }

  /**
   * Returns an adapter that expects this value wrapped by another value. Typically this occurs
   * when a value has both a context or application tag and a universal tag.
   *
   * Use this for EXPLICIT tag types:
   *
   * ```
   * [5] EXPLICIT UTF8String
   * ```
   *
   * @param forceConstructed non-null to set the constructed bit to the specified value, even if the
   *     writing process sets something else. This is used to encode SEQUENCES in values that are
   *     declared to have non-constructed values, like OCTET STRING values.
   */
  @Suppress("UNCHECKED_CAST") // read() produces a single element of the expected type.
  fun withExplicitBox(
    tagClass: Int = DerHeader.TAG_CLASS_CONTEXT_SPECIFIC,
    tag: Long,
    forceConstructed: Boolean? = null,
  ): BasicDerAdapter {
    val codec =
      object : BasicDerAdapter.Codec {
        override fun decode(reader: DerReader): T = fromDer(reader)

        override fun encode(
          writer: DerWriter,
          value: T,
        ) {
          toDer(writer, value)
          if (forceConstructed != null) {
            writer.constructed = forceConstructed
          }
        }
      }

    return BasicDerAdapter(
      name = "EXPLICIT",
      tagClass = tagClass,
      tag = tag,
      codec = codec,
    )
  }

  /** Returns an adapter that returns a list of values of this type. */
  fun asSequenceOf(
    name: String = "SEQUENCE OF",
    tagClass: Int = DerHeader.TAG_CLASS_UNIVERSAL,
    tag: Long = 16L,
  ): BasicDerAdapter> {
    val codec =
      object : BasicDerAdapter.Codec> {
        override fun encode(
          writer: DerWriter,
          value: List,
        ) {
          for (v in value) {
            toDer(writer, v)
          }
        }

        override fun decode(reader: DerReader): List {
          val result = mutableListOf()
          while (reader.hasNext()) {
            result += fromDer(reader)
          }
          return result
        }
      }

    return BasicDerAdapter(name, tagClass, tag, codec)
  }

  /** Returns an adapter that returns a set of values of this type. */
  fun asSetOf(): BasicDerAdapter> {
    return asSequenceOf(
      name = "SET OF",
      tagClass = DerHeader.TAG_CLASS_UNIVERSAL,
      tag = 17L,
    )
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy