GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — php72 ( 0f804f...6c57e4 )
by Joni
03:03
created
lib/X509/Certificate/Extension/Target/Targets.php 1 patch
Indentation   +121 added lines, -121 removed lines patch added patch discarded remove patch
@@ -14,135 +14,135 @@
 block discarded – undo
14 14
  */
15 15
 class Targets implements \Countable, \IteratorAggregate
16 16
 {
17
-    /**
18
-     * Target elements.
19
-     *
20
-     * @var Target[]
21
-     */
22
-    protected $_targets;
17
+	/**
18
+	 * Target elements.
19
+	 *
20
+	 * @var Target[]
21
+	 */
22
+	protected $_targets;
23 23
 
24
-    /**
25
-     * Constructor.
26
-     *
27
-     * @param Target ...$targets
28
-     */
29
-    public function __construct(Target ...$targets)
30
-    {
31
-        $this->_targets = $targets;
32
-    }
24
+	/**
25
+	 * Constructor.
26
+	 *
27
+	 * @param Target ...$targets
28
+	 */
29
+	public function __construct(Target ...$targets)
30
+	{
31
+		$this->_targets = $targets;
32
+	}
33 33
 
34
-    /**
35
-     * Initialize from ASN.1.
36
-     *
37
-     * @param Sequence $seq
38
-     *
39
-     * @return self
40
-     */
41
-    public static function fromASN1(Sequence $seq): self
42
-    {
43
-        $targets = array_map(
44
-            function (UnspecifiedType $el) {
45
-                return Target::fromASN1($el->asTagged());
46
-            }, $seq->elements());
47
-        return new self(...$targets);
48
-    }
34
+	/**
35
+	 * Initialize from ASN.1.
36
+	 *
37
+	 * @param Sequence $seq
38
+	 *
39
+	 * @return self
40
+	 */
41
+	public static function fromASN1(Sequence $seq): self
42
+	{
43
+		$targets = array_map(
44
+			function (UnspecifiedType $el) {
45
+				return Target::fromASN1($el->asTagged());
46
+			}, $seq->elements());
47
+		return new self(...$targets);
48
+	}
49 49
 
50
-    /**
51
-     * Get all targets.
52
-     *
53
-     * @return Target[]
54
-     */
55
-    public function all(): array
56
-    {
57
-        return $this->_targets;
58
-    }
50
+	/**
51
+	 * Get all targets.
52
+	 *
53
+	 * @return Target[]
54
+	 */
55
+	public function all(): array
56
+	{
57
+		return $this->_targets;
58
+	}
59 59
 
60
-    /**
61
-     * Get all name targets.
62
-     *
63
-     * @return Target[]
64
-     */
65
-    public function nameTargets(): array
66
-    {
67
-        return $this->_allOfType(Target::TYPE_NAME);
68
-    }
60
+	/**
61
+	 * Get all name targets.
62
+	 *
63
+	 * @return Target[]
64
+	 */
65
+	public function nameTargets(): array
66
+	{
67
+		return $this->_allOfType(Target::TYPE_NAME);
68
+	}
69 69
 
70
-    /**
71
-     * Get all group targets.
72
-     *
73
-     * @return Target[]
74
-     */
75
-    public function groupTargets(): array
76
-    {
77
-        return $this->_allOfType(Target::TYPE_GROUP);
78
-    }
70
+	/**
71
+	 * Get all group targets.
72
+	 *
73
+	 * @return Target[]
74
+	 */
75
+	public function groupTargets(): array
76
+	{
77
+		return $this->_allOfType(Target::TYPE_GROUP);
78
+	}
79 79
 
80
-    /**
81
-     * Check whether given target is present.
82
-     *
83
-     * @param Target $target
84
-     *
85
-     * @return bool
86
-     */
87
-    public function hasTarget(Target $target): bool
88
-    {
89
-        foreach ($this->_allOfType($target->type()) as $t) {
90
-            if ($target->equals($t)) {
91
-                return true;
92
-            }
93
-        }
94
-        return false;
95
-    }
80
+	/**
81
+	 * Check whether given target is present.
82
+	 *
83
+	 * @param Target $target
84
+	 *
85
+	 * @return bool
86
+	 */
87
+	public function hasTarget(Target $target): bool
88
+	{
89
+		foreach ($this->_allOfType($target->type()) as $t) {
90
+			if ($target->equals($t)) {
91
+				return true;
92
+			}
93
+		}
94
+		return false;
95
+	}
96 96
 
97
-    /**
98
-     * Generate ASN.1 structure.
99
-     *
100
-     * @return Sequence
101
-     */
102
-    public function toASN1(): Sequence
103
-    {
104
-        $elements = array_map(
105
-            function (Target $target) {
106
-                return $target->toASN1();
107
-            }, $this->_targets);
108
-        return new Sequence(...$elements);
109
-    }
97
+	/**
98
+	 * Generate ASN.1 structure.
99
+	 *
100
+	 * @return Sequence
101
+	 */
102
+	public function toASN1(): Sequence
103
+	{
104
+		$elements = array_map(
105
+			function (Target $target) {
106
+				return $target->toASN1();
107
+			}, $this->_targets);
108
+		return new Sequence(...$elements);
109
+	}
110 110
 
111
-    /**
112
-     * @see \Countable::count()
113
-     *
114
-     * @return int
115
-     */
116
-    public function count(): int
117
-    {
118
-        return count($this->_targets);
119
-    }
111
+	/**
112
+	 * @see \Countable::count()
113
+	 *
114
+	 * @return int
115
+	 */
116
+	public function count(): int
117
+	{
118
+		return count($this->_targets);
119
+	}
120 120
 
121
-    /**
122
-     * Get iterator for targets.
123
-     *
124
-     * @see \IteratorAggregate::getIterator()
125
-     *
126
-     * @return \ArrayIterator
127
-     */
128
-    public function getIterator(): \ArrayIterator
129
-    {
130
-        return new \ArrayIterator($this->_targets);
131
-    }
121
+	/**
122
+	 * Get iterator for targets.
123
+	 *
124
+	 * @see \IteratorAggregate::getIterator()
125
+	 *
126
+	 * @return \ArrayIterator
127
+	 */
128
+	public function getIterator(): \ArrayIterator
129
+	{
130
+		return new \ArrayIterator($this->_targets);
131
+	}
132 132
 
133
-    /**
134
-     * Get all targets of given type.
135
-     *
136
-     * @param int $type
137
-     *
138
-     * @return Target[]
139
-     */
140
-    protected function _allOfType(int $type): array
141
-    {
142
-        return array_values(
143
-            array_filter($this->_targets,
144
-                function (Target $target) use ($type) {
145
-                    return $target->type() == $type;
146
-                }));
147
-    }
133
+	/**
134
+	 * Get all targets of given type.
135
+	 *
136
+	 * @param int $type
137
+	 *
138
+	 * @return Target[]
139
+	 */
140
+	protected function _allOfType(int $type): array
141
+	{
142
+		return array_values(
143
+			array_filter($this->_targets,
144
+				function (Target $target) use ($type) {
145
+					return $target->type() == $type;
146
+				}));
147
+	}
148 148
 }
Please login to merge, or discard this patch.
lib/X509/Certificate/Extension/Target/Target.php 1 patch
Indentation   +81 added lines, -81 removed lines patch added patch discarded remove patch
@@ -14,92 +14,92 @@
 block discarded – undo
14 14
  */
15 15
 abstract class Target
16 16
 {
17
-    const TYPE_NAME = 0;
18
-    const TYPE_GROUP = 1;
19
-    const TYPE_CERT = 2;
17
+	const TYPE_NAME = 0;
18
+	const TYPE_GROUP = 1;
19
+	const TYPE_CERT = 2;
20 20
 
21
-    /**
22
-     * Type tag.
23
-     *
24
-     * @var int
25
-     */
26
-    protected $_type;
21
+	/**
22
+	 * Type tag.
23
+	 *
24
+	 * @var int
25
+	 */
26
+	protected $_type;
27 27
 
28
-    /**
29
-     * Generate ASN.1 element.
30
-     *
31
-     * @return Element
32
-     */
33
-    abstract public function toASN1(): Element;
28
+	/**
29
+	 * Generate ASN.1 element.
30
+	 *
31
+	 * @return Element
32
+	 */
33
+	abstract public function toASN1(): Element;
34 34
 
35
-    /**
36
-     * Get string value of the target.
37
-     *
38
-     * @return string
39
-     */
40
-    abstract public function string(): string;
35
+	/**
36
+	 * Get string value of the target.
37
+	 *
38
+	 * @return string
39
+	 */
40
+	abstract public function string(): string;
41 41
 
42
-    /**
43
-     * Initialize concrete object from the chosen ASN.1 element.
44
-     *
45
-     * @param TaggedType $el
46
-     *
47
-     * @return self
48
-     */
49
-    public static function fromChosenASN1(TaggedType $el): Target
50
-    {
51
-        throw new \BadMethodCallException(
52
-            __FUNCTION__ . ' must be implemented in the derived class.');
53
-    }
42
+	/**
43
+	 * Initialize concrete object from the chosen ASN.1 element.
44
+	 *
45
+	 * @param TaggedType $el
46
+	 *
47
+	 * @return self
48
+	 */
49
+	public static function fromChosenASN1(TaggedType $el): Target
50
+	{
51
+		throw new \BadMethodCallException(
52
+			__FUNCTION__ . ' must be implemented in the derived class.');
53
+	}
54 54
 
55
-    /**
56
-     * Parse from ASN.1.
57
-     *
58
-     * @param TaggedType $el
59
-     *
60
-     * @throws \UnexpectedValueException
61
-     *
62
-     * @return self
63
-     */
64
-    public static function fromASN1(TaggedType $el): self
65
-    {
66
-        switch ($el->tag()) {
67
-            case self::TYPE_NAME:
68
-                return TargetName::fromChosenASN1($el->asExplicit()->asTagged());
69
-            case self::TYPE_GROUP:
70
-                return TargetGroup::fromChosenASN1($el->asExplicit()->asTagged());
71
-            case self::TYPE_CERT:
72
-                throw new \RuntimeException('targetCert not supported.');
73
-        }
74
-        throw new \UnexpectedValueException(
75
-            'Target type ' . $el->tag() . ' not supported.');
76
-    }
55
+	/**
56
+	 * Parse from ASN.1.
57
+	 *
58
+	 * @param TaggedType $el
59
+	 *
60
+	 * @throws \UnexpectedValueException
61
+	 *
62
+	 * @return self
63
+	 */
64
+	public static function fromASN1(TaggedType $el): self
65
+	{
66
+		switch ($el->tag()) {
67
+			case self::TYPE_NAME:
68
+				return TargetName::fromChosenASN1($el->asExplicit()->asTagged());
69
+			case self::TYPE_GROUP:
70
+				return TargetGroup::fromChosenASN1($el->asExplicit()->asTagged());
71
+			case self::TYPE_CERT:
72
+				throw new \RuntimeException('targetCert not supported.');
73
+		}
74
+		throw new \UnexpectedValueException(
75
+			'Target type ' . $el->tag() . ' not supported.');
76
+	}
77 77
 
78
-    /**
79
-     * Get type tag.
80
-     *
81
-     * @return int
82
-     */
83
-    public function type(): int
84
-    {
85
-        return $this->_type;
86
-    }
78
+	/**
79
+	 * Get type tag.
80
+	 *
81
+	 * @return int
82
+	 */
83
+	public function type(): int
84
+	{
85
+		return $this->_type;
86
+	}
87 87
 
88
-    /**
89
-     * Check whether target is equal to another.
90
-     *
91
-     * @param Target $other
92
-     *
93
-     * @return bool
94
-     */
95
-    public function equals(Target $other): bool
96
-    {
97
-        if ($this->_type !== $other->_type) {
98
-            return false;
99
-        }
100
-        if ($this->toASN1()->toDER() !== $other->toASN1()->toDER()) {
101
-            return false;
102
-        }
103
-        return true;
104
-    }
88
+	/**
89
+	 * Check whether target is equal to another.
90
+	 *
91
+	 * @param Target $other
92
+	 *
93
+	 * @return bool
94
+	 */
95
+	public function equals(Target $other): bool
96
+	{
97
+		if ($this->_type !== $other->_type) {
98
+			return false;
99
+		}
100
+		if ($this->toASN1()->toDER() !== $other->toASN1()->toDER()) {
101
+			return false;
102
+		}
103
+		return true;
104
+	}
105 105
 }
Please login to merge, or discard this patch.
lib/X509/Certificate/Extension/TargetInformationExtension.php 1 patch
Indentation   +119 added lines, -119 removed lines patch added patch discarded remove patch
@@ -21,134 +21,134 @@
 block discarded – undo
21 21
  */
22 22
 class TargetInformationExtension extends Extension implements \Countable, \IteratorAggregate
23 23
 {
24
-    /**
25
-     * Targets elements.
26
-     *
27
-     * @var Targets[]
28
-     */
29
-    protected $_targets;
24
+	/**
25
+	 * Targets elements.
26
+	 *
27
+	 * @var Targets[]
28
+	 */
29
+	protected $_targets;
30 30
 
31
-    /**
32
-     * Targets[] merged to single Targets.
33
-     *
34
-     * @var null|Targets
35
-     */
36
-    private $_merged;
31
+	/**
32
+	 * Targets[] merged to single Targets.
33
+	 *
34
+	 * @var null|Targets
35
+	 */
36
+	private $_merged;
37 37
 
38
-    /**
39
-     * Constructor.
40
-     *
41
-     * @param bool    $critical
42
-     * @param Targets ...$targets
43
-     */
44
-    public function __construct(bool $critical, Targets ...$targets)
45
-    {
46
-        parent::__construct(self::OID_TARGET_INFORMATION, $critical);
47
-        $this->_targets = $targets;
48
-    }
38
+	/**
39
+	 * Constructor.
40
+	 *
41
+	 * @param bool    $critical
42
+	 * @param Targets ...$targets
43
+	 */
44
+	public function __construct(bool $critical, Targets ...$targets)
45
+	{
46
+		parent::__construct(self::OID_TARGET_INFORMATION, $critical);
47
+		$this->_targets = $targets;
48
+	}
49 49
 
50
-    /**
51
-     * Reset internal state on clone.
52
-     */
53
-    public function __clone()
54
-    {
55
-        $this->_merged = null;
56
-    }
50
+	/**
51
+	 * Reset internal state on clone.
52
+	 */
53
+	public function __clone()
54
+	{
55
+		$this->_merged = null;
56
+	}
57 57
 
58
-    /**
59
-     * Initialize from one or more Target objects.
60
-     *
61
-     * Extension criticality shall be set to true as specified by RFC 5755.
62
-     *
63
-     * @param Target ...$target
64
-     *
65
-     * @return TargetInformationExtension
66
-     */
67
-    public static function fromTargets(Target ...$target): self
68
-    {
69
-        return new self(true, new Targets(...$target));
70
-    }
58
+	/**
59
+	 * Initialize from one or more Target objects.
60
+	 *
61
+	 * Extension criticality shall be set to true as specified by RFC 5755.
62
+	 *
63
+	 * @param Target ...$target
64
+	 *
65
+	 * @return TargetInformationExtension
66
+	 */
67
+	public static function fromTargets(Target ...$target): self
68
+	{
69
+		return new self(true, new Targets(...$target));
70
+	}
71 71
 
72
-    /**
73
-     * Get all targets.
74
-     *
75
-     * @return Targets
76
-     */
77
-    public function targets(): Targets
78
-    {
79
-        if (!isset($this->_merged)) {
80
-            $a = [];
81
-            foreach ($this->_targets as $targets) {
82
-                $a = array_merge($a, $targets->all());
83
-            }
84
-            $this->_merged = new Targets(...$a);
85
-        }
86
-        return $this->_merged;
87
-    }
72
+	/**
73
+	 * Get all targets.
74
+	 *
75
+	 * @return Targets
76
+	 */
77
+	public function targets(): Targets
78
+	{
79
+		if (!isset($this->_merged)) {
80
+			$a = [];
81
+			foreach ($this->_targets as $targets) {
82
+				$a = array_merge($a, $targets->all());
83
+			}
84
+			$this->_merged = new Targets(...$a);
85
+		}
86
+		return $this->_merged;
87
+	}
88 88
 
89
-    /**
90
-     * Get all name targets.
91
-     *
92
-     * @return Target[]
93
-     */
94
-    public function names(): array
95
-    {
96
-        return $this->targets()->nameTargets();
97
-    }
89
+	/**
90
+	 * Get all name targets.
91
+	 *
92
+	 * @return Target[]
93
+	 */
94
+	public function names(): array
95
+	{
96
+		return $this->targets()->nameTargets();
97
+	}
98 98
 
99
-    /**
100
-     * Get all group targets.
101
-     *
102
-     * @return Target[]
103
-     */
104
-    public function groups(): array
105
-    {
106
-        return $this->targets()->groupTargets();
107
-    }
99
+	/**
100
+	 * Get all group targets.
101
+	 *
102
+	 * @return Target[]
103
+	 */
104
+	public function groups(): array
105
+	{
106
+		return $this->targets()->groupTargets();
107
+	}
108 108
 
109
-    /**
110
-     * @see \Countable::count()
111
-     *
112
-     * @return int
113
-     */
114
-    public function count(): int
115
-    {
116
-        return count($this->targets());
117
-    }
109
+	/**
110
+	 * @see \Countable::count()
111
+	 *
112
+	 * @return int
113
+	 */
114
+	public function count(): int
115
+	{
116
+		return count($this->targets());
117
+	}
118 118
 
119
-    /**
120
-     * Get iterator for targets.
121
-     *
122
-     * @see \IteratorAggregate::getIterator()
123
-     *
124
-     * @return \ArrayIterator
125
-     */
126
-    public function getIterator(): \ArrayIterator
127
-    {
128
-        return new \ArrayIterator($this->targets()->all());
129
-    }
119
+	/**
120
+	 * Get iterator for targets.
121
+	 *
122
+	 * @see \IteratorAggregate::getIterator()
123
+	 *
124
+	 * @return \ArrayIterator
125
+	 */
126
+	public function getIterator(): \ArrayIterator
127
+	{
128
+		return new \ArrayIterator($this->targets()->all());
129
+	}
130 130
 
131
-    /**
132
-     * {@inheritdoc}
133
-     */
134
-    protected static function _fromDER(string $data, bool $critical): Extension
135
-    {
136
-        $targets = array_map(
137
-            function (UnspecifiedType $el) {
138
-                return Targets::fromASN1($el->asSequence());
139
-            }, UnspecifiedType::fromDER($data)->asSequence()->elements());
140
-        return new self($critical, ...$targets);
141
-    }
131
+	/**
132
+	 * {@inheritdoc}
133
+	 */
134
+	protected static function _fromDER(string $data, bool $critical): Extension
135
+	{
136
+		$targets = array_map(
137
+			function (UnspecifiedType $el) {
138
+				return Targets::fromASN1($el->asSequence());
139
+			}, UnspecifiedType::fromDER($data)->asSequence()->elements());
140
+		return new self($critical, ...$targets);
141
+	}
142 142
 
143
-    /**
144
-     * {@inheritdoc}
145
-     */
146
-    protected function _valueASN1(): Element
147
-    {
148
-        $elements = array_map(
149
-            function (Targets $targets) {
150
-                return $targets->toASN1();
151
-            }, $this->_targets);
152
-        return new Sequence(...$elements);
153
-    }
143
+	/**
144
+	 * {@inheritdoc}
145
+	 */
146
+	protected function _valueASN1(): Element
147
+	{
148
+		$elements = array_map(
149
+			function (Targets $targets) {
150
+				return $targets->toASN1();
151
+			}, $this->_targets);
152
+		return new Sequence(...$elements);
153
+	}
154 154
 }
Please login to merge, or discard this patch.
lib/X509/Certificate/Extension/IssuerAlternativeNameExtension.php 1 patch
Indentation   +42 added lines, -42 removed lines patch added patch discarded remove patch
@@ -15,50 +15,50 @@
 block discarded – undo
15 15
  */
16 16
 class IssuerAlternativeNameExtension extends Extension
17 17
 {
18
-    /**
19
-     * Names.
20
-     *
21
-     * @var GeneralNames
22
-     */
23
-    protected $_names;
18
+	/**
19
+	 * Names.
20
+	 *
21
+	 * @var GeneralNames
22
+	 */
23
+	protected $_names;
24 24
 
25
-    /**
26
-     * Constructor.
27
-     *
28
-     * @param bool         $critical
29
-     * @param GeneralNames $names
30
-     */
31
-    public function __construct(bool $critical, GeneralNames $names)
32
-    {
33
-        parent::__construct(self::OID_ISSUER_ALT_NAME, $critical);
34
-        $this->_names = $names;
35
-    }
25
+	/**
26
+	 * Constructor.
27
+	 *
28
+	 * @param bool         $critical
29
+	 * @param GeneralNames $names
30
+	 */
31
+	public function __construct(bool $critical, GeneralNames $names)
32
+	{
33
+		parent::__construct(self::OID_ISSUER_ALT_NAME, $critical);
34
+		$this->_names = $names;
35
+	}
36 36
 
37
-    /**
38
-     * Get names.
39
-     *
40
-     * @return GeneralNames
41
-     */
42
-    public function names(): GeneralNames
43
-    {
44
-        return $this->_names;
45
-    }
37
+	/**
38
+	 * Get names.
39
+	 *
40
+	 * @return GeneralNames
41
+	 */
42
+	public function names(): GeneralNames
43
+	{
44
+		return $this->_names;
45
+	}
46 46
 
47
-    /**
48
-     * {@inheritdoc}
49
-     */
50
-    protected static function _fromDER(string $data, bool $critical): Extension
51
-    {
52
-        return new self($critical,
53
-            GeneralNames::fromASN1(
54
-                UnspecifiedType::fromDER($data)->asSequence()));
55
-    }
47
+	/**
48
+	 * {@inheritdoc}
49
+	 */
50
+	protected static function _fromDER(string $data, bool $critical): Extension
51
+	{
52
+		return new self($critical,
53
+			GeneralNames::fromASN1(
54
+				UnspecifiedType::fromDER($data)->asSequence()));
55
+	}
56 56
 
57
-    /**
58
-     * {@inheritdoc}
59
-     */
60
-    protected function _valueASN1(): Element
61
-    {
62
-        return $this->_names->toASN1();
63
-    }
57
+	/**
58
+	 * {@inheritdoc}
59
+	 */
60
+	protected function _valueASN1(): Element
61
+	{
62
+		return $this->_names->toASN1();
63
+	}
64 64
 }
Please login to merge, or discard this patch.
lib/X509/Certificate/Extension/AAControlsExtension.php 1 patch
Indentation   +203 added lines, -203 removed lines patch added patch discarded remove patch
@@ -19,207 +19,207 @@
 block discarded – undo
19 19
  */
20 20
 class AAControlsExtension extends Extension
21 21
 {
22
-    /**
23
-     * Path length contraint.
24
-     *
25
-     * @var null|int
26
-     */
27
-    protected $_pathLenConstraint;
28
-
29
-    /**
30
-     * Permitted attributes.
31
-     *
32
-     * Array of OID's.
33
-     *
34
-     * @var null|string[]
35
-     */
36
-    protected $_permittedAttrs;
37
-
38
-    /**
39
-     * Excluded attributes.
40
-     *
41
-     * Array of OID's.
42
-     *
43
-     * @var null|string[]
44
-     */
45
-    protected $_excludedAttrs;
46
-
47
-    /**
48
-     * Whether to permit unspecified attributes.
49
-     *
50
-     * @var bool
51
-     */
52
-    protected $_permitUnSpecified;
53
-
54
-    /**
55
-     * Constructor.
56
-     *
57
-     * @param bool          $critical
58
-     * @param null|int      $path_len
59
-     * @param null|string[] $permitted
60
-     * @param null|string[] $excluded
61
-     * @param bool          $permit_unspecified
62
-     */
63
-    public function __construct(bool $critical, ?int $path_len = null,
64
-        ?array $permitted = null, ?array $excluded = null, bool $permit_unspecified = true)
65
-    {
66
-        parent::__construct(self::OID_AA_CONTROLS, $critical);
67
-        $this->_pathLenConstraint = $path_len;
68
-        $this->_permittedAttrs = $permitted;
69
-        $this->_excludedAttrs = $excluded;
70
-        $this->_permitUnSpecified = $permit_unspecified;
71
-    }
72
-
73
-    /**
74
-     * Check whether path length constraint is present.
75
-     *
76
-     * @return bool
77
-     */
78
-    public function hasPathLen(): bool
79
-    {
80
-        return isset($this->_pathLenConstraint);
81
-    }
82
-
83
-    /**
84
-     * Get path length constraint.
85
-     *
86
-     * @throws \LogicException If not set
87
-     *
88
-     * @return int
89
-     */
90
-    public function pathLen(): int
91
-    {
92
-        if (!$this->hasPathLen()) {
93
-            throw new \LogicException('pathLen not set.');
94
-        }
95
-        return $this->_pathLenConstraint;
96
-    }
97
-
98
-    /**
99
-     * Check whether permitted attributes are present.
100
-     *
101
-     * @return bool
102
-     */
103
-    public function hasPermittedAttrs(): bool
104
-    {
105
-        return isset($this->_permittedAttrs);
106
-    }
107
-
108
-    /**
109
-     * Get OID's of permitted attributes.
110
-     *
111
-     * @throws \LogicException If not set
112
-     *
113
-     * @return string[]
114
-     */
115
-    public function permittedAttrs(): array
116
-    {
117
-        if (!$this->hasPermittedAttrs()) {
118
-            throw new \LogicException('permittedAttrs not set.');
119
-        }
120
-        return $this->_permittedAttrs;
121
-    }
122
-
123
-    /**
124
-     * Check whether excluded attributes are present.
125
-     *
126
-     * @return bool
127
-     */
128
-    public function hasExcludedAttrs(): bool
129
-    {
130
-        return isset($this->_excludedAttrs);
131
-    }
132
-
133
-    /**
134
-     * Get OID's of excluded attributes.
135
-     *
136
-     * @throws \LogicException If not set
137
-     *
138
-     * @return string[]
139
-     */
140
-    public function excludedAttrs(): array
141
-    {
142
-        if (!$this->hasExcludedAttrs()) {
143
-            throw new \LogicException('excludedAttrs not set.');
144
-        }
145
-        return $this->_excludedAttrs;
146
-    }
147
-
148
-    /**
149
-     * Whether to permit attributes that are not explicitly specified in
150
-     * neither permitted nor excluded list.
151
-     *
152
-     * @return bool
153
-     */
154
-    public function permitUnspecified(): bool
155
-    {
156
-        return $this->_permitUnSpecified;
157
-    }
158
-
159
-    /**
160
-     * {@inheritdoc}
161
-     */
162
-    protected static function _fromDER(string $data, bool $critical): Extension
163
-    {
164
-        $seq = UnspecifiedType::fromDER($data)->asSequence();
165
-        $path_len = null;
166
-        $permitted = null;
167
-        $excluded = null;
168
-        $permit_unspecified = true;
169
-        $idx = 0;
170
-        if ($seq->has($idx, Element::TYPE_INTEGER)) {
171
-            $path_len = $seq->at($idx++)->asInteger()->intNumber();
172
-        }
173
-        if ($seq->hasTagged(0)) {
174
-            $attr_seq = $seq->getTagged(0)->asImplicit(Element::TYPE_SEQUENCE)
175
-                ->asSequence();
176
-            $permitted = array_map(
177
-                function (UnspecifiedType $el) {
178
-                    return $el->asObjectIdentifier()->oid();
179
-                }, $attr_seq->elements());
180
-            ++$idx;
181
-        }
182
-        if ($seq->hasTagged(1)) {
183
-            $attr_seq = $seq->getTagged(1)->asImplicit(Element::TYPE_SEQUENCE)
184
-                ->asSequence();
185
-            $excluded = array_map(
186
-                function (UnspecifiedType $el) {
187
-                    return $el->asObjectIdentifier()->oid();
188
-                }, $attr_seq->elements());
189
-            ++$idx;
190
-        }
191
-        if ($seq->has($idx, Element::TYPE_BOOLEAN)) {
192
-            $permit_unspecified = $seq->at($idx++)->asBoolean()->value();
193
-        }
194
-        return new self($critical, $path_len, $permitted, $excluded, $permit_unspecified);
195
-    }
196
-
197
-    /**
198
-     * {@inheritdoc}
199
-     */
200
-    protected function _valueASN1(): Element
201
-    {
202
-        $elements = [];
203
-        if (isset($this->_pathLenConstraint)) {
204
-            $elements[] = new Integer($this->_pathLenConstraint);
205
-        }
206
-        if (isset($this->_permittedAttrs)) {
207
-            $oids = array_map(
208
-                function ($oid) {
209
-                    return new ObjectIdentifier($oid);
210
-                }, $this->_permittedAttrs);
211
-            $elements[] = new ImplicitlyTaggedType(0, new Sequence(...$oids));
212
-        }
213
-        if (isset($this->_excludedAttrs)) {
214
-            $oids = array_map(
215
-                function ($oid) {
216
-                    return new ObjectIdentifier($oid);
217
-                }, $this->_excludedAttrs);
218
-            $elements[] = new ImplicitlyTaggedType(1, new Sequence(...$oids));
219
-        }
220
-        if (true !== $this->_permitUnSpecified) {
221
-            $elements[] = new Boolean(false);
222
-        }
223
-        return new Sequence(...$elements);
224
-    }
22
+	/**
23
+	 * Path length contraint.
24
+	 *
25
+	 * @var null|int
26
+	 */
27
+	protected $_pathLenConstraint;
28
+
29
+	/**
30
+	 * Permitted attributes.
31
+	 *
32
+	 * Array of OID's.
33
+	 *
34
+	 * @var null|string[]
35
+	 */
36
+	protected $_permittedAttrs;
37
+
38
+	/**
39
+	 * Excluded attributes.
40
+	 *
41
+	 * Array of OID's.
42
+	 *
43
+	 * @var null|string[]
44
+	 */
45
+	protected $_excludedAttrs;
46
+
47
+	/**
48
+	 * Whether to permit unspecified attributes.
49
+	 *
50
+	 * @var bool
51
+	 */
52
+	protected $_permitUnSpecified;
53
+
54
+	/**
55
+	 * Constructor.
56
+	 *
57
+	 * @param bool          $critical
58
+	 * @param null|int      $path_len
59
+	 * @param null|string[] $permitted
60
+	 * @param null|string[] $excluded
61
+	 * @param bool          $permit_unspecified
62
+	 */
63
+	public function __construct(bool $critical, ?int $path_len = null,
64
+		?array $permitted = null, ?array $excluded = null, bool $permit_unspecified = true)
65
+	{
66
+		parent::__construct(self::OID_AA_CONTROLS, $critical);
67
+		$this->_pathLenConstraint = $path_len;
68
+		$this->_permittedAttrs = $permitted;
69
+		$this->_excludedAttrs = $excluded;
70
+		$this->_permitUnSpecified = $permit_unspecified;
71
+	}
72
+
73
+	/**
74
+	 * Check whether path length constraint is present.
75
+	 *
76
+	 * @return bool
77
+	 */
78
+	public function hasPathLen(): bool
79
+	{
80
+		return isset($this->_pathLenConstraint);
81
+	}
82
+
83
+	/**
84
+	 * Get path length constraint.
85
+	 *
86
+	 * @throws \LogicException If not set
87
+	 *
88
+	 * @return int
89
+	 */
90
+	public function pathLen(): int
91
+	{
92
+		if (!$this->hasPathLen()) {
93
+			throw new \LogicException('pathLen not set.');
94
+		}
95
+		return $this->_pathLenConstraint;
96
+	}
97
+
98
+	/**
99
+	 * Check whether permitted attributes are present.
100
+	 *
101
+	 * @return bool
102
+	 */
103
+	public function hasPermittedAttrs(): bool
104
+	{
105
+		return isset($this->_permittedAttrs);
106
+	}
107
+
108
+	/**
109
+	 * Get OID's of permitted attributes.
110
+	 *
111
+	 * @throws \LogicException If not set
112
+	 *
113
+	 * @return string[]
114
+	 */
115
+	public function permittedAttrs(): array
116
+	{
117
+		if (!$this->hasPermittedAttrs()) {
118
+			throw new \LogicException('permittedAttrs not set.');
119
+		}
120
+		return $this->_permittedAttrs;
121
+	}
122
+
123
+	/**
124
+	 * Check whether excluded attributes are present.
125
+	 *
126
+	 * @return bool
127
+	 */
128
+	public function hasExcludedAttrs(): bool
129
+	{
130
+		return isset($this->_excludedAttrs);
131
+	}
132
+
133
+	/**
134
+	 * Get OID's of excluded attributes.
135
+	 *
136
+	 * @throws \LogicException If not set
137
+	 *
138
+	 * @return string[]
139
+	 */
140
+	public function excludedAttrs(): array
141
+	{
142
+		if (!$this->hasExcludedAttrs()) {
143
+			throw new \LogicException('excludedAttrs not set.');
144
+		}
145
+		return $this->_excludedAttrs;
146
+	}
147
+
148
+	/**
149
+	 * Whether to permit attributes that are not explicitly specified in
150
+	 * neither permitted nor excluded list.
151
+	 *
152
+	 * @return bool
153
+	 */
154
+	public function permitUnspecified(): bool
155
+	{
156
+		return $this->_permitUnSpecified;
157
+	}
158
+
159
+	/**
160
+	 * {@inheritdoc}
161
+	 */
162
+	protected static function _fromDER(string $data, bool $critical): Extension
163
+	{
164
+		$seq = UnspecifiedType::fromDER($data)->asSequence();
165
+		$path_len = null;
166
+		$permitted = null;
167
+		$excluded = null;
168
+		$permit_unspecified = true;
169
+		$idx = 0;
170
+		if ($seq->has($idx, Element::TYPE_INTEGER)) {
171
+			$path_len = $seq->at($idx++)->asInteger()->intNumber();
172
+		}
173
+		if ($seq->hasTagged(0)) {
174
+			$attr_seq = $seq->getTagged(0)->asImplicit(Element::TYPE_SEQUENCE)
175
+				->asSequence();
176
+			$permitted = array_map(
177
+				function (UnspecifiedType $el) {
178
+					return $el->asObjectIdentifier()->oid();
179
+				}, $attr_seq->elements());
180
+			++$idx;
181
+		}
182
+		if ($seq->hasTagged(1)) {
183
+			$attr_seq = $seq->getTagged(1)->asImplicit(Element::TYPE_SEQUENCE)
184
+				->asSequence();
185
+			$excluded = array_map(
186
+				function (UnspecifiedType $el) {
187
+					return $el->asObjectIdentifier()->oid();
188
+				}, $attr_seq->elements());
189
+			++$idx;
190
+		}
191
+		if ($seq->has($idx, Element::TYPE_BOOLEAN)) {
192
+			$permit_unspecified = $seq->at($idx++)->asBoolean()->value();
193
+		}
194
+		return new self($critical, $path_len, $permitted, $excluded, $permit_unspecified);
195
+	}
196
+
197
+	/**
198
+	 * {@inheritdoc}
199
+	 */
200
+	protected function _valueASN1(): Element
201
+	{
202
+		$elements = [];
203
+		if (isset($this->_pathLenConstraint)) {
204
+			$elements[] = new Integer($this->_pathLenConstraint);
205
+		}
206
+		if (isset($this->_permittedAttrs)) {
207
+			$oids = array_map(
208
+				function ($oid) {
209
+					return new ObjectIdentifier($oid);
210
+				}, $this->_permittedAttrs);
211
+			$elements[] = new ImplicitlyTaggedType(0, new Sequence(...$oids));
212
+		}
213
+		if (isset($this->_excludedAttrs)) {
214
+			$oids = array_map(
215
+				function ($oid) {
216
+					return new ObjectIdentifier($oid);
217
+				}, $this->_excludedAttrs);
218
+			$elements[] = new ImplicitlyTaggedType(1, new Sequence(...$oids));
219
+		}
220
+		if (true !== $this->_permitUnSpecified) {
221
+			$elements[] = new Boolean(false);
222
+		}
223
+		return new Sequence(...$elements);
224
+	}
225 225
 }
Please login to merge, or discard this patch.
lib/X509/Certificate/Extension/BasicConstraintsExtension.php 1 patch
Indentation   +88 added lines, -88 removed lines patch added patch discarded remove patch
@@ -17,99 +17,99 @@
 block discarded – undo
17 17
  */
18 18
 class BasicConstraintsExtension extends Extension
19 19
 {
20
-    /**
21
-     * Whether certificate is a CA.
22
-     *
23
-     * @var bool
24
-     */
25
-    protected $_ca;
20
+	/**
21
+	 * Whether certificate is a CA.
22
+	 *
23
+	 * @var bool
24
+	 */
25
+	protected $_ca;
26 26
 
27
-    /**
28
-     * Maximum certification path length.
29
-     *
30
-     * @var null|int
31
-     */
32
-    protected $_pathLen;
27
+	/**
28
+	 * Maximum certification path length.
29
+	 *
30
+	 * @var null|int
31
+	 */
32
+	protected $_pathLen;
33 33
 
34
-    /**
35
-     * Constructor.
36
-     *
37
-     * @param bool     $critical
38
-     * @param bool     $ca
39
-     * @param null|int $path_len
40
-     */
41
-    public function __construct(bool $critical, bool $ca, ?int $path_len = null)
42
-    {
43
-        parent::__construct(self::OID_BASIC_CONSTRAINTS, $critical);
44
-        $this->_ca = $ca;
45
-        $this->_pathLen = $path_len;
46
-    }
34
+	/**
35
+	 * Constructor.
36
+	 *
37
+	 * @param bool     $critical
38
+	 * @param bool     $ca
39
+	 * @param null|int $path_len
40
+	 */
41
+	public function __construct(bool $critical, bool $ca, ?int $path_len = null)
42
+	{
43
+		parent::__construct(self::OID_BASIC_CONSTRAINTS, $critical);
44
+		$this->_ca = $ca;
45
+		$this->_pathLen = $path_len;
46
+	}
47 47
 
48
-    /**
49
-     * Whether certificate is a CA.
50
-     *
51
-     * @return bool
52
-     */
53
-    public function isCA(): bool
54
-    {
55
-        return $this->_ca;
56
-    }
48
+	/**
49
+	 * Whether certificate is a CA.
50
+	 *
51
+	 * @return bool
52
+	 */
53
+	public function isCA(): bool
54
+	{
55
+		return $this->_ca;
56
+	}
57 57
 
58
-    /**
59
-     * Whether path length is present.
60
-     *
61
-     * @return bool
62
-     */
63
-    public function hasPathLen(): bool
64
-    {
65
-        return isset($this->_pathLen);
66
-    }
58
+	/**
59
+	 * Whether path length is present.
60
+	 *
61
+	 * @return bool
62
+	 */
63
+	public function hasPathLen(): bool
64
+	{
65
+		return isset($this->_pathLen);
66
+	}
67 67
 
68
-    /**
69
-     * Get path length.
70
-     *
71
-     * @throws \LogicException If not set
72
-     *
73
-     * @return int
74
-     */
75
-    public function pathLen(): int
76
-    {
77
-        if (!$this->hasPathLen()) {
78
-            throw new \LogicException('pathLenConstraint not set.');
79
-        }
80
-        return $this->_pathLen;
81
-    }
68
+	/**
69
+	 * Get path length.
70
+	 *
71
+	 * @throws \LogicException If not set
72
+	 *
73
+	 * @return int
74
+	 */
75
+	public function pathLen(): int
76
+	{
77
+		if (!$this->hasPathLen()) {
78
+			throw new \LogicException('pathLenConstraint not set.');
79
+		}
80
+		return $this->_pathLen;
81
+	}
82 82
 
83
-    /**
84
-     * {@inheritdoc}
85
-     */
86
-    protected static function _fromDER(string $data, bool $critical): Extension
87
-    {
88
-        $seq = UnspecifiedType::fromDER($data)->asSequence();
89
-        $ca = false;
90
-        $path_len = null;
91
-        $idx = 0;
92
-        if ($seq->has($idx, Element::TYPE_BOOLEAN)) {
93
-            $ca = $seq->at($idx++)->asBoolean()->value();
94
-        }
95
-        if ($seq->has($idx, Element::TYPE_INTEGER)) {
96
-            $path_len = $seq->at($idx)->asInteger()->intNumber();
97
-        }
98
-        return new self($critical, $ca, $path_len);
99
-    }
83
+	/**
84
+	 * {@inheritdoc}
85
+	 */
86
+	protected static function _fromDER(string $data, bool $critical): Extension
87
+	{
88
+		$seq = UnspecifiedType::fromDER($data)->asSequence();
89
+		$ca = false;
90
+		$path_len = null;
91
+		$idx = 0;
92
+		if ($seq->has($idx, Element::TYPE_BOOLEAN)) {
93
+			$ca = $seq->at($idx++)->asBoolean()->value();
94
+		}
95
+		if ($seq->has($idx, Element::TYPE_INTEGER)) {
96
+			$path_len = $seq->at($idx)->asInteger()->intNumber();
97
+		}
98
+		return new self($critical, $ca, $path_len);
99
+	}
100 100
 
101
-    /**
102
-     * {@inheritdoc}
103
-     */
104
-    protected function _valueASN1(): Element
105
-    {
106
-        $elements = [];
107
-        if ($this->_ca) {
108
-            $elements[] = new Boolean(true);
109
-        }
110
-        if (isset($this->_pathLen)) {
111
-            $elements[] = new Integer($this->_pathLen);
112
-        }
113
-        return new Sequence(...$elements);
114
-    }
101
+	/**
102
+	 * {@inheritdoc}
103
+	 */
104
+	protected function _valueASN1(): Element
105
+	{
106
+		$elements = [];
107
+		if ($this->_ca) {
108
+			$elements[] = new Boolean(true);
109
+		}
110
+		if (isset($this->_pathLen)) {
111
+			$elements[] = new Integer($this->_pathLen);
112
+		}
113
+		return new Sequence(...$elements);
114
+	}
115 115
 }
Please login to merge, or discard this patch.
lib/X509/Certificate/CertificateBundle.php 1 patch
Indentation   +211 added lines, -211 removed lines patch added patch discarded remove patch
@@ -12,215 +12,215 @@
 block discarded – undo
12 12
  */
13 13
 class CertificateBundle implements \Countable, \IteratorAggregate
14 14
 {
15
-    /**
16
-     * Certificates.
17
-     *
18
-     * @var Certificate[]
19
-     */
20
-    protected $_certs;
21
-
22
-    /**
23
-     * Mapping from public key id to array of certificates.
24
-     *
25
-     * @var null|(Certificate[])[]
26
-     */
27
-    private $_keyIdMap;
28
-
29
-    /**
30
-     * Constructor.
31
-     *
32
-     * @param Certificate ...$certs Certificate objects
33
-     */
34
-    public function __construct(Certificate ...$certs)
35
-    {
36
-        $this->_certs = $certs;
37
-    }
38
-
39
-    /**
40
-     * Reset internal cached variables on clone.
41
-     */
42
-    public function __clone()
43
-    {
44
-        $this->_keyIdMap = null;
45
-    }
46
-
47
-    /**
48
-     * Initialize from PEMs.
49
-     *
50
-     * @param PEM ...$pems PEM objects
51
-     *
52
-     * @return self
53
-     */
54
-    public static function fromPEMs(PEM ...$pems): self
55
-    {
56
-        $certs = array_map(
57
-            function ($pem) {
58
-                return Certificate::fromPEM($pem);
59
-            }, $pems);
60
-        return new self(...$certs);
61
-    }
62
-
63
-    /**
64
-     * Initialize from PEM bundle.
65
-     *
66
-     * @param PEMBundle $pem_bundle
67
-     *
68
-     * @return self
69
-     */
70
-    public static function fromPEMBundle(PEMBundle $pem_bundle): self
71
-    {
72
-        return self::fromPEMs(...$pem_bundle->all());
73
-    }
74
-
75
-    /**
76
-     * Get self with certificates added.
77
-     *
78
-     * @param Certificate ...$cert
79
-     *
80
-     * @return self
81
-     */
82
-    public function withCertificates(Certificate ...$cert): self
83
-    {
84
-        $obj = clone $this;
85
-        $obj->_certs = array_merge($obj->_certs, $cert);
86
-        return $obj;
87
-    }
88
-
89
-    /**
90
-     * Get self with certificates from PEMBundle added.
91
-     *
92
-     * @param PEMBundle $pem_bundle
93
-     *
94
-     * @return self
95
-     */
96
-    public function withPEMBundle(PEMBundle $pem_bundle): self
97
-    {
98
-        $certs = $this->_certs;
99
-        foreach ($pem_bundle as $pem) {
100
-            $certs[] = Certificate::fromPEM($pem);
101
-        }
102
-        return new self(...$certs);
103
-    }
104
-
105
-    /**
106
-     * Get self with single certificate from PEM added.
107
-     *
108
-     * @param PEM $pem
109
-     *
110
-     * @return self
111
-     */
112
-    public function withPEM(PEM $pem): self
113
-    {
114
-        $certs = $this->_certs;
115
-        $certs[] = Certificate::fromPEM($pem);
116
-        return new self(...$certs);
117
-    }
118
-
119
-    /**
120
-     * Check whether bundle contains a given certificate.
121
-     *
122
-     * @param Certificate $cert
123
-     *
124
-     * @return bool
125
-     */
126
-    public function contains(Certificate $cert): bool
127
-    {
128
-        $id = self::_getCertKeyId($cert);
129
-        $map = $this->_getKeyIdMap();
130
-        if (!isset($map[$id])) {
131
-            return false;
132
-        }
133
-        foreach ($map[$id] as $c) {
134
-            /** @var Certificate $c */
135
-            if ($cert->equals($c)) {
136
-                return true;
137
-            }
138
-        }
139
-        return false;
140
-    }
141
-
142
-    /**
143
-     * Get all certificates that have given subject key identifier.
144
-     *
145
-     * @param string $id
146
-     *
147
-     * @return Certificate[]
148
-     */
149
-    public function allBySubjectKeyIdentifier(string $id): array
150
-    {
151
-        $map = $this->_getKeyIdMap();
152
-        if (!isset($map[$id])) {
153
-            return [];
154
-        }
155
-        return $map[$id];
156
-    }
157
-
158
-    /**
159
-     * Get all certificates in a bundle.
160
-     *
161
-     * @return Certificate[]
162
-     */
163
-    public function all(): array
164
-    {
165
-        return $this->_certs;
166
-    }
167
-
168
-    /**
169
-     * @see \Countable::count()
170
-     *
171
-     * @return int
172
-     */
173
-    public function count(): int
174
-    {
175
-        return count($this->_certs);
176
-    }
177
-
178
-    /**
179
-     * Get iterator for certificates.
180
-     *
181
-     * @see \IteratorAggregate::getIterator()
182
-     *
183
-     * @return \ArrayIterator
184
-     */
185
-    public function getIterator(): \ArrayIterator
186
-    {
187
-        return new \ArrayIterator($this->_certs);
188
-    }
189
-
190
-    /**
191
-     * Get certificate mapping by public key id.
192
-     *
193
-     * @return (Certificate[])[]
194
-     */
195
-    private function _getKeyIdMap(): array
196
-    {
197
-        // lazily build mapping
198
-        if (!isset($this->_keyIdMap)) {
199
-            $this->_keyIdMap = [];
200
-            foreach ($this->_certs as $cert) {
201
-                $id = self::_getCertKeyId($cert);
202
-                if (!isset($this->_keyIdMap[$id])) {
203
-                    $this->_keyIdMap[$id] = [];
204
-                }
205
-                array_push($this->_keyIdMap[$id], $cert);
206
-            }
207
-        }
208
-        return $this->_keyIdMap;
209
-    }
210
-
211
-    /**
212
-     * Get public key id for the certificate.
213
-     *
214
-     * @param Certificate $cert
215
-     *
216
-     * @return string
217
-     */
218
-    private static function _getCertKeyId(Certificate $cert): string
219
-    {
220
-        $exts = $cert->tbsCertificate()->extensions();
221
-        if ($exts->hasSubjectKeyIdentifier()) {
222
-            return $exts->subjectKeyIdentifier()->keyIdentifier();
223
-        }
224
-        return $cert->tbsCertificate()->subjectPublicKeyInfo()->keyIdentifier();
225
-    }
15
+	/**
16
+	 * Certificates.
17
+	 *
18
+	 * @var Certificate[]
19
+	 */
20
+	protected $_certs;
21
+
22
+	/**
23
+	 * Mapping from public key id to array of certificates.
24
+	 *
25
+	 * @var null|(Certificate[])[]
26
+	 */
27
+	private $_keyIdMap;
28
+
29
+	/**
30
+	 * Constructor.
31
+	 *
32
+	 * @param Certificate ...$certs Certificate objects
33
+	 */
34
+	public function __construct(Certificate ...$certs)
35
+	{
36
+		$this->_certs = $certs;
37
+	}
38
+
39
+	/**
40
+	 * Reset internal cached variables on clone.
41
+	 */
42
+	public function __clone()
43
+	{
44
+		$this->_keyIdMap = null;
45
+	}
46
+
47
+	/**
48
+	 * Initialize from PEMs.
49
+	 *
50
+	 * @param PEM ...$pems PEM objects
51
+	 *
52
+	 * @return self
53
+	 */
54
+	public static function fromPEMs(PEM ...$pems): self
55
+	{
56
+		$certs = array_map(
57
+			function ($pem) {
58
+				return Certificate::fromPEM($pem);
59
+			}, $pems);
60
+		return new self(...$certs);
61
+	}
62
+
63
+	/**
64
+	 * Initialize from PEM bundle.
65
+	 *
66
+	 * @param PEMBundle $pem_bundle
67
+	 *
68
+	 * @return self
69
+	 */
70
+	public static function fromPEMBundle(PEMBundle $pem_bundle): self
71
+	{
72
+		return self::fromPEMs(...$pem_bundle->all());
73
+	}
74
+
75
+	/**
76
+	 * Get self with certificates added.
77
+	 *
78
+	 * @param Certificate ...$cert
79
+	 *
80
+	 * @return self
81
+	 */
82
+	public function withCertificates(Certificate ...$cert): self
83
+	{
84
+		$obj = clone $this;
85
+		$obj->_certs = array_merge($obj->_certs, $cert);
86
+		return $obj;
87
+	}
88
+
89
+	/**
90
+	 * Get self with certificates from PEMBundle added.
91
+	 *
92
+	 * @param PEMBundle $pem_bundle
93
+	 *
94
+	 * @return self
95
+	 */
96
+	public function withPEMBundle(PEMBundle $pem_bundle): self
97
+	{
98
+		$certs = $this->_certs;
99
+		foreach ($pem_bundle as $pem) {
100
+			$certs[] = Certificate::fromPEM($pem);
101
+		}
102
+		return new self(...$certs);
103
+	}
104
+
105
+	/**
106
+	 * Get self with single certificate from PEM added.
107
+	 *
108
+	 * @param PEM $pem
109
+	 *
110
+	 * @return self
111
+	 */
112
+	public function withPEM(PEM $pem): self
113
+	{
114
+		$certs = $this->_certs;
115
+		$certs[] = Certificate::fromPEM($pem);
116
+		return new self(...$certs);
117
+	}
118
+
119
+	/**
120
+	 * Check whether bundle contains a given certificate.
121
+	 *
122
+	 * @param Certificate $cert
123
+	 *
124
+	 * @return bool
125
+	 */
126
+	public function contains(Certificate $cert): bool
127
+	{
128
+		$id = self::_getCertKeyId($cert);
129
+		$map = $this->_getKeyIdMap();
130
+		if (!isset($map[$id])) {
131
+			return false;
132
+		}
133
+		foreach ($map[$id] as $c) {
134
+			/** @var Certificate $c */
135
+			if ($cert->equals($c)) {
136
+				return true;
137
+			}
138
+		}
139
+		return false;
140
+	}
141
+
142
+	/**
143
+	 * Get all certificates that have given subject key identifier.
144
+	 *
145
+	 * @param string $id
146
+	 *
147
+	 * @return Certificate[]
148
+	 */
149
+	public function allBySubjectKeyIdentifier(string $id): array
150
+	{
151
+		$map = $this->_getKeyIdMap();
152
+		if (!isset($map[$id])) {
153
+			return [];
154
+		}
155
+		return $map[$id];
156
+	}
157
+
158
+	/**
159
+	 * Get all certificates in a bundle.
160
+	 *
161
+	 * @return Certificate[]
162
+	 */
163
+	public function all(): array
164
+	{
165
+		return $this->_certs;
166
+	}
167
+
168
+	/**
169
+	 * @see \Countable::count()
170
+	 *
171
+	 * @return int
172
+	 */
173
+	public function count(): int
174
+	{
175
+		return count($this->_certs);
176
+	}
177
+
178
+	/**
179
+	 * Get iterator for certificates.
180
+	 *
181
+	 * @see \IteratorAggregate::getIterator()
182
+	 *
183
+	 * @return \ArrayIterator
184
+	 */
185
+	public function getIterator(): \ArrayIterator
186
+	{
187
+		return new \ArrayIterator($this->_certs);
188
+	}
189
+
190
+	/**
191
+	 * Get certificate mapping by public key id.
192
+	 *
193
+	 * @return (Certificate[])[]
194
+	 */
195
+	private function _getKeyIdMap(): array
196
+	{
197
+		// lazily build mapping
198
+		if (!isset($this->_keyIdMap)) {
199
+			$this->_keyIdMap = [];
200
+			foreach ($this->_certs as $cert) {
201
+				$id = self::_getCertKeyId($cert);
202
+				if (!isset($this->_keyIdMap[$id])) {
203
+					$this->_keyIdMap[$id] = [];
204
+				}
205
+				array_push($this->_keyIdMap[$id], $cert);
206
+			}
207
+		}
208
+		return $this->_keyIdMap;
209
+	}
210
+
211
+	/**
212
+	 * Get public key id for the certificate.
213
+	 *
214
+	 * @param Certificate $cert
215
+	 *
216
+	 * @return string
217
+	 */
218
+	private static function _getCertKeyId(Certificate $cert): string
219
+	{
220
+		$exts = $cert->tbsCertificate()->extensions();
221
+		if ($exts->hasSubjectKeyIdentifier()) {
222
+			return $exts->subjectKeyIdentifier()->keyIdentifier();
223
+		}
224
+		return $cert->tbsCertificate()->subjectPublicKeyInfo()->keyIdentifier();
225
+	}
226 226
 }
Please login to merge, or discard this patch.
lib/X509/Certificate/CertificateChain.php 1 patch
Indentation   +122 added lines, -122 removed lines patch added patch discarded remove patch
@@ -13,136 +13,136 @@
 block discarded – undo
13 13
  */
14 14
 class CertificateChain implements \Countable, \IteratorAggregate
15 15
 {
16
-    /**
17
-     * List of certificates in a chain.
18
-     *
19
-     * @var Certificate[]
20
-     */
21
-    protected $_certs;
16
+	/**
17
+	 * List of certificates in a chain.
18
+	 *
19
+	 * @var Certificate[]
20
+	 */
21
+	protected $_certs;
22 22
 
23
-    /**
24
-     * Constructor.
25
-     *
26
-     * @param Certificate ...$certs List of certificates, end-entity first
27
-     */
28
-    public function __construct(Certificate ...$certs)
29
-    {
30
-        $this->_certs = $certs;
31
-    }
23
+	/**
24
+	 * Constructor.
25
+	 *
26
+	 * @param Certificate ...$certs List of certificates, end-entity first
27
+	 */
28
+	public function __construct(Certificate ...$certs)
29
+	{
30
+		$this->_certs = $certs;
31
+	}
32 32
 
33
-    /**
34
-     * Initialize from a list of PEMs.
35
-     *
36
-     * @param PEM ...$pems
37
-     *
38
-     * @return self
39
-     */
40
-    public static function fromPEMs(PEM ...$pems): self
41
-    {
42
-        $certs = array_map(
43
-            function (PEM $pem) {
44
-                return Certificate::fromPEM($pem);
45
-            }, $pems);
46
-        return new self(...$certs);
47
-    }
33
+	/**
34
+	 * Initialize from a list of PEMs.
35
+	 *
36
+	 * @param PEM ...$pems
37
+	 *
38
+	 * @return self
39
+	 */
40
+	public static function fromPEMs(PEM ...$pems): self
41
+	{
42
+		$certs = array_map(
43
+			function (PEM $pem) {
44
+				return Certificate::fromPEM($pem);
45
+			}, $pems);
46
+		return new self(...$certs);
47
+	}
48 48
 
49
-    /**
50
-     * Initialize from a string containing multiple PEM blocks.
51
-     *
52
-     * @param string $str
53
-     *
54
-     * @return self
55
-     */
56
-    public static function fromPEMString(string $str): self
57
-    {
58
-        $pems = PEMBundle::fromString($str)->all();
59
-        return self::fromPEMs(...$pems);
60
-    }
49
+	/**
50
+	 * Initialize from a string containing multiple PEM blocks.
51
+	 *
52
+	 * @param string $str
53
+	 *
54
+	 * @return self
55
+	 */
56
+	public static function fromPEMString(string $str): self
57
+	{
58
+		$pems = PEMBundle::fromString($str)->all();
59
+		return self::fromPEMs(...$pems);
60
+	}
61 61
 
62
-    /**
63
-     * Get all certificates in a chain ordered from the end-entity certificate
64
-     * to the trust anchor.
65
-     *
66
-     * @return Certificate[]
67
-     */
68
-    public function certificates(): array
69
-    {
70
-        return $this->_certs;
71
-    }
62
+	/**
63
+	 * Get all certificates in a chain ordered from the end-entity certificate
64
+	 * to the trust anchor.
65
+	 *
66
+	 * @return Certificate[]
67
+	 */
68
+	public function certificates(): array
69
+	{
70
+		return $this->_certs;
71
+	}
72 72
 
73
-    /**
74
-     * Get the end-entity certificate.
75
-     *
76
-     * @throws \LogicException
77
-     *
78
-     * @return Certificate
79
-     */
80
-    public function endEntityCertificate(): Certificate
81
-    {
82
-        if (!count($this->_certs)) {
83
-            throw new \LogicException('No certificates.');
84
-        }
85
-        return $this->_certs[0];
86
-    }
73
+	/**
74
+	 * Get the end-entity certificate.
75
+	 *
76
+	 * @throws \LogicException
77
+	 *
78
+	 * @return Certificate
79
+	 */
80
+	public function endEntityCertificate(): Certificate
81
+	{
82
+		if (!count($this->_certs)) {
83
+			throw new \LogicException('No certificates.');
84
+		}
85
+		return $this->_certs[0];
86
+	}
87 87
 
88
-    /**
89
-     * Get the trust anchor certificate.
90
-     *
91
-     * @throws \LogicException
92
-     *
93
-     * @return Certificate
94
-     */
95
-    public function trustAnchorCertificate(): Certificate
96
-    {
97
-        if (!count($this->_certs)) {
98
-            throw new \LogicException('No certificates.');
99
-        }
100
-        return $this->_certs[count($this->_certs) - 1];
101
-    }
88
+	/**
89
+	 * Get the trust anchor certificate.
90
+	 *
91
+	 * @throws \LogicException
92
+	 *
93
+	 * @return Certificate
94
+	 */
95
+	public function trustAnchorCertificate(): Certificate
96
+	{
97
+		if (!count($this->_certs)) {
98
+			throw new \LogicException('No certificates.');
99
+		}
100
+		return $this->_certs[count($this->_certs) - 1];
101
+	}
102 102
 
103
-    /**
104
-     * Convert certificate chain to certification path.
105
-     *
106
-     * @return CertificationPath
107
-     */
108
-    public function certificationPath(): CertificationPath
109
-    {
110
-        return CertificationPath::fromCertificateChain($this);
111
-    }
103
+	/**
104
+	 * Convert certificate chain to certification path.
105
+	 *
106
+	 * @return CertificationPath
107
+	 */
108
+	public function certificationPath(): CertificationPath
109
+	{
110
+		return CertificationPath::fromCertificateChain($this);
111
+	}
112 112
 
113
-    /**
114
-     * Convert certificate chain to string of PEM blocks.
115
-     *
116
-     * @return string
117
-     */
118
-    public function toPEMString(): string
119
-    {
120
-        return implode("\n",
121
-            array_map(
122
-                function (Certificate $cert) {
123
-                    return $cert->toPEM()->string();
124
-                }, $this->_certs));
125
-    }
113
+	/**
114
+	 * Convert certificate chain to string of PEM blocks.
115
+	 *
116
+	 * @return string
117
+	 */
118
+	public function toPEMString(): string
119
+	{
120
+		return implode("\n",
121
+			array_map(
122
+				function (Certificate $cert) {
123
+					return $cert->toPEM()->string();
124
+				}, $this->_certs));
125
+	}
126 126
 
127
-    /**
128
-     * @see \Countable::count()
129
-     *
130
-     * @return int
131
-     */
132
-    public function count(): int
133
-    {
134
-        return count($this->_certs);
135
-    }
127
+	/**
128
+	 * @see \Countable::count()
129
+	 *
130
+	 * @return int
131
+	 */
132
+	public function count(): int
133
+	{
134
+		return count($this->_certs);
135
+	}
136 136
 
137
-    /**
138
-     * Get iterator for certificates.
139
-     *
140
-     * @see \IteratorAggregate::getIterator()
141
-     *
142
-     * @return \ArrayIterator
143
-     */
144
-    public function getIterator(): \ArrayIterator
145
-    {
146
-        return new \ArrayIterator($this->_certs);
147
-    }
137
+	/**
138
+	 * Get iterator for certificates.
139
+	 *
140
+	 * @see \IteratorAggregate::getIterator()
141
+	 *
142
+	 * @return \ArrayIterator
143
+	 */
144
+	public function getIterator(): \ArrayIterator
145
+	{
146
+		return new \ArrayIterator($this->_certs);
147
+	}
148 148
 }
Please login to merge, or discard this patch.
lib/X509/Certificate/TBSCertificate.php 1 patch
Indentation   +618 added lines, -618 removed lines patch added patch discarded remove patch
@@ -27,622 +27,622 @@
 block discarded – undo
27 27
  */
28 28
 class TBSCertificate
29 29
 {
30
-    // Certificate version enumerations
31
-    const VERSION_1 = 0;
32
-    const VERSION_2 = 1;
33
-    const VERSION_3 = 2;
34
-
35
-    /**
36
-     * Certificate version.
37
-     *
38
-     * @var null|int
39
-     */
40
-    protected $_version;
41
-
42
-    /**
43
-     * Serial number.
44
-     *
45
-     * @var null|string
46
-     */
47
-    protected $_serialNumber;
48
-
49
-    /**
50
-     * Signature algorithm.
51
-     *
52
-     * @var null|SignatureAlgorithmIdentifier
53
-     */
54
-    protected $_signature;
55
-
56
-    /**
57
-     * Certificate issuer.
58
-     *
59
-     * @var Name
60
-     */
61
-    protected $_issuer;
62
-
63
-    /**
64
-     * Certificate validity period.
65
-     *
66
-     * @var Validity
67
-     */
68
-    protected $_validity;
69
-
70
-    /**
71
-     * Certificate subject.
72
-     *
73
-     * @var Name
74
-     */
75
-    protected $_subject;
76
-
77
-    /**
78
-     * Subject public key.
79
-     *
80
-     * @var PublicKeyInfo
81
-     */
82
-    protected $_subjectPublicKeyInfo;
83
-
84
-    /**
85
-     * Issuer unique identifier.
86
-     *
87
-     * @var null|UniqueIdentifier
88
-     */
89
-    protected $_issuerUniqueID;
90
-
91
-    /**
92
-     * Subject unique identifier.
93
-     *
94
-     * @var null|UniqueIdentifier
95
-     */
96
-    protected $_subjectUniqueID;
97
-
98
-    /**
99
-     * Extensions.
100
-     *
101
-     * @var Extensions
102
-     */
103
-    protected $_extensions;
104
-
105
-    /**
106
-     * Constructor.
107
-     *
108
-     * @param Name          $subject  Certificate subject
109
-     * @param PublicKeyInfo $pki      Subject public key
110
-     * @param Name          $issuer   Certificate issuer
111
-     * @param Validity      $validity Validity period
112
-     */
113
-    public function __construct(Name $subject, PublicKeyInfo $pki, Name $issuer,
114
-        Validity $validity)
115
-    {
116
-        $this->_subject = $subject;
117
-        $this->_subjectPublicKeyInfo = $pki;
118
-        $this->_issuer = $issuer;
119
-        $this->_validity = $validity;
120
-        $this->_extensions = new Extensions();
121
-    }
122
-
123
-    /**
124
-     * Initialize from ASN.1.
125
-     *
126
-     * @param Sequence $seq
127
-     *
128
-     * @return self
129
-     */
130
-    public static function fromASN1(Sequence $seq): self
131
-    {
132
-        $idx = 0;
133
-        if ($seq->hasTagged(0)) {
134
-            ++$idx;
135
-            $version = $seq->getTagged(0)->asExplicit()->asInteger()->intNumber();
136
-        } else {
137
-            $version = self::VERSION_1;
138
-        }
139
-        $serial = $seq->at($idx++)->asInteger()->number();
140
-        $algo = AlgorithmIdentifier::fromASN1($seq->at($idx++)->asSequence());
141
-        if (!$algo instanceof SignatureAlgorithmIdentifier) {
142
-            throw new \UnexpectedValueException(
143
-                'Unsupported signature algorithm ' . $algo->name() . '.');
144
-        }
145
-        $issuer = Name::fromASN1($seq->at($idx++)->asSequence());
146
-        $validity = Validity::fromASN1($seq->at($idx++)->asSequence());
147
-        $subject = Name::fromASN1($seq->at($idx++)->asSequence());
148
-        $pki = PublicKeyInfo::fromASN1($seq->at($idx++)->asSequence());
149
-        $tbs_cert = new self($subject, $pki, $issuer, $validity);
150
-        $tbs_cert->_version = $version;
151
-        $tbs_cert->_serialNumber = $serial;
152
-        $tbs_cert->_signature = $algo;
153
-        if ($seq->hasTagged(1)) {
154
-            $tbs_cert->_issuerUniqueID = UniqueIdentifier::fromASN1(
155
-                $seq->getTagged(1)->asImplicit(Element::TYPE_BIT_STRING)
156
-                    ->asBitString());
157
-        }
158
-        if ($seq->hasTagged(2)) {
159
-            $tbs_cert->_subjectUniqueID = UniqueIdentifier::fromASN1(
160
-                $seq->getTagged(2)->asImplicit(Element::TYPE_BIT_STRING)
161
-                    ->asBitString());
162
-        }
163
-        if ($seq->hasTagged(3)) {
164
-            $tbs_cert->_extensions = Extensions::fromASN1(
165
-                $seq->getTagged(3)->asExplicit()->asSequence());
166
-        }
167
-        return $tbs_cert;
168
-    }
169
-
170
-    /**
171
-     * Initialize from certification request.
172
-     *
173
-     * Note that signature is not verified and must be done by the caller.
174
-     *
175
-     * @param CertificationRequest $cr
176
-     *
177
-     * @return self
178
-     */
179
-    public static function fromCSR(CertificationRequest $cr): self
180
-    {
181
-        $cri = $cr->certificationRequestInfo();
182
-        $tbs_cert = new self($cri->subject(), $cri->subjectPKInfo(), new Name(),
183
-            Validity::fromStrings(null, null));
184
-        // if CSR has Extension Request attribute
185
-        if ($cri->hasAttributes()) {
186
-            $attribs = $cri->attributes();
187
-            if ($attribs->hasExtensionRequest()) {
188
-                $tbs_cert = $tbs_cert->withExtensions(
189
-                    $attribs->extensionRequest()->extensions());
190
-            }
191
-        }
192
-        // add Subject Key Identifier extension
193
-        return $tbs_cert->withAdditionalExtensions(
194
-            new SubjectKeyIdentifierExtension(false,
195
-                $cri->subjectPKInfo()->keyIdentifier()));
196
-    }
197
-
198
-    /**
199
-     * Get self with fields set from the issuer's certificate.
200
-     *
201
-     * Issuer shall be set to issuing certificate's subject.
202
-     * Authority key identifier extensions shall be added with a key identifier
203
-     * set to issuing certificate's public key identifier.
204
-     *
205
-     * @param Certificate $cert Issuing party's certificate
206
-     *
207
-     * @return self
208
-     */
209
-    public function withIssuerCertificate(Certificate $cert): self
210
-    {
211
-        $obj = clone $this;
212
-        // set issuer DN from cert's subject
213
-        $obj->_issuer = $cert->tbsCertificate()->subject();
214
-        // add authority key identifier extension
215
-        $key_id = $cert->tbsCertificate()->subjectPublicKeyInfo()->keyIdentifier();
216
-        $obj->_extensions = $obj->_extensions->withExtensions(
217
-            new AuthorityKeyIdentifierExtension(false, $key_id));
218
-        return $obj;
219
-    }
220
-
221
-    /**
222
-     * Get self with given version.
223
-     *
224
-     * If version is not set, appropriate version is automatically
225
-     * determined during signing.
226
-     *
227
-     * @param int $version
228
-     *
229
-     * @return self
230
-     */
231
-    public function withVersion(int $version): self
232
-    {
233
-        $obj = clone $this;
234
-        $obj->_version = $version;
235
-        return $obj;
236
-    }
237
-
238
-    /**
239
-     * Get self with given serial number.
240
-     *
241
-     * @param int|string $serial Base 10 number
242
-     *
243
-     * @return self
244
-     */
245
-    public function withSerialNumber($serial): self
246
-    {
247
-        $obj = clone $this;
248
-        $obj->_serialNumber = strval($serial);
249
-        return $obj;
250
-    }
251
-
252
-    /**
253
-     * Get self with random positive serial number.
254
-     *
255
-     * @param int $size Number of random bytes
256
-     *
257
-     * @return self
258
-     */
259
-    public function withRandomSerialNumber(int $size = 16): self
260
-    {
261
-        // ensure that first byte is always non-zero and having first bit unset
262
-        $num = gmp_init(mt_rand(1, 0x7f), 10);
263
-        for ($i = 1; $i < $size; ++$i) {
264
-            $num <<= 8;
265
-            $num += mt_rand(0, 0xff);
266
-        }
267
-        return $this->withSerialNumber(gmp_strval($num, 10));
268
-    }
269
-
270
-    /**
271
-     * Get self with given signature algorithm.
272
-     *
273
-     * @param SignatureAlgorithmIdentifier $algo
274
-     *
275
-     * @return self
276
-     */
277
-    public function withSignature(SignatureAlgorithmIdentifier $algo): self
278
-    {
279
-        $obj = clone $this;
280
-        $obj->_signature = $algo;
281
-        return $obj;
282
-    }
283
-
284
-    /**
285
-     * Get self with given issuer.
286
-     *
287
-     * @param Name $issuer
288
-     *
289
-     * @return self
290
-     */
291
-    public function withIssuer(Name $issuer): self
292
-    {
293
-        $obj = clone $this;
294
-        $obj->_issuer = $issuer;
295
-        return $obj;
296
-    }
297
-
298
-    /**
299
-     * Get self with given validity.
300
-     *
301
-     * @param Validity $validity
302
-     *
303
-     * @return self
304
-     */
305
-    public function withValidity(Validity $validity): self
306
-    {
307
-        $obj = clone $this;
308
-        $obj->_validity = $validity;
309
-        return $obj;
310
-    }
311
-
312
-    /**
313
-     * Get self with given subject.
314
-     *
315
-     * @param Name $subject
316
-     *
317
-     * @return self
318
-     */
319
-    public function withSubject(Name $subject): self
320
-    {
321
-        $obj = clone $this;
322
-        $obj->_subject = $subject;
323
-        return $obj;
324
-    }
325
-
326
-    /**
327
-     * Get self with given subject public key info.
328
-     *
329
-     * @param PublicKeyInfo $pub_key_info
330
-     *
331
-     * @return self
332
-     */
333
-    public function withSubjectPublicKeyInfo(PublicKeyInfo $pub_key_info): self
334
-    {
335
-        $obj = clone $this;
336
-        $obj->_subjectPublicKeyInfo = $pub_key_info;
337
-        return $obj;
338
-    }
339
-
340
-    /**
341
-     * Get self with issuer unique ID.
342
-     *
343
-     * @param UniqueIdentifier $id
344
-     *
345
-     * @return self
346
-     */
347
-    public function withIssuerUniqueID(UniqueIdentifier $id): self
348
-    {
349
-        $obj = clone $this;
350
-        $obj->_issuerUniqueID = $id;
351
-        return $obj;
352
-    }
353
-
354
-    /**
355
-     * Get self with subject unique ID.
356
-     *
357
-     * @param UniqueIdentifier $id
358
-     *
359
-     * @return self
360
-     */
361
-    public function withSubjectUniqueID(UniqueIdentifier $id): self
362
-    {
363
-        $obj = clone $this;
364
-        $obj->_subjectUniqueID = $id;
365
-        return $obj;
366
-    }
367
-
368
-    /**
369
-     * Get self with given extensions.
370
-     *
371
-     * @param Extensions $extensions
372
-     *
373
-     * @return self
374
-     */
375
-    public function withExtensions(Extensions $extensions): self
376
-    {
377
-        $obj = clone $this;
378
-        $obj->_extensions = $extensions;
379
-        return $obj;
380
-    }
381
-
382
-    /**
383
-     * Get self with extensions added.
384
-     *
385
-     * @param Extension ...$exts One or more Extension objects
386
-     *
387
-     * @return self
388
-     */
389
-    public function withAdditionalExtensions(Extension ...$exts): self
390
-    {
391
-        $obj = clone $this;
392
-        $obj->_extensions = $obj->_extensions->withExtensions(...$exts);
393
-        return $obj;
394
-    }
395
-
396
-    /**
397
-     * Check whether version is set.
398
-     *
399
-     * @return bool
400
-     */
401
-    public function hasVersion(): bool
402
-    {
403
-        return isset($this->_version);
404
-    }
405
-
406
-    /**
407
-     * Get certificate version.
408
-     *
409
-     * @throws \LogicException If not set
410
-     *
411
-     * @return int
412
-     */
413
-    public function version(): int
414
-    {
415
-        if (!$this->hasVersion()) {
416
-            throw new \LogicException('version not set.');
417
-        }
418
-        return $this->_version;
419
-    }
420
-
421
-    /**
422
-     * Check whether serial number is set.
423
-     *
424
-     * @return bool
425
-     */
426
-    public function hasSerialNumber(): bool
427
-    {
428
-        return isset($this->_serialNumber);
429
-    }
430
-
431
-    /**
432
-     * Get serial number.
433
-     *
434
-     * @throws \LogicException If not set
435
-     *
436
-     * @return string Base 10 integer
437
-     */
438
-    public function serialNumber(): string
439
-    {
440
-        if (!$this->hasSerialNumber()) {
441
-            throw new \LogicException('serialNumber not set.');
442
-        }
443
-        return $this->_serialNumber;
444
-    }
445
-
446
-    /**
447
-     * Check whether signature algorithm is set.
448
-     *
449
-     * @return bool
450
-     */
451
-    public function hasSignature(): bool
452
-    {
453
-        return isset($this->_signature);
454
-    }
455
-
456
-    /**
457
-     * Get signature algorithm.
458
-     *
459
-     * @throws \LogicException If not set
460
-     *
461
-     * @return SignatureAlgorithmIdentifier
462
-     */
463
-    public function signature(): SignatureAlgorithmIdentifier
464
-    {
465
-        if (!$this->hasSignature()) {
466
-            throw new \LogicException('signature not set.');
467
-        }
468
-        return $this->_signature;
469
-    }
470
-
471
-    /**
472
-     * Get issuer.
473
-     *
474
-     * @return Name
475
-     */
476
-    public function issuer(): Name
477
-    {
478
-        return $this->_issuer;
479
-    }
480
-
481
-    /**
482
-     * Get validity period.
483
-     *
484
-     * @return Validity
485
-     */
486
-    public function validity(): Validity
487
-    {
488
-        return $this->_validity;
489
-    }
490
-
491
-    /**
492
-     * Get subject.
493
-     *
494
-     * @return Name
495
-     */
496
-    public function subject(): Name
497
-    {
498
-        return $this->_subject;
499
-    }
500
-
501
-    /**
502
-     * Get subject public key.
503
-     *
504
-     * @return PublicKeyInfo
505
-     */
506
-    public function subjectPublicKeyInfo(): PublicKeyInfo
507
-    {
508
-        return $this->_subjectPublicKeyInfo;
509
-    }
510
-
511
-    /**
512
-     * Whether issuer unique identifier is present.
513
-     *
514
-     * @return bool
515
-     */
516
-    public function hasIssuerUniqueID(): bool
517
-    {
518
-        return isset($this->_issuerUniqueID);
519
-    }
520
-
521
-    /**
522
-     * Get issuerUniqueID.
523
-     *
524
-     * @throws \LogicException If not set
525
-     *
526
-     * @return UniqueIdentifier
527
-     */
528
-    public function issuerUniqueID(): UniqueIdentifier
529
-    {
530
-        if (!$this->hasIssuerUniqueID()) {
531
-            throw new \LogicException('issuerUniqueID not set.');
532
-        }
533
-        return $this->_issuerUniqueID;
534
-    }
535
-
536
-    /**
537
-     * Whether subject unique identifier is present.
538
-     *
539
-     * @return bool
540
-     */
541
-    public function hasSubjectUniqueID(): bool
542
-    {
543
-        return isset($this->_subjectUniqueID);
544
-    }
545
-
546
-    /**
547
-     * Get subjectUniqueID.
548
-     *
549
-     * @throws \LogicException If not set
550
-     *
551
-     * @return UniqueIdentifier
552
-     */
553
-    public function subjectUniqueID(): UniqueIdentifier
554
-    {
555
-        if (!$this->hasSubjectUniqueID()) {
556
-            throw new \LogicException('subjectUniqueID not set.');
557
-        }
558
-        return $this->_subjectUniqueID;
559
-    }
560
-
561
-    /**
562
-     * Get extensions.
563
-     *
564
-     * @return Extensions
565
-     */
566
-    public function extensions(): Extensions
567
-    {
568
-        return $this->_extensions;
569
-    }
570
-
571
-    /**
572
-     * Generate ASN.1 structure.
573
-     *
574
-     * @return Sequence
575
-     */
576
-    public function toASN1(): Sequence
577
-    {
578
-        $elements = [];
579
-        $version = $this->version();
580
-        // if version is not default
581
-        if (self::VERSION_1 != $version) {
582
-            $elements[] = new ExplicitlyTaggedType(0, new Integer($version));
583
-        }
584
-        $serial = $this->serialNumber();
585
-        $signature = $this->signature();
586
-        // add required elements
587
-        array_push($elements, new Integer($serial), $signature->toASN1(),
588
-            $this->_issuer->toASN1(), $this->_validity->toASN1(),
589
-            $this->_subject->toASN1(), $this->_subjectPublicKeyInfo->toASN1());
590
-        if (isset($this->_issuerUniqueID)) {
591
-            $elements[] = new ImplicitlyTaggedType(1,
592
-                $this->_issuerUniqueID->toASN1());
593
-        }
594
-        if (isset($this->_subjectUniqueID)) {
595
-            $elements[] = new ImplicitlyTaggedType(2,
596
-                $this->_subjectUniqueID->toASN1());
597
-        }
598
-        if (count($this->_extensions)) {
599
-            $elements[] = new ExplicitlyTaggedType(3,
600
-                $this->_extensions->toASN1());
601
-        }
602
-        return new Sequence(...$elements);
603
-    }
604
-
605
-    /**
606
-     * Create signed certificate.
607
-     *
608
-     * @param SignatureAlgorithmIdentifier $algo         Algorithm used for signing
609
-     * @param PrivateKeyInfo               $privkey_info Private key used for signing
610
-     * @param null|Crypto                  $crypto       Crypto engine, use default if not set
611
-     *
612
-     * @return Certificate
613
-     */
614
-    public function sign(SignatureAlgorithmIdentifier $algo,
615
-        PrivateKeyInfo $privkey_info, ?Crypto $crypto = null): Certificate
616
-    {
617
-        $crypto = $crypto ?? Crypto::getDefault();
618
-        $tbs_cert = clone $this;
619
-        if (!isset($tbs_cert->_version)) {
620
-            $tbs_cert->_version = $tbs_cert->_determineVersion();
621
-        }
622
-        if (!isset($tbs_cert->_serialNumber)) {
623
-            $tbs_cert->_serialNumber = strval(0);
624
-        }
625
-        $tbs_cert->_signature = $algo;
626
-        $data = $tbs_cert->toASN1()->toDER();
627
-        $signature = $crypto->sign($data, $privkey_info, $algo);
628
-        return new Certificate($tbs_cert, $algo, $signature);
629
-    }
630
-
631
-    /**
632
-     * Determine minimum version for the certificate.
633
-     *
634
-     * @return int
635
-     */
636
-    protected function _determineVersion(): int
637
-    {
638
-        // if extensions are present
639
-        if (count($this->_extensions)) {
640
-            return self::VERSION_3;
641
-        }
642
-        // if UniqueIdentifier is present
643
-        if (isset($this->_issuerUniqueID) || isset($this->_subjectUniqueID)) {
644
-            return self::VERSION_2;
645
-        }
646
-        return self::VERSION_1;
647
-    }
30
+	// Certificate version enumerations
31
+	const VERSION_1 = 0;
32
+	const VERSION_2 = 1;
33
+	const VERSION_3 = 2;
34
+
35
+	/**
36
+	 * Certificate version.
37
+	 *
38
+	 * @var null|int
39
+	 */
40
+	protected $_version;
41
+
42
+	/**
43
+	 * Serial number.
44
+	 *
45
+	 * @var null|string
46
+	 */
47
+	protected $_serialNumber;
48
+
49
+	/**
50
+	 * Signature algorithm.
51
+	 *
52
+	 * @var null|SignatureAlgorithmIdentifier
53
+	 */
54
+	protected $_signature;
55
+
56
+	/**
57
+	 * Certificate issuer.
58
+	 *
59
+	 * @var Name
60
+	 */
61
+	protected $_issuer;
62
+
63
+	/**
64
+	 * Certificate validity period.
65
+	 *
66
+	 * @var Validity
67
+	 */
68
+	protected $_validity;
69
+
70
+	/**
71
+	 * Certificate subject.
72
+	 *
73
+	 * @var Name
74
+	 */
75
+	protected $_subject;
76
+
77
+	/**
78
+	 * Subject public key.
79
+	 *
80
+	 * @var PublicKeyInfo
81
+	 */
82
+	protected $_subjectPublicKeyInfo;
83
+
84
+	/**
85
+	 * Issuer unique identifier.
86
+	 *
87
+	 * @var null|UniqueIdentifier
88
+	 */
89
+	protected $_issuerUniqueID;
90
+
91
+	/**
92
+	 * Subject unique identifier.
93
+	 *
94
+	 * @var null|UniqueIdentifier
95
+	 */
96
+	protected $_subjectUniqueID;
97
+
98
+	/**
99
+	 * Extensions.
100
+	 *
101
+	 * @var Extensions
102
+	 */
103
+	protected $_extensions;
104
+
105
+	/**
106
+	 * Constructor.
107
+	 *
108
+	 * @param Name          $subject  Certificate subject
109
+	 * @param PublicKeyInfo $pki      Subject public key
110
+	 * @param Name          $issuer   Certificate issuer
111
+	 * @param Validity      $validity Validity period
112
+	 */
113
+	public function __construct(Name $subject, PublicKeyInfo $pki, Name $issuer,
114
+		Validity $validity)
115
+	{
116
+		$this->_subject = $subject;
117
+		$this->_subjectPublicKeyInfo = $pki;
118
+		$this->_issuer = $issuer;
119
+		$this->_validity = $validity;
120
+		$this->_extensions = new Extensions();
121
+	}
122
+
123
+	/**
124
+	 * Initialize from ASN.1.
125
+	 *
126
+	 * @param Sequence $seq
127
+	 *
128
+	 * @return self
129
+	 */
130
+	public static function fromASN1(Sequence $seq): self
131
+	{
132
+		$idx = 0;
133
+		if ($seq->hasTagged(0)) {
134
+			++$idx;
135
+			$version = $seq->getTagged(0)->asExplicit()->asInteger()->intNumber();
136
+		} else {
137
+			$version = self::VERSION_1;
138
+		}
139
+		$serial = $seq->at($idx++)->asInteger()->number();
140
+		$algo = AlgorithmIdentifier::fromASN1($seq->at($idx++)->asSequence());
141
+		if (!$algo instanceof SignatureAlgorithmIdentifier) {
142
+			throw new \UnexpectedValueException(
143
+				'Unsupported signature algorithm ' . $algo->name() . '.');
144
+		}
145
+		$issuer = Name::fromASN1($seq->at($idx++)->asSequence());
146
+		$validity = Validity::fromASN1($seq->at($idx++)->asSequence());
147
+		$subject = Name::fromASN1($seq->at($idx++)->asSequence());
148
+		$pki = PublicKeyInfo::fromASN1($seq->at($idx++)->asSequence());
149
+		$tbs_cert = new self($subject, $pki, $issuer, $validity);
150
+		$tbs_cert->_version = $version;
151
+		$tbs_cert->_serialNumber = $serial;
152
+		$tbs_cert->_signature = $algo;
153
+		if ($seq->hasTagged(1)) {
154
+			$tbs_cert->_issuerUniqueID = UniqueIdentifier::fromASN1(
155
+				$seq->getTagged(1)->asImplicit(Element::TYPE_BIT_STRING)
156
+					->asBitString());
157
+		}
158
+		if ($seq->hasTagged(2)) {
159
+			$tbs_cert->_subjectUniqueID = UniqueIdentifier::fromASN1(
160
+				$seq->getTagged(2)->asImplicit(Element::TYPE_BIT_STRING)
161
+					->asBitString());
162
+		}
163
+		if ($seq->hasTagged(3)) {
164
+			$tbs_cert->_extensions = Extensions::fromASN1(
165
+				$seq->getTagged(3)->asExplicit()->asSequence());
166
+		}
167
+		return $tbs_cert;
168
+	}
169
+
170
+	/**
171
+	 * Initialize from certification request.
172
+	 *
173
+	 * Note that signature is not verified and must be done by the caller.
174
+	 *
175
+	 * @param CertificationRequest $cr
176
+	 *
177
+	 * @return self
178
+	 */
179
+	public static function fromCSR(CertificationRequest $cr): self
180
+	{
181
+		$cri = $cr->certificationRequestInfo();
182
+		$tbs_cert = new self($cri->subject(), $cri->subjectPKInfo(), new Name(),
183
+			Validity::fromStrings(null, null));
184
+		// if CSR has Extension Request attribute
185
+		if ($cri->hasAttributes()) {
186
+			$attribs = $cri->attributes();
187
+			if ($attribs->hasExtensionRequest()) {
188
+				$tbs_cert = $tbs_cert->withExtensions(
189
+					$attribs->extensionRequest()->extensions());
190
+			}
191
+		}
192
+		// add Subject Key Identifier extension
193
+		return $tbs_cert->withAdditionalExtensions(
194
+			new SubjectKeyIdentifierExtension(false,
195
+				$cri->subjectPKInfo()->keyIdentifier()));
196
+	}
197
+
198
+	/**
199
+	 * Get self with fields set from the issuer's certificate.
200
+	 *
201
+	 * Issuer shall be set to issuing certificate's subject.
202
+	 * Authority key identifier extensions shall be added with a key identifier
203
+	 * set to issuing certificate's public key identifier.
204
+	 *
205
+	 * @param Certificate $cert Issuing party's certificate
206
+	 *
207
+	 * @return self
208
+	 */
209
+	public function withIssuerCertificate(Certificate $cert): self
210
+	{
211
+		$obj = clone $this;
212
+		// set issuer DN from cert's subject
213
+		$obj->_issuer = $cert->tbsCertificate()->subject();
214
+		// add authority key identifier extension
215
+		$key_id = $cert->tbsCertificate()->subjectPublicKeyInfo()->keyIdentifier();
216
+		$obj->_extensions = $obj->_extensions->withExtensions(
217
+			new AuthorityKeyIdentifierExtension(false, $key_id));
218
+		return $obj;
219
+	}
220
+
221
+	/**
222
+	 * Get self with given version.
223
+	 *
224
+	 * If version is not set, appropriate version is automatically
225
+	 * determined during signing.
226
+	 *
227
+	 * @param int $version
228
+	 *
229
+	 * @return self
230
+	 */
231
+	public function withVersion(int $version): self
232
+	{
233
+		$obj = clone $this;
234
+		$obj->_version = $version;
235
+		return $obj;
236
+	}
237
+
238
+	/**
239
+	 * Get self with given serial number.
240
+	 *
241
+	 * @param int|string $serial Base 10 number
242
+	 *
243
+	 * @return self
244
+	 */
245
+	public function withSerialNumber($serial): self
246
+	{
247
+		$obj = clone $this;
248
+		$obj->_serialNumber = strval($serial);
249
+		return $obj;
250
+	}
251
+
252
+	/**
253
+	 * Get self with random positive serial number.
254
+	 *
255
+	 * @param int $size Number of random bytes
256
+	 *
257
+	 * @return self
258
+	 */
259
+	public function withRandomSerialNumber(int $size = 16): self
260
+	{
261
+		// ensure that first byte is always non-zero and having first bit unset
262
+		$num = gmp_init(mt_rand(1, 0x7f), 10);
263
+		for ($i = 1; $i < $size; ++$i) {
264
+			$num <<= 8;
265
+			$num += mt_rand(0, 0xff);
266
+		}
267
+		return $this->withSerialNumber(gmp_strval($num, 10));
268
+	}
269
+
270
+	/**
271
+	 * Get self with given signature algorithm.
272
+	 *
273
+	 * @param SignatureAlgorithmIdentifier $algo
274
+	 *
275
+	 * @return self
276
+	 */
277
+	public function withSignature(SignatureAlgorithmIdentifier $algo): self
278
+	{
279
+		$obj = clone $this;
280
+		$obj->_signature = $algo;
281
+		return $obj;
282
+	}
283
+
284
+	/**
285
+	 * Get self with given issuer.
286
+	 *
287
+	 * @param Name $issuer
288
+	 *
289
+	 * @return self
290
+	 */
291
+	public function withIssuer(Name $issuer): self
292
+	{
293
+		$obj = clone $this;
294
+		$obj->_issuer = $issuer;
295
+		return $obj;
296
+	}
297
+
298
+	/**
299
+	 * Get self with given validity.
300
+	 *
301
+	 * @param Validity $validity
302
+	 *
303
+	 * @return self
304
+	 */
305
+	public function withValidity(Validity $validity): self
306
+	{
307
+		$obj = clone $this;
308
+		$obj->_validity = $validity;
309
+		return $obj;
310
+	}
311
+
312
+	/**
313
+	 * Get self with given subject.
314
+	 *
315
+	 * @param Name $subject
316
+	 *
317
+	 * @return self
318
+	 */
319
+	public function withSubject(Name $subject): self
320
+	{
321
+		$obj = clone $this;
322
+		$obj->_subject = $subject;
323
+		return $obj;
324
+	}
325
+
326
+	/**
327
+	 * Get self with given subject public key info.
328
+	 *
329
+	 * @param PublicKeyInfo $pub_key_info
330
+	 *
331
+	 * @return self
332
+	 */
333
+	public function withSubjectPublicKeyInfo(PublicKeyInfo $pub_key_info): self
334
+	{
335
+		$obj = clone $this;
336
+		$obj->_subjectPublicKeyInfo = $pub_key_info;
337
+		return $obj;
338
+	}
339
+
340
+	/**
341
+	 * Get self with issuer unique ID.
342
+	 *
343
+	 * @param UniqueIdentifier $id
344
+	 *
345
+	 * @return self
346
+	 */
347
+	public function withIssuerUniqueID(UniqueIdentifier $id): self
348
+	{
349
+		$obj = clone $this;
350
+		$obj->_issuerUniqueID = $id;
351
+		return $obj;
352
+	}
353
+
354
+	/**
355
+	 * Get self with subject unique ID.
356
+	 *
357
+	 * @param UniqueIdentifier $id
358
+	 *
359
+	 * @return self
360
+	 */
361
+	public function withSubjectUniqueID(UniqueIdentifier $id): self
362
+	{
363
+		$obj = clone $this;
364
+		$obj->_subjectUniqueID = $id;
365
+		return $obj;
366
+	}
367
+
368
+	/**
369
+	 * Get self with given extensions.
370
+	 *
371
+	 * @param Extensions $extensions
372
+	 *
373
+	 * @return self
374
+	 */
375
+	public function withExtensions(Extensions $extensions): self
376
+	{
377
+		$obj = clone $this;
378
+		$obj->_extensions = $extensions;
379
+		return $obj;
380
+	}
381
+
382
+	/**
383
+	 * Get self with extensions added.
384
+	 *
385
+	 * @param Extension ...$exts One or more Extension objects
386
+	 *
387
+	 * @return self
388
+	 */
389
+	public function withAdditionalExtensions(Extension ...$exts): self
390
+	{
391
+		$obj = clone $this;
392
+		$obj->_extensions = $obj->_extensions->withExtensions(...$exts);
393
+		return $obj;
394
+	}
395
+
396
+	/**
397
+	 * Check whether version is set.
398
+	 *
399
+	 * @return bool
400
+	 */
401
+	public function hasVersion(): bool
402
+	{
403
+		return isset($this->_version);
404
+	}
405
+
406
+	/**
407
+	 * Get certificate version.
408
+	 *
409
+	 * @throws \LogicException If not set
410
+	 *
411
+	 * @return int
412
+	 */
413
+	public function version(): int
414
+	{
415
+		if (!$this->hasVersion()) {
416
+			throw new \LogicException('version not set.');
417
+		}
418
+		return $this->_version;
419
+	}
420
+
421
+	/**
422
+	 * Check whether serial number is set.
423
+	 *
424
+	 * @return bool
425
+	 */
426
+	public function hasSerialNumber(): bool
427
+	{
428
+		return isset($this->_serialNumber);
429
+	}
430
+
431
+	/**
432
+	 * Get serial number.
433
+	 *
434
+	 * @throws \LogicException If not set
435
+	 *
436
+	 * @return string Base 10 integer
437
+	 */
438
+	public function serialNumber(): string
439
+	{
440
+		if (!$this->hasSerialNumber()) {
441
+			throw new \LogicException('serialNumber not set.');
442
+		}
443
+		return $this->_serialNumber;
444
+	}
445
+
446
+	/**
447
+	 * Check whether signature algorithm is set.
448
+	 *
449
+	 * @return bool
450
+	 */
451
+	public function hasSignature(): bool
452
+	{
453
+		return isset($this->_signature);
454
+	}
455
+
456
+	/**
457
+	 * Get signature algorithm.
458
+	 *
459
+	 * @throws \LogicException If not set
460
+	 *
461
+	 * @return SignatureAlgorithmIdentifier
462
+	 */
463
+	public function signature(): SignatureAlgorithmIdentifier
464
+	{
465
+		if (!$this->hasSignature()) {
466
+			throw new \LogicException('signature not set.');
467
+		}
468
+		return $this->_signature;
469
+	}
470
+
471
+	/**
472
+	 * Get issuer.
473
+	 *
474
+	 * @return Name
475
+	 */
476
+	public function issuer(): Name
477
+	{
478
+		return $this->_issuer;
479
+	}
480
+
481
+	/**
482
+	 * Get validity period.
483
+	 *
484
+	 * @return Validity
485
+	 */
486
+	public function validity(): Validity
487
+	{
488
+		return $this->_validity;
489
+	}
490
+
491
+	/**
492
+	 * Get subject.
493
+	 *
494
+	 * @return Name
495
+	 */
496
+	public function subject(): Name
497
+	{
498
+		return $this->_subject;
499
+	}
500
+
501
+	/**
502
+	 * Get subject public key.
503
+	 *
504
+	 * @return PublicKeyInfo
505
+	 */
506
+	public function subjectPublicKeyInfo(): PublicKeyInfo
507
+	{
508
+		return $this->_subjectPublicKeyInfo;
509
+	}
510
+
511
+	/**
512
+	 * Whether issuer unique identifier is present.
513
+	 *
514
+	 * @return bool
515
+	 */
516
+	public function hasIssuerUniqueID(): bool
517
+	{
518
+		return isset($this->_issuerUniqueID);
519
+	}
520
+
521
+	/**
522
+	 * Get issuerUniqueID.
523
+	 *
524
+	 * @throws \LogicException If not set
525
+	 *
526
+	 * @return UniqueIdentifier
527
+	 */
528
+	public function issuerUniqueID(): UniqueIdentifier
529
+	{
530
+		if (!$this->hasIssuerUniqueID()) {
531
+			throw new \LogicException('issuerUniqueID not set.');
532
+		}
533
+		return $this->_issuerUniqueID;
534
+	}
535
+
536
+	/**
537
+	 * Whether subject unique identifier is present.
538
+	 *
539
+	 * @return bool
540
+	 */
541
+	public function hasSubjectUniqueID(): bool
542
+	{
543
+		return isset($this->_subjectUniqueID);
544
+	}
545
+
546
+	/**
547
+	 * Get subjectUniqueID.
548
+	 *
549
+	 * @throws \LogicException If not set
550
+	 *
551
+	 * @return UniqueIdentifier
552
+	 */
553
+	public function subjectUniqueID(): UniqueIdentifier
554
+	{
555
+		if (!$this->hasSubjectUniqueID()) {
556
+			throw new \LogicException('subjectUniqueID not set.');
557
+		}
558
+		return $this->_subjectUniqueID;
559
+	}
560
+
561
+	/**
562
+	 * Get extensions.
563
+	 *
564
+	 * @return Extensions
565
+	 */
566
+	public function extensions(): Extensions
567
+	{
568
+		return $this->_extensions;
569
+	}
570
+
571
+	/**
572
+	 * Generate ASN.1 structure.
573
+	 *
574
+	 * @return Sequence
575
+	 */
576
+	public function toASN1(): Sequence
577
+	{
578
+		$elements = [];
579
+		$version = $this->version();
580
+		// if version is not default
581
+		if (self::VERSION_1 != $version) {
582
+			$elements[] = new ExplicitlyTaggedType(0, new Integer($version));
583
+		}
584
+		$serial = $this->serialNumber();
585
+		$signature = $this->signature();
586
+		// add required elements
587
+		array_push($elements, new Integer($serial), $signature->toASN1(),
588
+			$this->_issuer->toASN1(), $this->_validity->toASN1(),
589
+			$this->_subject->toASN1(), $this->_subjectPublicKeyInfo->toASN1());
590
+		if (isset($this->_issuerUniqueID)) {
591
+			$elements[] = new ImplicitlyTaggedType(1,
592
+				$this->_issuerUniqueID->toASN1());
593
+		}
594
+		if (isset($this->_subjectUniqueID)) {
595
+			$elements[] = new ImplicitlyTaggedType(2,
596
+				$this->_subjectUniqueID->toASN1());
597
+		}
598
+		if (count($this->_extensions)) {
599
+			$elements[] = new ExplicitlyTaggedType(3,
600
+				$this->_extensions->toASN1());
601
+		}
602
+		return new Sequence(...$elements);
603
+	}
604
+
605
+	/**
606
+	 * Create signed certificate.
607
+	 *
608
+	 * @param SignatureAlgorithmIdentifier $algo         Algorithm used for signing
609
+	 * @param PrivateKeyInfo               $privkey_info Private key used for signing
610
+	 * @param null|Crypto                  $crypto       Crypto engine, use default if not set
611
+	 *
612
+	 * @return Certificate
613
+	 */
614
+	public function sign(SignatureAlgorithmIdentifier $algo,
615
+		PrivateKeyInfo $privkey_info, ?Crypto $crypto = null): Certificate
616
+	{
617
+		$crypto = $crypto ?? Crypto::getDefault();
618
+		$tbs_cert = clone $this;
619
+		if (!isset($tbs_cert->_version)) {
620
+			$tbs_cert->_version = $tbs_cert->_determineVersion();
621
+		}
622
+		if (!isset($tbs_cert->_serialNumber)) {
623
+			$tbs_cert->_serialNumber = strval(0);
624
+		}
625
+		$tbs_cert->_signature = $algo;
626
+		$data = $tbs_cert->toASN1()->toDER();
627
+		$signature = $crypto->sign($data, $privkey_info, $algo);
628
+		return new Certificate($tbs_cert, $algo, $signature);
629
+	}
630
+
631
+	/**
632
+	 * Determine minimum version for the certificate.
633
+	 *
634
+	 * @return int
635
+	 */
636
+	protected function _determineVersion(): int
637
+	{
638
+		// if extensions are present
639
+		if (count($this->_extensions)) {
640
+			return self::VERSION_3;
641
+		}
642
+		// if UniqueIdentifier is present
643
+		if (isset($this->_issuerUniqueID) || isset($this->_subjectUniqueID)) {
644
+			return self::VERSION_2;
645
+		}
646
+		return self::VERSION_1;
647
+	}
648 648
 }
Please login to merge, or discard this patch.