1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16 // [START digital-signature-example]
17 // A utility for signing and verifying files using digital signatures.
18 #include <iostream>
19 #include <memory>
20 #include <ostream>
21 #include <string>
22
23 #include "absl/flags/flag.h"
24 #include "absl/flags/parse.h"
25 #include "absl/log/check.h"
26 #include "util/util.h"
27 #include "tink/keyset_handle.h"
28 #include "tink/public_key_sign.h"
29 #include "tink/public_key_verify.h"
30 #include "tink/signature/signature_config.h"
31 #include "tink/util/status.h"
32
33 ABSL_FLAG(std::string, keyset_filename, "", "Keyset file in JSON format");
34 ABSL_FLAG(std::string, mode, "", "Mode of operation (sign|verify)");
35 ABSL_FLAG(std::string, input_filename, "", "Filename to operate on");
36 ABSL_FLAG(std::string, signature_filename, "", "Path to the signature file");
37
38 namespace {
39
40 using ::crypto::tink::KeysetHandle;
41 using ::crypto::tink::PublicKeySign;
42 using ::crypto::tink::PublicKeyVerify;
43 using ::crypto::tink::util::Status;
44 using ::crypto::tink::util::StatusOr;
45
46 constexpr absl::string_view kSign = "sign";
47 constexpr absl::string_view kVerify = "verify";
48
ValidateParams()49 void ValidateParams() {
50 // [START_EXCLUDE]
51 CHECK(absl::GetFlag(FLAGS_mode) == kSign ||
52 absl::GetFlag(FLAGS_mode) == kVerify)
53 << "Invalid mode; must be `" << kSign << "` or `" << kVerify << "`"
54 << std::endl;
55 CHECK(!absl::GetFlag(FLAGS_keyset_filename).empty())
56 << "Keyset file must be specified";
57 CHECK(!absl::GetFlag(FLAGS_input_filename).empty())
58 << "Input file must be specified";
59 CHECK(!absl::GetFlag(FLAGS_signature_filename).empty())
60 << "Signature file must be specified";
61 // [END_EXCLUDE]
62 }
63
64 } // namespace
65
66 namespace tink_cc_examples {
67
68 // Digital signature example CLI implementation.
DigitalSignatureCli(absl::string_view mode,const std::string & keyset_filename,const std::string & input_filename,const std::string & signature_filename)69 Status DigitalSignatureCli(absl::string_view mode,
70 const std::string& keyset_filename,
71 const std::string& input_filename,
72 const std::string& signature_filename) {
73 Status result = crypto::tink::SignatureConfig::Register();
74 if (!result.ok()) return result;
75
76 // Read the keyset from file.
77 StatusOr<std::unique_ptr<KeysetHandle>> keyset_handle =
78 ReadJsonCleartextKeyset(keyset_filename);
79 if (!keyset_handle.ok()) return keyset_handle.status();
80
81 // Read the input.
82 StatusOr<std::string> input_file_content = ReadFile(input_filename);
83 if (!input_file_content.ok()) return input_file_content.status();
84
85 if (mode == kSign) {
86 StatusOr<std::unique_ptr<PublicKeySign>> public_key_sign =
87 (*keyset_handle)->GetPrimitive<PublicKeySign>();
88 if (!public_key_sign.ok()) return public_key_sign.status();
89
90 StatusOr<std::string> signature =
91 (*public_key_sign)->Sign(*input_file_content);
92 if (!signature.ok()) return signature.status();
93
94 return WriteToFile(*signature, signature_filename);
95 } else { // mode == kVerify
96 StatusOr<std::unique_ptr<PublicKeyVerify>> public_key_verify =
97 (*keyset_handle)->GetPrimitive<PublicKeyVerify>();
98 if (!public_key_verify.ok()) return public_key_verify.status();
99
100 // Read the signature.
101 StatusOr<std::string> signature_file_content = ReadFile(signature_filename);
102 if (!signature_file_content.ok()) return signature_file_content.status();
103
104 return (*public_key_verify)
105 ->Verify(*signature_file_content, *input_file_content);
106 }
107 }
108
109 } // namespace tink_cc_examples
110
main(int argc,char ** argv)111 int main(int argc, char** argv) {
112 absl::ParseCommandLine(argc, argv);
113
114 ValidateParams();
115
116 std::string mode = absl::GetFlag(FLAGS_mode);
117 std::string keyset_filename = absl::GetFlag(FLAGS_keyset_filename);
118 std::string input_filename = absl::GetFlag(FLAGS_input_filename);
119 std::string signature_filename = absl::GetFlag(FLAGS_signature_filename);
120
121 std::clog << "Using keyset in " << keyset_filename << " to " << mode;
122 if (mode == kSign) {
123 std::clog << " file " << input_filename
124 << "; the resulting signature is written to "
125 << signature_filename << std::endl;
126 } else { // mode == kVerify
127 std::clog << " the signature in " << signature_filename
128 << " over the content of " << input_filename << std::endl;
129 }
130
131 CHECK_OK(tink_cc_examples::DigitalSignatureCli(
132 mode, keyset_filename, input_filename, signature_filename));
133 return 0;
134 }
135 // [END digital-signature-example]
136