From 7ea82c5013ab3c3d44b4b85cf767559e7019854f Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Tue, 12 Jul 2016 17:25:28 +0300 Subject: Add --cert-* rep-info command options --- bpkg/auth | 8 ++++++ bpkg/auth.cxx | 11 ++++++++ bpkg/openssl.cxx | 1 - bpkg/rep-info.cli | 38 ++++++++++++++++++++++---- bpkg/rep-info.cxx | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- tests/test.sh | 8 ++++++ 6 files changed, 140 insertions(+), 7 deletions(-) diff --git a/bpkg/auth b/bpkg/auth index 3d1ff65..a608667 100644 --- a/bpkg/auth +++ b/bpkg/auth @@ -91,6 +91,14 @@ namespace bpkg const string& key_name, // --key option value const string& cert_pem, const dir_path& repository); + + // Parse a repository certificate. The repository location argument is used + // for diagnostics only. + // + shared_ptr + parse_certificate (const common_options&, + const string& cert_pem, + const repository_location&); } #endif // BPKG_AUTH diff --git a/bpkg/auth.cxx b/bpkg/auth.cxx index 673e3ec..c152834 100644 --- a/bpkg/auth.cxx +++ b/bpkg/auth.cxx @@ -844,4 +844,15 @@ namespace bpkg throw failed (); } + + shared_ptr + parse_certificate (const common_options& co, + const string& cert_pem, + const repository_location& rl) + { + return parse_cert (co, + real_fingerprint (co, cert_pem, rl), + cert_pem, + rl.canonical_name ()); + } } diff --git a/bpkg/openssl.cxx b/bpkg/openssl.cxx index 67500b6..4e795cb 100644 --- a/bpkg/openssl.cxx +++ b/bpkg/openssl.cxx @@ -5,7 +5,6 @@ #include #include -#include #include diff --git a/bpkg/rep-info.cli b/bpkg/rep-info.cli index 5fa5d3d..faa6456 100644 --- a/bpkg/rep-info.cli +++ b/bpkg/rep-info.cli @@ -21,10 +21,14 @@ namespace bpkg The \cb{rep-info} command prints various information about the specified repository. By default it print the repository's name and location as the - first line followed by the list of complement and prerequisite - repositories and the list of available packages. This default behavior, - however, can be altered in various ways using options listed below. Note - that the information is written to \cb{STDOUT}, not \cb{STDERR}. + first line. If the repository is signed, the certificate information + (name/organization/email) is printed as the next line following by the + certificate fingerprint. Then comes the list of complement and + prerequisite repositories followed by the list of available packages. + + This default format can be altered in various ways using options listed + below. Note also that the information is written to \cb{STDOUT}, not + \cb{STDERR}. If the current working directory contains a \cb{bpkg} configuration, then \cb{rep-info} will use its certificate database for the repository @@ -42,7 +46,31 @@ namespace bpkg bool --name|-n { - "Print the specified repository's name and location." + "Print the repository's name and location." + } + + bool --cert-fingerprint + { + "Print the repository's certificate fingerprint or empty line if the + repository is unsigned." + } + + bool --cert-name + { + "Print the repository's certificate common name (CN) or empty line if + the repository is unsigned." + } + + bool --cert-organization + { + "Print the repository's certificate organization name (O) or empty line + if the repository is unsigned." + } + + bool --cert-email + { + "Print the repository's certificate email or empty line if the + repository is unsigned." } bool --repositories|-r diff --git a/bpkg/rep-info.cxx b/bpkg/rep-info.cxx index 9cad4fd..765bc70 100644 --- a/bpkg/rep-info.cxx +++ b/bpkg/rep-info.cxx @@ -6,6 +6,8 @@ #include // cout +#include // sha256_to_fingerprint() + #include #include @@ -94,7 +96,15 @@ namespace bpkg // Now print. // - bool all (!o.name () && !o.repositories () && !o.packages ()); + bool cert_info (o.cert_fingerprint () || + o.cert_name () || + o.cert_organization () || + o.cert_email ()); + + bool all (!o.name () && + !o.repositories () && + !o.packages () && + !cert_info); try { @@ -103,6 +113,75 @@ namespace bpkg if (all || o.name ()) cout << rl.canonical_name () << " " << rl << endl; + // Certificate. + // + if (all || cert_info) + { + if (cert_pem) + { + // Repository is signed. If we got the repository certificate as the + // result of authentication then use it for printing as well. + // Otherwise parse it's PEM representation. + // + if (cert == nullptr) + cert = parse_certificate (o, *cert_pem, rl); + else + assert (!cert->dummy ()); + } + else if (cert != nullptr) + { + // Reset the dummy certificate pointer that we got as a result of + // the unsigned repository authentication. + // + assert (cert->dummy ()); + cert = nullptr; + } + + if (all) + { + // Print in the human-friendly format (nothing for an unsigned + // repository). + // + if (cert != nullptr) + cout << "CN=" << cert->name << "/O=" << cert->organization << + "/" << cert->email << endl + << sha256_to_fingerprint (cert->fingerprint) << endl; + } + else + { + // Print in the structured format if any of --cert-* options are + // specified. Print empty lines for an unsigned repository. + // + if (o.cert_fingerprint ()) + { + if (cert != nullptr) + cout << sha256_to_fingerprint (cert->fingerprint); + cout << endl; + } + + if (o.cert_name ()) + { + if (cert != nullptr) + cout << "name:" << cert->name; + cout << endl; + } + + if (o.cert_organization ()) + { + if (cert != nullptr) + cout << cert->organization; + cout << endl; + } + + if (o.cert_email ()) + { + if (cert != nullptr) + cout << cert->email; + cout << endl; + } + } + } + // Repositories. // if (all || o.repositories ()) diff --git a/tests/test.sh b/tests/test.sh index b630bda..5f92c7c 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -1587,22 +1587,30 @@ fail rep-fetch --trust-yes # packages file signature:mismatch test cfg-create --wipe test rep-info --trust-no --trust $signed_fp -d $cfg $rep/auth/signed <