From ff06bfac111fe46f0b4453b19a7cfe2589644b87 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Mon, 12 Feb 2018 17:22:50 +0300 Subject: Use abbreviated to 16 chars SHA256 fingerprint as certificate id --- bpkg/auth.cxx | 62 ++++++++++++++++++++++++++++++++++-------------------- bpkg/package.hxx | 26 ++++++++++++----------- bpkg/package.xml | 3 ++- bpkg/rep-fetch.cxx | 26 ----------------------- bpkg/rep-info.cxx | 4 ++-- 5 files changed, 57 insertions(+), 64 deletions(-) diff --git a/bpkg/auth.cxx b/bpkg/auth.cxx index 06555e2..ebc98b0 100644 --- a/bpkg/auth.cxx +++ b/bpkg/auth.cxx @@ -113,10 +113,15 @@ namespace bpkg return cert; } - // Calculate the real repository certificate fingerprint. Return the compact - // form (no colons, lower case). + // Calculate the real repository certificate fingerprint. // - static string + struct fingerprint + { + string canonical; // Canonical representation. + string abbreviated; // No colons, lower case, first 16 chars only. + }; + + static fingerprint real_fingerprint (const common_options& co, const string& pem, const repository_location& rl) @@ -153,7 +158,11 @@ namespace bpkg if (os.wait () && s.size () > n && s.compare (0, n, "SHA256 Fingerprint=") == 0) - return fingerprint_to_sha256 (string (s, n)); + { + string fp (s, n); + string ab (fingerprint_to_sha256 (fp, 16)); + return {move (fp), move (ab)}; + } } catch (const invalid_argument&) { @@ -182,24 +191,26 @@ namespace bpkg throw failed (); } - // Calculate the repository certificate fingerprint. Return the compact form - // (no colons, lower case). + // Calculate the repository certificate fingerprint. For dummy certificate + // only the abbreviated form is meaningful (see certificate class definition + // for details). // - static string + static fingerprint cert_fingerprint (const common_options& co, const optional& pem, const repository_location& rl) { return pem ? real_fingerprint (co, *pem, rl) - : sha256 (name_prefix (rl)).string (); + : fingerprint {string (), + sha256 (name_prefix (rl)).abbreviated_string (16)}; } // Parse the PEM-encoded certificate representation. // static shared_ptr parse_cert (const common_options& co, - const string& fp, + const fingerprint& fp, const string& pem, const string& repo) { @@ -408,7 +419,8 @@ namespace bpkg shared_ptr cert ( make_shared ( - fp, + fp.abbreviated, + fp.canonical, move (name), move (org), move (email), @@ -472,7 +484,7 @@ namespace bpkg // static shared_ptr auth_real (const common_options& co, - const string& fp, + const fingerprint& fp, const string& pem, const repository_location& rl) { @@ -485,8 +497,6 @@ namespace bpkg verify_cert (*cert, rl); - string cert_fp (sha256_to_fingerprint (cert->fingerprint)); - // @@ Is there a way to intercept CLI parsing for the specific option of // the standard type to validate/convert the value? If there were, we could // validate the option value converting fp to sha (internal representation @@ -496,7 +506,7 @@ namespace bpkg // will probably be an overkill here. // bool trust (co.trust_yes () || - co.trust ().find (cert_fp) != co.trust ().end ()); + co.trust ().find (cert->fingerprint) != co.trust ().end ()); if (trust) { @@ -517,7 +527,7 @@ namespace bpkg << cert->organization << "\" <" << cert->email << ">"; text << "certificate SHA256 fingerprint:"; - text << cert_fp; + text << cert->fingerprint; } if (co.trust_no () || !yn_prompt ("trust this certificate? [y/n]")) @@ -539,8 +549,8 @@ namespace bpkg tracer trace ("auth_cert"); tracer_guard tg (db, trace); - string fp (cert_fingerprint (co, pem, rl)); - shared_ptr cert (db.find (fp)); + fingerprint fp (cert_fingerprint (co, pem, rl)); + shared_ptr cert (db.find (fp.abbreviated)); if (cert != nullptr) { @@ -549,14 +559,17 @@ namespace bpkg return cert; } - cert = pem ? auth_real (co, fp, *pem, rl) : auth_dummy (co, fp, rl); + cert = pem + ? auth_real (co, fp, *pem, rl) + : auth_dummy (co, fp.abbreviated, rl); + db.persist (cert); // Save the certificate file. // if (pem) { - path f (conf / certs_dir / path (fp + ".pem")); + path f (conf / certs_dir / path (cert->id + ".pem")); try { @@ -596,8 +609,10 @@ namespace bpkg // If we have no configuration, go straight to authenticating a new // certificate. // - string fp (cert_fingerprint (co, pem, rl)); - r = pem ? auth_real (co, fp, *pem, rl) : auth_dummy (co, fp, rl); + fingerprint fp (cert_fingerprint (co, pem, rl)); + r = pem + ? auth_real (co, fp, *pem, rl) + : auth_dummy (co, fp.abbreviated, rl); } else if (transaction::has_current ()) { @@ -660,7 +675,7 @@ namespace bpkg } else { - f = *conf / certs_dir / path (cert.fingerprint + ".pem"); + f = *conf / certs_dir / path (cert.id + ".pem"); } // Make sure the names are either equal or the certificate name is a @@ -835,7 +850,8 @@ namespace bpkg // No sense to calculate the fingerprint for the certificate being used // just to check the expiration date. // - shared_ptr cert (parse_cert (co, "", cert_pem, r)); + shared_ptr cert ( + parse_cert (co, fingerprint (), cert_pem, r)); timestamp now (system_clock::now ()); diff --git a/bpkg/package.hxx b/bpkg/package.hxx index 322fb2b..95b1bb3 100644 --- a/bpkg/package.hxx +++ b/bpkg/package.hxx @@ -632,9 +632,8 @@ namespace bpkg // certificate // // Information extracted from a repository X.509 certificate. The actual - // certificate is stored on disk as .bpkg/certificates/.pem (we - // have to store it as a file because that's the only way to pass it to - // openssl). + // certificate is stored on disk as .bpkg/certificates/.pem (we have to + // store it as a file because that's the only way to pass it to openssl). // // If a repository is not authenticated (has no certificate/signature, // called unauth from now on), then we ask for the user's confirmation and @@ -645,15 +644,16 @@ namespace bpkg // certificate not for this specific repository location but for a // repository location only up to the version, so the name member will // contain the name prefix rather than the full name (just like a normal - // certificate would). The fingerprint member for such a dummy certificate - // contains the SHA256 checksum of this name. Members other then name and - // fingerprint are meaningless for the dummy certificate. + // certificate would). The id member for such a dummy certificate contains + // the truncated to 16 chars SHA256 checksum of this name. Members other then + // name and id are meaningless for the dummy certificate. // #pragma db object pointer(shared_ptr) session class certificate { public: - string fingerprint; // Object id (note: SHA256 fingerprint). + string id; // SHA256 fingerprint truncated to 16 characters. + string fingerprint; // Fingerprint canonical representation. string name; // CN component of Subject. string organization; // O component of Subject. @@ -673,13 +673,15 @@ namespace bpkg } public: - certificate (string f, + certificate (string i, + string f, string n, string o, string e, timestamp sd, timestamp ed) - : fingerprint (move (f)), + : id (move (i)), + fingerprint (move (f)), name (move (n)), organization (move (o)), email (move (e)), @@ -690,8 +692,8 @@ namespace bpkg // Create dummy certificate. // - certificate (string f, string n) - : fingerprint (move (f)), + certificate (string i, string n) + : id (move (i)), name (move (n)), start_date (timestamp_unknown), end_date (timestamp_unknown) @@ -700,7 +702,7 @@ namespace bpkg // Database mapping. // - #pragma db member(fingerprint) id + #pragma db member(id) id private: friend class odb::access; diff --git a/bpkg/package.xml b/bpkg/package.xml index f77653f..b012d6d 100644 --- a/bpkg/package.xml +++ b/bpkg/package.xml @@ -236,6 +236,7 @@ + @@ -243,7 +244,7 @@ - +
diff --git a/bpkg/rep-fetch.cxx b/bpkg/rep-fetch.cxx index 5566114..6ed62ab 100644 --- a/bpkg/rep-fetch.cxx +++ b/bpkg/rep-fetch.cxx @@ -99,32 +99,6 @@ namespace bpkg // // 6. Return repository and package manifest (certificate is NULL). // - // Notes: - // - // - Should we truncate sha256 hash? Maybe to 16 chars (this is what we - // use for abbreviated git commit id in the version module). Also in - // auth? Add abbreviated_string(size_t) to sha1 and sha256 classes? - // - // @@ If to truncate hash for auth, we would still need to store the full - // fingerprint in the certificate object as rep-info needs it to print. - // Leaving the certificate unchanged and truncating fingerprint on the - // fly for the file naming seems wrong (good to have the certificate - // file name to match the id). Probably it makes sense to make the - // certificate as follows: - // - // class certificate - // { - // public: - // string id; // SHA256 fingerprint truncated to 16 characters. - // - // string fingerprint; // Fingerprint canonical representation. - // ... - // }; - // - // Yes, sounds good. - // - // - // if (conf != nullptr && conf->empty ()) conf = dir_exists (bpkg_dir) ? ¤t_dir : nullptr; diff --git a/bpkg/rep-info.cxx b/bpkg/rep-info.cxx index 128951a..9fc7676 100644 --- a/bpkg/rep-info.cxx +++ b/bpkg/rep-info.cxx @@ -102,7 +102,7 @@ namespace bpkg if (cert != nullptr) cout << "CN=" << cert->name << "/O=" << cert->organization << "/" << cert->email << endl - << sha256_to_fingerprint (cert->fingerprint) << endl; + << cert->fingerprint << endl; } else { @@ -112,7 +112,7 @@ namespace bpkg if (o.cert_fingerprint ()) { if (cert != nullptr) - cout << sha256_to_fingerprint (cert->fingerprint); + cout << cert->fingerprint; cout << endl; } -- cgit v1.1