1 /** 2 * DER Encoder 3 * 4 * Copyright: 5 * (C) 1999-2007 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Botan is released under the Simplified BSD License (see LICENSE.md) 10 */ 11 module botan.asn1.der_enc; 12 13 import botan.constants; 14 import botan.asn1.asn1_obj; 15 import botan.asn1.der_enc; 16 import botan.math.bigint.bigint; 17 import botan.utils.get_byte; 18 import botan.utils.parsing; 19 import botan.utils.bit_ops; 20 import botan.utils.types; 21 import std.algorithm; 22 23 import botan.utils.types; 24 25 26 /** 27 * General DER Encoding Object 28 */ 29 struct DEREncoder 30 { 31 public: 32 Vector!ubyte getContentsUnlocked() 33 { 34 //logTrace("DEREncoder.getContentsUnlocked"); 35 return unlock(getContents()); 36 } 37 38 /* 39 * Return the encoded m_contents 40 */ 41 SecureVector!ubyte getContents() 42 { 43 if (m_subsequences.length != 0) 44 throw new InvalidState("DEREncoder: Sequence hasn't been marked done"); 45 46 return m_contents.dup; 47 } 48 49 /* 50 * Return the encoded m_contents 51 */ 52 SecureArray!ubyte getContentsRef() 53 { 54 if (m_subsequences.length != 0) 55 throw new InvalidState("DEREncoder: Sequence hasn't been marked done"); 56 57 return m_contents.dupr; 58 } 59 60 /* 61 * Start a new ASN.1 ASN1Tag.SEQUENCE/SET/EXPLICIT 62 */ 63 ref DEREncoder startCons(ASN1Tag m_type_tag, ASN1Tag m_class_tag = ASN1Tag.UNIVERSAL) 64 { 65 m_subsequences.pushBack(DERSequence(m_type_tag, m_class_tag)); 66 return this; 67 } 68 69 /* 70 * Finish the current ASN.1 ASN1Tag.SEQUENCE/SET/EXPLICIT 71 */ 72 ref DEREncoder endCons() 73 { 74 if (m_subsequences.empty) 75 throw new InvalidState("endCons: No such sequence"); 76 77 SecureVector!ubyte seq = m_subsequences[m_subsequences.length-1].getContents(); 78 m_subsequences.removeBack(); 79 rawBytes(seq); 80 return this; 81 } 82 83 /* 84 * Start a new ASN.1 EXPLICIT encoding 85 */ 86 ref DEREncoder startExplicit(ushort type_no) 87 { 88 ASN1Tag m_type_tag = cast(ASN1Tag)(type_no); 89 90 if (m_type_tag == ASN1Tag.SET) 91 throw new InternalError("DEREncoder.startExplicit(SET); cannot perform"); 92 93 return startCons(m_type_tag, ASN1Tag.CONTEXT_SPECIFIC); 94 } 95 96 /* 97 * Finish the current ASN.1 EXPLICIT encoding 98 */ 99 ref DEREncoder endExplicit() 100 { 101 return endCons(); 102 } 103 104 /* 105 * Write raw bytes into the stream 106 */ 107 ref DEREncoder rawBytes(ALLOC)(auto const ref Vector!(ubyte, ALLOC) val) 108 { 109 return rawBytes(val.ptr, val.length); 110 } 111 112 ref DEREncoder rawBytes(ALLOC)(auto const ref RefCounted!(Vector!(ubyte, ALLOC), ALLOC) val) 113 { 114 return rawBytes(val.ptr, val.length); 115 } 116 117 /* 118 * Write raw bytes into the stream 119 */ 120 ref DEREncoder rawBytes(const(ubyte)* bytes, size_t length) 121 { 122 123 if (m_subsequences.length) 124 m_subsequences[m_subsequences.length-1].addBytes(bytes, length); 125 else 126 m_contents ~= bytes[0 .. length]; 127 //logTrace("Contents appended: ", m_contents.length); 128 return this; 129 } 130 131 /* 132 * Encode a NULL object 133 */ 134 ref DEREncoder encodeNull() 135 { 136 return addObject(ASN1Tag.NULL_TAG, ASN1Tag.UNIVERSAL, null, 0); 137 } 138 139 /* 140 * DER encode a BOOLEAN 141 */ 142 ref DEREncoder encode(bool is_true) 143 { 144 return encode(is_true, ASN1Tag.BOOLEAN, ASN1Tag.UNIVERSAL); 145 } 146 147 /* 148 * DER encode a small INTEGER 149 */ 150 ref DEREncoder encode(size_t n) 151 { 152 return encode(BigInt(n), ASN1Tag.INTEGER, ASN1Tag.UNIVERSAL); 153 } 154 155 /* 156 * DER encode a small INTEGER 157 */ 158 ref DEREncoder encode()(auto const ref BigInt n) 159 { 160 return encode(n, ASN1Tag.INTEGER, ASN1Tag.UNIVERSAL); 161 } 162 163 /* 164 * DER encode an OCTET STRING or BIT STRING 165 */ 166 ref DEREncoder encode(ALLOC)(auto const ref RefCounted!(Vector!(ubyte, ALLOC), ALLOC) bytes, ASN1Tag real_type) 167 { 168 return encode(bytes.ptr, bytes.length, real_type, real_type, ASN1Tag.UNIVERSAL); 169 } 170 171 /* 172 * DER encode an OCTET STRING or BIT STRING 173 */ 174 ref DEREncoder encode(ALLOC)(auto const ref Vector!(ubyte, ALLOC) bytes, ASN1Tag real_type) 175 { 176 return encode(bytes.ptr, bytes.length, real_type, real_type, ASN1Tag.UNIVERSAL); 177 } 178 179 /* 180 * Encode this object 181 */ 182 ref DEREncoder encode(const(ubyte)* bytes, size_t length, ASN1Tag real_type) 183 { 184 return encode(bytes, length, real_type, real_type, ASN1Tag.UNIVERSAL); 185 } 186 187 /* 188 * DER encode a BOOLEAN 189 */ 190 ref DEREncoder encode(bool is_true, ASN1Tag m_type_tag, ASN1Tag m_class_tag = ASN1Tag.CONTEXT_SPECIFIC) 191 { 192 ubyte val = is_true ? 0xFF : 0x00; 193 return addObject(m_type_tag, m_class_tag, &val, 1); 194 } 195 196 /* 197 * DER encode a small INTEGER 198 */ 199 ref DEREncoder encode(size_t n, ASN1Tag m_type_tag, ASN1Tag m_class_tag = ASN1Tag.CONTEXT_SPECIFIC) 200 { 201 return encode(BigInt(n), m_type_tag, m_class_tag); 202 } 203 204 /* 205 * DER encode an INTEGER 206 */ 207 ref DEREncoder encode()(auto const ref BigInt n, ASN1Tag m_type_tag, ASN1Tag m_class_tag = ASN1Tag.CONTEXT_SPECIFIC) 208 { 209 //logTrace("Encode BigInt: ", n.toString()); 210 if (n == 0) 211 return addObject(m_type_tag, m_class_tag, 0); 212 213 bool extra_zero = (n.bits() % 8 == 0); 214 SecureVector!ubyte m_contents = SecureVector!ubyte(extra_zero + n.bytes()); 215 BigInt.encode(m_contents.ptr + extra_zero, n); 216 if (n < 0) 217 { 218 foreach (size_t i; 0 .. m_contents.length) 219 m_contents[i] = ~m_contents[i]; 220 for (size_t i = m_contents.length; i > 0; --i) 221 if (++(m_contents[i-1])) 222 break; 223 } 224 225 return addObject(m_type_tag, m_class_tag, m_contents); 226 } 227 228 /* 229 * DER encode an OCTET STRING or BIT STRING 230 */ 231 ref DEREncoder encode(ALLOC)(auto const ref RefCounted!(Vector!(ubyte, ALLOC), ALLOC) bytes, 232 ASN1Tag real_type, 233 ASN1Tag m_type_tag, ASN1Tag m_class_tag = ASN1Tag.CONTEXT_SPECIFIC) 234 { 235 return encode(bytes.ptr, bytes.length, real_type, m_type_tag, m_class_tag); 236 } 237 238 /* 239 * DER encode an OCTET STRING or BIT STRING 240 */ 241 ref DEREncoder encode(ALLOC)(auto const ref Vector!(ubyte, ALLOC) bytes, 242 ASN1Tag real_type, 243 ASN1Tag m_type_tag, ASN1Tag m_class_tag = ASN1Tag.CONTEXT_SPECIFIC) 244 { 245 return encode(bytes.ptr, bytes.length, real_type, m_type_tag, m_class_tag); 246 } 247 248 /* 249 * DER encode an OCTET STRING or BIT STRING 250 */ 251 ref DEREncoder encode(const(ubyte)* bytes, size_t length, 252 ASN1Tag real_type, 253 ASN1Tag m_type_tag, ASN1Tag m_class_tag = ASN1Tag.CONTEXT_SPECIFIC) 254 { 255 if (real_type != ASN1Tag.OCTET_STRING && real_type != ASN1Tag.BIT_STRING) 256 throw new InvalidArgument("DEREncoder: Invalid tag for ubyte/bit string"); 257 258 if (real_type == ASN1Tag.BIT_STRING) 259 { 260 SecureVector!ubyte encoded; 261 encoded.pushBack(0); 262 encoded ~= bytes[0 .. length]; 263 return addObject(m_type_tag, m_class_tag, encoded); 264 } 265 else 266 return addObject(m_type_tag, m_class_tag, bytes, length); 267 } 268 269 /* 270 * Request for an object to encode itself 271 */ 272 ref DEREncoder encode(T)(auto const ref T obj) 273 { 274 obj.encodeInto(this); 275 return this; 276 } 277 278 /* 279 * Conditionally write some values to the stream 280 */ 281 ref DEREncoder encodeIf (bool cond, ref DEREncoder codec) 282 { 283 if (cond) 284 return rawBytes(codec.getContents()); 285 return this; 286 } 287 288 ref DEREncoder encodeIf(T)(bool cond, auto const ref T obj) 289 { 290 if (cond) 291 encode(obj); 292 return this; 293 } 294 295 ref DEREncoder encodeOptional(T)(in T value, in T default_value = T.init) 296 { 297 if (value != default_value) 298 encode(value); 299 return this; 300 } 301 302 ref DEREncoder encodeList(T, Alloc)(const ref Vector!(T, Alloc) values) 303 { 304 foreach (const ref value; values[]) 305 encode(value); 306 return this; 307 } 308 309 /* 310 * Write the encoding of the ubyte(s) 311 */ 312 ref DEREncoder addObject(ASN1Tag m_type_tag, ASN1Tag m_class_tag, in string rep_str) 313 { 314 const(ubyte)* rep = cast(const(ubyte)*)(rep_str.ptr); 315 const size_t rep_len = rep_str.length; 316 return addObject(m_type_tag, m_class_tag, rep, rep_len); 317 } 318 319 /* 320 * Write the encoding of the ubyte(s) 321 */ 322 ref DEREncoder addObject(ASN1Tag m_type_tag, ASN1Tag m_class_tag, const(ubyte)* rep, size_t length) 323 { 324 //logTrace("AddObject: ", m_type_tag); 325 SecureVector!ubyte buffer; 326 auto enc_tag = encodeTag(m_type_tag, m_class_tag); 327 auto enc_len = encodeLength(length); 328 buffer ~= enc_tag[]; 329 buffer ~= enc_len[]; 330 buffer ~= rep[0 .. length]; 331 //logTrace("Finish Add object"); 332 333 return rawBytes(buffer); 334 } 335 336 /* 337 * Write the encoding of the ubyte 338 */ 339 ref DEREncoder addObject(ASN1Tag m_type_tag, ASN1Tag m_class_tag, ubyte rep) 340 { 341 return addObject(m_type_tag, m_class_tag, &rep, 1); 342 } 343 344 345 ref DEREncoder addObject(ALLOC)(ASN1Tag m_type_tag, ASN1Tag m_class_tag, 346 auto const ref RefCounted!(Vector!(ubyte, ALLOC), ALLOC) rep) 347 { 348 return addObject(m_type_tag, m_class_tag, rep.ptr, rep.length); 349 } 350 351 ref DEREncoder addObject(ALLOC)(ASN1Tag m_type_tag, ASN1Tag m_class_tag, 352 auto const ref Vector!(ubyte, ALLOC) rep) 353 { 354 return addObject(m_type_tag, m_class_tag, rep.ptr, rep.length); 355 } 356 private: 357 alias DERSequence = RefCounted!DERSequenceImpl; 358 class DERSequenceImpl 359 { 360 public: 361 /* 362 * Return the type and class taggings 363 */ 364 const(ASN1Tag) tagOf() const 365 { 366 return m_type_tag | m_class_tag; 367 } 368 369 /* 370 * Return the encoded ASN1Tag.SEQUENCE/SET 371 */ 372 SecureVector!ubyte getContents() 373 { 374 //logTrace("Get Contents real class tag: ", m_class_tag); 375 const ASN1Tag real_class_tag = m_class_tag | ASN1Tag.CONSTRUCTED; 376 377 if (m_type_tag == ASN1Tag.SET) 378 { // TODO: check if sort works 379 auto set_contents = m_set_contents[]; 380 //logTrace("set contents before: ", set_contents[]); 381 sort!("a < b", SwapStrategy.stable)(set_contents); 382 //logTrace("set contents after: ", set_contents[]); 383 foreach (SecureArray!ubyte data; set_contents) 384 m_contents ~= data[]; 385 386 m_set_contents.clear(); 387 } 388 389 SecureVector!ubyte result; 390 auto enc_tag = encodeTag(m_type_tag, real_class_tag); 391 auto enc_len = encodeLength(m_contents.length); 392 result ~= enc_tag[]; 393 result ~= enc_len[]; 394 result ~= m_contents[]; 395 m_contents.clear(); 396 397 return result.move(); 398 } 399 400 /* 401 * Add an encoded value to the ASN1Tag.SEQUENCE/SET 402 */ 403 void addBytes(const(ubyte)* data, size_t length) 404 { 405 if (m_type_tag == ASN1Tag.SET) 406 m_set_contents.pushBack(SecureArray!ubyte(data[0 .. length])); 407 else 408 m_contents ~= data[0 .. length]; 409 } 410 411 /* 412 * DERSequence Constructor 413 */ 414 this(ASN1Tag t1, ASN1Tag t2) 415 { 416 m_type_tag = t1; 417 m_class_tag = t2; 418 } 419 420 private: 421 422 ASN1Tag m_type_tag; 423 ASN1Tag m_class_tag; 424 SecureVector!ubyte m_contents; 425 Vector!( SecureArray!ubyte ) m_set_contents; 426 } 427 428 SecureArray!ubyte m_contents; 429 Array!DERSequence m_subsequences; 430 } 431 432 /* 433 * DER encode an ASN.1 type tag 434 */ 435 SecureArray!ubyte encodeTag(ASN1Tag m_type_tag, ASN1Tag m_class_tag) 436 { 437 //logTrace("Encode type: ", m_type_tag); 438 //logTrace("Encode class: ", m_class_tag); 439 //assert(m_type_tag != 33 || m_class_tag != cast(ASN1Tag)96); 440 if ((m_class_tag | 0xE0) != 0xE0) 441 throw new EncodingError("DEREncoder: Invalid class tag " ~ to!string(m_class_tag)); 442 443 SecureArray!ubyte encoded_tag; 444 if (m_type_tag <= 30) 445 encoded_tag.pushBack(cast(ubyte) (m_type_tag | m_class_tag)); 446 else 447 { 448 size_t blocks = highBit(m_type_tag) + 6; 449 blocks = (blocks - (blocks % 7)) / 7; 450 auto blocks_tag = cast(ubyte) (m_class_tag | 0x1F); 451 encoded_tag.pushBack(blocks_tag); 452 foreach (size_t i; 0 .. (blocks - 1)) { 453 auto blocks_i_tag = cast(ubyte) (0x80 | ((m_type_tag >> 7*(blocks-i-1)) & 0x7F)); 454 encoded_tag.pushBack(blocks_i_tag); 455 } 456 auto blocks_end_tag = cast(ubyte) (m_type_tag & 0x7F); 457 encoded_tag.pushBack(blocks_end_tag); 458 } 459 //logTrace("Encoded tag: ", cast(ubyte[]) encoded_tag[]); 460 return encoded_tag; 461 } 462 463 /* 464 * DER encode an ASN.1 length field 465 */ 466 SecureArray!ubyte encodeLength(size_t length) 467 { 468 //logTrace("Encode length: ", length); 469 SecureArray!ubyte encoded_length; 470 if (length <= 127) 471 encoded_length.pushBack(cast(ubyte)(length)); 472 else 473 { 474 const size_t top_byte = significantBytes(length); 475 476 encoded_length.pushBack(cast(ubyte)(0x80 | top_byte)); 477 478 for (size_t i = (length).sizeof - top_byte; i != (length).sizeof; ++i) 479 encoded_length.pushBack(get_byte(i, length)); 480 } 481 return encoded_length; 482 }