// 最小 DER 解析与 RSA PKCS#1 v1.5 验签。
//
// 只实现验签需要的那一小部分 DER:SEQUENCE / INTEGER / BIT STRING。
// 模幂复用标准库 BigInt 的 pow(modulus=),填充与 DigestInfo 编码在这里自研。

///|
pub struct RsaPublicKey {
  modulus : @bigint.BigInt
  exponent : @bigint.BigInt
  /// 模数的字节长度,用于定长还原签名整数
  byte_len : Int
}

///|
/// 读取一个 DER TLV,返回 (tag, 内容起点, 内容长度, 下一个 TLV 起点)。
fn der_tlv(data : BytesView, offset : Int) -> (Int, Int, Int, Int)? {
  let len = data.length()
  if offset < 0 || offset + 2 > len {
    return None
  }
  let tag = data[offset].to_int()
  let first = data[offset + 1].to_uint()
  let content_len = if first < 0x80U {
    first.to_int()
  } else {
    let count = (first & 0x7FU).to_int()
    if count == 0 || count > 4 || offset + 2 + count > len {
      return None
    }
    let mut value = 0
    for i in 0.. len {
    return None
  }
  Some((tag, content_start, content_len, content_start + content_len))
}

///|
/// 从 RSAPublicKey 的 SEQUENCE 内容起点读取两个 INTEGER。
fn rsa_from_integers(data : BytesView, seq_start : Int) -> RsaPublicKey? {
  let n = der_tlv(data, seq_start)
  match n {
    None => None
    Some((tag_n, start_n, len_n, next_n)) => {
      if tag_n != 0x02 || len_n == 0 {
        return None
      }
      match der_tlv(data, next_n) {
        None => None
        Some((tag_e, start_e, len_e, _)) => {
          if tag_e != 0x02 || len_e == 0 {
            return None
          }
          let modulus = @bigint.BigInt::from_octets(
            data[start_n:start_n + len_n],
          )
          let exponent = @bigint.BigInt::from_octets(
            data[start_e:start_e + len_e],
          )
          if modulus.is_zero() || exponent.is_zero() {
            return None
          }
          Some({ modulus, exponent, byte_len: (modulus.bit_length() + 7) / 8, })
        }
      }
    }
  }
}

///|
/// 解析 DKIM `p=` 里的公钥:优先按 SubjectPublicKeyInfo,失败再按裸 RSAPublicKey。
///
/// 两种形式在真实邮件里都能遇到,因此不能只认一种。
pub fn rsa_public_key_from_der(der : Bytes) -> RsaPublicKey? {
  let view : BytesView = der
  match der_tlv(view, 0) {
    None => None
    Some((tag, start, _len, _next)) => {
      if tag != 0x30 {
        return None
      }
      match der_tlv(view, start) {
        None => None
        Some((child_tag, child_start, _child_len, child_next)) => {
          // 第一个子节点是 INTEGER:裸 RSAPublicKey
          if child_tag == 0x02 {
            return rsa_from_integers(view, start)
          }
          if child_tag != 0x30 {
            return None
          }
          // SPKI:AlgorithmIdentifier 之后必须是 BIT STRING
          match der_tlv(view, child_next) {
            None => None
            Some((bit_tag, bit_start, bit_len, _)) => {
              if bit_tag != 0x03 || bit_len < 2 || view[bit_start].to_int() != 0 {
                return None
              }
              match der_tlv(view, bit_start + 1) {
                None => None
                Some((inner_tag, inner_start, _inner_len, _)) => {
                  if inner_tag != 0x30 {
                    return None
                  }
                  rsa_from_integers(view, inner_start)
                }
              }
            }
          }
        }
      }
    }
  }
}

///|
/// SHA-256 的 DigestInfo 前缀(RFC 8017 附录 A.2.4)。
let sha256_digest_info : Array[Byte] = [
  b'\x30', b'\x31', b'\x30', b'\x0d', b'\x06', b'\x09', b'\x60', b'\x86', b'\x48',
  b'\x01', b'\x65', b'\x03', b'\x04', b'\x02', b'\x01', b'\x05', b'\x00', b'\x04',
  b'\x20',
]

///|
/// RSA PKCS#1 v1.5 + SHA-256 验签。
pub fn rsa_verify_sha256(
  key : RsaPublicKey,
  message : BytesView,
  signature : BytesView,
) -> Bool {
  let k = key.byte_len
  if k < 64 || signature.length() != k {
    return false
  }
  let s = @bigint.BigInt::from_octets(signature)
  if s.compare(key.modulus) >= 0 {
    return false
  }
  let m = s.pow(key.exponent, modulus=key.modulus)
  let em = m.to_octets(length=k)
  if em.length() != k {
    return false
  }
  // EM = 0x00 || 0x01 || PS(0xFF...) || 0x00 || T
  if em[0].to_int() != 0x00 || em[1].to_int() != 0x01 {
    return false
  }
  let mut i = 2
  while i < k && em[i].to_int() == 0xFF {
    i = i + 1
  }
  if i - 2 < 8 || i >= k || em[i].to_int() != 0x00 {
    return false
  }
  i = i + 1
  let digest = sha256(message)
  let expected_len = sha256_digest_info.length() + digest.length()
  if k - i != expected_len {
    return false
  }
  for j in 0.. Bool {
  let der = @base64.decode_lossy(public_key_b64, ignore_whitespace=true)
  let signature = @base64.decode_lossy(signature_b64, ignore_whitespace=true)
  match rsa_public_key_from_der(der) {
    Some(key) => rsa_verify_sha256(key, message, signature)
    None => false
  }
}