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 * @subpackage cms 23 */ 24 25/** 26 * CMS SignerInfo implementation. 27 * 28 * <pre> 29 * SignerInfo ::= SEQUENCE { 30 * version CMSVersion, 31 * sid SignerIdentifier, 32 * digestAlgorithm DigestAlgorithmIdentifier, 33 * signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL, 34 * signatureAlgorithm SignatureAlgorithmIdentifier, 35 * signature SignatureValue, 36 * unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL 37 * } 38 * </pre> 39 * 40 * @package asn1 41 * @subpackage cms 42 * 43 * @see http://tools.ietf.org/html/rfc3852#section-5.3 RFC 3852 44 */ 45class CMSSignerInfo { 46 47 private $version; 48 private $sid; 49 private $digestAlgorithm; 50 private $signedAttrs; 51 private $signatureAlgorithm; 52 private $signature; 53 private $unsignedAttrs; 54 55 /** 56 * Constructs a new instance of CMSSignerInfo. 57 */ 58 public function __construct() { 59 } 60 61 /** 62 * Decodes the given ASN1Sequence as CMSSignerInfo. 63 * 64 * @throws GTException 65 * @param ASN1Sequence $object CMSSignerInfo encoded as ASN1Sequence 66 * @return void 67 */ 68 public function decode($object) { 69 70 if (!$object instanceof ASN1Sequence) { 71 throw new GTException("Expecting an ASN1Sequence"); 72 } 73 74 $size = $object->getObjectCount(); 75 76 if ($size < 5 || $size > 7) { 77 throw new GTException("Invalid sequence size: {$size}"); 78 } 79 80 $version = $object->getObjectAt(0); 81 82 if (!$version instanceof ASN1Integer) { 83 throw new GTException("Expecting an ASN1Integer for version"); 84 } 85 86 $this->version = (int) $version->getValue(); 87 88 if ($this->version != 1) { 89 throw new GTException("Invalid version: {$this->version}"); 90 } 91 92 $sid = new CMSSignerIdentifier(); 93 $sid->decode($object->getObjectAt(1)); 94 95 $this->sid = $sid; 96 97 $digestAlgorithm = new X509AlgorithmIdentifier(); 98 $digestAlgorithm->decode($object->getObjectAt(2)); 99 100 $this->digestAlgorithm = $digestAlgorithm; 101 102 for ($i = 3; $i < $object->getObjectCount(); $i++) { 103 104 $item = $object->getObjectAt($i); 105 106 if ($item instanceof ASN1Tag) { 107 108 switch ($item->getTagValue()) { 109 110 case 0: 111 112 $this->signedAttrs = array(); 113 114 $items = $item->getObjectAs(ASN1_TAG_SET); 115 116 foreach ($items->getObjects() as $a) { 117 118 $attribute = new CMSAttribute(); 119 $attribute->decode($a); 120 121 array_push($this->signedAttrs, $attribute); 122 } 123 124 break; 125 126 case 1: 127 128 $this->unsignedAttrs = array(); 129 130 $items = $item->getObjectAs(ASN1_TAG_SET); 131 132 foreach ($items->getObjects() as $a) { 133 134 $attribute = new CMSAttribute(); 135 $attribute->decode($a); 136 137 array_push($this->unsignedAttrs, $attribute); 138 } 139 140 break; 141 142 default: 143 144 throw new GTException("Unsupported TAG value: " . $item->getTagValue()); 145 146 } 147 148 } else if ($item instanceof ASN1Sequence) { 149 150 // signature algorithm 151 $signatureAlgorithm = new X509AlgorithmIdentifier(); 152 $signatureAlgorithm->decode($item); 153 $this->signatureAlgorithm = $signatureAlgorithm; 154 155 } else if ($item instanceof ASN1OctetString) { 156 157 // signature 158 $this->signature = $item->getValue(); 159 160 } else { 161 162 throw new GTException("Unexpected ASN.1 TYPE: " . get_class($item)); 163 } 164 165 } 166 167 if ($this->signature === null) { 168 throw new GTException("Signature missing"); 169 } 170 171 if ($this->signatureAlgorithm === null) { 172 throw new GTException("Signature algorithm missing"); 173 } 174 175 } 176 177 /** 178 * Encodes this CMSSignerInfo using DER. 179 * 180 * @return array byte array that contains the DER encoding of this CMSSignerInfo 181 */ 182 public function encodeDER() { 183 184 $sequence = new ASN1Sequence(); 185 186 $sequence->add(new ASN1Integer((int) $this->version)); 187 $sequence->add($this->sid); 188 $sequence->add($this->digestAlgorithm); 189 190 if (!empty($this->signedAttrs)) { 191 192 $signed = new ASN1Set(); 193 194 foreach ($this->signedAttrs as $attr) { 195 $signed->add($attr); 196 } 197 198 $tag = new ASN1Tag(); 199 $tag->setExplicit(false); 200 $tag->setTagType(ASN1_TAG_CONSTRUCTED); 201 $tag->setTagClass(ASN1_TAG_CONTEXT); 202 $tag->setTagValue(0); 203 $tag->setObject($signed); 204 205 $sequence->add($tag); 206 207 } 208 209 $sequence->add($this->signatureAlgorithm); 210 $sequence->add(new ASN1OctetString($this->signature)); 211 212 if (!empty($this->unsignedAttrs)) { 213 214 $unsigned = new ASN1Set(); 215 216 foreach ($this->unsignedAttrs as $attr) { 217 $unsigned->add($attr); 218 } 219 220 $tag = new ASN1Tag(); 221 $tag->setExplicit(false); 222 $tag->setTagType(ASN1_TAG_CONSTRUCTED); 223 $tag->setTagClass(ASN1_TAG_CONTEXT); 224 $tag->setTagValue(1); 225 $tag->setObject($unsigned); 226 227 $sequence->add($tag); 228 229 } 230 231 return $sequence->encodeDER(); 232 233 } 234 235 /** 236 * Gets the sid. 237 * 238 * @return CMSSignerIdentifier sid 239 */ 240 public function getSid() { 241 return $this->sid; 242 } 243 244 /** 245 * Gets the signature. 246 * 247 * @return array byte array containing the signature 248 */ 249 public function getSignature() { 250 return $this->signature; 251 } 252 253 /** 254 * Sets the signature. 255 * 256 * @param $signature byte array containing the signature 257 * @return void 258 */ 259 public function setSignature($signature) { 260 261 $this->signature = $signature; 262 } 263 264 /** 265 * Gets the signature algorithm. 266 * 267 * @return X509AlgorithmIdentifier signature algorithm 268 */ 269 public function getSignatureAlgorithm() { 270 return $this->signatureAlgorithm; 271 } 272 273 /** 274 * Gets the digest algorithm. 275 * 276 * @return X509AlgorithmIdentifier digest algorithm 277 */ 278 public function getDigestAlgorithm() { 279 return $this->digestAlgorithm; 280 } 281 282 /** 283 * Gets the signet attributes. 284 * 285 * @return array array containing CMSAttribute instances 286 */ 287 public function getSignedAttrs() { 288 return $this->signedAttrs; 289 } 290 291 /** 292 * Gets the unsigned attributes. 293 * 294 * @return array array containing CMSAttribute instances 295 */ 296 public function getUnsignedAttrs() { 297 return $this->unsignedAttrs; 298 } 299} 300 301?> 302