monotone

monotone Mtn Source Tree

Root/cmd_key_cert.cc

1// Copyright (C) 2002 Graydon Hoare <graydon@pobox.com>
2//
3// This program is made available under the GNU GPL version 2.0 or
4// greater. See the accompanying file COPYING for details.
5//
6// This program is distributed WITHOUT ANY WARRANTY; without even the
7// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8// PURPOSE.
9
10#include "base.hh"
11#include <iostream>
12#include <sstream>
13#include <fstream>
14#include <iterator>
15
16#include "cert.hh"
17#include "charset.hh"
18#include "cmd.hh"
19#include "app_state.hh"
20#include "keys.hh"
21#include "transforms.hh"
22#include "ssh_agent.hh"
23#include "botan/pipe.h"
24
25using std::cout;
26using std::ostream_iterator;
27using std::ostringstream;
28using std::set;
29using std::string;
30using std::ofstream;
31using Botan::Pipe;
32using Botan::RSA_PrivateKey;
33
34CMD(genkey, "genkey", "", CMD_REF(key_and_cert), N_("KEYID"),
35 N_("Generates an RSA key-pair"),
36 "",
37 options::opts::none)
38{
39 if (args.size() != 1)
40 throw usage(execid);
41
42 rsa_keypair_id ident;
43 internalize_rsa_keypair_id(idx(args, 0), ident);
44 bool exists = app.keys.key_pair_exists(ident);
45 if (app.db.database_specified())
46 {
47 transaction_guard guard(app.db);
48 exists = exists || app.db.public_key_exists(ident);
49 guard.commit();
50 }
51
52 N(!exists, F("key '%s' already exists") % ident);
53
54 keypair kp;
55 P(F("generating key-pair '%s'") % ident);
56 generate_key_pair(app.lua, ident, kp);
57 P(F("storing key-pair '%s' in %s/")
58 % ident % app.keys.get_key_dir());
59 app.keys.put_key_pair(ident, kp);
60}
61
62CMD(dropkey, "dropkey", "", CMD_REF(key_and_cert), N_("KEYID"),
63 N_("Drops a public and/or private key"),
64 "",
65 options::opts::none)
66{
67 bool key_deleted = false;
68
69 if (args.size() != 1)
70 throw usage(execid);
71
72 rsa_keypair_id ident(idx(args, 0)());
73 bool checked_db = false;
74 if (app.db.database_specified())
75 {
76 transaction_guard guard(app.db);
77 if (app.db.public_key_exists(ident))
78 {
79 P(F("dropping public key '%s' from database") % ident);
80 app.db.delete_public_key(ident);
81 key_deleted = true;
82 }
83 guard.commit();
84 checked_db = true;
85 }
86
87 if (app.keys.key_pair_exists(ident))
88 {
89 P(F("dropping key pair '%s' from keystore") % ident);
90 app.keys.delete_key(ident);
91 key_deleted = true;
92 }
93
94 i18n_format fmt;
95 if (checked_db)
96 fmt = F("public or private key '%s' does not exist "
97 "in keystore or database");
98 else
99 fmt = F("public or private key '%s' does not exist "
100 "in keystore, and no database was specified");
101 N(key_deleted, fmt % idx(args, 0)());
102}
103
104CMD(passphrase, "passphrase", "", CMD_REF(key_and_cert), N_("KEYID"),
105 N_("Changes the passphrase of a private RSA key"),
106 "",
107 options::opts::none)
108{
109 if (args.size() != 1)
110 throw usage(execid);
111
112 rsa_keypair_id ident;
113 internalize_rsa_keypair_id(idx(args, 0), ident);
114
115 N(app.keys.key_pair_exists(ident),
116 F("key '%s' does not exist in the keystore") % ident);
117
118 keypair key;
119 app.keys.get_key_pair(ident, key);
120 change_key_passphrase(app.lua, ident, key.priv);
121 app.keys.delete_key(ident);
122 app.keys.put_key_pair(ident, key);
123 P(F("passphrase changed"));
124}
125
126CMD(ssh_agent_export, "ssh_agent_export", "", CMD_REF(key_and_cert),
127 N_("[FILENAME]"),
128 N_("Exports a private key for use with ssh-agent"),
129 "",
130 options::opts::none)
131{
132 if (args.size() > 1)
133 throw usage(execid);
134
135 rsa_keypair_id id;
136 keypair key;
137 get_user_key(id, app);
138 N(priv_key_exists(app, id), F("the key you specified cannot be found"));
139 app.keys.get_key_pair(id, key);
140 shared_ptr<RSA_PrivateKey> priv = get_private_key(app.lua, id, key.priv);
141 utf8 new_phrase;
142 get_passphrase(app.lua, id, new_phrase, true, true);
143 Pipe p;
144 p.start_msg();
145 if (new_phrase().length())
146 {
147 Botan::PKCS8::encrypt_key(*priv,
148 p,
149 new_phrase(),
150 "PBE-PKCS5v20(SHA-1,TripleDES/CBC)");
151 }
152 else
153 {
154 Botan::PKCS8::encode(*priv, p);
155 }
156 string decoded_key = p.read_all_as_string();
157 if (args.size() == 0)
158 cout << decoded_key;
159 else
160 {
161 string external_path = system_path(idx(args, 0)).as_external();
162 ofstream fout(external_path.c_str(), ofstream::out);
163 fout << decoded_key;
164 }
165}
166
167CMD(ssh_agent_add, "ssh_agent_add", "", CMD_REF(key_and_cert), "",
168 N_("Adds a private key to ssh-agent"),
169 "",
170 options::opts::none)
171{
172 if (args.size() > 1)
173 throw usage(execid);
174
175 rsa_keypair_id id;
176 keypair key;
177 get_user_key(id, app);
178 N(priv_key_exists(app, id), F("the key you specified cannot be found"));
179 app.keys.get_key_pair(id, key);
180 shared_ptr<RSA_PrivateKey> priv = get_private_key(app.lua, id, key.priv);
181 app.agent.add_identity(*priv, id());
182}
183
184CMD(cert, "cert", "", CMD_REF(key_and_cert),
185 N_("REVISION CERTNAME [CERTVAL]"),
186 N_("Creates a certificate for a revision"),
187 "",
188 options::opts::none)
189{
190 if ((args.size() != 3) && (args.size() != 2))
191 throw usage(execid);
192
193 transaction_guard guard(app.db);
194
195 revision_id rid;
196 complete(app, idx(args, 0)(), rid);
197
198 cert_name cname;
199 internalize_cert_name(idx(args, 1), cname);
200
201 rsa_keypair_id key;
202 get_user_key(key, app);
203
204 cert_value val;
205 if (args.size() == 3)
206 val = cert_value(idx(args, 2)());
207 else
208 {
209 data dat;
210 read_data_stdin(dat);
211 val = cert_value(dat());
212 }
213
214 app.get_project().put_cert(rid, cname, val);
215 guard.commit();
216}
217
218CMD(trusted, "trusted", "", CMD_REF(key_and_cert),
219 N_("REVISION NAME VALUE SIGNER1 [SIGNER2 [...]]"),
220 N_("Tests whether a hypothetical certificate would be trusted"),
221 N_("The current settings are used to run the test."),
222 options::opts::none)
223{
224 if (args.size() < 4)
225 throw usage(execid);
226
227 revision_id rid;
228 complete(app, idx(args, 0)(), rid, false);
229 hexenc<id> ident(rid.inner());
230
231 cert_name cname;
232 internalize_cert_name(idx(args, 1), cname);
233
234 cert_value value(idx(args, 2)());
235
236 set<rsa_keypair_id> signers;
237 for (unsigned int i = 3; i != args.size(); ++i)
238 {
239 rsa_keypair_id keyid;
240 internalize_rsa_keypair_id(idx(args, i), keyid);
241 signers.insert(keyid);
242 }
243
244
245 bool trusted = app.lua.hook_get_revision_cert_trust(signers, ident,
246 cname, value);
247
248
249 ostringstream all_signers;
250 copy(signers.begin(), signers.end(),
251 ostream_iterator<rsa_keypair_id>(all_signers, " "));
252
253 cout << (F("if a cert on: %s\n"
254 "with key: %s\n"
255 "and value: %s\n"
256 "was signed by: %s\n"
257 "it would be: %s")
258 % ident
259 % cname
260 % value
261 % all_signers.str()
262 % (trusted ? _("trusted") : _("UNtrusted")))
263 << '\n'; // final newline is kept out of the translation
264}
265
266CMD(tag, "tag", "", CMD_REF(review), N_("REVISION TAGNAME"),
267 N_("Puts a symbolic tag certificate on a revision"),
268 "",
269 options::opts::none)
270{
271 if (args.size() != 2)
272 throw usage(execid);
273
274 revision_id r;
275 complete(app, idx(args, 0)(), r);
276 cert_revision_tag(r, idx(args, 1)(), app);
277}
278
279
280CMD(testresult, "testresult", "", CMD_REF(review),
281 N_("ID (pass|fail|true|false|yes|no|1|0)"),
282 N_("Notes the results of running a test on a revision"),
283 "",
284 options::opts::none)
285{
286 if (args.size() != 2)
287 throw usage(execid);
288
289 revision_id r;
290 complete(app, idx(args, 0)(), r);
291 cert_revision_testresult(r, idx(args, 1)(), app);
292}
293
294
295CMD(approve, "approve", "", CMD_REF(review), N_("REVISION"),
296 N_("Approves a particular revision"),
297 "",
298 options::opts::branch)
299{
300 if (args.size() != 1)
301 throw usage(execid);
302
303 revision_id r;
304 complete(app, idx(args, 0)(), r);
305 guess_branch(r, app);
306 N(app.opts.branchname() != "", F("need --branch argument for approval"));
307 app.get_project().put_revision_in_branch(r, app.opts.branchname);
308}
309
310CMD(suspend, "suspend", "", CMD_REF(review), N_("REVISION"),
311 N_("Suspends a particular revision"),
312 "",
313 options::opts::branch)
314{
315 if (args.size() != 1)
316 throw usage(execid);
317
318 revision_id r;
319 complete(app, idx(args, 0)(), r);
320 guess_branch(r, app);
321 N(app.opts.branchname() != "", F("need --branch argument to suspend"));
322 app.get_project().suspend_revision_in_branch(r, app.opts.branchname);
323}
324
325CMD(comment, "comment", "", CMD_REF(review), N_("REVISION [COMMENT]"),
326 N_("Comments on a particular revision"),
327 "",
328 options::opts::none)
329{
330 if (args.size() != 1 && args.size() != 2)
331 throw usage(execid);
332
333 utf8 comment;
334 if (args.size() == 2)
335 comment = idx(args, 1);
336 else
337 {
338 external comment_external;
339 N(app.lua.hook_edit_comment(external(""), external(""), comment_external),
340 F("edit comment failed"));
341 system_to_utf8(comment_external, comment);
342 }
343
344 N(comment().find_first_not_of("\n\r\t ") != string::npos,
345 F("empty comment"));
346
347 revision_id r;
348 complete(app, idx(args, 0)(), r);
349 cert_revision_comment(r, comment, app);
350}
351
352// Local Variables:
353// mode: C++
354// fill-column: 76
355// c-file-style: "gnu"
356// indent-tabs-mode: nil
357// End:
358// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status