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