1 /** 2 * ASN.1 string type 3 * 4 * Copyright: 5 * (C) 1999-2010 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.asn1_str; 12 13 import botan.constants; 14 static if (BOTAN_HAS_PUBLIC_KEY_CRYPTO): 15 16 import botan.asn1.asn1_obj; 17 import botan.asn1.der_enc; 18 import botan.asn1.ber_dec; 19 import botan.utils.charset; 20 import botan.utils.parsing; 21 import botan.utils.types; 22 23 alias ASN1String = RefCounted!ASN1StringImpl; 24 25 /** 26 * Simple String 27 */ 28 final class ASN1StringImpl : ASN1Object 29 { 30 public: 31 32 /* 33 * DER encode an ASN1String 34 */ 35 override void encodeInto(ref DEREncoder encoder) const 36 { 37 string value = iso8859(); 38 if (tagging() == ASN1Tag.UTF8_STRING) 39 value = transcode(value, LATIN1_CHARSET, UTF8_CHARSET); 40 encoder.addObject(tagging(), ASN1Tag.UNIVERSAL, value); 41 } 42 43 /* 44 * Decode a BER encoded ASN1String 45 */ 46 override void decodeFrom(ref BERDecoder source) 47 { 48 BERObject obj = source.getNextObject(); 49 CharacterSet charset_is; 50 51 if (obj.type_tag == ASN1Tag.BMP_STRING) 52 charset_is = UCS2_CHARSET; 53 else if (obj.type_tag == ASN1Tag.UTF8_STRING) 54 charset_is = UTF8_CHARSET; 55 else 56 charset_is = LATIN1_CHARSET; 57 58 initialize(transcode(obj.toString(), 59 charset_is, 60 LOCAL_CHARSET), 61 obj.type_tag); 62 } 63 64 /* 65 * Return this string in local encoding 66 */ 67 string value() const 68 { 69 return transcode(m_iso_8859_str, LATIN1_CHARSET, LOCAL_CHARSET); 70 } 71 72 bool opEquals(in RefCounted!(ASN1StringImpl) other) const 73 { 74 if (m_tag != other.tagging()) return false; 75 if (m_iso_8859_str != other.iso8859()) return false; 76 return true; 77 } 78 79 /* 80 * Return this string in ISO 8859-1 encoding 81 */ 82 string iso8859() const 83 { 84 return m_iso_8859_str; 85 } 86 87 /* 88 * Return the type of this string object 89 */ 90 ASN1Tag tagging() const 91 { 92 return m_tag; 93 } 94 95 this(in string str, ASN1Tag t) 96 { 97 initialize(str, t); 98 } 99 100 this(in string str = "") 101 { 102 m_iso_8859_str = transcode(str, LOCAL_CHARSET, LATIN1_CHARSET); 103 m_tag = chooseEncoding(m_iso_8859_str, "latin1"); 104 } 105 106 107 private: 108 void initialize(in string str, ASN1Tag t) { 109 m_tag = t; 110 m_iso_8859_str = transcode(str, LOCAL_CHARSET, LATIN1_CHARSET); 111 112 if (m_tag == ASN1Tag.DIRECTORY_STRING) 113 m_tag = chooseEncoding(m_iso_8859_str, "latin1"); 114 115 if (m_tag != ASN1Tag.NUMERIC_STRING && 116 m_tag != ASN1Tag.PRINTABLE_STRING && 117 m_tag != ASN1Tag.VISIBLE_STRING && 118 m_tag != ASN1Tag.T61_STRING && 119 m_tag != ASN1Tag.IA5_STRING && 120 m_tag != ASN1Tag.UTF8_STRING && 121 m_tag != ASN1Tag.BMP_STRING) 122 throw new InvalidArgument("ASN1String: Unknown string type " ~ 123 to!string(m_tag)); 124 } 125 126 string m_iso_8859_str; 127 ASN1Tag m_tag; 128 } 129 130 /* 131 * Choose an encoding for the string 132 */ 133 ASN1Tag chooseEncoding(in string str, 134 in string type) 135 { 136 __gshared immutable bool[256] IS_PRINTABLE = [ 137 false, false, false, false, false, false, false, false, false, false, false, false, 138 false, false, false, false, false, false, false, false, false, false, false, false, 139 false, false, false, false, false, false, false, false, true, false, false, false, 140 false, false, false, false, true, true, false, true, true, true, true, true, 141 true, true, true, true, true, true, true, true, true, true, true, false, 142 false, true, false, true, false, true, true, true, true, true, true, true, 143 true, true, true, true, true, true, true, true, true, true, true, true, 144 true, true, true, true, true, true, true, false, false, false, false, false, 145 false, true, true, true, true, true, true, true, true, true, true, true, 146 true, true, true, true, true, true, true, true, true, true, true, true, 147 true, true, true, false, false, false, false, false, false, false, false, false, 148 false, false, false, false, false, false, false, false, false, false, false, false, 149 false, false, false, false, false, false, false, false, false, false, false, false, 150 false, false, false, false, false, false, false, false, false, false, false, false, 151 false, false, false, false, false, false, false, false, false, false, false, false, 152 false, false, false, false, false, false, false, false, false, false, false, false, 153 false, false, false, false, false, false, false, false, false, false, false, false, 154 false, false, false, false, false, false, false, false, false, false, false, false, 155 false, false, false, false, false, false, false, false, false, false, false, false, 156 false, false, false, false, false, false, false, false, false, false, false, false, 157 false, false, false, false, false, false, false, false, false, false, false, false, 158 false, false, false, false ]; 159 160 foreach (immutable(char) c; str) 161 { 162 if (!IS_PRINTABLE[cast(size_t) c]) 163 { 164 if (type == "utf8") return ASN1Tag.UTF8_STRING; 165 if (type == "latin1") return ASN1Tag.T61_STRING; 166 throw new InvalidArgument("chooseEncoding: Bad string type " ~ type); 167 } 168 } 169 return ASN1Tag.PRINTABLE_STRING; 170 }