OpenVAS Manager  7.0.3~git
lsc_crypt.c
Go to the documentation of this file.
1 /* OpenVAS Manager
2  * $Id$
3  * Description: LSC credentials encryption support
4  *
5  * Authors:
6  * Werner Koch <wk@gnupg.org>
7  *
8  * Copyright:
9  * Copyright (C) 2013 Greenbone Networks GmbH
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25 
26 #include <glib.h>
27 #include <glib/gstdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <stdint.h>
32 
33 #include <openvas/base/gpgme_util.h>
34 
35 #include "lsc_crypt.h"
36 
37 #undef G_LOG_DOMAIN
38 
41 #define G_LOG_DOMAIN "md crypt"
42 
50 #define ENCRYPTION_KEY_UID "OpenVAS Credential Encryption"
51 
58 #define MAX_VALUE_LENGTH (128 * 1024)
59 
60 
61 /* Provide a replacement for an error code in libgpg-error > 1.10. */
62 #ifndef GPG_ERR_AMBIGUOUS
63 # define GPG_ERR_AMBIGUOUS GPG_ERR_AMBIGUOUS_NAME
64 #endif
65 
69 struct namelist_s
70 {
71  struct namelist_s *next;
72  size_t valoff; /* Offset to the value in the plaintext buffer
73  or 0 if VALUE below is used instead. Note
74  that a value will never be at the begin of
75  the plaintext buffer. VALOFF and VALUE
76  0/NULL indicates a NULL value. */
77  char *value;
78  char name[1]; /* The name. */
79 };
80 
88 {
89  gpgme_ctx_t encctx;
90  gpgme_key_t enckey; /* The key to be used for encryption. */
91  char *plaintext;
92  size_t plaintextlen;
93  struct namelist_s *namelist; /* Info describing PLAINTEXT. */
94 };
95 
96 
97 /* Simple helper functions */
98 
107 static G_GNUC_CONST const char *
108 nonnull (const char *s)
109 {
110  return s? s :"[none]";
111 }
112 
113 
123 static void
124 put32 (GString *buffer, uint32_t value)
125 {
126  unsigned char tmp[4];
127  tmp[0] = value >> 24;
128  tmp[1] = value >> 16;
129  tmp[2] = value >> 8;
130  tmp[3] = value;
131  g_string_append_len (buffer, (char*)tmp, 4);
132 }
133 
134 
145 static G_GNUC_PURE uint32_t
146 get32 (const void *buffer)
147 {
148  const unsigned char *s = buffer;
149  uint32_t value;
150 
151  value = s[0] << 24;
152  value |= s[1] << 16;
153  value |= s[2] << 8;
154  value |= s[3];
155 
156  return value;
157 }
158 
171 static void
172 log_gpgme (GLogLevelFlags level, gpg_error_t err, const char *fmt, ...)
173 {
174  va_list arg_ptr;
175  char *msg;
176 
177  va_start (arg_ptr, fmt);
178  msg = g_strdup_vprintf (fmt, arg_ptr);
179  va_end (arg_ptr);
180  if (err && gpg_err_source (err) != GPG_ERR_SOURCE_ANY)
181  g_log (G_LOG_DOMAIN, level, "%s: %s <%s>",
182  msg, gpg_strerror (err), gpg_strsource (err));
183  else if (err)
184  g_log (G_LOG_DOMAIN, level, "%s: %s",
185  msg, gpg_strerror (err));
186  else
187  g_log (G_LOG_DOMAIN, level, "%s",
188  msg);
189  g_free (msg);
190 }
191 
192 
193 
194 
195 /* Local functions. */
196 
197 
207 static int
208 create_the_key (lsc_crypt_ctx_t ctx)
209 {
210  const char parms[] =
211  "<GnupgKeyParms format=\"internal\">\n"
212  "Key-Type: RSA\n"
213  "Key-Length: 2048\n"
214  "Key-Usage: encrypt\n"
215  "Name-Real: " ENCRYPTION_KEY_UID "\n"
216  "Expire-Date: 0\n"
217  "%no-protection\n"
218  "%no-ask-passphrase\n"
219  "</GnupgKeyParms>\n";
220  gpg_error_t err;
221 
222  log_gpgme (G_LOG_LEVEL_INFO, 0, "starting key generation ...");
223  err = gpgme_op_genkey (ctx->encctx, parms, NULL, NULL);
224  if (err)
225  {
226  log_gpgme(G_LOG_LEVEL_WARNING, err, "error creating OpenPGP key '%s'",
228  return -1;
229  }
230  log_gpgme (G_LOG_LEVEL_INFO, 0,
231  "OpenPGP key '%s' has been generated", ENCRYPTION_KEY_UID);
232  return 0;
233 }
234 
235 
247 static gpgme_key_t
248 find_the_key (lsc_crypt_ctx_t ctx, gboolean no_create)
249 {
250  gpg_error_t err;
251  int nfound, any_skipped;
252  gpgme_key_t found, key;
253 
254  again:
255  /* Search for the public key. Note that the "=" prefix flag enables
256  an exact search. */
257  err = gpgme_op_keylist_start (ctx->encctx, "="ENCRYPTION_KEY_UID, 0);
258  if (err)
259  {
260  log_gpgme (G_LOG_LEVEL_WARNING, err,
261  "error starting search for OpenPGP key '%s'",
263  return NULL;
264  }
265 
266  nfound = any_skipped = 0;
267  found = NULL;
268  while (!(err = gpgme_op_keylist_next (ctx->encctx, &key)))
269  {
270  if (!key->can_encrypt || key->revoked || key->expired
271  || key->disabled || key->invalid)
272  {
273  log_gpgme (G_LOG_LEVEL_MESSAGE, 0, "skipping unusable OpenPGP key %s",
274  key->subkeys? nonnull (key->subkeys->keyid):"?");
275  any_skipped = 1;
276  continue;
277  }
278  nfound++;
279  if (!found)
280  {
281  gpgme_key_ref (key);
282  found = key;
283  }
284  gpgme_key_unref (key);
285  }
286  if (gpgme_err_code (err) == GPG_ERR_EOF)
287  err = 0;
288  gpgme_op_keylist_end (ctx->encctx);
289 
290  if (err)
291  {
292  /* We better reset the gpgme context after an error. */
293  gpgme_release (ctx->encctx);
294  ctx->encctx = openvas_init_gpgme_ctx ("openvasmd");
295  if (!ctx->encctx)
296  {
297  g_critical ("%s: can't continue w/o a gpgme context\n", G_STRFUNC);
298  exit (EXIT_FAILURE);
299  }
300  }
301  else if (!found)
302  {
303  static int genkey_tried;
304 
305  /* Try to create the key if we have not seen any matching key at
306  all and if this is the first time in this process' lifetime. */
307  if (!any_skipped && !genkey_tried && !no_create)
308  {
309  genkey_tried = 1;
310  if (!create_the_key (ctx))
311  goto again; /* Created - search again. */
312  }
313 
314  err = gpg_err_make (GPG_ERR_SOURCE_ANY, GPG_ERR_NOT_FOUND);
315  }
316  else if (nfound > 1)
317  err = gpg_err_make (GPG_ERR_SOURCE_ANY, GPG_ERR_AMBIGUOUS);
318 
319  if (err)
320  {
321  log_gpgme (G_LOG_LEVEL_MESSAGE, err,
322  "error searching for OpenPGP key '%s'",
324  gpgme_key_unref (found);
325  found = NULL;
326  }
327 
328  return found;
329 }
330 
331 
345 static char *
346 do_encrypt (lsc_crypt_ctx_t ctx, const void *plaintext, size_t plaintextlen)
347 {
348  gpg_error_t err;
349  gpgme_data_t in, out;
350  gpgme_key_t keyarray[2];
351  char *ciphertext;
352  size_t ciphertextlen;
353  char *result;
354 
355  if (!ctx->enckey)
356  {
357  ctx->enckey = find_the_key (ctx, 0);
358  if (!ctx->enckey)
359  return NULL;
360  }
361 
362  err = gpgme_data_new_from_mem (&in, plaintext, plaintextlen, 0);
363  if (err)
364  {
365  log_gpgme (G_LOG_LEVEL_WARNING, err,
366  "%s: error creating data object from plaintext",
367  G_STRFUNC);
368  return NULL;
369  }
370 
371  err = gpgme_data_new (&out);
372  if (err)
373  {
374  log_gpgme (G_LOG_LEVEL_WARNING, err,
375  "%s: error creating data object for ciphertext",
376  G_STRFUNC);
377  gpgme_data_release (in);
378  return NULL;
379  }
380 
381  gpgme_set_armor (ctx->encctx, 0);
382  keyarray[0] = ctx->enckey;
383  keyarray[1] = NULL;
384  err = gpgme_op_encrypt (ctx->encctx, keyarray,
385  GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
386  gpgme_data_release (in);
387  if (err)
388  {
389  log_gpgme (G_LOG_LEVEL_WARNING, err,
390  "%s: error encrypting credential",
391  G_STRFUNC);
392  gpgme_data_release (out);
393  return NULL;
394  }
395  ciphertext = gpgme_data_release_and_get_mem (out, &ciphertextlen);
396  if (!ciphertext)
397  {
398  g_critical ("%s: error snatching memory", G_STRFUNC);
399  exit (EXIT_FAILURE);
400  }
401 
402  result = g_base64_encode ((unsigned char *)ciphertext, ciphertextlen);
403  gpgme_free (ciphertext);
404 
405  return result;
406 }
407 
408 
427 static char *
428 do_decrypt (lsc_crypt_ctx_t ctx, const char *cipherstring,
429  size_t *r_plaintextlen)
430 {
431  gpg_error_t err;
432  gpgme_data_t in, out;
433  char *ciphertext;
434  size_t ciphertextlen;
435  char *result;
436 
437  /* Unfortunately GPGME does not yet support plain base64 encoding. */
438  ciphertext = (char *)g_base64_decode (cipherstring, &ciphertextlen);
439  if (!ciphertext || !ciphertextlen)
440  return NULL; /* Empty or bad encoding. */
441 
442  err = gpgme_data_new_from_mem (&in, ciphertext, ciphertextlen, 0);
443  if (err)
444  {
445  log_gpgme (G_LOG_LEVEL_WARNING, err,
446  "%s: error creating data object from ciphertext",
447  G_STRFUNC);
448  g_free (ciphertext);
449  return NULL;
450  }
451  /* (We must release CIPHERTEXT only after IN.) */
452 
453  err = gpgme_data_new (&out);
454  if (err)
455  {
456  log_gpgme (G_LOG_LEVEL_WARNING, err,
457  "%s: error creating data object for plaintext",
458  G_STRFUNC);
459  gpgme_data_release (in);
460  g_free (ciphertext);
461  return NULL;
462  }
463 
464  err = gpgme_op_decrypt (ctx->encctx, in, out);
465  gpgme_data_release (in);
466  g_free (ciphertext);
467  if (err)
468  {
469  gpgme_decrypt_result_t decres;
470  gpgme_recipient_t recp;
471 
472  gpgme_data_release (out);
473  log_gpgme (G_LOG_LEVEL_WARNING, err, "error decrypting credential");
474  decres = gpgme_op_decrypt_result (ctx->encctx);
475  if (decres->unsupported_algorithm)
476  log_gpgme (G_LOG_LEVEL_INFO, 0, " unsupported algorithm (%s)",
477  decres->unsupported_algorithm);
478  if (decres->wrong_key_usage)
479  log_gpgme (G_LOG_LEVEL_INFO, 0, " wrong key usage");
480  for (recp = decres->recipients; recp; recp = recp->next)
481  log_gpgme (G_LOG_LEVEL_INFO, recp->status,
482  " encrypted to keyid %s, algo=%d",
483  recp->keyid, recp->pubkey_algo);
484  return NULL;
485  }
486  result = gpgme_data_release_and_get_mem (out, r_plaintextlen);
487  if (!result)
488  {
489  g_critical ("%s: error snatching memory", G_STRFUNC);
490  exit (EXIT_FAILURE);
491  }
492 
493  return result;
494 }
495 
496 
497 
498 /* API */
499 
508 {
509  lsc_crypt_ctx_t ctx;
510 
511  ctx = g_malloc0 (sizeof *ctx);
512  ctx->encctx = openvas_init_gpgme_ctx ("openvasmd");
513  if (!ctx->encctx)
514  {
515  g_critical ("%s: can't continue w/o a gpgme context\n", G_STRFUNC);
516  exit (EXIT_FAILURE);
517  }
518 
519  return ctx;
520 }
521 
527 void
529 {
530  if (!ctx)
531  return;
532  lsc_crypt_flush (ctx);
533  if (ctx->encctx) /* Check required for gpgme < 1.3.1 */
534  gpgme_release (ctx->encctx);
535  g_free (ctx);
536 }
537 
548 int
550 {
551  int res = -1;
552  lsc_crypt_ctx_t ctx;
553  gpgme_key_t key;
554 
555  ctx = lsc_crypt_new ();
556  key = find_the_key (ctx, TRUE);
557  if (key)
558  {
559  gpgme_key_unref (key);
560  g_warning ("A credentials encryption key already exists - "
561  "not creating another one.");
562  res = 1;
563  }
564  else
565  {
566  if (!create_the_key (ctx))
567  res = 0;
568  }
569 
570  lsc_crypt_release (ctx);
571  return res;
572 }
573 
574 
585 void
587 {
588  if (!ctx)
589  return;
590  while (ctx->namelist)
591  {
592  struct namelist_s *nl = ctx->namelist->next;
593  g_free (ctx->namelist->value);
594  g_free (ctx->namelist);
595  ctx->namelist = nl;
596  }
597  g_free (ctx->plaintext);
598  ctx->plaintext = NULL;
599 }
600 
601 
615 char *
616 lsc_crypt_encrypt (lsc_crypt_ctx_t ctx, const char *first_name, ...)
617 {
618  va_list arg_ptr;
619  GString *stringbuf;
620  char *plaintext;
621  size_t plaintextlen;
622  char *ciphertext;
623  const char *name, *value;
624  size_t len;
625 
626  if (!ctx || !first_name)
627  return NULL;
628 
629  /* Assuming a 2048 bit RSA ssh private key in PEM encoding, a buffer
630  with an initial size of 2k should be large enough. */
631  stringbuf = g_string_sized_new (2048);
632 
633  name = first_name;
634  va_start (arg_ptr, first_name);
635  do
636  {
637  value = va_arg (arg_ptr, const char *);
638  if (!value)
639  value = "";
640  len = strlen (name);
641  if (len) /* We skip pairs with an empty name. */
642  {
643  put32 (stringbuf, len);
644  g_string_append (stringbuf, name);
645  len = strlen (value);
646  if (len > MAX_VALUE_LENGTH)
647  {
648  g_warning ("%s: value for '%s' larger than our limit (%d)",
649  G_STRFUNC, name, MAX_VALUE_LENGTH);
650  g_string_free (stringbuf, TRUE);
651  va_end (arg_ptr);
652  return NULL;
653  }
654  put32 (stringbuf, len);
655  g_string_append (stringbuf, value);
656  }
657  }
658  while ((name = va_arg (arg_ptr, const char *)))
659  ;
660  va_end (arg_ptr);
661  plaintext = stringbuf->str;
662  plaintextlen = stringbuf->len;
663  g_string_free (stringbuf, FALSE);
664  g_assert (plaintextlen);
665 
666  ciphertext = do_encrypt (ctx, plaintext, plaintextlen);
667  g_free (plaintext);
668 
669  return ciphertext;
670 }
671 
672 
692 const char *
693 lsc_crypt_decrypt (lsc_crypt_ctx_t ctx, const char *ciphertext,
694  const char *name)
695 {
696  size_t namelen;
697  const char *p;
698  size_t len;
699  uint32_t n;
700  int found;
701  struct namelist_s *nl;
702 
703  if (!ctx || !name || !*name)
704  return NULL;
706  {
707  static gboolean shown;
708  if (!shown)
709  {
710  shown = 1;
711  g_warning ("note that decryption of credentials has been disabled");
712  }
713  return NULL;
714  }
715 
716  if (!ctx->plaintext)
717  {
718  if (!ciphertext)
719  return NULL;
720  ctx->plaintext = do_decrypt (ctx, ciphertext, &ctx->plaintextlen);
721  if (!ctx->plaintext)
722  return NULL;
723  }
724 
725  /* Try to return it from the cache. */
726  for (nl = ctx->namelist; nl; nl = nl->next)
727  if (!strcmp (nl->name, name))
728  {
729  return (nl->value
730  ? nl->value
731  : (nl->valoff ? (ctx->plaintext + nl->valoff) : NULL));
732  }
733 
734  /* Cache miss: Parse the data, cache the result, and return it. */
735  /* Fixme: Cache a not found status. */
736  namelen = strlen (name);
737  p = ctx->plaintext;
738  len = ctx->plaintextlen;
739  found = 0;
740  while (len)
741  {
742  if (len < 4)
743  goto failed;
744  n = get32 (p); p += 4; len -= 4;
745  if (n > len)
746  goto failed;
747  if (n == namelen && !memcmp (p, name, namelen))
748  found = 1;
749  p += n; len -= n;
750  if (len < 4)
751  goto failed;
752  n = get32 (p); p += 4; len -= 4;
753  if (n > len)
754  goto failed;
755  if (found)
756  {
757  if (n > MAX_VALUE_LENGTH)
758  {
759  g_warning ("%s: value for '%s' larger than our limit (%d)",
760  G_STRFUNC, name, MAX_VALUE_LENGTH);
761  return NULL;
762  }
763  nl = g_malloc (sizeof *nl + namelen);
764 #if 0
765  strcpy (nl->name, name);
766 #else
767  /* The pointer arithmetic helps Clang see that nl is allocated
768  * bigger than the size of *nl. */
769  strcpy (((char *) nl) + (nl->name - (char *) nl), name);
770 #endif
771 
772  if (n + 1 < len && p[n] == 0)
773  {
774  /* The values is followed by another name and the first
775  byte of that name's length is 0. Thus we don't need
776  to take a copy because that length byte acts as the
777  string terminator. */
778  nl->valoff = (p - ctx->plaintext);
779  nl->value = NULL;
780  }
781  else
782  {
783  /* We need to take a copy of the value, so that we can
784  add the string terminator. */
785  nl->valoff = 0;
786  nl->value = g_malloc (n + 1);
787  memcpy (nl->value, p, n);
788  nl->value[n] = 0;
789  }
790  nl->next = ctx->namelist;
791  ctx->namelist = nl;
792  return nl->value? nl->value : (ctx->plaintext + nl->valoff);
793  }
794  p += n; len -= n;
795  }
796  if (!len)
797  goto not_found;
798 
799  failed:
800  g_warning ("%s: decrypted credential data block is inconsistent;"
801  " %zu bytes remaining at offset %zu",
802  G_STRFUNC, len, (size_t)(p - ctx->plaintext));
803  not_found:
804  /* Cache a NULL value. */
805  nl = g_malloc (sizeof *nl + namelen);
806 #if 0
807  strcpy (nl->name, name);
808 #else
809  /* The pointer arithmetic helps Clang see that nl is allocated
810  * bigger than the size of *nl. */
811  strcpy (((char *) nl) + (nl->name - (char *) nl), name);
812 #endif
813  nl->valoff = 0;
814  nl->value = NULL;
815  nl->next = ctx->namelist;
816  ctx->namelist = nl;
817  return NULL;
818 }
819 
820 
839 const char *
840 lsc_crypt_get_password (lsc_crypt_ctx_t ctx, const char *ciphertext)
841 {
842  return lsc_crypt_decrypt (ctx, ciphertext, "password");
843 }
844 
863 const char *
864 lsc_crypt_get_private_key (lsc_crypt_ctx_t ctx, const char *ciphertext)
865 {
866  return lsc_crypt_decrypt (ctx, ciphertext, "private_key");
867 }
char * plaintext
Definition: lsc_crypt.c:91
lsc_crypt_ctx_t lsc_crypt_new()
Return a new context for LSC encryption.
Definition: lsc_crypt.c:507
struct namelist_s * next
Definition: lsc_crypt.c:71
#define MAX_VALUE_LENGTH
The maximum size of an encrypted value.
Definition: lsc_crypt.c:58
int lsc_crypt_create_key()
Create the standard credential encryption key.
Definition: lsc_crypt.c:549
#define G_LOG_DOMAIN
GLib log domain.
Definition: lsc_crypt.c:41
gpgme_key_t enckey
Definition: lsc_crypt.c:90
const char * lsc_crypt_get_private_key(lsc_crypt_ctx_t ctx, const char *ciphertext)
Return an encrypted private key in the clear.
Definition: lsc_crypt.c:864
A linked list to help caching results.
Definition: lsc_crypt.c:69
int disable_encrypted_credentials
Flag indicating that encrypted credentials are disabled.
Definition: openvasmd.c:275
void lsc_crypt_flush(lsc_crypt_ctx_t ctx)
Flush an LSC encryption context.
Definition: lsc_crypt.c:586
#define ENCRYPTION_KEY_UID
The name of the encryption key.
Definition: lsc_crypt.c:50
const char * lsc_crypt_get_password(lsc_crypt_ctx_t ctx, const char *ciphertext)
Return an encrypted password in the clear.
Definition: lsc_crypt.c:840
gpgme_ctx_t encctx
Definition: lsc_crypt.c:89
The context object for encryption operations.
Definition: lsc_crypt.c:87
const char * lsc_crypt_decrypt(lsc_crypt_ctx_t ctx, const char *ciphertext, const char *name)
Return an encrypted value in the clear.
Definition: lsc_crypt.c:693
size_t plaintextlen
Definition: lsc_crypt.c:92
struct namelist_s * namelist
Definition: lsc_crypt.c:93
char * lsc_crypt_encrypt(lsc_crypt_ctx_t ctx, const char *first_name,...)
Encrypt a list of name/value pairs.
Definition: lsc_crypt.c:616
char * value
Definition: lsc_crypt.c:77
#define GPG_ERR_AMBIGUOUS
Definition: lsc_crypt.c:63
void lsc_crypt_release(lsc_crypt_ctx_t ctx)
Release an LSC encryption context.
Definition: lsc_crypt.c:528
char name[1]
Definition: lsc_crypt.c:78
size_t valoff
Definition: lsc_crypt.c:72