protected static function _decodeFromDER(Identifier $identifier, $data, &$offset) { $idx = $offset; $length = Length::expectFromDER($data, $idx); $str = substr($data, $idx, $length->length()); $idx += $length->length(); if (!preg_match(self::REGEX, $str, $match)) { throw new DecodeException("Invalid GeneralizedTime format."); } list(, $year, $month, $day, $hour, $minute, $second) = $match; if (isset($match[7])) { $frac = $match[7]; // DER restricts trailing zeroes in fractional seconds component if ($frac[strlen($frac) - 1] === '0') { throw new DecodeException("Fractional seconds must omit trailing zeroes."); } $frac = (int) $frac; } else { $frac = 0; } $time = $year . $month . $day . $hour . $minute . $second . "." . $frac . self::TZ_UTC; $dt = \DateTimeImmutable::createFromFormat("!YmdHis.uT", $time, self::_createTimeZone(self::TZ_UTC)); if (!$dt) { throw new DecodeException("Failed to decode GeneralizedTime: " . self::_getLastDateTimeImmutableErrorsStr()); } $offset = $idx; return new self($dt); }
/** * Constructor * * @param string $data DER encoded data * @throws DecodeException If data does not adhere to DER */ public function __construct($data) { $this->_identifier = Identifier::fromDER($data, $this->_contentOffset); Length::expectFromDER($data, $this->_contentOffset); $this->_der = $data; $this->_typeTag = intval($this->_identifier->tag()); }
protected static function _decodeFromDER(Identifier $identifier, $data, &$offset) { $idx = $offset; $type = new DERTaggedType($identifier, $data, $idx); $length = Length::expectFromDER($data, $idx); $offset = $idx + $length->length(); return $type; }
protected static function _decodeFromDER(Identifier $identifier, $data, &$offset) { $idx = $offset; $len = Length::expectFromDER($data, $idx)->length(); $subids = self::_decodeSubIDs(substr($data, $idx, $len)); $offset = $idx + $len; return new self(self::_implodeSubIDs(...$subids)); }
protected static function _decodeFromDER(Identifier $identifier, $data, &$offset) { $idx = $offset; if (!$identifier->isPrimitive()) { throw new DecodeException("Null value must be primitive."); } // null type has always zero length Length::expectFromDER($data, $idx, 0); $offset = $idx; return new self(); }
protected static function _decodeFromDER(Identifier $identifier, $data, &$offset) { $idx = $offset; Length::expectFromDER($data, $idx, 1); $byte = ord($data[$idx++]); if ($byte != 0) { if ($byte != 0xff) { throw new DecodeException("DER encoded boolean true must have all bits set to 1."); } } $offset = $idx; return new self($byte != 0); }
protected static function _decodeFromDER(Identifier $identifier, $data, &$offset) { $idx = $offset; $len = Length::expectFromDER($data, $idx)->length(); $subids = self::_decodeSubIDs(substr($data, $idx, $len)); $idx += $len; // decode first subidentifier according to spec section 8.19.4 if (isset($subids[0])) { list($x, $y) = gmp_div_qr($subids[0], "40"); array_splice($subids, 0, 1, array($x, $y)); } $offset = $idx; return new self(self::_implodeSubIDs(...$subids)); }
protected static function _decodeFromDER(Identifier $identifier, $data, &$offset) { $idx = $offset; $length = Length::expectFromDER($data, $idx); $str = substr($data, $idx, $length->length()); $idx += $length->length(); if (!preg_match(self::REGEX, $str, $match)) { throw new DecodeException("Invalid UTCTime format."); } list(, $year, $month, $day, $hour, $minute, $second) = $match; $time = $year . $month . $day . $hour . $minute . $second . self::TZ_UTC; $dt = \DateTimeImmutable::createFromFormat("!ymdHisT", $time, self::_createTimeZone(self::TZ_UTC)); if (!$dt) { throw new DecodeException("Failed to decode UTCTime: " . self::_getLastDateTimeImmutableErrorsStr()); } $offset = $idx; return new self($dt); }
/** * * @see \ASN1\Element::_decodeFromDER() * @return self */ protected static function _decodeFromDER(Identifier $identifier, $data, &$offset) { $idx = $offset; if (!$identifier->isPrimitive()) { throw new DecodeException("DER encoded string must be primitive."); } $length = Length::expectFromDER($data, $idx); $str = $length->length() ? substr($data, $idx, $length->length()) : ""; // substr should never return false, since length is // checked by Length::expectFromDER. assert('is_string($str)', "substr"); $offset = $idx + $length->length(); try { return new static($str); } catch (\InvalidArgumentException $e) { throw new DecodeException($e->getMessage(), null, $e); } }
/** * * @see \ASN1\Feature\Encodable::toDER() * @return string */ public function toDER() { $identifier = new Identifier($this->typeClass(), $this->isConstructed() ? Identifier::CONSTRUCTED : Identifier::PRIMITIVE, $this->_typeTag); $content = $this->_encodedContentDER(); $length = new Length(strlen($content)); return $identifier->toDER() . $length->toDER() . $content; }
protected static function _decodeFromDER(Identifier $identifier, $data, &$offset) { $idx = $offset; $length = Length::expectFromDER($data, $idx); // if length is zero, value is zero (spec 8.5.2) if (!$length->length()) { $obj = new self(self::NR3_ZERO); } else { $bytes = substr($data, $idx, $length->length()); $byte = ord($bytes[0]); if (0x80 & $byte) { // bit 8 = 1 $obj = self::_decodeBinaryEncoding($bytes); } else { if ($byte >> 6 == 0x0) { // bit 8 = 0, bit 7 = 0 $obj = self::_decodeDecimalEncoding($bytes); } else { // bit 8 = 0, bit 7 = 1 $obj = self::_decodeSpecialRealValue($bytes); } } } $offset = $idx + $length->length(); return $obj; }
/** * Explode DER structure to DER encoded components that it contains. * * @param string $data * @throws DecodeException * @return string[] */ public static function explodeDER($data) { $offset = 0; $identifier = Identifier::fromDER($data, $offset); if (!$identifier->isConstructed()) { throw new DecodeException("Element is not constructed."); } $length = Length::expectFromDER($data, $offset); $end = $offset + $length->length(); $parts = array(); while ($offset < $end) { // start of the element $idx = $offset; // skip identifier Identifier::fromDER($data, $offset); // decode element length $length = Length::expectFromDER($data, $offset); // extract der encoding of the element $parts[] = substr($data, $idx, $offset - $idx + $length->length()); // update offset over content $offset += $length->length(); } return $parts; }
protected static function _decodeFromDER(Identifier $identifier, $data, &$offset) { $idx = $offset; $length = Length::expectFromDER($data, $idx); $bytes = substr($data, $idx, $length->length()); $idx += $length->length(); $neg = ord($bytes[0]) & 0x80; // negative, apply inversion of two's complement if ($neg) { $len = strlen($bytes); for ($i = 0; $i < $len; $i++) { $bytes[$i] = ~$bytes[$i]; } } $num = gmp_init(bin2hex($bytes), 16); // negative, apply addition of two's complement // and produce negative result if ($neg) { $num = gmp_neg($num + 1); } $offset = $idx; // late static binding since enumerated extends integer type return new static(gmp_strval($num, 10)); }
/** * * @see \ASN1\Type\Tagged\ExplicitTagging::explicit() * @return UnspecifiedType */ public function explicit($expectedTag = null) { $idx = $this->_offset; Length::expectFromDER($this->_data, $idx); $element = Element::fromDER($this->_data, $idx); if (isset($expectedTag)) { $element->expectType($expectedTag); } return new UnspecifiedType($element); }
protected static function _decodeFromDER(Identifier $identifier, $data, &$offset) { $idx = $offset; $length = Length::expectFromDER($data, $idx); if ($length->length() < 1) { throw new DecodeException("Bit string length must be at least 1."); } $unused_bits = ord($data[$idx++]); if ($unused_bits > 7) { throw new DecodeException("Unused bits in a bit string must be less than 8."); } $str_len = $length->length() - 1; if ($str_len) { $str = substr($data, $idx, $str_len); if ($unused_bits) { $mask = (1 << $unused_bits) - 1; if (ord($str[strlen($str) - 1]) & $mask) { throw new DecodeException("DER encoded bit string must have zero padding."); } } } else { $str = ""; } $offset = $idx + $str_len; return new self($str, $unused_bits); }