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