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