1 //! For storing OpenPGP certificates.
2 //!
3 //! The key store stores OpenPGP Certificates ("Certs") using an
4 //! arbitrary label.  Stored keys are automatically updated from
5 //! remote sources.  This ensures that updates like new subkeys and
6 //! revocations are discovered in a timely manner.
7 //!
8 //! # Security considerations
9 //!
10 //! Storing public keys potentially leaks communication partners.
11 //! Protecting against adversaries inspecting the local storage is out
12 //! of scope for Sequoia.  Please take the necessary precautions.
13 //!
14 //! Sequoia updates keys in compliance with the [network policy] used
15 //! to create the store.
16 //!
17 //! [network policy]: ../../sequoia_core/enum.NetworkPolicy.html
18 //!
19 //! # Example
20 //!
21 //! ```c, ignore
22 //! XXX
23 //! ```
24 
25 
26 use libc::c_char;
27 use std::ptr;
28 
29 extern crate sequoia_openpgp as openpgp;
30 
31 use sequoia_store::{
32     self, Mapping, MappingIter, Binding, BundleIter, Key, KeyIter, LogIter, Store,
33 };
34 
35 use super::error::Status;
36 use super::core::Context;
37 
38 use crate::openpgp::fingerprint::Fingerprint;
39 use crate::openpgp::keyid::KeyID;
40 use crate::openpgp::cert::Cert;
41 use crate::RefRaw;
42 use crate::MoveIntoRaw;
43 use crate::MoveResultIntoRaw;
44 use crate::Maybe;
45 use crate::to_time_t;
46 
47 /// Lists all mappings with the given prefix.
48 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_store_list_mappings(ctx: *mut Context, realm_prefix: *const c_char) -> *mut MappingIter49 fn sq_store_list_mappings(ctx: *mut Context,
50                         realm_prefix: *const c_char)
51                         -> *mut MappingIter {
52     let ctx = ffi_param_ref_mut!(ctx);
53     ffi_make_fry_from_ctx!(ctx);
54     let realm_prefix = ffi_param_cstr!(realm_prefix).to_string_lossy();
55 
56     ffi_try_box!(Mapping::list(&ctx.c, &realm_prefix))
57 }
58 
59 /// Returns the next mapping.
60 ///
61 /// Returns `NULL` on exhaustion.  If `realmp` is not `NULL`, the
62 /// mapping's realm is stored there.  If `namep` is not `NULL`, the
63 /// mapping's name is stored there.  If `policyp` is not `NULL`, the
64 /// mapping's network policy is stored there.
65 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_mapping_iter_next(iter: *mut MappingIter, realmp: Option<&mut *mut c_char>, namep: Option<&mut *mut c_char>, policyp: Option<&mut u8>) -> *mut Mapping66 fn sq_mapping_iter_next(iter: *mut MappingIter,
67                       realmp: Option<&mut *mut c_char>,
68                       namep: Option<&mut *mut c_char>,
69                       policyp: Option<&mut u8>)
70                       -> *mut Mapping {
71     let iter = ffi_param_ref_mut!(iter);
72     match iter.next() {
73         Some((realm, name, policy, mapping)) => {
74             if realmp.is_some() {
75                 *realmp.unwrap() = ffi_return_maybe_string!(realm);
76             }
77 
78             if namep.is_some() {
79                 *namep.unwrap() = ffi_return_maybe_string!(name);
80             }
81 
82             if policyp.is_some() {
83                 *policyp.unwrap() = (&policy).into();
84             }
85 
86             box_raw!(mapping)
87         },
88         None => ptr::null_mut(),
89     }
90 }
91 
92 /// Frees a sq_mapping_iter_t.
93 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_mapping_iter_free(iter: Option<&mut MappingIter>)94 fn sq_mapping_iter_free(iter: Option<&mut MappingIter>) {
95     ffi_free!(iter)
96 }
97 
98 /// Lists all keys in the common key pool.
99 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_store_list_keys(ctx: *mut Context) -> *mut KeyIter100 fn sq_store_list_keys(ctx: *mut Context) -> *mut KeyIter {
101     let ctx = ffi_param_ref_mut!(ctx);
102     ffi_make_fry_from_ctx!(ctx);
103 
104     ffi_try_box!(Store::list_keys(&ctx.c))
105 }
106 
107 /// Lists all log entries.
108 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_store_server_log(ctx: *mut Context) -> *mut LogIter109 fn sq_store_server_log(ctx: *mut Context) -> *mut LogIter {
110     let ctx = ffi_param_ref_mut!(ctx);
111     ffi_make_fry_from_ctx!(ctx);
112 
113     ffi_try_box!(Store::server_log(&ctx.c))
114 }
115 
116 /// Returns the next key.
117 ///
118 /// Returns `NULL` on exhaustion.  If `fpp` is not `NULL`, the key's
119 /// fingerprint is stored there.
120 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_key_iter_next(iter: *mut KeyIter, fpp: Option<&mut Maybe<Fingerprint>>) -> *mut Key121 fn sq_key_iter_next(iter: *mut KeyIter,
122                     fpp: Option<&mut Maybe<Fingerprint>>)
123                     -> *mut Key {
124     let iter = ffi_param_ref_mut!(iter);
125     match iter.next() {
126         Some((fingerprint, key)) => {
127             if fpp.is_some() {
128                 *fpp.unwrap() = Some(fingerprint).move_into_raw();
129             }
130 
131             box_raw!(key)
132         },
133         None => {
134             if fpp.is_some() {
135                 *fpp.unwrap() = None;
136             }
137             ptr::null_mut()
138         },
139     }
140 }
141 
142 /// Frees a sq_key_iter_t.
143 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_key_iter_free(iter: Option<&mut KeyIter>)144 fn sq_key_iter_free(iter: Option<&mut KeyIter>) {
145     ffi_free!(iter)
146 }
147 
148 
149 /// Returns the next log entry.
150 ///
151 /// Returns `NULL` on exhaustion.
152 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_log_iter_next(iter: *mut LogIter) -> *mut Log153 fn sq_log_iter_next(iter: *mut LogIter) -> *mut Log {
154     let iter = ffi_param_ref_mut!(iter);
155     match iter.next() {
156         Some(e) => {
157             let (status, error) = match e.status {
158                 Ok(s) => (ffi_return_string!(&s), ptr::null_mut()),
159                 Err((s, e)) => (ffi_return_string!(&s), ffi_return_string!(&e)),
160             };
161 
162             box_raw!(Log{
163                 timestamp: to_time_t(e.timestamp),
164                 mapping: maybe_box_raw!(e.mapping),
165                 binding: maybe_box_raw!(e.binding),
166                 key: maybe_box_raw!(e.key),
167                 slug: ffi_return_string!(&e.slug),
168                 status,
169                 error,
170             })
171         },
172         None => ptr::null_mut(),
173     }
174 }
175 
176 /// Frees a sq_log_iter_t.
177 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_log_iter_free(iter: Option<&mut LogIter>)178 fn sq_log_iter_free(iter: Option<&mut LogIter>) {
179     ffi_free!(iter)
180 }
181 
182 /// Opens a mapping.
183 ///
184 /// Opens a mapping with the given name.  If the mapping does not
185 /// exist, it is created.  Mappings are handles for objects
186 /// maintained by a background service.  The background service
187 /// associates state with this name.
188 ///
189 /// The mapping updates Certs in compliance with the network policy
190 /// of the context that created the mapping in the first place.
191 /// Opening the mapping with a different network policy is
192 /// forbidden.
193 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_mapping_open(ctx: *mut Context, realm: *const c_char, name: *const c_char) -> *mut Mapping194 fn sq_mapping_open(ctx: *mut Context,
195                  realm: *const c_char,
196                  name: *const c_char)
197                  -> *mut Mapping {
198     let ctx = ffi_param_ref_mut!(ctx);
199     ffi_make_fry_from_ctx!(ctx);
200     let realm = ffi_param_cstr!(realm).to_string_lossy();
201     let name = ffi_param_cstr!(name).to_string_lossy();
202 
203     ffi_try_box!(Mapping::open(&ctx.c, &realm, &name))
204 }
205 
206 /// Frees a sq_mapping_t.
207 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_mapping_free(mapping: Option<&mut Mapping>)208 fn sq_mapping_free(mapping: Option<&mut Mapping>) {
209     ffi_free!(mapping)
210 }
211 
212 /// Adds a key identified by fingerprint to the mapping.
213 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_mapping_add(ctx: *mut Context, mapping: *const Mapping, label: *const c_char, fingerprint: *const Fingerprint) -> *mut Binding214 fn sq_mapping_add(ctx: *mut Context,
215                 mapping: *const Mapping,
216                 label: *const c_char,
217                 fingerprint: *const Fingerprint)
218                 -> *mut Binding {
219     let ctx = ffi_param_ref_mut!(ctx);
220     ffi_make_fry_from_ctx!(ctx);
221     let mapping = ffi_param_ref!(mapping);
222     let label = ffi_param_cstr!(label).to_string_lossy();
223     let fingerprint = fingerprint.ref_raw();
224 
225     ffi_try_box!(mapping.add(&label, fingerprint))
226 }
227 
228 /// Imports a key into the mapping.
229 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_mapping_import(ctx: *mut Context, mapping: *const Mapping, label: *const c_char, cert: *const Cert) -> Maybe<Cert>230 fn sq_mapping_import(ctx: *mut Context,
231                    mapping: *const Mapping,
232                    label: *const c_char,
233                    cert: *const Cert)
234                    -> Maybe<Cert> {
235     let ctx = ffi_param_ref_mut!(ctx);
236     ffi_make_fry_from_ctx!(ctx);
237     let mapping = ffi_param_ref!(mapping);
238     let label = ffi_param_cstr!(label).to_string_lossy();
239     let cert = cert.ref_raw();
240 
241     mapping.import(&label, cert).move_into_raw(Some(ctx.errp()))
242 }
243 
244 /// Returns the binding for the given label.
245 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_mapping_lookup(ctx: *mut Context, mapping: *const Mapping, label: *const c_char) -> *mut Binding246 fn sq_mapping_lookup(ctx: *mut Context,
247                    mapping: *const Mapping,
248                    label: *const c_char)
249                    -> *mut Binding {
250     let ctx = ffi_param_ref_mut!(ctx);
251     ffi_make_fry_from_ctx!(ctx);
252     let mapping = ffi_param_ref!(mapping);
253     let label = ffi_param_cstr!(label).to_string_lossy();
254 
255     ffi_try_box!(mapping.lookup(&label))
256 }
257 
258 /// Looks up a key in the common key pool by KeyID.
259 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_store_lookup_by_keyid(ctx: *mut Context, keyid: *const KeyID) -> *mut Key260 fn sq_store_lookup_by_keyid(ctx: *mut Context, keyid: *const KeyID)
261     -> *mut Key
262 {
263     let ctx = ffi_param_ref_mut!(ctx);
264     ffi_make_fry_from_ctx!(ctx);
265     let keyid = keyid.ref_raw();
266 
267     ffi_try_box!(Store::lookup_by_keyid(&ctx.c, keyid))
268 }
269 
270 /// Looks up a key in the common key pool by (Sub)KeyID.
271 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_store_lookup_by_subkeyid(ctx: *mut Context, keyid: *const KeyID) -> *mut Key272 fn sq_store_lookup_by_subkeyid(ctx: *mut Context, keyid: *const KeyID)
273     -> *mut Key
274 {
275     let ctx = ffi_param_ref_mut!(ctx);
276     ffi_make_fry_from_ctx!(ctx);
277     let keyid = keyid.ref_raw();
278 
279     ffi_try_box!(Store::lookup_by_subkeyid(&ctx.c, keyid))
280 }
281 
282 /// Deletes this mapping.
283 ///
284 /// Consumes `mapping`.  Returns != 0 on error.
285 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_mapping_delete(ctx: *mut Context, mapping: *mut Mapping) -> Status286 fn sq_mapping_delete(ctx: *mut Context, mapping: *mut Mapping)
287                    -> Status {
288     let ctx = ffi_param_ref_mut!(ctx);
289     ffi_make_fry_from_ctx!(ctx);
290     let mapping = ffi_param_move!(mapping);
291 
292     ffi_try_status!(mapping.delete())
293 }
294 
295 /// Lists all bindings.
296 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_mapping_iter(ctx: *mut Context, mapping: *const Mapping) -> *mut BundleIter297 fn sq_mapping_iter(ctx: *mut Context, mapping: *const Mapping)
298                  -> *mut BundleIter {
299     let ctx = ffi_param_ref_mut!(ctx);
300     ffi_make_fry_from_ctx!(ctx);
301     let mapping = ffi_param_ref!(mapping);
302 
303     ffi_try_box!(mapping.iter())
304 }
305 
306 /// Returns the next binding.
307 ///
308 /// Returns `NULL` on exhaustion.  If `labelp` is not `NULL`, the
309 /// bindings label is mappingd there.  If `fpp` is not `NULL`, the
310 /// bindings fingerprint is mappingd there.
311 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_binding_iter_next(iter: *mut BundleIter, labelp: Option<&mut *mut c_char>, fpp: Option<&mut Maybe<Fingerprint>>) -> *mut Binding312 fn sq_binding_iter_next(iter: *mut BundleIter,
313                         labelp: Option<&mut *mut c_char>,
314                         fpp: Option<&mut Maybe<Fingerprint>>)
315                         -> *mut Binding {
316     let iter = ffi_param_ref_mut!(iter);
317     match iter.next() {
318         Some((label, fp, binding)) => {
319             if labelp.is_some() {
320                 *labelp.unwrap() = ffi_return_maybe_string!(label);
321             }
322 
323             if fpp.is_some() {
324                 *fpp.unwrap() = Some(fp).move_into_raw();
325             }
326 
327             box_raw!(binding)
328         },
329         None => {
330             if fpp.is_some() {
331                 *fpp.unwrap() = None;
332             }
333             ptr::null_mut()
334         },
335     }
336 }
337 
338 /// Frees a sq_binding_iter_t.
339 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_binding_iter_free(iter: Option<&mut BundleIter>)340 fn sq_binding_iter_free(iter: Option<&mut BundleIter>) {
341     ffi_free!(iter)
342 }
343 
344 /// Lists all log entries related to this mapping.
345 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_mapping_log(ctx: *mut Context, mapping: *const Mapping) -> *mut LogIter346 fn sq_mapping_log(ctx: *mut Context, mapping: *const Mapping)
347                 -> *mut LogIter {
348     let ctx = ffi_param_ref_mut!(ctx);
349     ffi_make_fry_from_ctx!(ctx);
350     let mapping = ffi_param_ref!(mapping);
351 
352     ffi_try_box!(mapping.log())
353 }
354 
355 /// Frees a sq_binding_t.
356 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_binding_free(binding: Option<&mut Binding>)357 fn sq_binding_free(binding: Option<&mut Binding>) {
358     ffi_free!(binding)
359 }
360 
361 /// Frees a sq_key_t.
362 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_key_free(key: Option<&mut Key>)363 fn sq_key_free(key: Option<&mut Key>) {
364     ffi_free!(key)
365 }
366 
367 /// Frees a sq_log_t.
368 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_log_free(log: Option<&mut Log>)369 fn sq_log_free(log: Option<&mut Log>) {
370     if let Some(log) = log {
371         let log = unsafe { Box::from_raw(log) };
372         if ! log.mapping.is_null() {
373             ffi_param_move!(log.mapping);
374         }
375         if ! log.binding.is_null() {
376             ffi_param_move!(log.binding);
377         }
378         if ! log.key.is_null() {
379             ffi_param_move!(log.key);
380         }
381         unsafe {
382             libc::free(log.slug as *mut libc::c_void);
383             libc::free(log.status as *mut libc::c_void);
384             libc::free(log.error as *mut libc::c_void);
385         }
386         drop(log)
387     }
388 }
389 
390 /// Returns the `sq_stats_t` of this binding.
391 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_binding_stats(ctx: *mut Context, binding: *const Binding) -> *mut Stats392 fn sq_binding_stats(ctx: *mut Context, binding: *const Binding)
393                     -> *mut Stats {
394     let ctx = ffi_param_ref_mut!(ctx);
395     ffi_make_fry_from_ctx!(ctx);
396     let binding = ffi_param_ref!(binding);
397 
398     box_raw!(Stats::new(ffi_try!(binding.stats())))
399 }
400 
401 /// Returns the `sq_key_t` of this binding.
402 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_binding_key(ctx: *mut Context, binding: *const Binding) -> *mut Key403 fn sq_binding_key(ctx: *mut Context, binding: *const Binding)
404                   -> *mut Key {
405     let ctx = ffi_param_ref_mut!(ctx);
406     ffi_make_fry_from_ctx!(ctx);
407     let binding = ffi_param_ref!(binding);
408 
409     ffi_try_box!(binding.key())
410 }
411 
412 /// Returns the `pgp_cert_t` of this binding.
413 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_binding_cert(ctx: *mut Context, binding: *const Binding) -> Maybe<Cert>414 fn sq_binding_cert(ctx: *mut Context, binding: *const Binding)
415                   -> Maybe<Cert> {
416     let ctx = ffi_param_ref_mut!(ctx);
417     ffi_make_fry_from_ctx!(ctx);
418     let binding = ffi_param_ref!(binding);
419 
420     binding.cert().move_into_raw(Some(ctx.errp()))
421 }
422 
423 /// Updates this binding with the given Cert.
424 ///
425 /// If the new key `cert` matches the current key, i.e. they have
426 /// the same fingerprint, both keys are merged and normalized.
427 /// The returned key contains all packets known to Sequoia, and
428 /// should be used instead of `cert`.
429 ///
430 /// If the new key does not match the current key, but carries a
431 /// valid signature from the current key, it replaces the current
432 /// key.  This provides a natural way for key rotations.
433 ///
434 /// If the new key does not match the current key, and it does not
435 /// carry a valid signature from the current key, an
436 /// `Error::Conflict` is returned, and you have to resolve the
437 /// conflict, either by ignoring the new key, or by using
438 /// `sq_binding_rotate` to force a rotation.
439 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_binding_import(ctx: *mut Context, binding: *const Binding, cert: *const Cert) -> Maybe<Cert>440 fn sq_binding_import(ctx: *mut Context,
441                      binding: *const Binding,
442                      cert: *const Cert)
443                      -> Maybe<Cert> {
444     let ctx = ffi_param_ref_mut!(ctx);
445     ffi_make_fry_from_ctx!(ctx);
446     let binding = ffi_param_ref!(binding);
447     let cert = cert.ref_raw();
448 
449     binding.import(&cert).move_into_raw(Some(ctx.errp()))
450 }
451 
452 
453 /// Forces a keyrotation to the given Cert.
454 ///
455 /// The current key is replaced with the new key `cert`, even if
456 /// they do not have the same fingerprint.  If a key with the same
457 /// fingerprint as `cert` is already in the mapping, is merged with
458 /// `cert` and normalized.  The returned key contains all packets
459 /// known to Sequoia, and should be used instead of `cert`.
460 ///
461 /// Use this function to resolve conflicts returned from
462 /// `sq_binding_import`.  Make sure that you have authenticated
463 /// `cert` properly.  How to do that depends on your thread model.
464 /// You could simply ask Alice to call her communication partner
465 /// Bob and confirm that he rotated his keys.
466 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_binding_rotate(ctx: *mut Context, binding: *const Binding, cert: *const Cert) -> Maybe<Cert>467 fn sq_binding_rotate(ctx: *mut Context,
468                      binding: *const Binding,
469                      cert: *const Cert)
470                      -> Maybe<Cert> {
471     let ctx = ffi_param_ref_mut!(ctx);
472     ffi_make_fry_from_ctx!(ctx);
473     let binding = ffi_param_ref!(binding);
474     let cert = cert.ref_raw();
475 
476     binding.rotate(&cert).move_into_raw(Some(ctx.errp()))
477 }
478 
479 /// Deletes this binding.
480 ///
481 /// Consumes `binding`.  Returns != 0 on error.
482 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_binding_delete(ctx: *mut Context, binding: *mut Binding) -> Status483 fn sq_binding_delete(ctx: *mut Context,
484                      binding: *mut Binding)
485                      -> Status {
486     let ctx = ffi_param_ref_mut!(ctx);
487     ffi_make_fry_from_ctx!(ctx);
488     let binding = ffi_param_move!(binding);
489 
490     ffi_try_status!(binding.delete())
491 }
492 
493 /// Lists all log entries related to this binding.
494 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_binding_log(ctx: *mut Context, binding: *const Binding) -> *mut LogIter495 fn sq_binding_log(ctx: *mut Context,
496                   binding: *const Binding)
497                   -> *mut LogIter {
498     let ctx = ffi_param_ref_mut!(ctx);
499     ffi_make_fry_from_ctx!(ctx);
500     let binding = ffi_param_ref!(binding);
501 
502     ffi_try_box!(binding.log())
503 }
504 
505 /// Returns the `sq_stats_t` of this key.
506 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_key_stats(ctx: *mut Context, key: *const Key) -> *mut Stats507 fn sq_key_stats(ctx: *mut Context,
508                 key: *const Key)
509                 -> *mut Stats {
510     let ctx = ffi_param_ref_mut!(ctx);
511     ffi_make_fry_from_ctx!(ctx);
512     let key = ffi_param_ref!(key);
513 
514     box_raw!(Stats::new(ffi_try!(key.stats())))
515 }
516 
517 /// Returns the `pgp_cert_t`.
518 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_key_cert(ctx: *mut Context, key: *const Key) -> Maybe<Cert>519 fn sq_key_cert(ctx: *mut Context,
520               key: *const Key)
521               -> Maybe<Cert> {
522     let ctx = ffi_param_ref_mut!(ctx);
523     ffi_make_fry_from_ctx!(ctx);
524     let key = ffi_param_ref!(key);
525 
526     key.cert().move_into_raw(Some(ctx.errp()))
527 }
528 
529 /// Updates this stored key with the given Cert.
530 ///
531 /// If the new key `cert` matches the current key, i.e. they have
532 /// the same fingerprint, both keys are merged and normalized.
533 /// The returned key contains all packets known to Sequoia, and
534 /// should be used instead of `cert`.
535 ///
536 /// If the new key does not match the current key,
537 /// `Error::Conflict` is returned.
538 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_key_import(ctx: *mut Context, key: *const Key, cert: *const Cert) -> Maybe<Cert>539 fn sq_key_import(ctx: *mut Context,
540                  key: *const Key,
541                  cert: *const Cert)
542                  -> Maybe<Cert> {
543     let ctx = ffi_param_ref_mut!(ctx);
544     ffi_make_fry_from_ctx!(ctx);
545     let key = ffi_param_ref!(key);
546     let cert = cert.ref_raw();
547 
548     key.import(&cert).move_into_raw(Some(ctx.errp()))
549 }
550 
551 /// Lists all log entries related to this key.
552 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_key_log(ctx: *mut Context, key: *const Key) -> *mut LogIter553 fn sq_key_log(ctx: *mut Context,
554               key: *const Key)
555               -> *mut LogIter {
556     let ctx = ffi_param_ref_mut!(ctx);
557     ffi_make_fry_from_ctx!(ctx);
558     let key = ffi_param_ref!(key);
559 
560     ffi_try_box!(key.log())
561 }
562 
563 /// Frees a sq_stats_t.
564 #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
sq_stats_free(stats: Option<&mut Stats>)565 fn sq_stats_free(stats: Option<&mut Stats>) {
566     ffi_free!(stats)
567 }
568 
569 /// Counter and timestamps.
570 #[repr(C)]
571 pub struct Stamps {
572     /// Counts how many times this has been used.
573     pub count: u64,
574 
575     /// Records the time when this has been used first.
576     pub first:  libc::time_t,
577 
578     /// Records the time when this has been used last.
579     pub last: libc::time_t,
580 }
581 
582 impl Stamps {
new(s: &sequoia_store::Stamps) -> Stamps583     fn new(s: &sequoia_store::Stamps) -> Stamps {
584         Stamps{
585             count: s.count as u64,
586             first: to_time_t(s.first),
587             last: to_time_t(s.last),
588         }
589     }
590 }
591 
592 /// Statistics about bindings and stored keys.
593 ///
594 /// We collect some data about binginds and stored keys.  This
595 /// information can be used to make informed decisions about key
596 /// transitions.
597 #[repr(C)]
598 pub struct Stats {
599     /// Records the time this item was created.
600     pub created: libc::time_t,
601 
602     /// Records the time this item was last updated.
603     pub updated: libc::time_t,
604 
605     /// Records counters and timestamps of encryptions.
606     pub encryption: Stamps,
607 
608     /// Records counters and timestamps of verifications.
609     pub verification: Stamps,
610 }
611 
612 impl Stats {
new(s: sequoia_store::Stats) -> Stats613     fn new(s: sequoia_store::Stats) -> Stats {
614         Stats {
615             created: to_time_t(s.created),
616             updated: to_time_t(s.updated),
617             encryption: Stamps::new(&s.encryption),
618             verification: Stamps::new(&s.verification),
619         }
620     }
621 }
622 
623 /// Represents a log entry.
624 #[repr(C)]
625 pub struct Log {
626     /// Records the time of the entry.
627     pub timestamp: libc::time_t,
628 
629     /// Relates the entry to a mapping.
630     ///
631     /// May be `NULL`.
632     pub mapping: *mut Mapping,
633 
634     /// Relates the entry to a binding.
635     ///
636     /// May be `NULL`.
637     pub binding: *mut Binding,
638 
639     /// Relates the entry to a key.
640     ///
641     /// May be `NULL`.
642     pub key: *mut Key,
643 
644     /// Relates the entry to some object.
645     ///
646     /// This is a human-readable description of what this log entry is
647     /// mainly concerned with.
648     pub slug: *mut c_char,
649 
650     /// Holds the log message.
651     pub status: *mut c_char,
652 
653     /// Holds the error message, if any.
654     ///
655     /// May be `NULL`.
656     pub error: *mut c_char,
657 }
658