1<?php
2/*
3 * Copyright 2008-2010 GuardTime AS
4 *
5 * This file is part of the GuardTime PHP SDK.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *     http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20/**
21 * @package asn1
22 */
23
24/**
25 * ASN.1 Tag implementation.
26 *
27 * @throws GTException
28 * @package asn1
29 */
30class ASN1Tag extends ASN1Object {
31
32    private $bytes;
33    private $object;
34
35    private $explicit = true;
36
37    /**
38     * Decodes an ASN1Tag from the given byte stream.
39     *
40     * @param  $bytes V bytes from the encoding of an ASN1Tag TLV
41     * @return void
42     */
43    public function decodeDER($bytes) {
44        $this->bytes = $bytes;
45    }
46
47    /**
48     * Encodes the contents of this ASN1Tag.
49     *
50     * @throws GTException
51     * @return array array of bytes containing the encoding of this ASN1Tag
52     * @see setExplicit
53     * @see setObject
54     */
55    public function encodeDER() {
56
57        $bytes = array();
58
59        if ($this->object != null) {
60
61            // this is for objects we have actually decoded
62            $this->append($bytes, $this->object->encodeDER());
63
64        } else if ($this->bytes != null) {
65
66            // for passthrough objects that we don't decode (like x509 certs)
67            $this->append($bytes, $this->bytes);
68
69        } else {
70
71            throw new GTException("Nothing to encode inside ASN1Tag");
72
73        }
74
75        if ($this->explicit) {
76
77            $this->prepend($bytes, ASN1DER::encodeLength(count($bytes)));
78            $this->prepend($bytes, array(0)); // placeholder
79
80        }
81
82        $tag = $this->tagValue;
83
84        if ($this->tagType == ASN1_TAG_CONSTRUCTED) {
85            $tag = $tag | 0x20;
86        }
87
88        switch ($this->tagClass) {
89
90            case ASN1_TAG_APPLICATION:
91                $tag = $tag | 0x40;
92                break;
93
94            case ASN1_TAG_PRIVATE:
95                $tag = $tag | 0xC0;
96                break;
97
98            case ASN1_TAG_CONTEXT:
99                $tag = $tag | 0x80;
100                break;
101
102        }
103
104        $bytes[0] = $tag;
105
106        return $bytes;
107
108    }
109
110    /**
111     * Return the object embedded inside this ASN.1 Tag.
112     *
113     * This method is for explicit tags only.
114     *
115     * @throws GTException
116     * @return ASN1Object object embedded inside this tag
117     */
118    public function getObject() {
119        $object = ASN1DER::decodeType($this->bytes);
120        $length = ASN1DER::decodeLength($this->bytes);
121
122        $object->decodeDER($this->readBytes($this->bytes, $length));
123
124        if (count($this->bytes) > 0) {
125            throw new GTException("Invalid explicit tag encoding with trailing bytes");
126        }
127
128        return $object;
129    }
130
131    /**
132     * Returns the object embedded inside this ASN.1 Tag.
133     *
134     * This method is for implicit tags only.
135     *
136     * @param  $tag the type of asn1 object to decode this tag as
137     * @return ASN1Object object embedded inside this tag
138     */
139    public function getObjectAs($tag) {
140
141        $tag = array($tag);
142
143        $object = ASN1DER::decodeType($tag);
144        $object->decodeDER($this->bytes);
145
146        return $object;
147    }
148
149    /**
150     * Sets the object embedded inside this ASN.1 Tag.
151     *
152     * @param  ASN1Object $object ASN1Object to embed inside this tag
153     * @return void
154     */
155    public function setObject($object) {
156        $this->object = $object;
157    }
158
159
160    /**
161     * Marks this tag as explicit.
162     *
163     * @param  $explicit boolean indicating if this tag is explicit
164     * @return void
165     */
166    public function setExplicit($explicit) {
167        $this->explicit = $explicit;
168    }
169
170    /**
171     * Checks if this tag is marked as explicit.
172     *
173     * @return bool true when this tag is explicit
174     */
175    public function isExplicit() {
176        return $this->explicit;
177    }
178
179}
180
181?>
182