aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2018-02-12 17:22:50 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2018-02-12 17:35:01 +0300
commitff06bfac111fe46f0b4453b19a7cfe2589644b87 (patch)
treef7a5646b1db002534eef857a232d30fb2795f08c
parent1ac50a35f4183cd7cd4bae0b310e20474a2d1f69 (diff)
Use abbreviated to 16 chars SHA256 fingerprint as certificate id
-rw-r--r--bpkg/auth.cxx62
-rw-r--r--bpkg/package.hxx26
-rw-r--r--bpkg/package.xml3
-rw-r--r--bpkg/rep-fetch.cxx26
-rw-r--r--bpkg/rep-info.cxx4
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<string>& 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<certificate>
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<certificate> cert (
make_shared<certificate> (
- fp,
+ fp.abbreviated,
+ fp.canonical,
move (name),
move (org),
move (email),
@@ -472,7 +484,7 @@ namespace bpkg
//
static shared_ptr<certificate>
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<certificate> cert (db.find<certificate> (fp));
+ fingerprint fp (cert_fingerprint (co, pem, rl));
+ shared_ptr<certificate> cert (db.find<certificate> (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<certificate> cert (parse_cert (co, "", cert_pem, r));
+ shared_ptr<certificate> 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/<fingerprint>.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/<id>.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 @@
</foreign-key>
</table>
<table name="certificate" kind="object">
+ <column name="id" type="TEXT" null="true"/>
<column name="fingerprint" type="TEXT" null="true"/>
<column name="name" type="TEXT" null="true"/>
<column name="organization" type="TEXT" null="true"/>
@@ -243,7 +244,7 @@
<column name="start_date" type="INTEGER" null="true"/>
<column name="end_date" type="INTEGER" null="true"/>
<primary-key>
- <column name="fingerprint"/>
+ <column name="id"/>
</primary-key>
</table>
</model>
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) ? &current_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;
}