Botan  1.11.15
src/lib/base/scan_name.cpp
Go to the documentation of this file.
00001 /*
00002 * SCAN Name Abstraction
00003 * (C) 2008-2009,2015 Jack Lloyd
00004 *
00005 * Botan is released under the Simplified BSD License (see license.txt)
00006 */
00007 
00008 #include <botan/scan_name.h>
00009 #include <botan/parsing.h>
00010 #include <botan/exceptn.h>
00011 #include <stdexcept>
00012 
00013 namespace Botan {
00014 
00015 namespace {
00016 
00017 std::string make_arg(
00018    const std::vector<std::pair<size_t, std::string> >& name, size_t start)
00019    {
00020    std::string output = name[start].second;
00021    size_t level = name[start].first;
00022 
00023    size_t paren_depth = 0;
00024 
00025    for(size_t i = start + 1; i != name.size(); ++i)
00026       {
00027       if(name[i].first <= name[start].first)
00028          break;
00029 
00030       if(name[i].first > level)
00031          {
00032          output += '(' + name[i].second;
00033          ++paren_depth;
00034          }
00035       else if(name[i].first < level)
00036          {
00037          output += ")," + name[i].second;
00038          --paren_depth;
00039          }
00040       else
00041          {
00042          if(output[output.size() - 1] != '(')
00043             output += ",";
00044          output += name[i].second;
00045          }
00046 
00047       level = name[i].first;
00048       }
00049 
00050    for(size_t i = 0; i != paren_depth; ++i)
00051       output += ')';
00052 
00053    return output;
00054    }
00055 
00056 std::pair<size_t, std::string>
00057 deref_aliases(const std::pair<size_t, std::string>& in)
00058    {
00059    return std::make_pair(in.first,
00060                          SCAN_Name::deref_alias(in.second));
00061    }
00062 
00063 }
00064 
00065 SCAN_Name::SCAN_Name(std::string algo_spec, const std::string& extra) : SCAN_Name(algo_spec)
00066    {
00067    alg_name += extra;
00068    }
00069 
00070 SCAN_Name::SCAN_Name(const char* algo_spec) : SCAN_Name(std::string(algo_spec))
00071    {
00072    }
00073 
00074 SCAN_Name::SCAN_Name(std::string algo_spec)
00075    {
00076    orig_algo_spec = algo_spec;
00077 
00078    std::vector<std::pair<size_t, std::string> > name;
00079    size_t level = 0;
00080    std::pair<size_t, std::string> accum = std::make_pair(level, "");
00081 
00082    const std::string decoding_error = "Bad SCAN name '" + algo_spec + "': ";
00083 
00084    algo_spec = SCAN_Name::deref_alias(algo_spec);
00085 
00086    for(size_t i = 0; i != algo_spec.size(); ++i)
00087       {
00088       char c = algo_spec[i];
00089 
00090       if(c == '/' || c == ',' || c == '(' || c == ')')
00091          {
00092          if(c == '(')
00093             ++level;
00094          else if(c == ')')
00095             {
00096             if(level == 0)
00097                throw Decoding_Error(decoding_error + "Mismatched parens");
00098             --level;
00099             }
00100 
00101          if(c == '/' && level > 0)
00102             accum.second.push_back(c);
00103          else
00104             {
00105             if(accum.second != "")
00106                name.push_back(deref_aliases(accum));
00107             accum = std::make_pair(level, "");
00108             }
00109          }
00110       else
00111          accum.second.push_back(c);
00112       }
00113 
00114    if(accum.second != "")
00115       name.push_back(deref_aliases(accum));
00116 
00117    if(level != 0)
00118       throw Decoding_Error(decoding_error + "Missing close paren");
00119 
00120    if(name.size() == 0)
00121       throw Decoding_Error(decoding_error + "Empty name");
00122 
00123    alg_name = name[0].second;
00124 
00125    bool in_modes = false;
00126 
00127    for(size_t i = 1; i != name.size(); ++i)
00128       {
00129       if(name[i].first == 0)
00130          {
00131          mode_info.push_back(make_arg(name, i));
00132          in_modes = true;
00133          }
00134       else if(name[i].first == 1 && !in_modes)
00135          args.push_back(make_arg(name, i));
00136       }
00137    }
00138 
00139 std::string SCAN_Name::all_arguments() const
00140    {
00141    std::string out;
00142    if(arg_count())
00143       {
00144       out += '(';
00145       for(size_t i = 0; i != arg_count(); ++i)
00146          {
00147          out += arg(i);
00148          if(i != arg_count() - 1)
00149             out += ',';
00150          }
00151       out += ')';
00152       }
00153    return out;
00154    }
00155 
00156 std::string SCAN_Name::arg(size_t i) const
00157    {
00158    if(i >= arg_count())
00159       throw std::range_error("SCAN_Name::arg " + std::to_string(i) +
00160                              " out of range for '" + as_string() + "'");
00161    return args[i];
00162    }
00163 
00164 std::string SCAN_Name::arg(size_t i, const std::string& def_value) const
00165    {
00166    if(i >= arg_count())
00167       return def_value;
00168    return args[i];
00169    }
00170 
00171 size_t SCAN_Name::arg_as_integer(size_t i, size_t def_value) const
00172    {
00173    if(i >= arg_count())
00174       return def_value;
00175    return to_u32bit(args[i]);
00176    }
00177 
00178 std::mutex SCAN_Name::g_alias_map_mutex;
00179 std::map<std::string, std::string> SCAN_Name::g_alias_map = {
00180    { "3DES",            "TripleDES" },
00181    { "ARC4",            "RC4" },
00182    { "CAST5",           "CAST-128" },
00183    { "DES-EDE",         "TripleDES" },
00184    { "EME-OAEP",        "OAEP" },
00185    { "EME-PKCS1-v1_5",  "PKCS1v15" },
00186    { "EME1",            "OAEP" },
00187    { "EMSA-PKCS1-v1_5", "EMSA_PKCS1" },
00188    { "EMSA-PSS",        "PSSR" },
00189    { "EMSA2",           "EMSA_X931" },
00190    { "EMSA3",           "EMSA_PKCS1" },
00191    { "EMSA4",           "PSSR" },
00192    { "GOST-34.11",      "GOST-R-34.11-94" },
00193    { "MARK-4",          "RC4(256)" },
00194    { "OMAC",            "CMAC" },
00195    { "PSS-MGF1",        "PSSR" },
00196    { "SHA-1",           "SHA-160" },
00197    { "SHA1",            "SHA-160" },
00198    { "X9.31",           "EMSA2" }
00199 };
00200 
00201 void SCAN_Name::add_alias(const std::string& alias, const std::string& basename)
00202    {
00203    std::lock_guard<std::mutex> lock(g_alias_map_mutex);
00204 
00205    if(g_alias_map.find(alias) == g_alias_map.end())
00206       g_alias_map[alias] = basename;
00207    }
00208 
00209 std::string SCAN_Name::deref_alias(const std::string& alias)
00210    {
00211    std::lock_guard<std::mutex> lock(g_alias_map_mutex);
00212 
00213    std::string name = alias;
00214 
00215    for(auto i = g_alias_map.find(name); i != g_alias_map.end(); i = g_alias_map.find(name))
00216       name = i->second;
00217 
00218    return name;
00219    }
00220 
00221 }