monotone

monotone Mtn Source Tree

Root/src/keys.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 <cstring>
12
13#include "keys.hh"
14#include "sanity.hh"
15#include "constants.hh"
16#include "platform.hh"
17#include "transforms.hh"
18#include "simplestring_xform.hh"
19#include "charset.hh"
20#include "lua_hooks.hh"
21#include "options.hh"
22#include "project.hh"
23#include "key_store.hh"
24#include "database.hh"
25#include "uri.hh"
26#include "globish.hh"
27#include "network/connection_info.hh"
28
29using std::string;
30using std::vector;
31using std::memset;
32
33// there will probably forever be bugs in this file. it's very
34// hard to get right, portably and securely. sorry about that.
35
36// Loads a key pair for a given key id, considering it a user error
37// if that key pair is not available.
38
39void
40load_key_pair(key_store & keys, key_id const & id)
41{
42 E(keys.key_pair_exists(id), origin::user,
43 F("no key pair %s found in key store '%s'")
44 % id % keys.get_key_dir());
45}
46
47void
48load_key_pair(key_store & keys,
49 key_id const & id,
50 keypair & kp)
51{
52 load_key_pair(keys, id);
53 keys.get_key_pair(id, kp);
54}
55
56void
57load_key_pair(key_store & keys,
58 key_id const & id,
59 key_name & name,
60 keypair & kp)
61{
62 load_key_pair(keys, id);
63 keys.get_key_pair(id, name, kp);
64}
65
66namespace {
67 void check_and_save_chosen_key(database & db,
68 key_store & keys,
69 key_id const & chosen_key)
70 {
71 // Ensure that the specified key actually exists.
72 key_name name;
73 keypair priv_key;
74 load_key_pair(keys, chosen_key, name, priv_key);
75
76 if (db.database_specified())
77 {
78 // If the database doesn't have this public key, add it now; otherwise
79 // make sure the database and key-store agree on the public key.
80 if (!db.public_key_exists(chosen_key))
81 db.put_key(name, priv_key.pub);
82 else
83 {
84 rsa_pub_key pub_key;
85 db.get_key(chosen_key, pub_key);
86 E(keys_match(name, pub_key, name, priv_key.pub),
87 origin::no_fault,
88 F("the key %s stored in your database does\n"
89 "not match the version in your local key store!")
90 % chosen_key);
91 }
92 }
93
94 // Decrypt and cache the key now.
95 keys.cache_decrypted_key(chosen_key);
96 }
97 bool get_only_key(key_store & keys, key_requiredness_flag key_requiredness, key_id & key)
98 {
99 vector<key_id> all_privkeys;
100 keys.get_key_ids(all_privkeys);
101 E(key_requiredness == key_optional || !all_privkeys.empty(), origin::user,
102 F("you have no private key to make signatures with.\n"
103 "Perhaps you need to 'genkey <your email>'"));
104 E(key_requiredness == key_optional || all_privkeys.size() < 2, origin::user,
105 F("you have multiple private keys.\n"
106 "Pick one to use for signatures by adding "
107 "'-k<keyname>' to your command"));
108
109 if (all_privkeys.size() == 1)
110 {
111 key = all_privkeys[0];
112 return true;
113 }
114 else
115 {
116 return false;
117 }
118 }
119}
120
121void
122get_user_key(options const & opts, lua_hooks & lua,
123 database & db, key_store & keys,
124 project_t & project, key_id & key,
125 key_cache_flag const cache)
126{
127 if (keys.have_signing_key())
128 {
129 key = keys.signing_key;
130 return;
131 }
132
133 if (opts.key_given || !opts.key().empty())
134 {
135 if (!opts.key().empty())
136 {
137 key_identity_info identity;
138 project.get_key_identity(keys, lua, opts.key, identity);
139 key = identity.id;
140 }
141 else
142 {
143 E(false, origin::user,
144 F("a key is required for this operation, but the '--key' option "
145 "was given with an empty argument"));
146 }
147 }
148 else if (lua.hook_get_branch_key(opts.branch, keys, project, key))
149 ; // the lua hook sets the key
150 else
151 {
152 get_only_key(keys, key_required, key);
153 }
154
155 if (cache == cache_enable)
156 check_and_save_chosen_key(db, keys, key);
157}
158
159void
160cache_netsync_key(options const & opts,
161 project_t & project,
162 key_store & keys,
163 lua_hooks & lua,
164 shared_conn_info const & info,
165 key_requiredness_flag key_requiredness)
166{
167 if (keys.have_signing_key())
168 {
169 return;
170 }
171
172 bool found_key = false;
173 key_id key;
174
175 if (opts.key_given || !opts.key().empty())
176 {
177 key_identity_info identity;
178 // maybe they specifically requested no key ("--key ''")
179 if (!opts.key().empty())
180 {
181 project.get_key_identity(keys, lua, opts.key, identity);
182 key = identity.id;
183 found_key = true;
184 }
185 }
186 else if (info->info_type == netsync_connection_info::client_info &&
187 lua.hook_get_netsync_client_key(utf8(info->client.get_uri().resource(), origin::user),
188 info->client.get_include_pattern(),
189 info->client.get_exclude_pattern(),
190 keys, project, key))
191 {
192 found_key = true;
193 }
194 else if (info->info_type == netsync_connection_info::server_info &&
195 lua.hook_get_netsync_server_key(info->server.addrs,
196 keys, project, key))
197 {
198 found_key = true;
199 }
200 else
201 {
202 found_key = get_only_key(keys, key_requiredness, key);
203 }
204
205 if (found_key)
206 {
207 check_and_save_chosen_key(project.db, keys, key);
208 }
209}
210
211void
212cache_user_key(options const & opts,
213 project_t & project,
214 key_store & keys,
215 lua_hooks & lua)
216{
217 key_id key;
218 get_user_key(opts, lua, project.db, keys, project, key);
219}
220
221void
222key_hash_code(key_name const & ident,
223 rsa_pub_key const & pub,
224 key_id & out)
225{
226 data tdat(ident() + ":" + remove_ws(encode_base64(pub)()),
227 origin::internal);
228 id tmp;
229 calculate_ident(tdat, tmp);
230 out = key_id(tmp);
231}
232
233// helper to compare if two keys have the same hash
234// (ie are the same key)
235bool
236keys_match(key_name const & id1,
237 rsa_pub_key const & key1,
238 key_name const & id2,
239 rsa_pub_key const & key2)
240{
241 key_id hash1, hash2;
242 key_hash_code(id1, key1, hash1);
243 key_hash_code(id2, key2, hash2);
244 return hash1 == hash2;
245}
246
247// Local Variables:
248// mode: C++
249// fill-column: 76
250// c-file-style: "gnu"
251// indent-tabs-mode: nil
252// End:
253// 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