aboutsummaryrefslogtreecommitdiff
path: root/openssl/agent/pkcs11/url.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'openssl/agent/pkcs11/url.cxx')
-rw-r--r--openssl/agent/pkcs11/url.cxx303
1 files changed, 303 insertions, 0 deletions
diff --git a/openssl/agent/pkcs11/url.cxx b/openssl/agent/pkcs11/url.cxx
new file mode 100644
index 0000000..0b9c3ac
--- /dev/null
+++ b/openssl/agent/pkcs11/url.cxx
@@ -0,0 +1,303 @@
+// file : openssl/agent/pkcs11/url.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <openssl/agent/pkcs11/url.hxx>
+
+#include <cerrno>
+#include <cstdlib> // strtoull()
+#include <iterator> // back_inserter()
+
+namespace openssl
+{
+ namespace agent
+ {
+ namespace pkcs11
+ {
+ using namespace std;
+
+ // Convenience functions.
+ //
+ static uint64_t
+ parse_uint64 (const string& s,
+ uint64_t min,
+ uint64_t max,
+ const char* what)
+ {
+ if (s[0] != '-' && s[0] != '+') // strtoull() allows these.
+ {
+ const char* b (s.c_str ());
+ char* e (nullptr);
+ uint64_t v (strtoull (b, &e, 10)); // Can't throw.
+
+ if (errno != ERANGE && e == b + s.size () && v >= min && v <= max)
+ return v;
+ }
+
+ throw invalid_argument (string ("invalid ") + what + " '" + s + "'");
+ }
+
+ // url_traits
+ //
+ optional<url_traits::scheme_type> url_traits::
+ translate_scheme (const string_type& /* url */,
+ string_type&& scheme,
+ optional<authority_type>& authority,
+ optional<path_type>& path,
+ optional<string_type>& /* query */,
+ optional<string_type>& fragment,
+ bool& rootless)
+ {
+ // If something is wrong with the URL leave the basic_url constructor
+ // to throw.
+ //
+ if (scheme.empty ())
+ return nullopt;
+
+ if (casecmp (scheme, "pkcs11") != 0)
+ throw invalid_argument ("invalid scheme");
+
+ if (authority)
+ throw invalid_argument ("unexpected authority");
+
+ if (path && (!rootless || path->find ('/') != string::npos))
+ throw invalid_argument ("one-level path expected");
+
+ if (fragment)
+ throw invalid_argument ("unexpected fragment");
+
+ return move (scheme);
+ }
+
+ url_traits::string_type url_traits::
+ translate_scheme (string_type& /* url */,
+ const scheme_type& scheme,
+ const optional<authority_type>& /* authority */,
+ const optional<path_type>& /* path */,
+ const optional<string_type>& /* query */,
+ const optional<string_type>& /* fragment */,
+ bool /* rootless */)
+ {
+ return scheme;
+ }
+
+ url_traits::path_type url_traits::
+ translate_path (string_type&& path)
+ {
+ return move (path);
+ }
+
+ url_traits::string_type url_traits::
+ translate_path (const path_type& path)
+ {
+ return path;
+ }
+
+ // library_version
+ //
+ library_version::
+ library_version (const string& s)
+ {
+ auto num = [] (const string& s, const char* what)
+ {
+ return static_cast<unsigned char> (parse_uint64 (s, 0, 255, what));
+ };
+
+ size_t p (s.find ('.'));
+
+ if (p != string::npos)
+ {
+ major = num (string (s, 0, p), "library major version");
+ minor = num (string (s, p + 1), "library minor version");
+ }
+ else
+ {
+ major = num (s, "library major version");
+ minor = 0;
+ }
+ }
+
+ // Parse the attribute name=value representation. The value can contain
+ // binary data.
+ //
+ // It would probably be cleaner to return pair<string, vector<char>>,
+ // but this would uglify a client code quite a bit and make it less
+ // efficient.
+ //
+ static pair<string, string>
+ attribute (const string& s, size_t b, size_t n)
+ {
+ size_t i (b);
+ size_t e (b + n);
+
+ for (; i != e && s[i] != '='; ++i) ;
+
+ if (i == e)
+ throw invalid_argument (
+ "no value for attribute '" + string (s, b, n) + "'");
+
+ string a;
+ url::decode (s.begin () + b, s.begin () + i, back_inserter (a));
+
+ string v;
+ url::decode (s.begin () + i + 1, s.begin () + e, back_inserter (v));
+
+ return make_pair (move (a), move (v));
+ }
+
+ // identity
+ //
+ identity::
+ identity (const url& u)
+ {
+ const optional<string>& path (u.path);
+
+ // If URL path component is absent then create the identity that
+ // matches all PKCS#11 entities in the system.
+ //
+ if (!path)
+ return;
+
+ for (size_t b (0), e (0), n; (n = next_word (*path, b, e, ';')); )
+ {
+ pair<string, string> a (attribute (*path, b, n));
+
+ const string& an (a.first);
+ string& av (a.second);
+
+ auto set = [&an] (auto& attr, auto&& val)
+ {
+ if (attr)
+ throw invalid_argument ("duplicate attribute '" + an + "'");
+
+ attr = move (val);
+ };
+
+ // Module.
+ //
+ if (an == "library-manufacturer")
+ set (library_manufacturer, move (av));
+ else if (an == "library-version")
+ set (library_version, library_version_type (av));
+ else if (an == "library-description")
+ set (library_description, move (av));
+
+ // Slot.
+ //
+ else if (an == "slot-id")
+ set (slot_id,
+ static_cast<unsigned long> (
+ parse_uint64 (av, 0, ~0UL, "slot-id attribute value")));
+ else if (an == "slot-manufacturer")
+ set (slot_manufacturer, move (av));
+ else if (an == "slot-description")
+ set (slot_description, move (av));
+
+ // Token.
+ //
+ else if (an == "serial")
+ set (serial, move (av));
+ else if (an == "token")
+ set (token, move (av));
+ else if (an == "model")
+ set (model, move (av));
+ else if (an == "manufacturer")
+ set (manufacturer, move (av));
+
+ // Storage object.
+ //
+ else if (an == "id")
+ set (id, vector<unsigned char> (av.begin (), av.end ()));
+ else if (an == "object")
+ set (object, move (av));
+ else if (an == "type")
+ set (type, move (av));
+ else
+ throw invalid_argument ("unknown attribute '" + an + "'");
+ }
+ }
+
+ // access
+ //
+ access::
+ access (const url& u)
+ {
+ const optional<string>& query (u.query);
+
+ // If URL query component is absent then create an object that
+ // provides no access attributes.
+ //
+ if (!query)
+ return;
+
+ for (size_t b (0), e (0), n; (n = next_word (*query, b, e, ';')); )
+ {
+ pair<string, string> a (attribute (*query, b, n));
+
+ const string& an (a.first);
+ string& av (a.second);
+
+ auto set = [&an] (auto& attr, auto&& val)
+ {
+ if (attr)
+ throw invalid_argument ("duplicate attribute '" + an + "'");
+
+ attr = move (val);
+ };
+
+ // Note that unrecognized attributes are ignored (see the traits
+ // class notes for details).
+ //
+ if (an == "pin-source")
+ set (pin_source, move (av));
+ else if (an == "pin-value")
+ set (pin_value, move (av));
+ else if (an == "module-name")
+ {
+ try
+ {
+ path p (av);
+
+ if (!p.empty () && p.simple ())
+ {
+ set (module_name, move (p));
+ continue;
+ }
+
+ // Fall through.
+ }
+ catch (const invalid_path& e)
+ {
+ // Fall through.
+ }
+
+ throw invalid_argument (
+ "invalid value '" + av + "' for module-name attribute");
+ }
+ else if (an == "module-path")
+ {
+ try
+ {
+ path p (move (av));
+
+ if (p.relative ())
+ throw invalid_argument ("relative path '" + p.string () +
+ "' for module-path attribute");
+
+ set (module_path, move (p));
+ }
+ catch (const invalid_path& e)
+ {
+ throw invalid_argument (
+ "invalid path '" + e.path + "' for module-path attribute");
+ }
+ }
+ }
+
+ if (pin_source && pin_value)
+ throw invalid_argument (
+ "both pin-source and pin-value attributes specified");
+ }
+ }
+ }
+}