From 057a5d5d435d53166d1b8751748a9ba0a317bee3 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Fri, 29 Apr 2016 10:07:03 +0300 Subject: Add signature_manifest class --- NEWS | 7 +++- bpkg/manifest | 33 ++++++++++++++++ bpkg/manifest.cxx | 96 ++++++++++++++++++++++++++++++++++++++++++++++- tests/manifest/.gitignore | 1 + tests/manifest/buildfile | 10 +++-- tests/manifest/driver.cxx | 4 +- tests/manifest/signature | 13 +++++++ 7 files changed, 158 insertions(+), 6 deletions(-) create mode 100644 tests/manifest/signature diff --git a/NEWS b/NEWS index b1e2143..f733de5 100644 --- a/NEWS +++ b/NEWS @@ -1,10 +1,15 @@ +Version 0.4.0 + + * Add signature_manifest class. + + * Add repository_manifest::certificate. + Version 0.3.0 * Reimplement *-file manifest values as C++11 unions. * Add support for comments in the repository manifest email values. - Version 0.2.0 * First public release. diff --git a/bpkg/manifest b/bpkg/manifest index d55e714..0c9362f 100644 --- a/bpkg/manifest +++ b/bpkg/manifest @@ -588,6 +588,39 @@ namespace bpkg void serialize (manifest_serializer&) const; }; + + class signature_manifest + { + public: + // Checksum of the corresponding package_manifests. + // + std::string sha256sum; + + // Signature of the corresponding package_manifests. Calculated by + // encrypting package_manifests checksum (stored in sha256sum) with the + // repository certificate private key. + // + std::vector signature; + + public: + signature_manifest () = default; + signature_manifest (manifest_parser&, bool ignore_unknown = false); + + // Serialize sha256sum and base64-encoded representation of the signature. + // + void + serialize (manifest_serializer&) const; + + private: + // Used for delegating in public constructor. Strictly speaking is not + // required, as a signature_manifest currently never appears as a part of + // a manifest list, but kept for the consistency with other manifests + // implementations. + // + signature_manifest (manifest_parser&, + manifest_name_value start, + bool ignore_unknown); + }; } #endif // BPKG_MANIFEST diff --git a/bpkg/manifest.cxx b/bpkg/manifest.cxx index b94c2c6..ff1c88f 100644 --- a/bpkg/manifest.cxx +++ b/bpkg/manifest.cxx @@ -18,6 +18,7 @@ #include // invalid_argument #include +#include #include #include @@ -1197,7 +1198,7 @@ namespace bpkg { // @@ Should we check that all non-optional values are specified ? // @@ Should we check that values are valid: name is not empty, version - // release is not empty, sha256sum is a proper string, ... + // release is not empty, sha256sum is a proper string, ...? // @@ Currently we don't know if we are serializing the individual package // manifest or the package list manifest, so can't ensure all values // allowed in the current context (location, sha256sum, *-file values). @@ -2072,4 +2073,97 @@ namespace bpkg s.next ("", ""); // End of stream. } + + // signature_manifest + // + signature_manifest:: + signature_manifest (parser& p, bool iu) + : signature_manifest (p, p.next (), iu) // Delegate + { + // Make sure this is the end. + // + name_value nv (p.next ()); + if (!nv.empty ()) + throw parsing (p.name (), nv.name_line, nv.name_column, + "single signature manifest expected"); + } + + signature_manifest:: + signature_manifest (parser& p, name_value nv, bool iu) + { + auto bad_name ([&p, &nv](const string& d) { + throw parsing (p.name (), nv.name_line, nv.name_column, d);}); + + auto bad_value ([&p, &nv](const string& d) { + throw parsing (p.name (), nv.value_line, nv.value_column, d);}); + + // Make sure this is the start and we support the version. + // + if (!nv.name.empty ()) + bad_name ("start of signature manifest expected"); + + if (nv.value != "1") + bad_value ("unsupported format version"); + + for (nv = p.next (); !nv.empty (); nv = p.next ()) + { + string& n (nv.name); + string& v (nv.value); + + if (n == "sha256sum") + { + if (!sha256sum.empty ()) + bad_name ("sha256sum redefinition"); + + if (v.empty ()) + bad_value ("empty sha256sum"); + + if (!valid_sha256 (v)) + bad_value ("invalid sha256sum"); + + sha256sum = move (v); + } + else if (n == "signature") + { + if (!signature.empty ()) + bad_name ("signature redefinition"); + + if (v.empty ()) + bad_value ("empty signature"); + + // Try to base64-decode as a sanity check. + // + try + { + signature = base64_decode (v); + } + catch (const invalid_argument&) + { + bad_value ("invalid signature"); + } + } + else if (!iu) + bad_name ("unknown name '" + n + "' in signature manifest"); + } + + // Verify all non-optional values were specified. + // + if (sha256sum.empty ()) + bad_value ("no sha256sum specified"); + else if (signature.empty ()) + bad_value ("no signature specified"); + } + + void signature_manifest:: + serialize (serializer& s) const + { + // @@ Should we check that values are valid ? + // + s.next ("", "1"); // Start of manifest. + + s.next ("sha256sum", sha256sum); + s.next ("signature", base64_encode (signature)); + + s.next ("", ""); // End of manifest. + } } diff --git a/tests/manifest/.gitignore b/tests/manifest/.gitignore index d0bb148..d9c2bbc 100644 --- a/tests/manifest/.gitignore +++ b/tests/manifest/.gitignore @@ -1,2 +1,3 @@ pdriver rdriver +sdriver diff --git a/tests/manifest/buildfile b/tests/manifest/buildfile index 0696a1c..c417a08 100644 --- a/tests/manifest/buildfile +++ b/tests/manifest/buildfile @@ -7,7 +7,7 @@ # @@ Hack until build2 supports multiple tests. Also remove .gitignore. # -./: exe{pdriver} exe{rdriver} +./: exe{pdriver} exe{rdriver} exe{sdriver} exe{pdriver}: obj{pdriver} exe{pdriver}: test.roundtrip = packages @@ -15,10 +15,14 @@ exe{pdriver}: test.roundtrip = packages exe{rdriver}: obj{rdriver} exe{rdriver}: test.roundtrip = repositories -obj{pdriver rdriver}: cxx{driver} -exe{pdriver rdriver} obj{pdriver rdriver}: ../../bpkg/lib{bpkg} +exe{sdriver}: obj{sdriver} +exe{sdriver}: test.roundtrip = signature + +obj{pdriver rdriver sdriver}: cxx{driver} +exe{pdriver rdriver sdriver} obj{pdriver rdriver sdriver}: ../../bpkg/lib{bpkg} obj{pdriver}: cxx.poptions += -DTEST_PACKAGES obj{rdriver}: cxx.poptions += -DTEST_REPOSITORIES +obj{sdriver}: cxx.poptions += -DTEST_SIGNATURE include ../../bpkg/ diff --git a/tests/manifest/driver.cxx b/tests/manifest/driver.cxx index e9551ae..c153477 100644 --- a/tests/manifest/driver.cxx +++ b/tests/manifest/driver.cxx @@ -31,8 +31,10 @@ main (int argc, char* argv[]) #ifdef TEST_PACKAGES package_manifests ms (p); -#else +#elif TEST_REPOSITORIES repository_manifests ms (p); +#else + signature_manifest ms (p); #endif manifest_serializer s (cout, "stdout"); diff --git a/tests/manifest/signature b/tests/manifest/signature new file mode 100644 index 0000000..5a83eeb --- /dev/null +++ b/tests/manifest/signature @@ -0,0 +1,13 @@ +: 1 +sha256sum: a2b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +signature: \ +geWdw7Gm+Rt+CLDMBby5Y796E8rxwImb0bmcZwGWar9D3vkFm9Kjh00Buuo1PuU7tP1dV6yvRbH8 +NzC0IryEoUJHx9909AJ449ET9Zb+C3ykEeBlKH2wonj7cAVK9ZEDpPEGAtp56XWZQEawl50mwq6t +XkZAABxtOswXiicdh3HK7kaPHp38/9CBMc0rva6wDnkbTigUYA2ULqLtP5a5mLovVc48zI9A/hmb +Qx1/Nr7nzTZNDGK7CwTAb1fPam9rZklTfCTPSPUUjvWjM9XdY8cbRE1FrE14TXdyQPxCLzHO2dUO +YWH5/qMikEoCYhYXQ6KhekoT/MUiVC3PMcYQbYOrOtSxq6RcgnymexBe1XIyld5Rfo1eXu8TK11r +QPULIqAGy6RwEUhGznuEiGHQwb1UymNyJ/qgr4vBPjJtlvptqG5XNmtiJ22f07nmeVRi2Vg2UyOw +HoVpy5t/w0tEnUXPA39Vt0v1bUm7Knhc8qL4JFEqK/j/CzEHzEtAjn0aoGuKubCO0WUa+v6ZlkLU +YrNUIdgT1wgj4yEhLO3g+NsnxFH05D2sfR16rrkI2E6st5crAHR8FOl2FDsWxgKqNbzXZw7rl+Fa +TobGycX7MDf2mbBmR/KmEkMBJ4mziWLAycSAGyE5VRYDwHPJlQE0143wBzT8eNw4VLm/r+88VYw= +\ -- cgit v1.1