/* * Parse an ASN.1 OID string */ std::vector<u32bit> parse_asn1_oid(const std::string& oid) { std::string substring; std::vector<u32bit> oid_elems; for(auto i = oid.begin(); i != oid.end(); ++i) { char c = *i; if(c == '.') { if(substring.empty()) throw Invalid_OID(oid); oid_elems.push_back(to_u32bit(substring)); substring.clear(); } else substring += c; } if(substring.empty()) throw Invalid_OID(oid); oid_elems.push_back(to_u32bit(substring)); if(oid_elems.size() < 2) throw Invalid_OID(oid); return oid_elems; }
/************************************************* * Parse an ASN.1 OID string * *************************************************/ std::vector<u32bit> parse_asn1_oid(const std::string& oid) { std::string substring; std::vector<u32bit> oid_elems; for(std::string::const_iterator j = oid.begin(); j != oid.end(); ++j) { char c = *j; if(c == '.') { if(substring == "") throw Invalid_OID(oid); oid_elems.push_back(to_u32bit(substring)); substring.clear(); } else substring += c; } if(substring == "") throw Invalid_OID(oid); oid_elems.push_back(to_u32bit(substring)); if(oid_elems.size() < 2) throw Invalid_OID(oid); return oid_elems; }
/* * Set the time with a human readable string */ void EAC_Time::set_to(const std::string& time_str) { if(time_str == "") { year = month = day = 0; return; } std::vector<std::string> params; std::string current; for(u32bit j = 0; j != time_str.size(); ++j) { if(Charset::is_digit(time_str[j])) current += time_str[j]; else { if(current != "") params.push_back(current); current.clear(); } } if(current != "") params.push_back(current); if(params.size() != 3) throw Invalid_Argument("Invalid time specification " + time_str); year = to_u32bit(params[0]); month = to_u32bit(params[1]); day = to_u32bit(params[2]); if(!passes_sanity_check()) throw Invalid_Argument("Invalid time specification " + time_str); }
/************************************************* * Convert a string into a time duration * *************************************************/ u32bit timespec_to_u32bit(const std::string& timespec) { if(timespec == "") return 0; const char suffix = timespec[timespec.size()-1]; std::string value = timespec.substr(0, timespec.size()-1); u32bit scale = 1; if(Charset::is_digit(suffix)) value += suffix; else if(suffix == 's') scale = 1; else if(suffix == 'm') scale = 60; else if(suffix == 'h') scale = 60 * 60; else if(suffix == 'd') scale = 24 * 60 * 60; else if(suffix == 'y') scale = 365 * 24 * 60 * 60; else throw Decoding_Error("timespec_to_u32bit: Bad input " + timespec); return scale * to_u32bit(value); }
/* * Get a single u32bit atom */ u32bit Data_Store::get1_u32bit(const std::string& key, u32bit default_val) const { std::vector<std::string> vals = get(key); if(vals.empty()) return default_val; else if(vals.size() > 1) throw Invalid_State("Data_Store::get1_u32bit: Multiple values for " + key); return to_u32bit(vals[0]); }
bool check_bcrypt(const std::string& pass, const std::string& hash) { if(hash.size() != 60 || hash[0] != '$' || hash[1] != '2' || hash[2] != 'a' || hash[3] != '$' || hash[6] != '$') { return false; } const u16bit workfactor = to_u32bit(hash.substr(4, 2)); const std::vector<byte> salt = bcrypt_base64_decode(hash.substr(7, 22)); if(salt.size() != 16) return false; const std::string compare = make_bcrypt(pass, salt, workfactor); return same_mem(hash.data(), compare.data(), compare.size()); }
/************************************************* * Convert a decimal-dotted string to binary IP * *************************************************/ u32bit string_to_ipv4(const std::string& str) { std::vector<std::string> parts = split_on(str, '.'); if(parts.size() != 4) throw Decoding_Error("Invalid IP string " + str); u32bit ip = 0; for(size_t j = 0; j != parts.size(); j++) { u32bit octet = to_u32bit(parts[j]); if(octet > 255) throw Decoding_Error("Invalid IP string " + str); ip = (ip << 8) | (octet & 0xFF); } return ip; }
/* * Convert a decimal-dotted string to binary IP */ u32bit string_to_ipv4(const std::string& str) { std::vector<std::string> parts = split_on(str, '.'); if(parts.size() != 4) throw Decoding_Error("Invalid IP string " + str); u32bit ip = 0; for(auto part = parts.begin(); part != parts.end(); ++part) { u32bit octet = to_u32bit(*part); if(octet > 255) throw Decoding_Error("Invalid IP string " + str); ip = (ip << 8) | (octet & 0xFF); } return ip; }
size_t SCAN_Name::arg_as_integer(size_t i, size_t def_value) const { if(i >= arg_count()) return def_value; return to_u32bit(args[i]); }
std::unique_ptr<Private_Key> create_private_key(const std::string& alg_name, RandomNumberGenerator& rng, const std::string& params, const std::string& provider) { /* * Default paramaters are chosen for work factor > 2**128 where possible */ #if defined(BOTAN_HAS_CURVE_25519) if(alg_name == "Curve25519") return std::unique_ptr<Private_Key>(new Curve25519_PrivateKey(rng)); #endif #if defined(BOTAN_HAS_RSA) if(alg_name == "RSA") { const size_t rsa_bits = (params.empty() ? 3072 : to_u32bit(params)); #if defined(BOTAN_HAS_OPENSSL) if(provider.empty() || provider == "openssl") { std::unique_ptr<Botan::Private_Key> pk; if((pk = make_openssl_rsa_private_key(rng, rsa_bits))) return pk; if(!provider.empty()) return nullptr; } #endif return std::unique_ptr<Private_Key>(new RSA_PrivateKey(rng, rsa_bits)); } #endif #if defined(BOTAN_HAS_MCELIECE) if(alg_name == "McEliece") { std::vector<std::string> mce_param = Botan::split_on(params.empty() ? "2960,57" : params, ','); if(mce_param.size() != 2) throw Invalid_Argument("create_private_key bad McEliece parameters " + params); size_t mce_n = Botan::to_u32bit(mce_param[0]); size_t mce_t = Botan::to_u32bit(mce_param[1]); return std::unique_ptr<Botan::Private_Key>(new Botan::McEliece_PrivateKey(rng, mce_n, mce_t)); } #endif #if defined(BOTAN_HAS_XMSS) if(alg_name == "XMSS") { return std::unique_ptr<Private_Key>( new XMSS_PrivateKey(XMSS_Parameters(params.empty() ? "XMSS_SHA2-512_W16_H10" : params).oid(), rng)); } #endif #if defined(BOTAN_HAS_ED25519) if(alg_name == "Ed25519") { return std::unique_ptr<Private_Key>(new Ed25519_PrivateKey(rng)); } #endif // ECC crypto #if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) if(alg_name == "ECDSA" || alg_name == "ECDH" || alg_name == "ECKCDSA" || alg_name == "ECGDSA" || alg_name == "SM2" || alg_name == "SM2_Sig" || alg_name == "SM2_Enc" || alg_name == "GOST-34.10") { const EC_Group ec_group(params.empty() ? default_ec_group_for(alg_name) : params); #if defined(BOTAN_HAS_ECDSA) if(alg_name == "ECDSA") return std::unique_ptr<Private_Key>(new ECDSA_PrivateKey(rng, ec_group)); #endif #if defined(BOTAN_HAS_ECDH) if(alg_name == "ECDH") return std::unique_ptr<Private_Key>(new ECDH_PrivateKey(rng, ec_group)); #endif #if defined(BOTAN_HAS_ECKCDSA) if(alg_name == "ECKCDSA") return std::unique_ptr<Private_Key>(new ECKCDSA_PrivateKey(rng, ec_group)); #endif #if defined(BOTAN_HAS_GOST_34_10_2001) if(alg_name == "GOST-34.10") return std::unique_ptr<Private_Key>(new GOST_3410_PrivateKey(rng, ec_group)); #endif #if defined(BOTAN_HAS_SM2) if(alg_name == "SM2" || alg_name == "SM2_Sig" || alg_name == "SM2_Enc") return std::unique_ptr<Private_Key>(new SM2_PrivateKey(rng, ec_group)); #endif #if defined(BOTAN_HAS_ECGDSA) if(alg_name == "ECGDSA") return std::unique_ptr<Private_Key>(new ECGDSA_PrivateKey(rng, ec_group)); #endif } #endif // DL crypto #if defined(BOTAN_HAS_DL_GROUP) if(alg_name == "DH" || alg_name == "DSA" || alg_name == "ElGamal") { std::string default_group = (alg_name == "DSA") ? "dsa/botan/2048" : "modp/ietf/2048"; DL_Group modp_group(params.empty() ? default_group : params); #if defined(BOTAN_HAS_DIFFIE_HELLMAN) if(alg_name == "DH") return std::unique_ptr<Private_Key>(new DH_PrivateKey(rng, modp_group)); #endif #if defined(BOTAN_HAS_DSA) if(alg_name == "DSA") return std::unique_ptr<Private_Key>(new DSA_PrivateKey(rng, modp_group)); #endif #if defined(BOTAN_HAS_ELGAMAL) if(alg_name == "ElGamal") return std::unique_ptr<Private_Key>(new ElGamal_PrivateKey(rng, modp_group)); #endif } #endif BOTAN_UNUSED(alg_name, rng, params, provider); return std::unique_ptr<Private_Key>(); }
void X509_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag) { if(spec_tag == UTC_OR_GENERALIZED_TIME) { try { set_to(t_spec, GENERALIZED_TIME); return; } catch(Invalid_Argument&) {} // Not a generalized time. Continue try { set_to(t_spec, UTC_TIME); return; } catch(Invalid_Argument&) {} // Not a UTC time. Continue throw Invalid_Argument("Time string could not be parsed as GeneralizedTime or UTCTime."); } BOTAN_ASSERT(spec_tag == UTC_TIME || spec_tag == GENERALIZED_TIME, "Invalid tag."); if(t_spec.empty()) throw Invalid_Argument("Time string must not be empty."); if(t_spec.back() != 'Z') throw Unsupported_Argument("Botan does not support times with timezones other than Z: " + t_spec); if(spec_tag == GENERALIZED_TIME) { if(t_spec.size() != 15) throw Invalid_Argument("Invalid GeneralizedTime string: '" + t_spec + "'"); } else if(spec_tag == UTC_TIME) { if(t_spec.size() != 13) throw Invalid_Argument("Invalid UTCTime string: '" + t_spec + "'"); } const size_t YEAR_SIZE = (spec_tag == UTC_TIME) ? 2 : 4; std::vector<std::string> params; std::string current; for(size_t j = 0; j != YEAR_SIZE; ++j) current += t_spec[j]; params.push_back(current); current.clear(); for(size_t j = YEAR_SIZE; j != t_spec.size() - 1; ++j) { current += t_spec[j]; if(current.size() == 2) { params.push_back(current); current.clear(); } } m_year = to_u32bit(params[0]); m_month = to_u32bit(params[1]); m_day = to_u32bit(params[2]); m_hour = to_u32bit(params[3]); m_minute = to_u32bit(params[4]); m_second = (params.size() == 6) ? to_u32bit(params[5]) : 0; m_tag = spec_tag; if(spec_tag == UTC_TIME) { if(m_year >= 50) m_year += 1900; else m_year += 2000; } if(!passes_sanity_check()) throw Invalid_Argument("Time did not pass sanity check: " + t_spec); }
Response http_sync(http_exch_fn http_transact, const std::string& verb, const std::string& url, const std::string& content_type, const std::vector<byte>& body, size_t allowable_redirects) { if(url.empty()) throw HTTP_Error("URL empty"); const auto protocol_host_sep = url.find("://"); if(protocol_host_sep == std::string::npos) throw HTTP_Error("Invalid URL '" + url + "'"); const auto host_loc_sep = url.find('/', protocol_host_sep + 3); std::string hostname, loc; if(host_loc_sep == std::string::npos) { hostname = url.substr(protocol_host_sep + 3, std::string::npos); loc = "/"; } else { hostname = url.substr(protocol_host_sep + 3, host_loc_sep-protocol_host_sep-3); loc = url.substr(host_loc_sep, std::string::npos); } std::ostringstream outbuf; outbuf << verb << " " << loc << " HTTP/1.0\r\n"; outbuf << "Host: " << hostname << "\r\n"; if(verb == "GET") { outbuf << "Accept: */*\r\n"; outbuf << "Cache-Control: no-cache\r\n"; } else if(verb == "POST") outbuf << "Content-Length: " << body.size() << "\r\n"; if(!content_type.empty()) outbuf << "Content-Type: " << content_type << "\r\n"; outbuf << "Connection: close\r\n\r\n"; outbuf.write(reinterpret_cast<const char*>(body.data()), body.size()); std::istringstream io(http_transact(hostname, outbuf.str())); std::string line1; std::getline(io, line1); if(!io || line1.empty()) throw HTTP_Error("No response"); std::stringstream response_stream(line1); std::string http_version; unsigned int status_code; std::string status_message; response_stream >> http_version >> status_code; std::getline(response_stream, status_message); if(!response_stream || http_version.substr(0,5) != "HTTP/") throw HTTP_Error("Not an HTTP response"); std::map<std::string, std::string> headers; std::string header_line; while (std::getline(io, header_line) && header_line != "\r") { auto sep = header_line.find(": "); if(sep == std::string::npos || sep > header_line.size() - 2) throw HTTP_Error("Invalid HTTP header " + header_line); const std::string key = header_line.substr(0, sep); if(sep + 2 < header_line.size() - 1) { const std::string val = header_line.substr(sep + 2, (header_line.size() - 1) - (sep + 2)); headers[key] = val; } } if(status_code == 301 && headers.count("Location")) { if(allowable_redirects == 0) throw HTTP_Error("HTTP redirection count exceeded"); return GET_sync(headers["Location"], allowable_redirects - 1); } std::vector<byte> resp_body; std::vector<byte> buf(4096); while(io.good()) { io.read(reinterpret_cast<char*>(buf.data()), buf.size()); resp_body.insert(resp_body.end(), buf.data(), &buf[io.gcount()]); } const std::string header_size = search_map(headers, std::string("Content-Length")); if(!header_size.empty()) { if(resp_body.size() != to_u32bit(header_size)) throw HTTP_Error("Content-Length disagreement, header says " + header_size + " got " + std::to_string(resp_body.size())); } return Response(status_code, status_message, resp_body, headers); }