]> git.sur5r.net Git - bacula/bacula/commitdiff
Merge the Bacula Encryption branch to HEAD.
authorLandon Fuller <landonf@opendarwin.org>
Sun, 4 Dec 2005 02:09:23 +0000 (02:09 +0000)
committerLandon Fuller <landonf@opendarwin.org>
Sun, 4 Dec 2005 02:09:23 +0000 (02:09 +0000)
Approved by: Kern

git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@2638 91ce42f0-d328-0410-95d8-f526ca767f89

55 files changed:
bacula/autoconf/config.h.in
bacula/autoconf/configure.in
bacula/configure
bacula/src/baconfig.h
bacula/src/bacula.h
bacula/src/cats/bdb_update.c
bacula/src/cats/cats.h
bacula/src/cats/protos.h
bacula/src/cats/sql_create.c
bacula/src/cats/sql_get.c
bacula/src/cats/sql_update.c
bacula/src/console/console.c
bacula/src/dird/catreq.c
bacula/src/dird/dird.c
bacula/src/dird/fd_cmds.c
bacula/src/dird/inc_conf.c
bacula/src/dird/job.c
bacula/src/dird/verify.c
bacula/src/filed/Makefile.in
bacula/src/filed/backup.c
bacula/src/filed/chksum.c [deleted file]
bacula/src/filed/chksum.h [deleted file]
bacula/src/filed/filed.c
bacula/src/filed/filed.h
bacula/src/filed/filed_conf.c
bacula/src/filed/filed_conf.h
bacula/src/filed/job.c
bacula/src/filed/protos.h
bacula/src/filed/restore.c
bacula/src/filed/verify.c
bacula/src/filed/verify_vol.c
bacula/src/findlib/bfile.c
bacula/src/findlib/find.h
bacula/src/gnome2-console/console.c
bacula/src/jcr.h
bacula/src/lib/Makefile.in
bacula/src/lib/base64.h [new file with mode: 0644]
bacula/src/lib/crypto.c [new file with mode: 0644]
bacula/src/lib/crypto.h [new file with mode: 0644]
bacula/src/lib/hmac.c
bacula/src/lib/lib.h
bacula/src/lib/md5.h
bacula/src/lib/openssl.c [new file with mode: 0644]
bacula/src/lib/openssl.h [new file with mode: 0644]
bacula/src/lib/parse_conf.c
bacula/src/lib/protos.h
bacula/src/lib/tls.c
bacula/src/lib/tls.h
bacula/src/stored/append.c
bacula/src/stored/bextract.c
bacula/src/stored/bscan.c
bacula/src/stored/read_record.c
bacula/src/stored/record.c
bacula/src/stored/stored.c
bacula/src/wx-console/console_thread.cpp

index 89a173a3921e9336c808b6a65c7ad5666a82f465..c9eee566605568e3d0cde802e9c7669f4772ef2c 100644 (file)
 /* Set if Bacula conio support enabled */
 #undef HAVE_CONIO
 
+/* Define if encryption support should be enabled */
+#undef HAVE_CRYPTO
+
+/* Define if the SHA-2 family of digest algorithms is available */
+#undef HAVE_SHA2
+
 /* Define to 1 if you have the <curses.h> header file. */
 #undef HAVE_CURSES_H
 
index 1844cb79fe6254857e236b14a9fa98d0d94ceab8..c0cac2b5481a6ec32a94b46496720e0563ebf5a3 100644 (file)
@@ -193,6 +193,7 @@ support_conio=yes
 support_gnome=no
 support_wx_console=no
 support_tls=no
+support_crypto=no
 gnome_version=
 wx_version=
 support_static_tools=no
@@ -751,19 +752,34 @@ if test "x$with_openssl_directory" != "x"; then
 
        AC_TRY_LINK([ #include <openssl/ssl.h> ],
                [ CRYPTO_set_id_callback(NULL); ],
-               [ support_tls="yes" ],
+               [
+                       support_tls="yes"
+                       support_crypto="yes"
+               ],
                [ support_tls="no" ]
        )
 
+       AC_TRY_LINK([ #include <openssl/evp.h> ],
+               [ EVP_sha512(); ],
+               [ ac_cv_openssl_sha2="yes" ],
+               [ ac_cv_openssl_sha2="no" ]
+       )
+
        LIBS="$saved_LIBS"
        CFLAGS="$saved_CFLAGS"
 
        if test "$support_tls" = "yes"; then
                AC_DEFINE(HAVE_OPENSSL, 1, [Define if OpenSSL library is available])
                AC_DEFINE(HAVE_TLS, 1, [Define if TLS support should be enabled])
+               AC_DEFINE(HAVE_CRYPTO, 1, [Define if encryption support should be enabled])
+       fi
+
+       if test "$ac_cv_openssl_sha2" = "yes"; then
+               AC_DEFINE(HAVE_SHA2, 1, [Define if the SHA-2 family of digest algorithms is available])
        fi
 else
        support_tls="no"
+       support_crypto="no"
        OPENSSL_LIBS=""
        OPENSSL_INC=""
 fi
@@ -2112,6 +2128,7 @@ Configuration on `date`:
   readline support:          ${got_readline} ${PRTREADLINE_SRC}
   TCP Wrappers support:       ${TCPW_MSG} ${WRAPLIBS}
   TLS support:               ${support_tls}
+  Encryption support:        ${support_crypto} 
   ZLIB support:              ${have_zlib}
   enable-smartalloc:         ${support_smartalloc} 
   enable-gnome:              ${support_gnome} ${gnome_version}
index 48c8e5a5bfab9d4d7046d78cb78f70bfbc482af7..ff48c3ab6684bd12609af26705e0ece8d30a0c4c 100755 (executable)
@@ -12770,6 +12770,7 @@ support_conio=yes
 support_gnome=no
 support_wx_console=no
 support_tls=no
+support_crypto=no
 gnome_version=
 wx_version=
 support_static_tools=no
@@ -15880,13 +15881,64 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
   ac_status=$?
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); }; }; then
-   support_tls="yes"
+
+                       support_tls="yes"
+                       support_crypto="yes"
+
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
  support_tls="no"
 
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+ #include <openssl/evp.h>
+int
+main ()
+{
+ EVP_sha512();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+   ac_cv_openssl_sha2="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_openssl_sha2="no"
+
 fi
 rm -f conftest.err conftest.$ac_objext \
       conftest$ac_exeext conftest.$ac_ext
@@ -15905,9 +15957,23 @@ cat >>confdefs.h <<\_ACEOF
 #define HAVE_TLS 1
 _ACEOF
 
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_CRYPTO 1
+_ACEOF
+
+       fi
+
+       if test "$ac_cv_openssl_sha2" = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SHA2 1
+_ACEOF
+
        fi
 else
        support_tls="no"
+       support_crypto="no"
        OPENSSL_LIBS=""
        OPENSSL_INC=""
 fi
@@ -31536,6 +31602,7 @@ Configuration on `date`:
   readline support:          ${got_readline} ${PRTREADLINE_SRC}
   TCP Wrappers support:       ${TCPW_MSG} ${WRAPLIBS}
   TLS support:               ${support_tls}
+  Encryption support:        ${support_crypto}
   ZLIB support:              ${have_zlib}
   enable-smartalloc:         ${support_smartalloc}
   enable-gnome:              ${support_gnome} ${gnome_version}
index 53a6ac150838ce1e94c21e01b9c1d74364599fb2..e1139b5c1b45e50e5437fbd6507996163786e475 100644 (file)
  *
  *   STREAM_UNIX_ATTRIBUTES
  *   STREAM_UNIX_ATTRIBUTES_EX
- *   STREAM_MD5_SIGNATURE
- *   STREAM_SHA1_SIGNATURE
+ *   STREAM_MD5_DIGEST
+ *   STREAM_SHA1_DIGEST
+ *   STREAM_SHA256_DIGEST
+ *   STREAM_SHA512_DIGEST
  */
+#define STREAM_NONE               0    /* Reserved Non-Stream */
 #define STREAM_UNIX_ATTRIBUTES    1    /* Generic Unix attributes */
 #define STREAM_FILE_DATA          2    /* Standard uncompressed data */
-#define STREAM_MD5_SIGNATURE      3    /* MD5 signature for the file */
+#define STREAM_MD5_DIGEST         3    /* MD5 digest for the file */
 #define STREAM_GZIP_DATA          4    /* GZip compressed file data */
 /* Extended Unix attributes with Win32 Extended data.  Deprecated. */
 #define STREAM_UNIX_ATTRIBUTES_EX 5    /* Extended Unix attr for Win32 EX */
 #define STREAM_SPARSE_GZIP_DATA   7
 #define STREAM_PROGRAM_NAMES      8    /* program names for program data */
 #define STREAM_PROGRAM_DATA       9    /* Data needing program */
-#define STREAM_SHA1_SIGNATURE    10    /* SHA1 signature for the file */
+#define STREAM_SHA1_DIGEST       10    /* SHA1 digest for the file */
 #define STREAM_WIN32_DATA        11    /* Win32 BackupRead data */
 #define STREAM_WIN32_GZIP_DATA   12    /* Gzipped Win32 BackupRead data */
 #define STREAM_MACOS_FORK_DATA   13    /* Mac resource fork */
 #define STREAM_UNIX_ATTRIBUTES_ACCESS_ACL 15 /* Standard ACL attributes on UNIX */
 #define STREAM_UNIX_ATTRIBUTES_DEFAULT_ACL 16 /* Default ACL attributes on UNIX */
 /*** FIXME ***/
+#define STREAM_SHA256_DIGEST     17    /* SHA-256 digest for the file */
+#define STREAM_SHA512_DIGEST     18    /* SHA-512 digest for the file */
+#define STREAM_SIGNED_DIGEST     19    /* Signed File Digest, ASN.1 Encoded */
+#define STREAM_ENCRYPTED_FILE_DATA 20  /* Encrypted, uncompressed data */
+#define STREAM_ENCRYPTED_WIN32_DATA 21 /* Encrypted, uncompressed Win32 BackupRead data */
 
 
 /*
 /* Definitions for upper part of type word (see above). */
 #define AR_DATA_STREAM (1<<16)        /* Data stream id present */
 
-/*
- * Internal code for Signature types
- */
-#define NO_SIG   0
-#define MD5_SIG  1
-#define SHA1_SIG 2
-
 /*
  * Tape label types -- stored in catalog
  */
index e820a93c0e7f811ca84f3c8b2673a4545f6791dc..6225d44e11d64bdac605acbd8071cc40bbff6b47 100644 (file)
 #include <openssl/x509v3.h>
 #include <openssl/rand.h>
 #include <openssl/err.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
 #undef STORE
 #endif
 
index bea9cc8bec097a7c8fdfcee7e4c5a4f65651ece4..7b1f054f8d88e41f8ed1abb8a5759498e9554ea1 100755 (executable)
@@ -197,7 +197,7 @@ int db_update_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
    return stat;
 }
 
-int db_add_SIG_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *SIG, int type)
+int db_add_digest_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *digest, int type)
 {
    return 1;
 }
index 069d9257f72e3308f6526ec601dc2f2a2c3227e0..00ea5a097457c192b3e13d2b542b291ed96b9b6d 100644 (file)
@@ -614,8 +614,8 @@ struct ATTR_DBR {
    DBId_t PathId;
    DBId_t FilenameId;
    FileId_t FileId;
-   char *Sig;
-   int SigType;
+   char *Digest;
+   int DigestType;
 };
 
 
@@ -628,8 +628,8 @@ struct FILE_DBR {
    DBId_t PathId;
    JobId_t  MarkId;
    char LStat[256];
-   char SIG[50];
-   int SigType;                       /* NO_SIG/MD5_SIG/SHA1_SIG */
+   char Digest[BASE64_SIZE(CRYPTO_DIGEST_MAX_SIZE)];
+   int DigestType;                    /* NO_SIG/MD5_SIG/SHA1_SIG */
 };
 
 /* Pool record -- same format as database */
index 24e5c2c8d5b216cf0f74ba2fb634e0f55673f7eb..580d3c387b7fc3719bfa997b2747209ab7eb04ed 100644 (file)
@@ -110,7 +110,7 @@ bool db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr);
 int  db_update_media_record(JCR *jcr, B_DB *db, MEDIA_DBR *mr);
 int  db_update_media_defaults(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr);
 int  db_update_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr);
-int  db_add_SIG_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *SIG, int type);
+int  db_add_digest_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *digest, int type);
 int  db_mark_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, JobId_t JobId);
 void db_make_inchanger_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr);
 
index fb46704122f6135f0d67e384cd026149d537130d..8f0609815657402856413855ee0adaad5388984c 100644 (file)
@@ -709,17 +709,17 @@ bail_out:
 static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
 {
    int stat;
-   static char *no_sig = "0";
-   char *sig;
+   static char *no_digest = "0";
+   char *digest;
 
    ASSERT(ar->JobId);
    ASSERT(ar->PathId);
    ASSERT(ar->FilenameId);
 
-   if (ar->Sig == NULL) {
-      sig = no_sig;
+   if (ar->Digest == NULL) {
+      digest = no_digest;
    } else {
-      sig = ar->Sig;
+      digest = ar->Digest;
    }
 
    /* Must create it */
@@ -727,7 +727,7 @@ static int db_create_file_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
         "INSERT INTO File (FileIndex,JobId,PathId,FilenameId,"
         "LStat,MD5) VALUES (%u,%u,%u,%u,'%s','%s')",
         ar->FileIndex, ar->JobId, ar->PathId, ar->FilenameId,
-        ar->attr, sig);
+        ar->attr, digest);
 
    if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
       Mmsg2(&mdb->errmsg, _("Create db File record %s failed. ERR=%s"),
index 701332e2d56609d1822957571cfee238dcaa1af0..c461cba6b5983b6d3d2f3524eebec8964aae1deb 100644 (file)
@@ -136,7 +136,7 @@ int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr)
          } else {
             fdbr->FileId = (FileId_t)str_to_int64(row[0]);
             bstrncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat));
-            bstrncpy(fdbr->SIG, row[2], sizeof(fdbr->SIG));
+            bstrncpy(fdbr->Digest, row[2], sizeof(fdbr->Digest));
             stat = 1;
          }
       } else {
index 3e27669f771720f42a4f9d8af317f9cc66e0cd98..9294d3c68c5cd0ee8d0e7a25d1230639a861fce4 100644 (file)
@@ -53,16 +53,16 @@ extern int UpdateDB(const char *file, int line, JCR *jcr, B_DB *db, char *update
  *
  * -----------------------------------------------------------------------
  */
-/* Update the attributes record by adding the MD5 signature */
+/* Update the attributes record by adding the file digest */
 int
-db_add_SIG_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *SIG,
+db_add_digest_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *digest,
                           int type)
 {
    int stat;
-   char ed1[50];
+   char ed1[CRYPTO_DIGEST_MAX_SIZE];
 
    db_lock(mdb);
-   Mmsg(mdb->cmd, "UPDATE File SET MD5='%s' WHERE FileId=%s", SIG
+   Mmsg(mdb->cmd, "UPDATE File SET MD5='%s' WHERE FileId=%s", digest
       edit_int64(FileId, ed1));
    stat = UPDATE_DB(jcr, mdb, mdb->cmd);
    db_unlock(mdb);
index 9bea604bd5f126bb26c5a0cce5137dc92818e858..7611e9008e7b42b5097bf5e99e5f8a05bc498793 100644 (file)
@@ -396,8 +396,8 @@ int main(int argc, char *argv[])
 
    parse_config(configfile);
 
-   if (init_tls() != 0) {
-      Emsg0(M_ERROR_TERM, 0, _("TLS library initialization failed.\n"));
+   if (init_crypto() != 0) {
+      Emsg0(M_ERROR_TERM, 0, _("Cryptography library initialization failed.\n"));
    }
 
    if (!check_resources()) {
@@ -549,7 +549,7 @@ static void terminate_console(int sig)
       exit(1);
    }
    already_here = true;
-   cleanup_tls();
+   cleanup_crypto();
    free_pool_memory(args);
    con_term();
    (void)WSACleanup();               /* Cleanup Windows sockets */
index 41cebc6d29146daf0d54fb4febeaf1f83bf13485..5ac184d4f529701665be001d5717c3b37a9ac60e 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "bacula.h"
 #include "dird.h"
+#include "findlib/find.h"
 
 /*
  * Handle catalog request
@@ -396,8 +397,8 @@ void catalog_update(JCR *jcr, BSOCK *bs)
       ar->Stream = Stream;
       ar->link = NULL;
       ar->JobId = jcr->JobId;
-      ar->Sig = NULL;
-      ar->SigType = 0;
+      ar->Digest = NULL;
+      ar->DigestType = CRYPTO_DIGEST_NONE;
       jcr->cached_attribute = true;
 
       Dmsg2(400, "dird<filed: stream=%d %s\n", Stream, fname);
@@ -408,34 +409,52 @@ void catalog_update(JCR *jcr, BSOCK *bs)
          Jmsg1(jcr, M_FATAL, 0, _("Attribute create error. %s"), db_strerror(jcr->db));
       }
 #endif
-   } else if (Stream == STREAM_MD5_SIGNATURE || Stream == STREAM_SHA1_SIGNATURE) {
+   } else if (crypto_digest_stream_type(Stream) != CRYPTO_DIGEST_NONE) {
       fname = p;
       if (ar->FileIndex != FileIndex) {
-         Jmsg(jcr, M_WARNING, 0, _("Got MD5/SHA1 but not same File as attributes\n"));
+         Jmsg(jcr, M_WARNING, 0, _("Got %s but not same File as attributes\n"), stream_to_ascii(Stream));
       } else {
-         /* Update signature in catalog */
-         char SIGbuf[50];           /* 24 bytes should be enough */
-         int len, type;
-         if (Stream == STREAM_MD5_SIGNATURE) {
-            len = 16;
-            type = MD5_SIG;
-         } else {
-            len = 20;
-            type = SHA1_SIG;
+         /* Update digest in catalog */
+         char digestbuf[CRYPTO_DIGEST_MAX_SIZE];
+         int len = 0;
+         int type = CRYPTO_DIGEST_NONE;
+
+         switch(Stream) {
+         case STREAM_MD5_DIGEST:
+            len = CRYPTO_DIGEST_MD5_SIZE;
+            type = CRYPTO_DIGEST_MD5;
+            break;
+         case STREAM_SHA1_DIGEST:
+            len = CRYPTO_DIGEST_SHA1_SIZE;
+            type = CRYPTO_DIGEST_SHA1;
+            break;
+         case STREAM_SHA256_DIGEST:
+            len = CRYPTO_DIGEST_SHA256_SIZE;
+            type = CRYPTO_DIGEST_SHA256;
+            break;
+         case STREAM_SHA512_DIGEST:
+            len = CRYPTO_DIGEST_SHA512_SIZE;
+            type = CRYPTO_DIGEST_SHA512;
+            break;
+         default:
+            /* Never reached ... */
+            Jmsg(jcr, M_ERROR, 0, _("Catalog error updating file digest. Unsupported digest stream type: %d"),
+                 Stream);
          }
-         bin_to_base64(SIGbuf, fname, len);
-         Dmsg3(400, "SIGlen=%d SIG=%s type=%d\n", strlen(SIGbuf), SIGbuf, Stream);
+
+         bin_to_base64(digestbuf, fname, len);
+         Dmsg3(400, "DigestLen=%d Digest=%s type=%d\n", strlen(digestbuf), digestbuf, Stream);
          if (jcr->cached_attribute) {
-            ar->Sig = SIGbuf;
-            ar->SigType = type;
-            Dmsg2(400, "Cached attr with SIG. Stream=%d fname=%s\n", ar->Stream, ar->fname);
+            ar->Digest = digestbuf;
+            ar->DigestType = type;
+            Dmsg2(400, "Cached attr with digest. Stream=%d fname=%s\n", ar->Stream, ar->fname);
             if (!db_create_file_attributes_record(jcr, jcr->db, ar)) {
                Jmsg1(jcr, M_FATAL, 0, _("Attribute create error. %s"), db_strerror(jcr->db));
             }
             jcr->cached_attribute = false; 
          } else {
-            if (!db_add_SIG_to_file_record(jcr, jcr->db, ar->FileId, SIGbuf, type)) {
-               Jmsg(jcr, M_ERROR, 0, _("Catalog error updating MD5/SHA1. %s"),
+            if (!db_add_digest_to_file_record(jcr, jcr->db, ar->FileId, digestbuf, type)) {
+               Jmsg(jcr, M_ERROR, 0, _("Catalog error updating file digest. %s"),
                   db_strerror(jcr->db));
             }
          }
index eec2b9f2cac91bdb1dd39da86af30de6269cf98f..20b32fcdd7c8cf5b47044103c7df2132bcd84581 100644 (file)
@@ -192,8 +192,8 @@ int main (int argc, char *argv[])
 
    parse_config(configfile);
 
-   if (init_tls() != 0) {
-      Jmsg((JCR *)NULL, M_ERROR_TERM, 0, _("TLS library initialization failed.\n"));
+   if (init_crypto() != 0) {
+      Jmsg((JCR *)NULL, M_ERROR_TERM, 0, _("Cryptography library initialization failed.\n"));
    }
 
    if (!check_resources()) {
@@ -280,7 +280,7 @@ static void terminate_dird(int sig)
    term_ua_server();
    term_msg();                        /* terminate message handler */
    stop_watchdog();
-   cleanup_tls();
+   cleanup_crypto();
    close_memory_pool();               /* release free memory in pool */
    sm_dump(false);
    exit(sig);
index d3c02e1c322c19b4ab7fa1d75b39ffde11582a55..5855adf4e327d3cdc0ad650d52c2c37e240fec9c 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "bacula.h"
 #include "dird.h"
+#include "findlib/find.h"
 
 /* Commands sent to File daemon */
 static char filesetcmd[]  = "fileset%s\n"; /* set full fileset */
@@ -508,7 +509,7 @@ int get_attributes_and_put_in_catalog(JCR *jcr)
    jcr->FileIndex = 0;
 
    Dmsg0(120, "bdird: waiting to receive file attributes\n");
-   /* Pickup file attributes and signature */
+   /* Pickup file attributes and digest */
    while (!fd->errors && (n = bget_dirmsg(fd)) > 0) {
 
    /*****FIXME****** improve error handling to stop only on
@@ -518,11 +519,11 @@ int get_attributes_and_put_in_catalog(JCR *jcr)
       long file_index;
       int stream, len;
       char *attr, *p, *fn;
-      char Opts_SIG[MAXSTRING];      /* either Verify opts or MD5/SHA1 signature */
-      char SIG[MAXSTRING];
+      char Opts_Digest[MAXSTRING];      /* either Verify opts or MD5/SHA1 digest */
+      char digest[CRYPTO_DIGEST_MAX_SIZE];
 
       jcr->fname = check_pool_memory_size(jcr->fname, fd->msglen);
-      if ((len = sscanf(fd->msg, "%ld %d %s", &file_index, &stream, Opts_SIG)) != 3) {
+      if ((len = sscanf(fd->msg, "%ld %d %s", &file_index, &stream, Opts_Digest)) != 3) {
          Jmsg(jcr, M_FATAL, 0, _("<filed: bad attributes, expected 3 fields got %d\n"
 "msglen=%d msg=%s\n"), len, fd->msglen, fd->msg);
          set_jcr_job_status(jcr, JS_ErrorTerminated);
@@ -554,8 +555,8 @@ int get_attributes_and_put_in_catalog(JCR *jcr)
          ar.ClientId = jcr->ClientId;
          ar.PathId = 0;
          ar.FilenameId = 0;
-         ar.Sig = NULL;
-         ar.SigType = 0;
+         ar.Digest = NULL;
+         ar.DigestType = CRYPTO_DIGEST_NONE;
 
          Dmsg2(111, "dird<filed: stream=%d %s\n", stream, jcr->fname);
          Dmsg1(120, "dird<filed: attr=%s\n", attr);
@@ -566,17 +567,17 @@ int get_attributes_and_put_in_catalog(JCR *jcr)
             continue;
          }
          jcr->FileId = ar.FileId;
-      } else if (stream == STREAM_MD5_SIGNATURE || stream == STREAM_SHA1_SIGNATURE) {
+      } else if (crypto_digest_stream_type(stream) != CRYPTO_DIGEST_NONE) {
          if (jcr->FileIndex != (uint32_t)file_index) {
-            Jmsg2(jcr, M_ERROR, 0, _("MD5/SHA1 index %d not same as attributes %d\n"),
-               file_index, jcr->FileIndex);
+            Jmsg3(jcr, M_ERROR, 0, _("%s index %d not same as attributes %d\n"),
+               stream_to_ascii(stream), file_index, jcr->FileIndex);
             set_jcr_job_status(jcr, JS_Error);
             continue;
          }
-         db_escape_string(SIG, Opts_SIG, strlen(Opts_SIG));
-         Dmsg2(120, "SIGlen=%d SIG=%s\n", strlen(SIG), SIG);
-         if (!db_add_SIG_to_file_record(jcr, jcr->db, jcr->FileId, SIG,
-                   stream==STREAM_MD5_SIGNATURE?MD5_SIG:SHA1_SIG)) {
+         db_escape_string(digest, Opts_Digest, strlen(Opts_Digest));
+         Dmsg2(120, "DigestLen=%d Digest=%s\n", strlen(digest), digest);
+         if (!db_add_digest_to_file_record(jcr, jcr->db, jcr->FileId, digest,
+                   crypto_digest_stream_type(stream))) {
             Jmsg1(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
             set_jcr_job_status(jcr, JS_Error);
          }
index 0ca26731ab20e9edf9dca00bbdf875e2a3eeef12..67ebde2ac8dcbe1c1ac8167898f0646dd700853f 100644 (file)
@@ -103,7 +103,7 @@ static RES_ITEM options_items[] = {
 enum {
    INC_KW_NONE,
    INC_KW_COMPRESSION,
-   INC_KW_SIGNATURE,
+   INC_KW_DIGEST,
    INC_KW_ENCRYPTION,
    INC_KW_VERIFY,
    INC_KW_ONEFS,
@@ -129,7 +129,7 @@ enum {
  */
 static struct s_kw FS_option_kw[] = {
    {"compression", INC_KW_COMPRESSION},
-   {"signature",   INC_KW_SIGNATURE},
+   {"signature",   INC_KW_DIGEST},
    {"encryption",  INC_KW_ENCRYPTION},
    {"verify",      INC_KW_VERIFY},
    {"onefs",       INC_KW_ONEFS},
@@ -163,8 +163,10 @@ struct s_fs_opt {
  * included files.
  */
 static struct s_fs_opt FS_options[] = {
-   {"md5",      INC_KW_SIGNATURE,    "M"},
-   {"sha1",     INC_KW_SIGNATURE,    "S"},
+   {"md5",      INC_KW_DIGEST,        "M"},
+   {"sha1",     INC_KW_DIGEST,        "S"},
+   {"sha256",   INC_KW_DIGEST,       "S2"},
+   {"sha512",   INC_KW_DIGEST,       "S3"},
    {"gzip",     INC_KW_COMPRESSION,  "Z6"},
    {"gzip1",    INC_KW_COMPRESSION,  "Z1"},
    {"gzip2",    INC_KW_COMPRESSION,  "Z2"},
index 38bc8f9080cb640caba4b8abc4d075617b2108fd..13a52f09ac333d99e4e484843895ea579bc29a52 100644 (file)
@@ -644,13 +644,13 @@ bool get_or_create_fileset_record(JCR *jcr)
    bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
    if (jcr->fileset->have_MD5) {
       struct MD5Context md5c;
-      unsigned char signature[16];
+      unsigned char digest[MD5HashSize];
       memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
-      MD5Final(signature, &md5c);
-      bin_to_base64(fsr.MD5, (char *)signature, 16); /* encode 16 bytes */
+      MD5Final(digest, &md5c);
+      bin_to_base64(fsr.MD5, (char *)digest, MD5HashSize);
       bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
    } else {
-      Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 signature not found.\n"));
+      Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
    }
    if (!jcr->fileset->ignore_fs_changes ||
        !db_get_fileset_record(jcr, jcr->db, &fsr)) {
index f15233465f6ba664d69c712947f99dde1cb55f4a..8081532727a3222543a380cc8d94a9616087183c 100644 (file)
@@ -498,7 +498,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
    int stat = JS_Terminated;
    char buf[MAXSTRING];
    POOLMEM *fname = get_pool_memory(PM_MESSAGE);
-   int do_SIG = NO_SIG;
+   int do_Digest = CRYPTO_DIGEST_NONE;
    int32_t file_index = 0;
 
    memset(&fdbr, 0, sizeof(FILE_DBR));
@@ -512,7 +512,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
     * We expect:
     *   FileIndex
     *   Stream
-    *   Options or SIG (MD5/SHA1)
+    *   Options or Digest (MD5/SHA1)
     *   Filename
     *   Attributes
     *   Link name  ???
@@ -520,11 +520,11 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
    while ((n=bget_dirmsg(fd)) >= 0 && !job_canceled(jcr)) {
       int stream;
       char *attr, *p, *fn;
-      char Opts_SIG[MAXSTRING];        /* Verify Opts or MD5/SHA1 signature */
+      char Opts_Digest[MAXSTRING];        /* Verify Opts or MD5/SHA1 digest */
 
       fname = check_pool_memory_size(fname, fd->msglen);
       jcr->fname = check_pool_memory_size(jcr->fname, fd->msglen);
-      Dmsg1(200, "Atts+SIG=%s\n", fd->msg);
+      Dmsg1(200, "Atts+Digest=%s\n", fd->msg);
       if ((len = sscanf(fd->msg, "%ld %d %100s", &file_index, &stream,
             fname)) != 3) {
          Jmsg3(jcr, M_FATAL, 0, _("bird<filed: bad attributes, expected 3 fields got %d\n"
@@ -535,13 +535,13 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
        * We read the Options or Signature into fname
        *  to prevent overrun, now copy it to proper location.
        */
-      bstrncpy(Opts_SIG, fname, sizeof(Opts_SIG));
+      bstrncpy(Opts_Digest, fname, sizeof(Opts_Digest));
       p = fd->msg;
       skip_nonspaces(&p);             /* skip FileIndex */
       skip_spaces(&p);
       skip_nonspaces(&p);             /* skip Stream */
       skip_spaces(&p);
-      skip_nonspaces(&p);             /* skip Opts_SIG */
+      skip_nonspaces(&p);             /* skip Opts_Digest */
       p++;                            /* skip space */
       fn = fname;
       while (*p != 0) {
@@ -558,7 +558,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
          jcr->JobFiles++;
          jcr->FileIndex = file_index;    /* remember attribute file_index */
          decode_stat(attr, &statf, &LinkFIf);  /* decode file stat packet */
-         do_SIG = NO_SIG;
+         do_Digest = CRYPTO_DIGEST_NONE;
          jcr->fn_printed = false;
          pm_strcpy(jcr->fname, fname);  /* move filename into JCR */
 
@@ -584,13 +584,13 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
          }
 
          Dmsg3(400, "Found %s in catalog. inx=%d Opts=%s\n", jcr->fname,
-            file_index, Opts_SIG);
+            file_index, Opts_Digest);
          decode_stat(fdbr.LStat, &statc, &LinkFIc); /* decode catalog stat */
          /*
           * Loop over options supplied by user and verify the
           * fields he requests.
           */
-         for (p=Opts_SIG; *p; p++) {
+         for (p=Opts_Digest; *p; p++) {
             char ed1[30], ed2[30];
             switch (*p) {
             case 'i':                /* compare INODEs */
@@ -675,10 +675,10 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
                break;
             case '5':                /* compare MD5 */
                Dmsg1(500, "set Do_MD5 for %s\n", jcr->fname);
-               do_SIG = MD5_SIG;
+               do_Digest = CRYPTO_DIGEST_MD5;
                break;
             case '1':                 /* compare SHA1 */
-               do_SIG = SHA1_SIG;
+               do_Digest = CRYPTO_DIGEST_SHA1;
                break;
             case ':':
             case 'V':
@@ -687,13 +687,13 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
             }
          }
       /*
-       * Got SIG Signature from Storage daemon
-       *  It came across in the Opts_SIG field.
+       * Got Digest Signature from Storage daemon
+       *  It came across in the Opts_Digest field.
        */
-      } else if (stream == STREAM_MD5_SIGNATURE || stream == STREAM_SHA1_SIGNATURE) {
-         Dmsg2(400, "stream=SIG inx=%d SIG=%s\n", file_index, Opts_SIG);
+      } else if (crypto_digest_stream_type(stream) != CRYPTO_DIGEST_NONE) {
+         Dmsg2(400, "stream=Digest inx=%d Digest=%s\n", file_index, Opts_Digest);
          /*
-          * When ever we get a signature is MUST have been
+          * When ever we get a digest is MUST have been
           * preceded by an attributes record, which sets attr_file_index
           */
          if (jcr->FileIndex != (uint32_t)file_index) {
@@ -701,20 +701,20 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId)
                file_index, jcr->FileIndex);
             return false;
          }
-         if (do_SIG) {
-            db_escape_string(buf, Opts_SIG, strlen(Opts_SIG));
-            if (strcmp(buf, fdbr.SIG) != 0) {
+         if (do_Digest != CRYPTO_DIGEST_NONE) {
+            db_escape_string(buf, Opts_Digest, strlen(Opts_Digest));
+            if (strcmp(buf, fdbr.Digest) != 0) {
                prt_fname(jcr);
                if (debug_level >= 10) {
                   Jmsg(jcr, M_INFO, 0, _("      %s not same. File=%s Cat=%s\n"),
-                       stream==STREAM_MD5_SIGNATURE?"MD5":"SHA1", buf, fdbr.SIG);
+                       stream_to_ascii(stream), buf, fdbr.Digest);
                } else {
                   Jmsg(jcr, M_INFO, 0, _("      %s differs.\n"),
-                       stream==STREAM_MD5_SIGNATURE?"MD5":"SHA1");
+                       stream_to_ascii(stream));
                }
                stat = JS_Differences;
             }
-            do_SIG = FALSE;
+            do_Digest = CRYPTO_DIGEST_NONE;
          }
       }
       jcr->JobFiles = file_index;
index ff1dde0cd81b86145a90e058f5231cc1baf2f9cc..c0e86adb7fe5c766b598539e0c19ca6fe41e224a 100755 (executable)
@@ -31,10 +31,10 @@ first_rule: all
 dummy:
 
 #
-SVRSRCS = filed.c authenticate.c acl.c backup.c chksum.c estimate.c \
+SVRSRCS = filed.c authenticate.c acl.c backup.c estimate.c \
          filed_conf.c heartbeat.c job.c pythonfd.c \
          restore.c status.c verify.c verify_vol.c
-SVROBJS = filed.o authenticate.o acl.o backup.o chksum.o estimate.o \
+SVROBJS = filed.o authenticate.o acl.o backup.o estimate.o \
          filed_conf.o heartbeat.o job.o pythonfd.o \
          restore.o status.o verify.o verify_vol.o
 
index cb489d6114bae9e9cd0a952a371d7d7fb409b13d..e25d7d0f8644860f47bb0889fc4e78f73a1da6ef 100644 (file)
@@ -27,7 +27,7 @@
 
 /* Forward referenced functions */
 static int save_file(FF_PKT *ff_pkt, void *pkt, bool top_level);
-static int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, struct CHKSUM *chksum);
+static int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, DIGEST *digest, DIGEST *signature_digest);
 static bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream);
 static bool read_and_send_acl(JCR *jcr, int acltype, int stream);
 
@@ -125,7 +125,15 @@ bool blast_data_to_storage_daemon(JCR *jcr, char *addr)
 static int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level)
 {
    int stat, data_stream;
-   struct CHKSUM chksum;
+   DIGEST *digest = NULL;
+   DIGEST *signing_digest = NULL;
+   int digest_stream = STREAM_NONE;
+   // TODO landonf: Allow the user to specify the digest algorithm
+#ifdef HAVE_SHA2
+   crypto_digest_t signing_algorithm = CRYPTO_DIGEST_SHA256;
+#else
+   crypto_digest_t signing_algorithm = CRYPTO_DIGEST_SHA1;
+#endif
    BSOCK *sd;
    JCR *jcr = (JCR *)vjcr;
 
@@ -224,13 +232,55 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level)
 
    Dmsg1(130, "bfiled: sending %s to stored\n", ff_pkt->fname);
 
+   if (!encode_and_send_attributes(jcr, ff_pkt, data_stream)) {
+      return 0;
+   }
+
+   /*
+    * Setup for digest handling. If this fails, the digest will be set to NULL
+    * and not used.
+    */
+   if (ff_pkt->flags & FO_MD5) {
+      digest = crypto_digest_new(CRYPTO_DIGEST_MD5);
+      digest_stream = STREAM_MD5_DIGEST;
+
+   } else if (ff_pkt->flags & FO_SHA1) {
+      digest = crypto_digest_new(CRYPTO_DIGEST_SHA1);
+      digest_stream = STREAM_SHA1_DIGEST;
+
+   } else if (ff_pkt->flags & FO_SHA256) {
+      digest = crypto_digest_new(CRYPTO_DIGEST_SHA256);
+      digest_stream = STREAM_SHA256_DIGEST;
+
+   } else if (ff_pkt->flags & FO_SHA512) {
+      digest = crypto_digest_new(CRYPTO_DIGEST_SHA512);
+      digest_stream = STREAM_SHA512_DIGEST;
+   }
+
+   /* Did digest initialization fail? */
+   if (digest_stream != STREAM_NONE && digest == NULL) {
+      Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"),
+         stream_to_ascii(digest_stream));
+   }
 
    /*
-    * Setup for signature handling.
-    * Then initialise the file descriptor we use for data and other streams.
+    * Set up signature digest handling. If this fails, the signature digest will be set to
+    * NULL and not used.
     */
-   chksum_init(&chksum, ff_pkt->flags);
+   // TODO landonf: We should really only calculate the digest once, for both verification and signing.
+   if (jcr->pki_sign) {
+      signing_digest = crypto_digest_new(signing_algorithm);
+   }
 
+   /* Full-stop if a failure occured initializing the signature digest */
+   if (jcr->pki_sign && signing_digest == NULL) {
+      Jmsg(jcr, M_NOTSAVED, 0, _("%s signature digest initialization failed\n"),
+         stream_to_ascii(signing_algorithm));
+      jcr->Errors++;
+      return 1;
+   }
+
+   /* Initialise the file descriptor we use for data and other streams. */
    binit(&ff_pkt->bfd);
    if (ff_pkt->flags & FO_PORTABLE) {
       set_portable_backup(&ff_pkt->bfd); /* disable Win32 BackupRead() */
@@ -243,10 +293,6 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level)
       }
    }
 
-   if (!encode_and_send_attributes(jcr, ff_pkt, data_stream)) {
-      return 0;
-   }
-
    /*
     * Open any file with data that we intend to save, then save it.
     *
@@ -279,7 +325,7 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level)
          stop_thread_timer(tid);
          tid = NULL;
       }
-      stat = send_data(jcr, data_stream, ff_pkt, &chksum);
+      stat = send_data(jcr, data_stream, ff_pkt, digest, signing_digest);
       bclose(&ff_pkt->bfd);
       if (!stat) {
          return 0;
@@ -305,7 +351,7 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level)
          }
          flags = ff_pkt->flags;
          ff_pkt->flags &= ~(FO_GZIP|FO_SPARSE);
-         stat = send_data(jcr, STREAM_MACOS_FORK_DATA, ff_pkt, &chksum);
+         stat = send_data(jcr, STREAM_MACOS_FORK_DATA, ff_pkt, digest);
          ff_pkt->flags = flags;
          bclose(&ff_pkt->bfd);
          if (!stat) {
@@ -318,7 +364,12 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level)
       Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
       memcpy(sd->msg, ff_pkt->hfsinfo.fndrinfo, 32);
       sd->msglen = 32;
-      chksum_update(&chksum, (unsigned char *)sd->msg, sd->msglen);
+      if (digest) {
+         crypto_digest_update(digest, sd->msg, sd->msglen);
+      }
+      if (signature_digest) {
+         crypto_digest_update(signature_digest, sd->msg, sd->msglen);
+      }
       bnet_send(sd);
       bnet_sig(sd, BNET_EOD);
    }
@@ -337,25 +388,78 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level)
       }
    }
 
-   /* Terminate any signature and send it to Storage daemon and the Director */
-   if (chksum.updated) {
-      int stream = 0;
-      chksum_final(&chksum);
-      if (chksum.type == CHKSUM_MD5) {
-         stream = STREAM_MD5_SIGNATURE;
-      } else if (chksum.type == CHKSUM_SHA1) {
-         stream = STREAM_SHA1_SIGNATURE;
-      } else {
-         Jmsg1(jcr, M_WARNING, 0, _("Unknown signature type %i.\n"), chksum.type);
+   /* Terminate the signing digest and send it to the Storage daemon */
+   if (signing_digest) {
+      SIGNATURE *sig;
+      size_t size = 0;
+      void *buf;
+
+      if ((sig = crypto_sign_new()) == NULL) {
+         Jmsg(jcr, M_FATAL, 0, _("Failed to allocate memory for stream signature.\n"));
+         return 0;
       }
-      if (stream != 0) {
-         bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, stream);
+
+      if (crypto_sign_add_signer(sig, signing_digest, jcr->pki_keypair) == false) {
+         Jmsg(jcr, M_FATAL, 0, _("An error occured while signing the stream.\n"));
+         return 0;
+      }
+
+      /* Get signature size */
+      if (crypto_sign_encode(sig, NULL, &size) == false) {
+         Jmsg(jcr, M_FATAL, 0, _("An error occured while signing the stream.\n"));
+         return 0;
+      }
+
+      /* Allocate signature data buffer */
+      buf = malloc(size);
+      if (!buf) {
+         free(buf);
+         return 0;
+      }
+
+      /* Encode signature data */
+      if (crypto_sign_encode(sig, buf, &size) == false) {
+         Jmsg(jcr, M_FATAL, 0, _("An error occured while signing the stream.\n"));
+         return 0;
+      }
+
+      /* Send our header */
+      bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, STREAM_SIGNED_DIGEST);
+      Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
+
+      /* Grow the bsock buffer to fit our message if necessary */
+      if ((size_t) sizeof_pool_memory(sd->msg) < size) {
+         sd->msg = realloc_pool_memory(sd->msg, size);
+      }
+
+      /* Copy our message over and send it */
+      memcpy(sd->msg, buf, size);
+      sd->msglen = size;
+      bnet_send(sd);
+      bnet_sig(sd, BNET_EOD);              /* end of checksum */
+
+      crypto_digest_free(signing_digest);
+      crypto_sign_free(sig);        
+      free(buf);
+   }
+
+   /* Terminate any digest and send it to Storage daemon and the Director */
+   if (digest) {
+      char md[CRYPTO_DIGEST_MAX_SIZE];
+      size_t size;
+
+      size = sizeof(md);
+
+      if (crypto_digest_finalize(digest, &md, &size) == true) {
+         bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, digest_stream);
          Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
-         memcpy(sd->msg, chksum.signature, chksum.length);
-         sd->msglen = chksum.length;
+         memcpy(sd->msg, md, size);
+         sd->msglen = size;
          bnet_send(sd);
          bnet_sig(sd, BNET_EOD);              /* end of checksum */
       }
+
+      crypto_digest_free(digest);
    }
 
    return 1;
@@ -371,7 +475,7 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level)
  * Currently this is not a problem as the only other stream, resource forks,
  * are not handled as sparse files.
  */
-static int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, struct CHKSUM *chksum)
+int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, DIGEST *digest, DIGEST *signing_digest)
 {
    BSOCK *sd = jcr->store_bsock;
    uint64_t fileAddr = 0;             /* file address */
@@ -461,7 +565,14 @@ static int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, struct CHKSUM *chksum
       fileAddr += sd->msglen;
 
       /* Update checksum if requested */
-      chksum_update(chksum, (unsigned char *)rbuf, sd->msglen);
+      if (digest) {
+         crypto_digest_update(digest, rbuf, sd->msglen);
+      }
+
+      /* Update signing digest if requested */
+      if (signing_digest) {
+         crypto_digest_update(signing_digest, rbuf, sd->msglen);
+      }
 
 #ifdef HAVE_LIBZ
       /* Do compression if turned on */
diff --git a/bacula/src/filed/chksum.c b/bacula/src/filed/chksum.c
deleted file mode 100644 (file)
index 721d760..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * General routines for handling the various checksum supported.
- *
- *  Written by Preben 'Peppe' Guldberg, December MMIV
- */
-/*
-   Copyright (C) 2004-2005 Kern Sibbald
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License
-   version 2 as amended with additional clauses defined in the
-   file LICENSE in the main source directory.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
-   the file LICENSE for additional details.
-
- */
-
-#include "bacula.h"
-#include "filed.h"
-
-/* return 0 on success, otherwise some handler specific error code. */
-int chksum_init(CHKSUM *chksum, int flags)
-{
-   int status = 0;
-
-   chksum->type = CHKSUM_NONE;
-   bstrncpy(chksum->name, "NONE", sizeof(chksum->name));
-   chksum->updated = false;
-   if (flags & CHKSUM_MD5) {
-      chksum->length = 16;
-      MD5Init(&chksum->context.md5);
-      chksum->type = CHKSUM_MD5;
-      bstrncpy(chksum->name, "MD5", sizeof(chksum->name));
-   } else if (flags & CHKSUM_SHA1) {
-      chksum->length = 20;
-      status = SHA1Init(&chksum->context.sha1);
-      if (status == 0) {
-         chksum->type = CHKSUM_SHA1;
-         bstrncpy(chksum->name, "SHA1", sizeof(chksum->name));
-      }
-   }
-   return status;
-}
-
-/* return 0 on success, otherwise some handler specific error code. */
-int chksum_update(CHKSUM *chksum, void *buf, unsigned len)
-{
-   int status;
-   switch (chksum->type) {
-   case CHKSUM_NONE:
-      return 0;
-   case CHKSUM_MD5:
-      MD5Update(&chksum->context.md5, (unsigned char *)buf, len);
-      chksum->updated = true;
-      return 0;
-   case CHKSUM_SHA1:
-      status = SHA1Update(&chksum->context.sha1, (uint8_t *)buf, len);
-      if (status == 0) {
-         chksum->updated = true;
-      }
-      return status;
-   default:
-      return -1;
-   }
-}
-
-/* return 0 on success, otherwise some handler specific error code. */
-int chksum_final(CHKSUM *chksum)
-{
-   switch (chksum->type) {
-   case CHKSUM_NONE:
-      return 0;
-   case CHKSUM_MD5:
-      MD5Final(chksum->signature, &chksum->context.md5);
-      return 0;
-   case CHKSUM_SHA1:
-      return SHA1Final(&chksum->context.sha1, chksum->signature);
-   default:
-      return -1;
-   }
-}
diff --git a/bacula/src/filed/chksum.h b/bacula/src/filed/chksum.h
deleted file mode 100644 (file)
index 7be2633..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * General routines for handling the various checksum supported.
- */
-/*
-   Copyright (C) 2000-2005 Kern Sibbald
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License
-   version 2 as amended with additional clauses defined in the
-   file LICENSE in the main source directory.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
-   the file LICENSE for additional details.
-
- */
-
-#ifndef _CHKSUM_H_
-#define _CHKSUM_H_
-
-#include "bacula.h"
-
-/*
- * Link these to findlib options. Doing so allows for simpler handling of
- * signatures in the callers.
- * If multiple signatures are specified, the order in chksum_init() matters.
- * Still, spell out our own names in case we want to change the approach.
- */
-#define CHKSUM_NONE     0
-#define CHKSUM_MD5      FO_MD5
-#define CHKSUM_SHA1     FO_SHA1
-
-union chksumContext {
-   MD5Context  md5;
-   SHA1Context sha1;
-};
-
-struct CHKSUM {
-   int            type;                /* One of CHKSUM_* above */
-   char           name[5];             /* Big enough for NONE, MD5, SHA1, etc. */
-   bool           updated;             /* True if updated by chksum_update() */
-   chksumContext  context;             /* Context for the algorithm at hand */
-   int            length;              /* Length of signature */
-   unsigned char  signature[30];       /* Large enough for either signature */
-};
-
-int chksum_init(CHKSUM *chksum, int flags);
-int chksum_update(CHKSUM *chksum, void *buf, unsigned len);
-int chksum_final(CHKSUM *chksum);
-
-#endif
index fd36fa3df57311d0443c6aef8938ff71fa79b55f..fe6b33c37d61760f3cdc4e30dce0484388e66c53 100644 (file)
@@ -179,8 +179,8 @@ int main (int argc, char *argv[])
 
    parse_config(configfile);
 
-   if (init_tls() != 0) {
-      Emsg0(M_ERROR, 0, _("TLS library initialization failed.\n"));
+   if (init_crypto() != 0) {
+      Emsg0(M_ERROR, 0, _("Cryptography library initialization failed.\n"));
       terminate_filed(1);
    }
 
@@ -260,7 +260,7 @@ void terminate_filed(int sig)
    free_config_resources();
    term_msg();
    stop_watchdog();
-   cleanup_tls();
+   cleanup_crypto();
    close_memory_pool();               /* release free memory in pool */
    sm_dump(false);                    /* dump orphaned buffers */
    exit(sig);
@@ -328,6 +328,75 @@ static int check_resources()
             OK = false;
          }
       }
+
+      if (me->pki_encrypt || me->pki_sign) {
+#ifndef HAVE_CRYPTO
+         Jmsg(NULL, M_FATAL, 0, _("PKI encryption/signing enabled but not compiled into Bacula.\n"));
+         OK = false;
+#endif
+      }
+
+      /* pki_encrypt implies pki_sign */
+      if (me->pki_encrypt) {
+         me->pki_sign = true;
+      }
+
+      if ((me->pki_encrypt || me->pki_sign) && !me->pki_keypairfile) {
+         Emsg2(M_FATAL, 0, _("\"PKI Key Pair\" must be defined for File"
+            " daemon \"%s\" in %s if either \"PKI Sign\" or"
+           " \"PKI Encrypt\" are enabled.\n"), me->hdr.name, configfile);
+         OK = false;
+      }
+
+      /* If everything is well, attempt to initialize our public/private keys */
+      if (OK && (me->pki_encrypt || me->pki_sign)) {
+         char *filepath;
+
+         /* Load our keypair */
+         me->pki_keypair = crypto_keypair_new();
+         if (!me->pki_keypair) {
+            Emsg0(M_FATAL, 0, _("Failed to allocate a new keypair object.\n"));
+            OK = false;
+         } else {
+            if (!crypto_keypair_load_cert(me->pki_keypair, me->pki_keypairfile)) {
+               Emsg2(M_FATAL, 0, _("Failed to load public certificate for File"
+                     " daemon \"%s\" in %s.\n"), me->hdr.name, configfile);
+               OK = false;
+            }
+
+            if (!crypto_keypair_load_key(me->pki_keypair, me->pki_keypairfile, NULL, NULL)) {
+               Emsg2(M_FATAL, 0, _("Failed to load private key for File"
+                     " daemon \"%s\" in %s.\n"), me->hdr.name, configfile);
+               OK = false;
+            }
+         }
+
+         /*
+          * Trusted Signers. We're always trusted. me->pki_keypair
+          * will be deallocated when me->pki_signers is deallocated.
+          */
+         me->pki_signers = New(alist(10, not_owned_by_alist));
+         me->pki_signers->append(me->pki_keypair);
+
+         /* If additional trusted keys have been specified, load them up */
+         foreach_alist(filepath, me->pki_trustedkeys) {
+            X509_KEYPAIR *keypair;
+
+            keypair = crypto_keypair_new();
+            if (!keypair) {
+               Emsg0(M_FATAL, 0, _("Failed to allocate a new keypair object.\n"));
+               OK = false;
+            } else {
+               if (crypto_keypair_load_cert(keypair, filepath)) {
+                  me->pki_signers->append(keypair);
+               } else {
+                  Emsg3(M_FATAL, 0, _("Failed to load trusted signer certificate"
+                     " from file %s for File daemon \"%s\" in %s.\n"), filepath, me->hdr.name, configfile);
+                  OK = false;
+               }
+            }
+         }
+      }
    }
 
 
index 4137317ee9b07edcd61e9bd983b46d5ecb017cf3..43a8e3fa92f526394aea6ae4cafc58761b3cde13 100644 (file)
@@ -27,7 +27,6 @@
 
 #define FILE_DAEMON 1
 #include "filed_conf.h"
-#include "chksum.h"
 #include "findlib/find.h"
 #include "jcr.h"
 #include "acl.h"
index 1739ce7484c08862b2bb17803cfd90bd06ebdfcd..242eab9ab8ee3ccd49d2db6eab69ed1fae8eb31c 100644 (file)
@@ -89,12 +89,16 @@ static RES_ITEM cli_items[] = {
    {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0},
    {"sdconnecttimeout", store_time,ITEM(res_client.SDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
    {"maximumnetworkbuffersize", store_pint, ITEM(res_client.max_network_buffer_size), 0, 0, 0},
-   {"tlsenable",            store_yesno,     ITEM(res_client.tls_enable), 1, 0, 0},
-   {"tlsrequire",           store_yesno,     ITEM(res_client.tls_require), 1, 0, 0},
-   {"tlscacertificatefile", store_dir,       ITEM(res_client.tls_ca_certfile), 0, 0, 0},
-   {"tlscacertificatedir",  store_dir,       ITEM(res_client.tls_ca_certdir), 0, 0, 0},
-   {"tlscertificate",       store_dir,       ITEM(res_client.tls_certfile), 0, 0, 0},
-   {"tlskey",               store_dir,       ITEM(res_client.tls_keyfile), 0, 0, 0},
+   {"pkisignatures",         store_yesno,     ITEM(res_client.pki_sign), 1, ITEM_DEFAULT, 0},
+   {"pkiencryption",         store_yesno,     ITEM(res_client.pki_encrypt), 1, ITEM_DEFAULT, 0},
+   {"pkikeypair",            store_dir,       ITEM(res_client.pki_keypairfile), 0, 0, 0},
+   {"pkitrustedsigner",      store_alist_str, ITEM(res_client.pki_trustedkeys), 0, 0, 0},
+   {"tlsenable",             store_yesno,     ITEM(res_client.tls_enable),  1, 0, 0},
+   {"tlsrequire",            store_yesno,     ITEM(res_client.tls_require), 1, 0, 0},
+   {"tlscacertificatefile",  store_dir,       ITEM(res_client.tls_ca_certfile), 0, 0, 0},
+   {"tlscacertificatedir",   store_dir,       ITEM(res_client.tls_ca_certdir), 0, 0, 0},
+   {"tlscertificate",        store_dir,       ITEM(res_client.tls_certfile), 0, 0, 0},
+   {"tlskey",                store_dir,       ITEM(res_client.tls_keyfile), 0, 0, 0},
    {NULL, NULL, NULL, 0, 0, 0}
 };
 
@@ -240,6 +244,20 @@ void free_resource(RES *sres, int type)
       if (res->res_client.FDaddrs) {
          free_addresses(res->res_client.FDaddrs);
       }
+      if (res->res_client.pki_keypairfile) { 
+         free(res->res_client.pki_keypairfile);
+      }
+      /* Also frees res_client.pki_keypair */
+      if (res->res_client.pki_trustedkeys) {
+         delete res->res_client.pki_trustedkeys;
+      }
+      if (res->res_client.pki_signers) {
+         X509_KEYPAIR *keypair;
+         foreach_alist(keypair, res->res_client.pki_signers) {
+            crypto_keypair_free(keypair);
+         }
+         delete res->res_client.pki_signers;
+      }
       if (res->res_client.tls_ctx) { 
          free_tls_context(res->res_client.tls_ctx);
       }
@@ -321,6 +339,8 @@ void save_resource(int type, RES_ITEM *items, int pass)
             if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_dir.hdr.name)) == NULL) {
                Emsg1(M_ABORT, 0, _("Cannot find Client resource %s\n"), res_all.res_dir.hdr.name);
             }
+            res->res_client.pki_trustedkeys = res_all.res_client.pki_trustedkeys;
+            res->res_client.pki_signers = res_all.res_client.pki_signers;
             res->res_client.messages = res_all.res_client.messages;
             break;
          default:
index 8594228f94da9a84eab26b96b71bd8c97f93f1c0..396fae14a7ea800c2574ff5bfcf78ea4333e36a1 100644 (file)
@@ -71,6 +71,10 @@ struct CLIENT {
    utime_t heartbeat_interval;        /* Interval to send heartbeats to Dir */
    utime_t SDConnectTimeout;          /* timeout in seconds */
    uint32_t max_network_buffer_size;  /* max network buf size */
+   int pki_sign;                      /* Enable Data Integrity Verification via Digital Signatures */
+   int pki_encrypt;                   /* Enable Data Encryption */
+   char *pki_keypairfile;             /* PKI Key Pair File */
+   alist *pki_trustedkeys;            /* PKI Trusted Public Keys */
    int tls_enable;                    /* Enable TLS */
    int tls_require;                   /* Require TLS */
    char *tls_ca_certfile;             /* TLS CA Certificate File */
@@ -78,6 +82,8 @@ struct CLIENT {
    char *tls_certfile;                /* TLS Client Certificate File */
    char *tls_keyfile;                 /* TLS Client Key File */
 
+   X509_KEYPAIR *pki_keypair;         /* Shared PKI Public/Private Keypair */
+   alist *pki_signers;                /* Shared PKI Trusted Signers */
    TLS_CONTEXT *tls_ctx;              /* Shared TLS Context */
 };
 
index edbac446d9bbdd5931000f36a3e891b23f706914..7af7ce10b06e0a12486f198ddb1620f5f4a93eca 100644 (file)
@@ -173,6 +173,10 @@ void *handle_client_request(void *dirp)
    jcr->last_fname[0] = 0;
    jcr->client_name = get_memory(strlen(my_name) + 1);
    pm_strcpy(jcr->client_name, my_name);
+   jcr->pki_sign = me->pki_sign;
+   jcr->pki_encrypt = me->pki_encrypt;
+   jcr->pki_keypair = me->pki_keypair;
+   jcr->pki_signers = me->pki_signers;
    dir->jcr = jcr;
    enable_backup_privileges(NULL, 1 /* ignore_errors */);
 
@@ -865,7 +869,32 @@ static void set_options(findFOPTS *fo, const char *opts)
          fo->flags |= FO_READFIFO;
          break;
       case 'S':
-         fo->flags |= FO_SHA1;
+        switch(*(p + 1)) {
+         case ' ':
+            /* Old director did not specify SHA variant */
+            fo->flags |= FO_SHA1;
+            break;
+        case '1':
+           fo->flags |= FO_SHA1;
+            p++;
+           break;
+#ifdef HAVE_SHA2
+        case '2':
+           fo->flags |= FO_SHA256;
+            p++;
+           break;
+        case '3':
+           fo->flags |= FO_SHA512;
+            p++;
+           break;
+#endif
+        default:
+           /* Automatically downgrade to SHA-1 if an unsupported
+            * SHA variant is specified */
+           fo->flags |= FO_SHA1;
+            p++;
+           break;
+        }
          break;
       case 's':
          fo->flags |= FO_SPARSE;
index 952f56ff117d6370ed28161fe62dfc001e446f01..92d0a3c83cb7b970d67e2f76adf42aa0bea98621 100644 (file)
  */
 
 extern bool blast_data_to_storage_daemon(JCR *jcr, char *addr);
-extern void do_verify(JCR *jcr);
 extern void do_verify_volume(JCR *jcr);
 extern void do_restore(JCR *jcr);
 extern int authenticate_director(JCR *jcr);
 extern int authenticate_storagedaemon(JCR *jcr);
 extern int make_estimate(JCR *jcr);
 
+/* From verify.c */
+int digest_file(JCR *jcr, FF_PKT *ff_pkt, DIGEST *digest);
+void do_verify(JCR *jcr);
+
 /* From heartbeat.c */
 void start_heartbeat_monitor(JCR *jcr);
 void stop_heartbeat_monitor(JCR *jcr);
index f218a6a7e1b0c8da28ade955cd4d36ef9cdbce94..353233e364c19075e9a1d2e5e049f06f0df5f2b3 100644 (file)
@@ -36,6 +36,7 @@ static char rec_header[] = "rechdr %ld %ld %ld %ld %ld";
 static const char *zlib_strerror(int stat);
 #endif
 
+int verify_signature(JCR *jcr, SIGNATURE *sig);
 int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
       uint64_t *addr, int flags);
 
@@ -81,6 +82,7 @@ void do_restore(JCR *jcr)
    BFILE altbfd;                      /* Alternative data stream */
    uint64_t alt_addr = 0;             /* Write address for alternative stream */
    intmax_t alt_size = 0;             /* Size of alternate stream */
+   SIGNATURE *sig = NULL;             /* Cryptographic signature (if any) for file */
    int flags;                         /* Options for extract_data() */
    int stat;
    ATTR *attr;
@@ -137,7 +139,8 @@ void do_restore(JCR *jcr)
     *    or  c. Alternate data stream (e.g. Resource Fork)
     *    or  d. Finder info
     *    or  e. ACLs
-    *    or  f. Possibly MD5 or SHA1 record
+    *    or  f. Possibly a cryptographic signature
+    *    or  g. Possibly MD5 or SHA1 record
     *   3. Repeat step 1
     *
     * NOTE: We keep track of two bacula file descriptors:
@@ -195,7 +198,7 @@ void do_restore(JCR *jcr)
          Dmsg1(30, "Stream=Unix Attributes. extract=%d\n", extract);
          /*
           * If extracting, it was from previous stream, so
-          * close the output file.
+          * close the output file and validate the signature.
           */
          if (extract) {
             if (size > 0 && !is_bopen(&bfd)) {
@@ -203,6 +206,23 @@ void do_restore(JCR *jcr)
             }
             set_attributes(jcr, attr, &bfd);
             extract = false;
+
+            /* Verify the cryptographic signature, if any */
+            if (jcr->pki_sign) {
+               if (sig) {
+                  if (!verify_signature(jcr, sig)) {
+                     // TODO landonf: Better signature failure handling.
+                     // The failure is reported to the director in verify_signature() ...
+                     Dmsg1(100, "Bad signature on %s\n", jcr->last_fname);
+                  } else {
+                     Dmsg1(100, "Signature good on %s\n", jcr->last_fname);
+                  }
+                  crypto_sign_free(sig);
+                  sig = NULL;
+               } else {
+                  Jmsg1(jcr, M_ERROR, 0, _("Missing cryptographic signature for %s\n"), jcr->last_fname);
+               }
+            }
             Dmsg0(30, "Stop extracting.\n");
          } else if (is_bopen(&bfd)) {
             Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n"));
@@ -370,8 +390,15 @@ void do_restore(JCR *jcr)
 #endif
          break;
 
-      case STREAM_MD5_SIGNATURE:
-      case STREAM_SHA1_SIGNATURE:
+      case STREAM_SIGNED_DIGEST:
+         /* Save signature. */
+         sig = crypto_sign_decode(sd->msg, (size_t) sd->msglen);
+         break;
+
+      case STREAM_MD5_DIGEST:
+      case STREAM_SHA1_DIGEST:
+      case STREAM_SHA256_DIGEST:
+      case STREAM_SHA512_DIGEST:
          break;
 
       case STREAM_PROGRAM_NAMES:
@@ -475,6 +502,66 @@ static const char *zlib_strerror(int stat)
 }
 #endif
 
+static int do_file_digest(FF_PKT *ff_pkt, void *pkt, bool top_level) {
+   JCR *jcr = (JCR *) pkt;
+   return (digest_file(jcr, ff_pkt, jcr->digest));
+}
+
+/*
+ * Verify the signature for the last restored file
+ * Return value is either true (signature correct)
+ * or false (signature could not be verified).
+ */
+int verify_signature(JCR *jcr, SIGNATURE *sig)
+{
+   X509_KEYPAIR *keypair;
+   DIGEST *digest = NULL;
+   crypto_error_t err;
+
+
+   /* Iterate through the trusted signers */
+   foreach_alist(keypair, jcr->pki_signers) {
+      err = crypto_sign_get_digest(sig, jcr->pki_keypair, &digest);
+
+      switch (err) {
+      case CRYPTO_ERROR_NONE:
+         /* Signature found, digest allocated */
+         jcr->digest = digest;
+
+         /* Checksum the entire file */
+         if (find_one_file(jcr, jcr->ff, do_file_digest, jcr, jcr->last_fname, (dev_t)-1, 1) != 0) {
+            Jmsg(jcr, M_ERROR, 0, _("Signature validation failed for %s: \n"), jcr->last_fname);
+            return false;
+         }
+
+         /* Verify the signature */
+         if ((err = crypto_sign_verify(sig, keypair, digest)) != CRYPTO_ERROR_NONE) {
+            Jmsg2(jcr, M_ERROR, 0, _("Signature validation failed for %s: %s\n"), jcr->last_fname, crypto_strerror(err));
+            crypto_digest_free(digest);
+            return false;
+         }
+
+         /* Valid signature */
+         crypto_digest_free(digest);
+         return true;
+
+      case CRYPTO_ERROR_NOSIGNER:
+         /* Signature not found, try again */
+         continue;
+      default:
+         /* Something strange happened (that shouldn't happen!)... */
+         Jmsg2(jcr, M_ERROR, 0, _("Signature validation failed for %s: %s\n"), jcr->last_fname, crypto_strerror(err));
+         if (digest) {
+            crypto_digest_free(digest);
+         }
+         return false;
+      }
+   }
+
+   /* Unreachable */
+   return false;
+}
+
 /*
  * In the context of jcr, write data to bfd.
  * We write buflen bytes in buf at addr. addr is updated in place.
index c25f8294ccc034514f8541171b6b298a2fa89e76..850c9596733809366867896c0b6ccc1b9c2c809c 100644 (file)
@@ -30,7 +30,7 @@
 #include "filed.h"
 
 static int verify_file(FF_PKT *ff_pkt, void *my_pkt, bool);
-static int read_chksum(BFILE *bfd, CHKSUM *chksum, JCR *jcr);
+static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr);
 
 /*
  * Find all the requested files and send attributes
@@ -67,9 +67,9 @@ static int verify_file(FF_PKT *ff_pkt, void *pkt, bool top_level)
 {
    char attribs[MAXSTRING];
    char attribsEx[MAXSTRING];
+   int digest_stream = STREAM_NONE;
    int stat;
-   BFILE bfd;
-   struct CHKSUM chksum;
+   DIGEST *digest = NULL;
    BSOCK *dir;
    JCR *jcr = (JCR *)pkt;
 
@@ -201,80 +201,130 @@ static int verify_file(FF_PKT *ff_pkt, void *pkt, bool top_level)
     * First we initialise, then we read files, other streams and Finder Info.
     */
    if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
-            ff_pkt->flags & (FO_MD5|FO_SHA1))) {
-      chksum_init(&chksum, ff_pkt->flags);
-      binit(&bfd);
-
-      if (ff_pkt->statp.st_size > 0 || ff_pkt->type == FT_RAW
-            || ff_pkt->type == FT_FIFO) {
-         if ((bopen(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0)) < 0) {
-            ff_pkt->ff_errno = errno;
-            berrno be;
-            be.set_errno(bfd.berrno);
-            Jmsg(jcr, M_NOTSAVED, 1, _("     Cannot open %s: ERR=%s.\n"),
-                 ff_pkt->fname, be.strerror());
-            jcr->Errors++;
-            return 1;
-         }
-         read_chksum(&bfd, &chksum, jcr);
-         bclose(&bfd);
+            ff_pkt->flags & (FO_MD5|FO_SHA1|FO_SHA256|FO_SHA512))) {
+      /*
+       * Create our digest context. If this fails, the digest will be set to NULL
+       * and not used.
+       */
+      if (ff_pkt->flags & FO_MD5) {
+        digest = crypto_digest_new(CRYPTO_DIGEST_MD5);
+         digest_stream = STREAM_MD5_DIGEST;
+
+      } else if (ff_pkt->flags & FO_SHA1) {
+        digest = crypto_digest_new(CRYPTO_DIGEST_SHA1);
+         digest_stream = STREAM_SHA1_DIGEST;
+
+      } else if (ff_pkt->flags & FO_SHA256) {
+         digest = crypto_digest_new(CRYPTO_DIGEST_SHA256);
+         digest_stream = STREAM_SHA256_DIGEST;
+
+      } else if (ff_pkt->flags & FO_SHA512) {
+         digest = crypto_digest_new(CRYPTO_DIGEST_SHA512);
+         digest_stream = STREAM_SHA512_DIGEST;
       }
 
-#ifdef HAVE_DARWIN_OS
-      /* Open resource fork if necessary */
-      if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->hfsinfo.rsrclength > 0) {
-         if (bopen_rsrc(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
-            ff_pkt->ff_errno = errno;
-            berrno be;
-            Jmsg(jcr, M_NOTSAVED, -1, _("     Cannot open resource fork for %s: ERR=%s.\n"),
-                  ff_pkt->fname, be.strerror());
+      /* Did digest initialization fail? */
+      if (digest_stream != STREAM_NONE && digest == NULL) {
+         Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"),
+              stream_to_ascii(digest_stream));
+      }
+
+      /* compute MD5 or SHA1 hash */
+      if (digest) {
+         char md[CRYPTO_DIGEST_MAX_SIZE];
+         size_t size;
+
+         size = sizeof(md);
+        
+         if (digest_file(jcr, ff_pkt, digest) != 0) {
             jcr->Errors++;
-            if (is_bopen(&ff_pkt->bfd)) {
-               bclose(&ff_pkt->bfd);
-            }
             return 1;
          }
-         read_chksum(&bfd, &chksum, jcr);
-         bclose(&bfd);
+
+         if (crypto_digest_finalize(digest, &md, &size) == true) {
+            char *digest_buf;
+            const char *digest_name;
+           
+            digest_buf = (char *) malloc(BASE64_SIZE(size));
+            digest_name = crypto_digest_name(digest);
+
+            bin_to_base64(digest_buf, (char *) md, size);
+           Dmsg3(400, "send inx=%d %s=%s\n", jcr->JobFiles, digest_name, digest_buf);
+            bnet_fsend(dir, "%d %d %s *%s-%d*", jcr->JobFiles, digest_stream, digest_buf,
+                       digest_name, jcr->JobFiles);
+            Dmsg3(20, "bfiled>bdird: %s len=%d: msg=%s\n", digest_name,
+            dir->msglen, dir->msg);
+
+            free(digest_buf);
+         }
+
+         crypto_digest_free(digest);
       }
-      if (ff_pkt->flags & FO_HFSPLUS) {
-         chksum_update(&chksum, ((unsigned char *)ff_pkt->hfsinfo.fndrinfo), 32);
+   }
+
+   return 1;
+}
+
+/*
+ * Compute message digest for the file specified by ff_pkt.
+ * In case of errors we need the job control record and file name.
+ */
+int digest_file(JCR *jcr, FF_PKT *ff_pkt, DIGEST *digest)
+{
+   BFILE bfd;
+
+   binit(&bfd);
+
+   if (ff_pkt->statp.st_size > 0 || ff_pkt->type == FT_RAW
+         || ff_pkt->type == FT_FIFO) {
+      if ((bopen(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0)) < 0) {
+         ff_pkt->ff_errno = errno;
+         berrno be;
+         be.set_errno(bfd.berrno);
+         Jmsg(jcr, M_NOTSAVED, 1, _("     Cannot open %s: ERR=%s.\n"),
+               ff_pkt->fname, be.strerror());
+         return 1;
       }
-#endif
+      read_digest(&bfd, digest, jcr);
+      bclose(&bfd);
+   }
 
-      /* compute MD5 or SHA1 hash */
-      if (chksum.updated) {
-         char chksumbuf[40];                  /* 24 should do */
-         int stream = 0;
-
-         chksum_final(&chksum);
-         if (chksum.type == CHKSUM_MD5) {
-            stream = STREAM_MD5_SIGNATURE;
-         } else if (chksum.type == CHKSUM_SHA1) {
-            stream = STREAM_SHA1_SIGNATURE;
+#ifdef HAVE_DARWIN_OS
+      /* Open resource fork if necessary */
+   if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->hfsinfo.rsrclength > 0) {
+      if (bopen_rsrc(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
+         ff_pkt->ff_errno = errno;
+         berrno be;
+         Jmsg(jcr, M_NOTSAVED, -1, _("     Cannot open resource fork for %s: ERR=%s.\n"),
+               ff_pkt->fname, be.strerror());
+         if (is_bopen(&ff_pkt->bfd)) {
+            bclose(&ff_pkt->bfd);
          }
-         bin_to_base64(chksumbuf, (char *)chksum.signature, chksum.length);
-         Dmsg3(400, "send inx=%d %s=%s\n", jcr->JobFiles, chksum.name, chksumbuf);
-         bnet_fsend(dir, "%d %d %s *%s-%d*", jcr->JobFiles, stream, chksumbuf,
-               chksum.name, jcr->JobFiles);
-         Dmsg3(20, "bfiled>bdird: %s len=%d: msg=%s\n", chksum.name,
-               dir->msglen, dir->msg);
+         return 1;
       }
+      read_digest(&bfd, digest, jcr);
+      bclose(&bfd);
    }
 
-   return 1;
+   if (digest && ff_pkt->flags & FO_HFSPLUS) {
+      crypto_digest_update(digest, ff_pkt->hfsinfo.fndrinfo, 32);
+   }
+#endif
+
+   return 0;
 }
 
 /*
- * Read checksum of bfd, updating chksum
+ * Read message digest of bfd, updating digest
  * In case of errors we need the job control record and file name.
  */
-int read_chksum(BFILE *bfd, CHKSUM *chksum, JCR *jcr)
+int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr)
 {
+   char buf[DEFAULT_NETWORK_BUFFER_SIZE];
    int64_t n;
 
-   while ((n=bread(bfd, jcr->big_buf, jcr->buf_size)) > 0) {
-      chksum_update(chksum, ((unsigned char *)jcr->big_buf), (int)n);
+   while ((n=bread(bfd, &buf, sizeof(buf))) > 0) {
+      crypto_digest_update(digest, &buf, n);
       jcr->JobBytes += n;
       jcr->ReadBytes += n;
    }
index 23940b0920a905a5e43ad1fc20f80533bd6dcac7..119edf8d6bbfd5b6449d234b840b78b07c55ab5c 100644 (file)
@@ -49,6 +49,7 @@ void do_verify_volume(JCR *jcr)
    uint32_t size;
    uint32_t VolSessionId, VolSessionTime, file_index;
    uint32_t record_file_index;
+   char digest[BASE64_SIZE(CRYPTO_DIGEST_MAX_SIZE)];
    int type, stat;
 
    sd = jcr->store_bsock;
@@ -209,27 +210,42 @@ void do_verify_volume(JCR *jcr)
       case STREAM_WIN32_GZIP_DATA:
       case STREAM_GZIP_DATA:
       case STREAM_SPARSE_GZIP_DATA:
+      case STREAM_SIGNED_DIGEST:
 
        /* Do nothing */
        break;
 
-      case STREAM_MD5_SIGNATURE:
-        char MD5buf[30];
-        bin_to_base64(MD5buf, (char *)sd->msg, 16); /* encode 16 bytes */
-         Dmsg2(400, "send inx=%d MD5=%s\n", jcr->JobFiles, MD5buf);
-         bnet_fsend(dir, "%d %d %s *MD5-%d*", jcr->JobFiles, STREAM_MD5_SIGNATURE, MD5buf,
-           jcr->JobFiles);
+      case STREAM_MD5_DIGEST:
+         bin_to_base64(digest, (char *)sd->msg, CRYPTO_DIGEST_MD5_SIZE);
+         Dmsg2(400, "send inx=%d MD5=%s\n", jcr->JobFiles, digest);
+         bnet_fsend(dir, "%d %d %s *MD5-%d*", jcr->JobFiles, STREAM_MD5_DIGEST, digest,
+                    jcr->JobFiles);
          Dmsg2(20, "bfiled>bdird: MD5 len=%d: msg=%s\n", dir->msglen, dir->msg);
-        break;
+         break;
 
-      case STREAM_SHA1_SIGNATURE:
-        char SHA1buf[30];
-        bin_to_base64(SHA1buf, (char *)sd->msg, 20); /* encode 20 bytes */
-         Dmsg2(400, "send inx=%d SHA1=%s\n", jcr->JobFiles, SHA1buf);
-         bnet_fsend(dir, "%d %d %s *SHA1-%d*", jcr->JobFiles, STREAM_SHA1_SIGNATURE,
-           SHA1buf, jcr->JobFiles);
+      case STREAM_SHA1_DIGEST:
+         bin_to_base64(digest, (char *)sd->msg, CRYPTO_DIGEST_SHA1_SIZE);
+         Dmsg2(400, "send inx=%d SHA1=%s\n", jcr->JobFiles, digest);
+         bnet_fsend(dir, "%d %d %s *SHA1-%d*", jcr->JobFiles, STREAM_SHA1_DIGEST,
+                    digest, jcr->JobFiles);
          Dmsg2(20, "bfiled>bdird: SHA1 len=%d: msg=%s\n", dir->msglen, dir->msg);
-        break;
+         break;
+
+      case STREAM_SHA256_DIGEST:
+         bin_to_base64(digest, (char *)sd->msg, CRYPTO_DIGEST_SHA256_SIZE);
+         Dmsg2(400, "send inx=%d SHA256=%s\n", jcr->JobFiles, digest);
+         bnet_fsend(dir, "%d %d %s *SHA256-%d*", jcr->JobFiles, STREAM_SHA256_DIGEST,
+                    digest, jcr->JobFiles);
+         Dmsg2(20, "bfiled>bdird: SHA256 len=%d: msg=%s\n", dir->msglen, dir->msg);
+         break;
+
+      case STREAM_SHA512_DIGEST:
+         bin_to_base64(digest, (char *)sd->msg, CRYPTO_DIGEST_SHA512_SIZE);
+         Dmsg2(400, "send inx=%d SHA512=%s\n", jcr->JobFiles, digest);
+         bnet_fsend(dir, "%d %d %s *SHA512-%d*", jcr->JobFiles, STREAM_SHA512_DIGEST,
+                    digest, jcr->JobFiles);
+         Dmsg2(20, "bfiled>bdird: SHA512 len=%d: msg=%s\n", dir->msglen, dir->msg);
+         break;
 
       default:
          Pmsg2(0, "None of above!!! stream=%d data=%s\n", stream,sd->msg);
index 61cd8dc79792920d6e174bd5933a5f239d8faf19..f9f66652d938616086978ce96715bd64b89e02eb 100644 (file)
@@ -70,8 +70,8 @@ const char *stream_to_ascii(int stream)
       return _("File attributes");
    case STREAM_FILE_DATA:
       return _("File data");
-   case STREAM_MD5_SIGNATURE:
-      return _("MD5 signature");
+   case STREAM_MD5_DIGEST:
+      return _("MD5 digest");
    case STREAM_UNIX_ATTRIBUTES_EX:
       return _("Extended attributes");
    case STREAM_SPARSE_DATA:
@@ -80,12 +80,18 @@ const char *stream_to_ascii(int stream)
       return _("Program names");
    case STREAM_PROGRAM_DATA:
       return _("Program data");
-   case STREAM_SHA1_SIGNATURE:
-      return _("SHA1 signature");
+   case STREAM_SHA1_DIGEST:
+      return _("SHA1 digest");
    case STREAM_MACOS_FORK_DATA:
       return _("HFS+ resource fork");
    case STREAM_HFSPLUS_ATTRIBUTES:
       return _("HFS+ Finder Info");
+   case STREAM_SHA256_DIGEST:
+      return _("SHA256 digest");
+   case STREAM_SHA512_DIGEST:
+      return _("SHA512 digest");
+   case STREAM_SIGNED_DIGEST:
+      return _("Signed digest");
    default:
       sprintf(buf, "%d", stream);
       return (const char *)buf;
@@ -322,12 +328,19 @@ bool is_restore_stream_supported(int stream)
    case STREAM_WIN32_DATA:
    case STREAM_UNIX_ATTRIBUTES:
    case STREAM_FILE_DATA:
-   case STREAM_MD5_SIGNATURE:
+   case STREAM_MD5_DIGEST:
    case STREAM_UNIX_ATTRIBUTES_EX:
    case STREAM_SPARSE_DATA:
    case STREAM_PROGRAM_NAMES:
    case STREAM_PROGRAM_DATA:
-   case STREAM_SHA1_SIGNATURE:
+   case STREAM_SHA1_DIGEST:
+#ifdef HAVE_SHA2
+   case STREAM_SHA256_DIGEST:
+   case STREAM_SHA512_DIGEST:
+#endif
+#ifdef HAVE_CRYPTO
+   case STREAM_SIGNED_DIGEST:
+#endif
    case 0:                            /* compatibility with old tapes */
       return true;
    }
@@ -691,12 +704,16 @@ bool is_restore_stream_supported(int stream)
    case STREAM_WIN32_DATA:
    case STREAM_UNIX_ATTRIBUTES:
    case STREAM_FILE_DATA:
-   case STREAM_MD5_SIGNATURE:
+   case STREAM_MD5_DIGEST:
    case STREAM_UNIX_ATTRIBUTES_EX:
    case STREAM_SPARSE_DATA:
    case STREAM_PROGRAM_NAMES:
    case STREAM_PROGRAM_DATA:
-   case STREAM_SHA1_SIGNATURE:
+   case STREAM_SHA1_DIGEST:
+#ifdef HAVE_SHA2
+   case STREAM_SHA256_DIGEST:
+   case STREAM_SHA512_DIGEST:
+#endif
 #ifdef HAVE_DARWIN_OS
    case STREAM_MACOS_FORK_DATA:
    case STREAM_HFSPLUS_ATTRIBUTES:
index cb1e44e002fcf81740240158630ce711619ab33c..752d009fe00f35a584b3d3247e71913cb98d1f84 100755 (executable)
@@ -86,6 +86,8 @@ enum {
 #define FO_IGNORECASE   (1<<16)       /* Ignore file name case */
 #define FO_HFSPLUS      (1<<17)       /* Resource forks and Finder Info */
 #define FO_WIN32DECOMP  (1<<18)       /* Use BackupRead decomposition */
+#define FO_SHA256       (1<<19)       /* Do SHA256 checksum */
+#define FO_SHA512       (1<<20)       /* Do SHA512 checksum */
 
 struct s_included_file {
    struct s_included_file *next;
index 38fc765ac94be74363b44cdf143044cdb991fd9b..17643ef706d9442e83e511006e5344295c67a856 100644 (file)
@@ -267,8 +267,8 @@ int main(int argc, char *argv[])
 
    parse_config(configfile);
 
-   if (init_tls() != 0) {
-      Emsg0(M_ERROR_TERM, 0, _("TLS library initialization failed.\n"));
+   if (init_crypto() != 0) {
+      Emsg0(M_ERROR_TERM, 0, _("Cryptography library initialization failed.\n"));
    }
 
    if (!check_resources()) {
@@ -672,7 +672,7 @@ void terminate_console(int sig)
    if (already_here)                  /* avoid recursive temination problems */
       exit(1);
    already_here = true;
-   cleanup_tls();
+   cleanup_crypto();
    disconnect_from_director((gpointer)NULL);
    gtk_main_quit();
    exit(0);
index 4bd623ea726be93d1c122cf4b49e19b3f29c56f8..65d176357c80ae4b6ca458fb7b49089b7534a668 100644 (file)
@@ -229,6 +229,11 @@ public:
    volatile BSOCK *hb_bsock;          /* duped SD socket */
    volatile BSOCK *hb_dir_bsock;      /* duped DIR socket */
    POOLMEM *RunAfterJob;              /* Command to run after job */
+   bool pki_sign;                     /* Enable PKI Signatures? */
+   bool pki_encrypt;                  /* Enable PKI Encryption? */
+   DIGEST *digest;                    /* Last file's digest context */
+   X509_KEYPAIR *pki_keypair;         /* Encryption key pair */
+   alist *pki_signers;                /* Trusted Signers */
    DIRRES* director;                  /* Director resource */
 #endif /* FILE_DAEMON */
 
index 862ebf8d809273da56aacd95f14c04377b833af9..0e2e40e0ffb61979a3a2cb11ba3e19ca80fd5662 100644 (file)
@@ -25,9 +25,9 @@ dummy:
 LIBSRCS = alloc.c attr.c base64.c berrno.c bsys.c bget_msg.c \
          bnet.c bnet_server.c \
          bpipe.c bshm.c bsnprintf.c btime.c \
-         cram-md5.c crc32.c daemon.c edit.c fnmatch.c \
+         cram-md5.c crc32.c crypto.c daemon.c edit.c fnmatch.c \
          hmac.c idcache.c jcr.c lex.c alist.c dlist.c \
-         md5.c message.c mem_pool.c parse_conf.c \
+         md5.c message.c mem_pool.c openssl.c parse_conf.c \
          queue.c regex.c \
          res.c rwlock.c scan.c serial.c sha1.c \
          semlock.c signal.c smartall.c tls.c tree.c \
@@ -38,9 +38,9 @@ LIBSRCS = alloc.c attr.c base64.c berrno.c bsys.c bget_msg.c \
 LIBOBJS = alloc.o attr.o base64.o berrno.o bsys.o bget_msg.o \
          bnet.o bnet_server.o \
          bpipe.o bshm.o bsnprintf.o btime.o \
-         cram-md5.o crc32.o daemon.o edit.o fnmatch.o \
+         cram-md5.o crc32.o crypto.o daemon.o edit.o fnmatch.o \
          hmac.o idcache.o jcr.o lex.o alist.o dlist.o \
-         md5.o message.o mem_pool.o parse_conf.o \
+         md5.o message.o mem_pool.o openssl.o parse_conf.o \
          queue.o regex.o \
          res.o rwlock.o scan.o serial.o sha1.o \
          semlock.o signal.o smartall.o tls.o tree.o \
diff --git a/bacula/src/lib/base64.h b/bacula/src/lib/base64.h
new file mode 100644 (file)
index 0000000..ae33182
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *   Generic base 64 input and output routines
+ *
+ *    Written by Kern E. Sibbald, March MM.
+ *
+ *   Version $Id$
+ */
+
+/*
+   Copyright (C) 2000-2005 Kern Sibbald and John Walker
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public
+   License along with this program; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA.
+
+ */
+
+/* Maximum size of len bytes after base64 encoding */
+#define BASE64_SIZE(len) (((len + 3 - (len % 3)) / 3) * 4)
diff --git a/bacula/src/lib/crypto.c b/bacula/src/lib/crypto.c
new file mode 100644 (file)
index 0000000..d2a2d4a
--- /dev/null
@@ -0,0 +1,1078 @@
+/*
+ * crypto.c Encryption support functions
+ *
+ * Author: Landon Fuller <landonf@opendarwin.org>
+ *
+ * Version $Id$
+ *
+ * Copyright (C) 2005 Kern Sibbald
+ *
+ * This file was contributed to the Bacula project by Landon Fuller.
+ *
+ * Landon Fuller has been granted a perpetual, worldwide, non-exclusive,
+ * no-charge, royalty-free, irrevocable copyright license to reproduce,
+ * prepare derivative works of, publicly display, publicly perform,
+ * sublicense, and distribute the original work contributed by Landon Fuller
+ * to the Bacula project in source or object form.
+ *
+ * If you wish to license these contributions under an alternate open source
+ * license please contact Landon Fuller <landonf@opendarwin.org>.
+ */
+/*
+   Copyright (C) 2005 Kern Sibbald
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   version 2 as amended with additional clauses defined in the
+   file LICENSE in the main source directory.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
+   the file LICENSE for additional details.
+
+ */
+
+
+#include "bacula.h"
+#include <assert.h>
+
+/*
+ * Bacula ASN.1 Syntax
+ *
+ * OID Allocation:
+ * Prefix: iso.org.dod.internet.private.enterprise.threerings.external.bacula (1.3.6.1.4.1.22054.500.2)
+ * Organization: Bacula Project
+ * Contact Name: Kern Sibbald
+ * Contact E-mail: kern@sibbald.com
+ *
+ * Top Level Allocations - 500.2
+ * 1 - Published Allocations
+ *   1.1 - Bacula Encryption
+ *
+ * Bacula Encryption - 500.2.1.1
+ * 1 - ASN.1 Modules
+ *    1.1 - BaculaCrypto
+ * 2 - ASN.1 Object Identifiers
+ *    2.1 - SignatureData
+ *    2.2 - SignerInfo
+ *    2.3 - CryptoData
+ *    2.4 - RecipientInfo
+ *
+ * BaculaCrypto { iso(1) identified-organization(3) usdod(6)
+ *                internet(1) private(4) enterprises(1) three-rings(22054)
+ *                external(500) bacula(2) published(1) bacula-encryption(1)
+ *                asn1-modules(1) bacula-crypto(1) }
+ *
+ * DEFINITIONS AUTOMATIC TAGS ::=
+ * BEGIN
+ *
+ * SignatureData ::= SEQUENCE {
+ *    version         Version DEFAULT v0,
+ *    signerInfo      SignerInfo }
+ *
+ * CryptoData ::= SEQUENCE {
+ *    version                     Version DEFAULT v0,
+ *    contentEncryptionAlgorithm  ContentEncryptionAlgorithmIdentifier
+ *    recipientInfo               RecipientInfo
+ * }
+ *
+ * SignerInfo ::= SET OF SignerInfo
+ * RecipientInfo ::= SET OF RecipientInfo
+ *
+ * Version ::= INTEGER { v0(0) }
+ *
+ * SignerInfo ::= SEQUENCE {
+ *    version                 Version,
+ *    subjectKeyIdentifier    SubjectKeyIdentifier,
+ *    digestAlgorithm         DigestAlgorithmIdentifier,
+ *    signatureAlgorithm      SignatureAlgorithmIdentifier,
+ *    signature               SignatureValue }
+ *
+ * RecipientInfo ::= SEQUENCE {
+ *    version                 Version
+ *    subjectKeyIdentifier    SubjectKeyIdentifier
+ *    keyEncryptionAlgorithm  KeyEncryptionAlgorithmIdentifier
+ *    encryptedKey            EncryptedKey
+ * }
+ *
+ * SubjectKeyIdentifier ::= OCTET STRING
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * SignatureAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * SignatureValue ::= OCTET STRING
+ *
+ * EncryptedKey ::= OCTET STRING
+ *
+ * AlgorithmIdentifier ::= OBJECT IDENTIFIER
+ *
+ * END
+ */
+
+#ifdef HAVE_CRYPTO /* Is encryption enabled? */
+#ifdef HAVE_OPENSSL /* How about OpenSSL? */
+
+/* Are we initialized? */
+static int crypto_initialized = false;
+
+/* ASN.1 Declarations */
+#define BACULA_ASN1_VERSION 0
+
+typedef struct {
+   ASN1_INTEGER *version;
+   ASN1_OCTET_STRING *subjectKeyIdentifier;
+   ASN1_OBJECT *digestAlgorithm;
+   ASN1_OBJECT *signatureAlgorithm;
+   ASN1_OCTET_STRING *signature;
+} SignerInfo;
+
+typedef struct {
+   ASN1_INTEGER *version;
+   ASN1_OCTET_STRING *subjectKeyIdentifier;
+   ASN1_OBJECT *keyEncryptionAlgorithm;
+   ASN1_OCTET_STRING *encryptedKey;
+} RecipientInfo;
+
+ASN1_SEQUENCE(SignerInfo) = {
+   ASN1_SIMPLE(SignerInfo, version, ASN1_INTEGER),
+   ASN1_SIMPLE(SignerInfo, subjectKeyIdentifier, ASN1_OCTET_STRING),
+   ASN1_SIMPLE(SignerInfo, digestAlgorithm, ASN1_OBJECT),
+   ASN1_SIMPLE(SignerInfo, signatureAlgorithm, ASN1_OBJECT),
+   ASN1_SIMPLE(SignerInfo, signature, ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(SignerInfo);
+
+ASN1_SEQUENCE(RecipientInfo) = {
+   ASN1_SIMPLE(RecipientInfo, version, ASN1_INTEGER),
+   ASN1_SIMPLE(RecipientInfo, subjectKeyIdentifier, ASN1_OCTET_STRING),
+   ASN1_SIMPLE(RecipientInfo, keyEncryptionAlgorithm, ASN1_OBJECT),
+   ASN1_SIMPLE(RecipientInfo, encryptedKey, ASN1_OCTET_STRING),
+} ASN1_SEQUENCE_END(RecipientInfo);
+
+typedef struct {
+   ASN1_INTEGER *version;
+   STACK_OF(SignerInfo) *signerInfo;
+} SignatureData;
+
+typedef struct {
+   ASN1_INTEGER *version;
+   ASN1_OBJECT *contentEncryptionAlgorithm;
+   STACK_OF(RecipientInfo) *recipientInfo;
+} CryptoData;
+
+ASN1_SEQUENCE(SignatureData) = {
+   ASN1_SIMPLE(SignatureData, version, ASN1_INTEGER),
+   ASN1_SET_OF(SignatureData, signerInfo, SignerInfo),
+} ASN1_SEQUENCE_END(SignatureData);
+
+ASN1_SEQUENCE(CryptoData) = {
+   ASN1_SIMPLE(CryptoData, version, ASN1_INTEGER),
+   ASN1_SET_OF(CryptoData, recipientInfo, RecipientInfo)
+} ASN1_SEQUENCE_END(CryptoData);
+
+IMPLEMENT_ASN1_FUNCTIONS(SignerInfo)
+IMPLEMENT_ASN1_FUNCTIONS(SignatureData)
+IMPLEMENT_ASN1_FUNCTIONS(CryptoData)
+IMPLEMENT_STACK_OF(SignerInfo)
+IMPLEMENT_STACK_OF(RecipientInfo)
+
+/*
+ * SignerInfo and RecipientInfo stack macros, generated by OpenSSL's util/mkstack.pl.
+ */
+#define sk_SignerInfo_new(st) SKM_sk_new(SignerInfo, (st))
+#define sk_SignerInfo_new_null() SKM_sk_new_null(SignerInfo)
+#define sk_SignerInfo_free(st) SKM_sk_free(SignerInfo, (st))
+#define sk_SignerInfo_num(st) SKM_sk_num(SignerInfo, (st))
+#define sk_SignerInfo_value(st, i) SKM_sk_value(SignerInfo, (st), (i))
+#define sk_SignerInfo_set(st, i, val) SKM_sk_set(SignerInfo, (st), (i), (val))
+#define sk_SignerInfo_zero(st) SKM_sk_zero(SignerInfo, (st))
+#define sk_SignerInfo_push(st, val) SKM_sk_push(SignerInfo, (st), (val))
+#define sk_SignerInfo_unshift(st, val) SKM_sk_unshift(SignerInfo, (st), (val))
+#define sk_SignerInfo_find(st, val) SKM_sk_find(SignerInfo, (st), (val))
+#define sk_SignerInfo_delete(st, i) SKM_sk_delete(SignerInfo, (st), (i))
+#define sk_SignerInfo_delete_ptr(st, ptr) SKM_sk_delete_ptr(SignerInfo, (st), (ptr))
+#define sk_SignerInfo_insert(st, val, i) SKM_sk_insert(SignerInfo, (st), (val), (i))
+#define sk_SignerInfo_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(SignerInfo, (st), (cmp))
+#define sk_SignerInfo_dup(st) SKM_sk_dup(SignerInfo, st)
+#define sk_SignerInfo_pop_free(st, free_func) SKM_sk_pop_free(SignerInfo, (st), (free_func))
+#define sk_SignerInfo_shift(st) SKM_sk_shift(SignerInfo, (st))
+#define sk_SignerInfo_pop(st) SKM_sk_pop(SignerInfo, (st))
+#define sk_SignerInfo_sort(st) SKM_sk_sort(SignerInfo, (st))
+#define sk_SignerInfo_is_sorted(st) SKM_sk_is_sorted(SignerInfo, (st))
+
+#define d2i_ASN1_SET_OF_SignerInfo(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+       SKM_ASN1_SET_OF_d2i(SignerInfo, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_SignerInfo(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+       SKM_ASN1_SET_OF_i2d(SignerInfo, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_SignerInfo(st, i2d_func, buf, len) \
+       SKM_ASN1_seq_pack(SignerInfo, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_SignerInfo(buf, len, d2i_func, free_func) \
+       SKM_ASN1_seq_unpack(SignerInfo, (buf), (len), (d2i_func), (free_func))
+
+#define sk_RecipientInfo_new(st) SKM_sk_new(RecipientInfo, (st))
+#define sk_RecipientInfo_new_null() SKM_sk_new_null(RecipientInfo)
+#define sk_RecipientInfo_free(st) SKM_sk_free(RecipientInfo, (st))
+#define sk_RecipientInfo_num(st) SKM_sk_num(RecipientInfo, (st))
+#define sk_RecipientInfo_value(st, i) SKM_sk_value(RecipientInfo, (st), (i))
+#define sk_RecipientInfo_set(st, i, val) SKM_sk_set(RecipientInfo, (st), (i), (val))
+#define sk_RecipientInfo_zero(st) SKM_sk_zero(RecipientInfo, (st))
+#define sk_RecipientInfo_push(st, val) SKM_sk_push(RecipientInfo, (st), (val))
+#define sk_RecipientInfo_unshift(st, val) SKM_sk_unshift(RecipientInfo, (st), (val))
+#define sk_RecipientInfo_find(st, val) SKM_sk_find(RecipientInfo, (st), (val))
+#define sk_RecipientInfo_delete(st, i) SKM_sk_delete(RecipientInfo, (st), (i))
+#define sk_RecipientInfo_delete_ptr(st, ptr) SKM_sk_delete_ptr(RecipientInfo, (st), (ptr))
+#define sk_RecipientInfo_insert(st, val, i) SKM_sk_insert(RecipientInfo, (st), (val), (i))
+#define sk_RecipientInfo_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(RecipientInfo, (st), (cmp))
+#define sk_RecipientInfo_dup(st) SKM_sk_dup(RecipientInfo, st)
+#define sk_RecipientInfo_pop_free(st, free_func) SKM_sk_pop_free(RecipientInfo, (st), (free_func))
+#define sk_RecipientInfo_shift(st) SKM_sk_shift(RecipientInfo, (st))
+#define sk_RecipientInfo_pop(st) SKM_sk_pop(RecipientInfo, (st))
+#define sk_RecipientInfo_sort(st) SKM_sk_sort(RecipientInfo, (st))
+#define sk_RecipientInfo_is_sorted(st) SKM_sk_is_sorted(RecipientInfo, (st))
+
+#define d2i_ASN1_SET_OF_RecipientInfo(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+       SKM_ASN1_SET_OF_d2i(RecipientInfo, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_RecipientInfo(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+       SKM_ASN1_SET_OF_i2d(RecipientInfo, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_RecipientInfo(st, i2d_func, buf, len) \
+       SKM_ASN1_seq_pack(RecipientInfo, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_RecipientInfo(buf, len, d2i_func, free_func) \
+       SKM_ASN1_seq_unpack(RecipientInfo, (buf), (len), (d2i_func), (free_func))
+/* End of util/mkstack.pl block */
+
+/* X509 Public/Private Key Pair Structure */
+struct X509_Keypair {
+   ASN1_OCTET_STRING *keyid;
+   EVP_PKEY *pubkey;
+   EVP_PKEY *privkey;
+};
+
+/* Message Digest Structure */
+struct Digest {
+   crypto_digest_t type;
+   EVP_MD_CTX ctx;
+};
+
+/* Message Signature Structure */
+struct Signature {
+   SignatureData *sigData;
+};
+
+/* PEM Password Dispatch Context */
+typedef struct PEM_CB_Context {
+   CRYPTO_PEM_PASSWD_CB *pem_callback;
+   const void *pem_userdata;
+} PEM_CB_CONTEXT;
+
+/*
+ * Extract subjectKeyIdentifier from x509 certificate.
+ * Returns: On success, an ASN1_OCTET_STRING that must be freed via M_ASN1_OCTET_STRING_free().
+ *          NULL on failure.
+ */
+static ASN1_OCTET_STRING *openssl_cert_keyid(X509 *cert){
+   X509_EXTENSION *ext;
+   X509V3_EXT_METHOD *method;
+   ASN1_OCTET_STRING *keyid;
+   int i;
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800FL)
+   const unsigned char *ext_value_data;
+#else
+   unsigned char *ext_value_data;
+#endif
+
+
+   /* Find the index to the subjectKeyIdentifier extension */
+   i = X509_get_ext_by_NID(cert, NID_subject_key_identifier, -1);
+   if (i < 0) {
+      /* Not found */
+      return NULL;
+   }
+
+   /* Grab the extension */
+   ext = X509_get_ext(cert, i);
+
+   /* Get x509 extension method structure */
+   if (!(method = X509V3_EXT_get(ext))) {
+      return NULL;
+   }
+
+   ext_value_data = ext->value->data;
+
+#if (OPENSSL_VERSION_NUMBER > 0x00907000L)
+   if (method->it) {
+      /* New style ASN1 */
+
+      /* Decode ASN1 item in data */
+      keyid = (ASN1_OCTET_STRING *) ASN1_item_d2i(NULL, &ext_value_data, ext->value->length,
+                                                  ASN1_ITEM_ptr(method->it));
+   } else {
+      /* Old style ASN1 */
+
+      /* Decode ASN1 item in data */
+      keyid = (ASN1_OCTET_STRING *) method->d2i(NULL, &ext_value_data, ext->value->length);
+   }
+
+#else
+   keyid = (ASN1_OCTET_STRING *) method->d2i(NULL, &ext_value_data, ext->value->length);
+#endif
+
+   return keyid;
+}
+
+/*
+ * Create a new keypair object.
+ *  Returns: A pointer to a X509 KEYPAIR object on success.
+ *           NULL on failure.
+ */
+X509_KEYPAIR *crypto_keypair_new (void) {
+   X509_KEYPAIR *keypair;
+
+   /* Allocate our keypair structure */
+   keypair = (X509_KEYPAIR *) malloc(sizeof(X509_KEYPAIR));
+   if (!keypair) {
+      return NULL;
+   }
+
+   /* Initialize our keypair structure */
+   keypair->keyid = NULL;
+   keypair->pubkey = NULL;
+   keypair->privkey = NULL;
+
+   return keypair;
+}
+
+/*
+ * Load a public key from a PEM-encoded x509 certificate.
+ *  Returns: true on success
+ *           false on failure
+ */
+int crypto_keypair_load_cert (X509_KEYPAIR *keypair, const char *file)
+{
+   BIO *bio;
+   X509 *cert;
+
+   /* Open the file */
+   if (!(bio = BIO_new_file(file, "r"))) {
+      openssl_post_errors(M_ERROR, _("Unable to open certificate file"));
+      return false;
+   }
+
+   cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+   BIO_free(bio);
+   if (!cert) {
+      openssl_post_errors(M_ERROR, _("Unable to read certificate from file"));
+      return false;
+   }
+
+   /* Extract the public key */
+   if (!(keypair->pubkey = X509_get_pubkey(cert))) {
+      openssl_post_errors(M_ERROR, _("Unable to extract public key from certificate"));
+      goto err;
+   }
+
+   /* Extract the subjectKeyIdentifier extension field */
+   if ((keypair->keyid = openssl_cert_keyid(cert)) == NULL) {
+      Emsg0(M_ERROR, 0, _("Provided certificate does not include the required subjectKeyIdentifier extension."));
+      goto err;
+   }
+
+   /* Validate the public key type (only RSA is supported) */
+   if (EVP_PKEY_type(keypair->pubkey->type) != EVP_PKEY_RSA) {
+       Emsg1(M_ERROR, 0, _("Unsupported key type provided: %d\n"), EVP_PKEY_type(keypair->pubkey->type));
+       goto err;
+   }
+
+   return true;
+
+err:
+   X509_free(cert);
+   if (keypair->pubkey) {
+      EVP_PKEY_free(keypair->pubkey);
+   }
+   return false;
+}
+
+/* Dispatch user PEM encryption callbacks */
+static int crypto_pem_callback_dispatch (char *buf, int size, int rwflag, void *userdata)
+{
+   PEM_CB_CONTEXT *ctx = (PEM_CB_CONTEXT *) userdata;
+   return (ctx->pem_callback(buf, size, ctx->pem_userdata));
+}
+
+/*
+ * Load a PEM-encoded private key.
+ *  Returns: true on success
+ *           false on failure
+ */
+int crypto_keypair_load_key (X509_KEYPAIR *keypair, const char *file,
+                             CRYPTO_PEM_PASSWD_CB *pem_callback,
+                             const void *pem_userdata)
+{
+   BIO *bio;
+   PEM_CB_CONTEXT ctx;
+
+   /* Open the file */
+   if (!(bio = BIO_new_file(file, "r"))) {
+      openssl_post_errors(M_ERROR, _("Unable to open private key file"));
+      return false;
+   }
+
+   /* Set up PEM encryption callback */
+   if (pem_callback) {
+      ctx.pem_callback = pem_callback;
+      ctx.pem_userdata = pem_userdata;
+   } else {
+      ctx.pem_callback = crypto_default_pem_callback;
+      ctx.pem_userdata = NULL;
+   }
+
+   keypair->privkey = PEM_read_bio_PrivateKey(bio, NULL, crypto_pem_callback_dispatch, &ctx);
+   BIO_free(bio);
+   if (!keypair->privkey) {
+      openssl_post_errors(M_ERROR, _("Unable to read private key from file"));
+      return false;
+   }
+
+   return true;
+}
+
+/*
+ * Free memory associated with a keypair object.
+ */
+void crypto_keypair_free (X509_KEYPAIR *keypair)
+{
+   if (keypair->pubkey) {
+      EVP_PKEY_free(keypair->pubkey);
+   }
+   if (keypair->privkey) {
+      EVP_PKEY_free(keypair->privkey);
+   }
+   if (keypair->keyid) {
+      M_ASN1_OCTET_STRING_free(keypair->keyid);
+   }
+   free(keypair);
+}
+
+/*
+ * Create a new message digest context of the specified type
+ *  Returns: A pointer to a DIGEST object on success.
+ *           NULL on failure.
+ */
+DIGEST *crypto_digest_new (crypto_digest_t type)
+{
+   DIGEST *digest;
+   const EVP_MD *md = NULL; /* Quell invalid uninitialized warnings */
+
+   digest = (DIGEST *) malloc(sizeof(DIGEST));
+   digest->type = type;
+
+   /* Initialize the OpenSSL message digest context */
+   EVP_MD_CTX_init(&digest->ctx);
+
+   /* Determine the correct OpenSSL message digest type */
+   switch (type) {
+   case CRYPTO_DIGEST_MD5:
+      md = EVP_md5();
+      break;
+   case CRYPTO_DIGEST_SHA1:
+      md = EVP_sha1();
+      break;
+#ifdef HAVE_SHA2
+   case CRYPTO_DIGEST_SHA256:
+      md = EVP_sha256();
+      break;
+   case CRYPTO_DIGEST_SHA512:
+      md = EVP_sha512();
+      break;
+#endif
+   default:
+      Emsg1(M_ERROR, 0, _("Unsupported digest type: %d\n"), type);
+      goto err;
+   }
+
+   /* Initialize the backing OpenSSL context */
+   if (EVP_DigestInit_ex(&digest->ctx, md, NULL) == 0) {
+      goto err;
+   }
+
+   return digest;
+
+err:
+   /* This should not happen, but never say never ... */
+   openssl_post_errors(M_ERROR, _("OpenSSL digest initialization failed"));
+   crypto_digest_free(digest);
+   return NULL;
+}
+
+/*
+ * Hash length bytes of data into the provided digest context.
+ * Returns: true on success
+ *          false on failure
+ */
+int crypto_digest_update (DIGEST *digest, const void *data, size_t length) {
+   if (EVP_DigestUpdate(&digest->ctx, data, length) == 0) {
+      return true;
+   } else { 
+      return false;
+   }
+}
+
+/*
+ * Finalize the data in digest, storing the result in dest and the result size
+ * in length. The result size can be determined with crypto_digest_size().
+ *
+ * Returns: true on success
+ *          false on failure
+ */
+int crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
+   if (!EVP_DigestFinal(&digest->ctx, (unsigned char *) dest, length)) {
+      return false;
+   } else {
+      return true;
+   }
+}
+
+/*
+ * Free memory associated with a digest object.
+ */
+void crypto_digest_free (DIGEST *digest)
+{
+  EVP_MD_CTX_cleanup(&digest->ctx);
+  free (digest);
+}
+
+/*
+ * Create a new message signature context.
+ *  Returns: A pointer to a SIGNATURE object on success.
+ *           NULL on failure.
+ */
+SIGNATURE *crypto_sign_new (void)
+{
+   SIGNATURE *sig;
+
+   sig = (SIGNATURE *) malloc(sizeof(SIGNATURE));
+   if (!sig) {
+      return NULL;
+   }
+
+   sig->sigData = SignatureData_new();
+
+   if (!sig->sigData) {
+      /* Allocation failed in OpenSSL */
+      free(sig);
+      return NULL;
+   }
+
+   /* Set the ASN.1 structure version number */
+   ASN1_INTEGER_set(sig->sigData->version, BACULA_ASN1_VERSION);
+
+   return sig;
+}
+
+/*
+ * For a given public key, find the associated SignatureInfo record
+ * and create a digest context for signature validation
+ * Returns: CRYPTO_ERROR_NONE on success, with the newly allocated DIGEST in digest.
+ *          A crypto_error_t value on failure.
+ */
+crypto_error_t crypto_sign_get_digest(SIGNATURE *sig, X509_KEYPAIR *keypair, DIGEST **digest)
+{
+   STACK_OF(SignerInfo) *signers;
+   SignerInfo *si;
+   int i;
+
+   signers = sig->sigData->signerInfo;
+
+   for (i = 0; i < sk_SignerInfo_num(signers); i++) {
+      si = sk_SignerInfo_value(signers, i);
+      if (M_ASN1_OCTET_STRING_cmp(keypair->keyid, si->subjectKeyIdentifier) == 0) {
+         /* Get the digest algorithm and allocate a digest context */
+         switch (OBJ_obj2nid(si->digestAlgorithm)) {
+         case NID_md5:
+            *digest = crypto_digest_new(CRYPTO_DIGEST_MD5);
+            break;
+         case NID_sha1:
+            *digest = crypto_digest_new(CRYPTO_DIGEST_SHA1);
+            break;
+#ifdef HAVE_SHA2
+         case NID_sha256:
+            *digest = crypto_digest_new(CRYPTO_DIGEST_SHA256);
+            break;
+         case NID_sha512:
+            *digest = crypto_digest_new(CRYPTO_DIGEST_SHA512);
+            break;
+#endif
+         default:
+            *digest = NULL;
+            return CRYPTO_ERROR_INVALID_DIGEST;
+         }
+
+         /* Shouldn't happen */
+         if (*digest == NULL) {
+            return CRYPTO_ERROR_INVALID_DIGEST;
+         } else {
+            return CRYPTO_ERROR_NONE;
+         }
+      }
+   }
+
+   return CRYPTO_ERROR_NOSIGNER;
+}
+
+/*
+ * For a given signature, public key, and digest, verify the SIGNATURE.
+ * Returns: CRYPTO_ERROR_NONE on success.
+ *          A crypto_error_t value on failure.
+ */
+crypto_error_t crypto_sign_verify(SIGNATURE *sig, X509_KEYPAIR *keypair, DIGEST *digest)
+{
+   STACK_OF(SignerInfo) *signers;
+   SignerInfo *si;
+   int ok, i;
+   unsigned int sigLen;
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800FL)
+   const unsigned char *sigData;
+#else
+   unsigned char *sigData;
+#endif
+
+   signers = sig->sigData->signerInfo;
+
+   /* Find the signer */
+   for (i = 0; i < sk_SignerInfo_num(signers); i++) {
+      si = sk_SignerInfo_value(signers, i);
+      if (M_ASN1_OCTET_STRING_cmp(keypair->keyid, si->subjectKeyIdentifier) == 0) {
+         /* Extract the signature data */
+         sigLen = M_ASN1_STRING_length(si->signature);
+         sigData = M_ASN1_STRING_data(si->signature);
+
+         ok = EVP_VerifyFinal(&digest->ctx, sigData, sigLen, keypair->pubkey);
+         if (ok >= 1) {
+            return CRYPTO_ERROR_NONE;
+         } else if (ok == 0) {
+            return CRYPTO_ERROR_BAD_SIGNATURE;
+         } else if (ok < 0) {
+            /* Shouldn't happen */
+            openssl_post_errors(M_ERROR, _("OpenSSL error occured"));
+            return CRYPTO_ERROR_INTERNAL;
+         }
+      }
+   }
+
+   /* Signer wasn't found. */
+   return CRYPTO_ERROR_NOSIGNER;
+}
+
+
+/*
+ * Add a new signer
+ *  Returns: true on success
+ *           false on failure
+ */
+int crypto_sign_add_signer(SIGNATURE *sig, DIGEST *digest, X509_KEYPAIR *keypair)
+{
+   SignerInfo *si = NULL;
+   unsigned char *buf = NULL;
+   unsigned int len;
+
+   si = SignerInfo_new();
+
+   if (!si) {
+      /* Allocation failed in OpenSSL */
+      return false;
+   }
+
+   /* Set the ASN.1 structure version number */
+   ASN1_INTEGER_set(si->version, BACULA_ASN1_VERSION);
+
+   /* Set the digest algorithm identifier */
+   switch (digest->type) {
+   case CRYPTO_DIGEST_MD5:
+      si->digestAlgorithm = OBJ_nid2obj(NID_md5);
+      break;
+   case CRYPTO_DIGEST_SHA1:
+      si->digestAlgorithm = OBJ_nid2obj(NID_sha1);
+      break;
+#ifdef HAVE_SHA2
+   case CRYPTO_DIGEST_SHA256:
+      si->digestAlgorithm = OBJ_nid2obj(NID_sha256);
+      break;
+   case CRYPTO_DIGEST_SHA512:
+      si->digestAlgorithm = OBJ_nid2obj(NID_sha512);
+      break;
+#endif
+   default:
+      /* This should never happen */
+      goto err;
+   }
+
+   /* Drop the string allocated by OpenSSL, and add our subjectKeyIdentifier */
+   M_ASN1_OCTET_STRING_free(si->subjectKeyIdentifier);
+   si->subjectKeyIdentifier = M_ASN1_OCTET_STRING_dup(keypair->keyid);
+
+   /* Set our signature algorithm. We currently require RSA */
+   assert(EVP_PKEY_type(keypair->pubkey->type) == EVP_PKEY_RSA);
+   /* This is slightly evil. Reach into the MD structure and grab the key type */
+   si->signatureAlgorithm = OBJ_nid2obj(digest->ctx.digest->pkey_type);
+
+   /* Finalize/Sign our Digest */
+   len = EVP_PKEY_size(keypair->privkey);
+   buf = (unsigned char *) malloc(len);
+   if (!EVP_SignFinal(&digest->ctx, buf, &len, keypair->privkey)) {
+      openssl_post_errors(M_ERROR, _("Signature creation failed"));
+      goto err;
+   }
+
+   /* Add the signature to the SignerInfo structure */
+   if (!M_ASN1_OCTET_STRING_set(si->signature, buf, len)) {
+      /* Allocation failed in OpenSSL */
+      goto err;
+   }
+
+   /* No longer needed */
+   free(buf);
+
+   /* Push the new SignerInfo structure onto the stack */
+   sk_SignerInfo_push(sig->sigData->signerInfo, si);
+
+   return true;
+
+err:
+   if (si) {
+      SignerInfo_free(si);
+   }
+   if (buf) {
+      free(buf);
+   }
+
+   return false;
+}
+
+/*
+ * Encodes the SignatureData structure. The length argument is used to specify the
+ * size of dest. A length of 0 will cause no data to be written to dest, and the
+ * required length to be written to length. The caller can then allocate sufficient
+ * space for the output.
+ *
+ * Returns: true on success, stores the encoded data in dest, and the size in length.
+ *          false on failure.
+ */
+int crypto_sign_encode(SIGNATURE *sig, void *dest, size_t *length)
+{
+   if (*length == 0) {
+      *length = i2d_SignatureData(sig->sigData, NULL);
+      return true;
+   }
+
+   *length = i2d_SignatureData(sig->sigData, (unsigned char **) &dest);
+   return true;
+}
+
+/*
+ * Decodes the SignatureData structure. The length argument is used to specify the
+ * size of sigData.
+ *
+ * Returns: SIGNATURE instance on success.
+ *          NULL on failure.
+
+ */
+
+SIGNATURE *crypto_sign_decode(const void *sigData, size_t length)
+{
+   SIGNATURE *sig;
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800FL)
+   const unsigned char *p = (const unsigned char *) sigData;
+#else
+   unsigned char *p = (unsigned char *) sigData;
+#endif
+
+   sig = (SIGNATURE *) malloc(sizeof(SIGNATURE));
+   if (!sig) {
+      return NULL;
+   }
+
+   /* d2i_SignatureData modifies the supplied pointer */
+   sig->sigData  = d2i_SignatureData(NULL, &p, length);
+
+   if (!sig->sigData) {
+      /* Allocation / Decoding failed in OpenSSL */
+      openssl_post_errors(M_ERROR, _("Signature decoding failed"));
+      return NULL;
+   }
+
+   return sig;
+}
+
+/*
+ * Free memory associated with a signature object.
+ */
+void crypto_sign_free(SIGNATURE *sig)
+{
+   SignatureData_free(sig->sigData);
+   free (sig);
+}
+
+/*
+ * Perform global initialization of OpenSSL
+ * This function is not thread safe.
+ *  Returns: 0 on success
+ *           errno on failure
+ */
+int init_crypto (void)
+{
+   int stat;
+
+   if ((stat = openssl_init_threads()) != 0) {
+      Emsg1(M_ABORT, 0, _("Unable to init OpenSSL threading: ERR=%s\n"), strerror(stat));
+   }
+
+   /* Load libssl and libcrypto human-readable error strings */
+   SSL_load_error_strings();
+
+   /* Register OpenSSL ciphers */
+   SSL_library_init();
+
+   if (!openssl_seed_prng()) {
+      Emsg0(M_ERROR_TERM, 0, _("Failed to seed OpenSSL PRNG\n"));
+   }
+
+   crypto_initialized = true;
+
+   return stat;
+}
+
+/*
+ * Perform global cleanup of OpenSSL
+ * All cryptographic operations must be completed before calling this function.
+ * This function is not thread safe.
+ *  Returns: 0 on success
+ *           errno on failure
+ */
+int cleanup_crypto (void)
+{
+   /*
+    * Ensure that we've actually been initialized; Doing this here decreases the
+    * complexity of client's termination/cleanup code.
+    */
+   if (!crypto_initialized) {
+      return 0;
+   }
+
+   if (!openssl_save_prng()) {
+      Emsg0(M_ERROR, 0, _("Failed to save OpenSSL PRNG\n"));
+   }
+
+   openssl_cleanup_threads();
+
+   /* Free libssl and libcrypto error strings */
+   ERR_free_strings();
+
+   /* Free memory used by PRNG */
+   RAND_cleanup();
+
+   crypto_initialized = false;
+
+   return 0;
+}
+
+
+#else /* HAVE_OPENSSL */
+# error No encryption library available
+#endif /* HAVE_OPENSSL */
+
+#else /* HAVE_CRYPTO */
+
+/*
+ * Cryptography Support Disabled
+ */
+
+/* Message Digest Structure */
+struct Digest {
+   crypto_digest_t type;
+   union {
+      SHA1Context sha1;
+      MD5Context md5;
+   };
+};
+
+/* Dummy Signature Structure */
+struct Signature {
+};
+
+DIGEST *crypto_digest_new (crypto_digest_t type)
+{
+   DIGEST *digest;
+
+   digest = (DIGEST *) malloc(sizeof(DIGEST));
+   digest->type = type;
+
+   switch (type) {
+   case CRYPTO_DIGEST_MD5:
+      MD5Init(&digest->md5);
+      break;
+   case CRYPTO_DIGEST_SHA1:
+      SHA1Init(&digest->sha1);
+      break;
+   default:
+      Emsg0(M_ERROR, 0, _("Unsupported digest type specified\n"));
+      free(digest);
+      return NULL;
+   }
+
+   return (digest);
+}
+
+int crypto_digest_update (DIGEST *digest, const void *data, size_t length) {
+   switch (digest->type) {
+   case CRYPTO_DIGEST_MD5:
+      /* Doesn't return anything ... */
+      MD5Update(&digest->md5, (unsigned char *) data, length);
+      return true;
+   case CRYPTO_DIGEST_SHA1:
+      int ret;
+      if ((ret = SHA1Update(&digest->sha1, (const u_int8_t *) data, length)) == shaSuccess) {
+        return true;
+      } else {
+         Emsg1(M_ERROR, 0, _("SHA1Update() returned an error: %d\n"), ret);
+        return false;
+      }
+      break;
+   default:
+      return false;
+   }
+}
+
+int crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
+
+   switch (digest->type) {
+   case CRYPTO_DIGEST_MD5:
+      /* Guard against programmer error by either the API client or
+       * an out-of-sync CRYPTO_DIGEST_MAX_SIZE */
+      assert(*length >= CRYPTO_DIGEST_MD5_SIZE);
+      *length = CRYPTO_DIGEST_MD5_SIZE;
+      /* Doesn't return anything ... */
+      MD5Final((unsigned char *) dest, &digest->md5);
+      return true;
+   case CRYPTO_DIGEST_SHA1:
+      /* Guard against programmer error by either the API client or
+       * an out-of-sync CRYPTO_DIGEST_MAX_SIZE */
+      assert(*length >= CRYPTO_DIGEST_SHA1_SIZE);
+      *length = CRYPTO_DIGEST_SHA1_SIZE;
+      if (SHA1Final(&digest->sha1, (u_int8_t *) dest) == shaSuccess) {
+        return true;
+      } else {
+        return false;
+      }
+      break;
+   default:
+      return false;
+   }
+
+   return false;
+}
+
+void crypto_digest_free (DIGEST *digest)
+{
+   free (digest);
+}
+
+/* Dummy routines */
+int init_crypto (void) { return 0; }
+int cleanup_crypto (void) { return 0; }
+
+SIGNATURE *crypto_sign_new (void) { return NULL; }
+
+crypto_error_t crypto_sign_get_digest (SIGNATURE *sig, X509_KEYPAIR *keypair, DIGEST **digest) { return CRYPTO_ERROR_INTERNAL; }
+crypto_error_t crypto_sign_verify (SIGNATURE *sig, X509_KEYPAIR *keypair, DIGEST *digest) { return CRYPTO_ERROR_INTERNAL; }
+
+int crypto_sign_add_signer (SIGNATURE *sig, DIGEST *digest, X509_KEYPAIR *keypair) { return false; }
+int crypto_sign_encode (SIGNATURE *sig, void *dest, size_t *length) { return false; }
+
+SIGNATURE *crypto_sign_decode (const void *sigData, size_t length) { return false; }
+void crypto_sign_free (SIGNATURE *sig) { }
+
+
+X509_KEYPAIR *crypto_keypair_new (void) { return NULL; }
+int crypto_keypair_load_cert (X509_KEYPAIR *keypair, const char *file) { return false; }
+int crypto_keypair_load_key (X509_KEYPAIR *keypair, const char *file, CRYPTO_PEM_PASSWD_CB *pem_callback, const void *pem_userdata) { return false; }
+void crypto_keypair_free (X509_KEYPAIR *keypair) { }
+
+#endif /* HAVE_CRYPTO */
+
+/* Shared Code */
+
+/*
+ * Default PEM encryption passphrase callback.
+ * Returns an empty password.
+ */
+int crypto_default_pem_callback(char *buf, int size, const void *userdata)
+{
+   bstrncpy(buf, "", size);
+   return (strlen(buf));
+}
+
+/*
+ * Returns the ASCII name of the digest type.
+ * Returns: ASCII name of digest type.
+ */
+const char *crypto_digest_name (DIGEST *digest) {
+   switch (digest->type) {
+   case CRYPTO_DIGEST_MD5:
+      return "MD5";
+   case CRYPTO_DIGEST_SHA1:
+      return "SHA1";
+   case CRYPTO_DIGEST_SHA256:
+      return "SHA256";
+   case CRYPTO_DIGEST_SHA512:
+      return "SHA512";
+   case CRYPTO_DIGEST_NONE:
+      return "None";
+   default:
+      return "Invalid Digest Type";
+   }
+
+}
+
+/*
+ * Given a stream type, returns the associated
+ * crypto_digest_t value.
+ */
+crypto_digest_t crypto_digest_stream_type (int stream) {
+   switch (stream) {
+   case STREAM_MD5_DIGEST:
+      return CRYPTO_DIGEST_MD5;
+   case STREAM_SHA1_DIGEST:
+      return CRYPTO_DIGEST_SHA1;
+   case STREAM_SHA256_DIGEST:
+      return CRYPTO_DIGEST_SHA256;
+   case STREAM_SHA512_DIGEST:
+      return CRYPTO_DIGEST_SHA512;
+   default:
+      return CRYPTO_DIGEST_NONE;
+   }
+}
+
+/*
+ *  * Given a crypto_error_t value, return the associated
+ *   * error string
+ *    */
+const char *crypto_strerror(crypto_error_t error) {
+   switch (error) {
+   case CRYPTO_ERROR_NONE:
+      return "No error";
+   case CRYPTO_ERROR_NOSIGNER:
+      return "Signer not found";
+   case CRYPTO_ERROR_INVALID_DIGEST:
+      return "Unsupported digest algorithm";
+   case CRYPTO_ERROR_BAD_SIGNATURE:
+      return "Signature is invalid";
+   case CRYPTO_ERROR_INTERNAL:
+      /* This shouldn't happen */
+      return "Internal error";
+   default:
+      return "Unknown error";
+   }
+}
diff --git a/bacula/src/lib/crypto.h b/bacula/src/lib/crypto.h
new file mode 100644 (file)
index 0000000..1519cf4
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * crypto.h Encryption support functions
+ *
+ * Author: Landon Fuller <landonf@opendarwin.org>
+ *
+ * Version $Id$
+ *
+ * Copyright (C) 2005 Kern Sibbald
+ *
+ * This file was contributed to the Bacula project by Landon Fuller.
+ *
+ * Landon Fuller has been granted a perpetual, worldwide, non-exclusive,
+ * no-charge, royalty-free, irrevocable copyright * license to reproduce,
+ * prepare derivative works of, publicly display, publicly perform,
+ * sublicense, and distribute the original work contributed by Landon Fuller
+ * to the Bacula project in source or object form.
+ *
+ * If you wish to license these contributions under an alternate open source
+ * license please contact Landon Fuller <landonf@opendarwin.org>.
+ */
+/*
+   Copyright (C) 2005 Kern Sibbald
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   version 2 as amended with additional clauses defined in the
+   file LICENSE in the main source directory.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
+   the file LICENSE for additional details.
+
+ */
+
+#ifndef __CRYPTO_H_
+#define __CRYPTO_H_
+
+/* Opaque X509 Public/Private Key Pair Structure */
+typedef struct X509_Keypair X509_KEYPAIR;
+
+/* Opaque Message Digest Structure */
+typedef struct Digest DIGEST;
+
+/* Opaque Message Signature Structure */
+typedef struct Signature SIGNATURE;
+
+/* PEM Decryption Passphrase Callback */
+typedef int (CRYPTO_PEM_PASSWD_CB) (char *buf, int size, const void *userdata);
+
+/* Digest Types */
+typedef enum {
+   /* These are stored on disk and MUST NOT change */
+   CRYPTO_DIGEST_NONE = 0,
+   CRYPTO_DIGEST_MD5 = 1,
+   CRYPTO_DIGEST_SHA1 = 2,
+   CRYPTO_DIGEST_SHA256 = 3,
+   CRYPTO_DIGEST_SHA512 = 4
+} crypto_digest_t;
+
+/* Crypto API Errors */
+typedef enum {
+   CRYPTO_ERROR_NONE           = 0, /* No error */
+   CRYPTO_ERROR_NOSIGNER       = 1, /* Signer not found */
+   CRYPTO_ERROR_INVALID_DIGEST = 2, /* Unsupported digest algorithm */
+   CRYPTO_ERROR_BAD_SIGNATURE  = 3, /* Signature is invalid */
+   CRYPTO_ERROR_INTERNAL       = 4  /* Internal Error */
+} crypto_error_t;
+
+/* Message Digest Sizes */
+#define CRYPTO_DIGEST_MD5_SIZE 16     /* 128 bits */
+#define CRYPTO_DIGEST_SHA1_SIZE 20    /* 160 bits */
+#define CRYPTO_DIGEST_SHA256_SIZE 32  /* 256 bits */
+#define CRYPTO_DIGEST_SHA512_SIZE 64  /* 512 bits */
+
+/* Maximum Message Digest Size */
+#ifdef HAVE_OPENSSL
+
+/* Let OpenSSL define it */
+#define CRYPTO_DIGEST_MAX_SIZE EVP_MAX_MD_SIZE
+
+#else /* HAVE_OPENSSL */
+
+/*
+ * This must be kept in sync with the available message digest algorithms.
+ * Just in case someone forgets, I've added assertions
+ * to crypto_digest_finalize().
+ *     MD5: 128 bits
+ *     SHA-1: 160 bits
+ */
+#ifndef HAVE_SHA2
+#define CRYPTO_DIGEST_MAX_SIZE CRYPTO_DIGEST_SHA1_SIZE
+#else
+#define CRYPTO_DIGEST_MAX_SIZE CRYPTO_DIGEST_SHA512_SIZE
+#endif
+
+#endif /* HAVE_OPENSSL */
+
+#endif /* __CRYPTO_H_ */
index bfe0bc9d1e0491fd20e1f83ed95ccaecdd6f9a17..7dade4c1367feeecefad52c8ce4769eadc913cca 100644 (file)
@@ -29,8 +29,8 @@
 
 #include "bacula.h"
 
-#define PAD_LEN 64                   /* PAD length */
-#define SIG_LEN 16                   /* MD5 signature length */
+#define PAD_LEN 64           /* PAD length */
+#define SIG_LEN MD5HashSize  /* MD5 digest length */
 
 void
 hmac_md5(
index 7d7df09f142356706f7e017ef909b765f389214c..5b5b6a82e14f24df72d2e09f123f677cb5354cbf 100644 (file)
 #include "smartall.h"
 #include "alist.h"
 #include "dlist.h"
+#include "base64.h"
 #include "bits.h"
 #include "btime.h"
+#include "crypto.h"
 #include "mem_pool.h"
 #include "message.h"
+#include "openssl.h"
 #include "lex.h"
 #include "parse_conf.h"
 #include "tls.h"
index a927064be58dc25853c3a9a5ddcb72a5e66b970f..f97e00d4032e724aa38e4c4db7d659901db011c3 100644 (file)
@@ -28,6 +28,8 @@
 #ifndef __BMD5_H
 #define __BMD5_H
 
+#define MD5HashSize 16
+
 struct MD5Context {
    uint32_t buf[4];
    uint32_t bits[2];
diff --git a/bacula/src/lib/openssl.c b/bacula/src/lib/openssl.c
new file mode 100644 (file)
index 0000000..929dee7
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * openssl.c OpenSSL support functions
+ *
+ * Author: Landon Fuller <landonf@opendarwin.org>
+ *
+ * Version $Id$
+ *
+ * Copyright (C) 2005 Kern Sibbald
+ *
+ * This file was contributed to the Bacula project by Landon Fuller.
+ *
+ * Landon Fuller has been granted a perpetual, worldwide, non-exclusive,
+ * no-charge, royalty-free, irrevocable copyright license to reproduce,
+ * prepare derivative works of, publicly display, publicly perform,
+ * sublicense, and distribute the original work contributed by Landon Fuller
+ * to the Bacula project in source or object form.
+ *
+ * If you wish to license these contributions under an alternate open source
+ * license please contact Landon Fuller <landonf@opendarwin.org>.
+ */
+/*
+   Copyright (C) 2005 Kern Sibbald
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   version 2 as amended with additional clauses defined in the
+   file LICENSE in the main source directory.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
+   the file LICENSE for additional details.
+
+ */
+
+
+#include "bacula.h"
+#include <assert.h>
+
+#ifdef HAVE_OPENSSL
+
+/* Array of mutexes for use with OpenSSL static locking */
+static pthread_mutex_t *mutexes;
+
+/* OpenSSL dynamic locking structure */
+struct CRYPTO_dynlock_value {
+   pthread_mutex_t mutex;
+};
+
+
+/*
+ * Post all per-thread openssl errors
+ */
+void openssl_post_errors(int code, const char *errstring)
+{
+   char buf[512];
+   unsigned long sslerr;
+
+   /* Pop errors off of the per-thread queue */
+   while((sslerr = ERR_get_error()) != 0) {
+      /* Acquire the human readable string */
+      ERR_error_string_n(sslerr, (char *) &buf, sizeof(buf));
+      Emsg2(M_ERROR, 0, "%s: ERR=%s\n", errstring, buf);
+   }
+}
+
+/*
+ * Return an OpenSSL thread ID
+ *  Returns: thread ID
+ *
+ */
+static unsigned long get_openssl_thread_id (void)
+{
+   /* Comparison without use of pthread_equal() is mandated by the OpenSSL API */
+   return ((unsigned long) pthread_self());
+}
+
+/*
+ * Allocate a dynamic OpenSSL mutex
+ */
+static struct CRYPTO_dynlock_value *openssl_create_dynamic_mutex (const char *file, int line)
+{
+   struct CRYPTO_dynlock_value *dynlock;
+   int stat;
+
+   dynlock = (struct CRYPTO_dynlock_value *) malloc(sizeof(struct CRYPTO_dynlock_value));
+
+   if ((stat = pthread_mutex_init(&dynlock->mutex, NULL)) != 0) {
+      Emsg1(M_ABORT, 0, _("Unable to init mutex: ERR=%s\n"), strerror(stat));
+   }
+
+   return dynlock;
+}
+
+static void openssl_update_dynamic_mutex (int mode, struct CRYPTO_dynlock_value *dynlock, const char *file, int line)
+{
+   if (mode & CRYPTO_LOCK) {
+      P(dynlock->mutex);
+   } else {
+      V(dynlock->mutex);
+   }
+}
+
+static void openssl_destroy_dynamic_mutex (struct CRYPTO_dynlock_value *dynlock, const char *file, int line)
+{
+   int stat;
+
+   if ((stat = pthread_mutex_destroy(&dynlock->mutex)) != 0) {
+      Emsg1(M_ABORT, 0, _("Unable to destroy mutex: ERR=%s\n"), strerror(stat));
+   }
+
+   free(dynlock);
+}
+
+/*
+ * (Un)Lock a static OpenSSL mutex
+ */
+static void openssl_update_static_mutex (int mode, int i, const char *file, int line)
+{
+   if (mode & CRYPTO_LOCK) {
+      P(mutexes[i]);
+   } else {
+      V(mutexes[i]);
+   }
+}
+
+/*
+ * Initialize OpenSSL thread support
+ *  Returns: 0 on success
+ *           errno on failure
+ */
+int openssl_init_threads (void)
+{
+   int i, numlocks;
+   int stat;
+
+
+   /* Set thread ID callback */
+   CRYPTO_set_id_callback(get_openssl_thread_id);
+
+   /* Initialize static locking */
+   numlocks = CRYPTO_num_locks();
+   mutexes = (pthread_mutex_t *) malloc(numlocks * sizeof(pthread_mutex_t));
+   for (i = 0; i < numlocks; i++) {
+      if ((stat = pthread_mutex_init(&mutexes[i], NULL)) != 0) {
+         Emsg1(M_ERROR, 0, _("Unable to init mutex: ERR=%s\n"), strerror(stat));
+         return stat;
+      }
+   }
+
+   /* Set static locking callback */
+   CRYPTO_set_locking_callback(openssl_update_static_mutex);
+
+   /* Initialize dyanmic locking */
+   CRYPTO_set_dynlock_create_callback(openssl_create_dynamic_mutex);
+   CRYPTO_set_dynlock_lock_callback(openssl_update_dynamic_mutex);
+   CRYPTO_set_dynlock_destroy_callback(openssl_destroy_dynamic_mutex);
+
+   return 0;
+}
+
+/*
+ * Clean up OpenSSL threading support
+ */
+void openssl_cleanup_threads (void)
+{
+   int i, numlocks;
+   int stat;
+
+   /* Unset thread ID callback */
+   CRYPTO_set_id_callback(NULL);
+  
+   /* Deallocate static lock mutexes */
+   numlocks = CRYPTO_num_locks();
+   for (i = 0; i < numlocks; i++) {
+      if ((stat = pthread_mutex_destroy(&mutexes[i])) != 0) {
+         /* We don't halt execution, reporting the error should be sufficient */
+         Emsg1(M_ERROR, 0, _("Unable to destroy mutex: ERR=%s\n"), strerror(stat));
+      }
+   }
+
+   /* Unset static locking callback */
+   CRYPTO_set_locking_callback(NULL);
+
+   /* Free static lock array */
+   free(mutexes);
+
+   /* Unset dynamic locking callbacks */
+   CRYPTO_set_dynlock_create_callback(NULL);
+   CRYPTO_set_dynlock_lock_callback(NULL);
+   CRYPTO_set_dynlock_destroy_callback(NULL);
+}
+
+
+/*
+ * Seed OpenSSL PRNG
+ *  Returns: 1 on success
+ *           0 on failure
+ */
+int openssl_seed_prng (void)
+{
+   const char *names[]  = { "/dev/urandom", "/dev/random", NULL };
+   int i;
+
+   // ***FIXME***
+   // Win32 Support
+   // Read saved entropy?
+
+   for (i = 0; names[i]; i++) {
+      if (RAND_load_file(names[i], 1024) != -1) {
+         /* Success */
+         return 1;
+      }
+   }
+
+   /* Fail */
+   return 0;
+}
+
+/*
+ * Save OpenSSL Entropy
+ *  Returns: 1 on success
+ *           0 on failure
+ */
+int openssl_save_prng (void)
+{
+   // ***FIXME***
+   // Implement PRNG state save
+   return 1;
+}
+
+#endif /* HAVE_OPENSSL */
diff --git a/bacula/src/lib/openssl.h b/bacula/src/lib/openssl.h
new file mode 100644 (file)
index 0000000..7654e17
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * openssl.h OpenSSL support functions
+ *
+ * Author: Landon Fuller <landonf@opendarwin.org>
+ *
+ * Version $Id$
+ *
+ * Copyright (C) 2005 Kern Sibbald
+ *
+ * This file was contributed to the Bacula project by Landon Fuller.
+ *
+ * Landon Fuller has been granted a perpetual, worldwide, non-exclusive,
+ * no-charge, royalty-free, irrevocable copyright * license to reproduce,
+ * prepare derivative works of, publicly display, publicly perform,
+ * sublicense, and distribute the original work contributed by Landon Fuller
+ * to the Bacula project in source or object form.
+ *
+ * If you wish to license these contributions under an alternate open source
+ * license please contact Landon Fuller <landonf@opendarwin.org>.
+ */
+/*
+   Copyright (C) 2005 Kern Sibbald
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   version 2 as amended with additional clauses defined in the
+   file LICENSE in the main source directory.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
+   the file LICENSE for additional details.
+
+ */
+
+#ifndef __OPENSSL_H_
+#define __OPENSSL_H_
+
+#ifdef HAVE_OPENSSL
+void             openssl_post_errors     (int code, const char *errstring);
+int              openssl_init_threads    (void);
+void             openssl_cleanup_threads (void);
+int              openssl_seed_prng       (void);
+int              openssl_save_prng       (void);
+#endif /* HAVE_OPENSSL */
+
+#endif /* __OPENSSL_H_ */
index 18a103a65e5e4632ab52585e237824a5ac1f3abb..41307bd07b5d9ecca4cea74468e612154dfb09ca 100755 (executable)
@@ -423,7 +423,7 @@ void store_password(LEX *lc, RES_ITEM *item, int index, int pass)
 {
    unsigned int i, j;
    struct MD5Context md5c;
-   unsigned char signature[16];
+   unsigned char digest[CRYPTO_DIGEST_MD5_SIZE];
    char sig[100];
 
 
@@ -431,9 +431,9 @@ void store_password(LEX *lc, RES_ITEM *item, int index, int pass)
    if (pass == 1) {
       MD5Init(&md5c);
       MD5Update(&md5c, (unsigned char *) (lc->str), lc->str_len);
-      MD5Final(signature, &md5c);
-      for (i = j = 0; i < sizeof(signature); i++) {
-         sprintf(&sig[j], "%02x", signature[i]);
+      MD5Final(digest, &md5c);
+      for (i = j = 0; i < sizeof(digest); i++) {
+         sprintf(&sig[j], "%02x", digest[i]);
          j += 2;
       }
       *(item->value) = bstrdup(sig);
index 61c01a7cab8d099013957d96942b1d03253a9564..244f1ca49cb603dc2d01b480b7bfd970313035a0 100644 (file)
@@ -113,6 +113,29 @@ void hmac_md5(uint8_t* text, int text_len, uint8_t*  key,
 
 uint32_t bcrc32(uint8_t *buf, int len);
 
+/* crypto.c */
+int              init_crypto                 (void);
+int              cleanup_crypto              (void);
+DIGEST *         crypto_digest_new           (crypto_digest_t type);
+int              crypto_digest_update        (DIGEST *digest, const void *data, size_t length);
+int              crypto_digest_finalize      (DIGEST *digest, void *dest, size_t *length);
+void             crypto_digest_free          (DIGEST *digest);
+SIGNATURE *      crypto_sign_new             (void);
+crypto_error_t   crypto_sign_get_digest      (SIGNATURE *sig, X509_KEYPAIR *keypair, DIGEST **digest);
+crypto_error_t   crypto_sign_verify          (SIGNATURE *sig, X509_KEYPAIR *keypair, DIGEST *digest);
+int              crypto_sign_add_signer      (SIGNATURE *sig, DIGEST *digest, X509_KEYPAIR *keypair);
+int              crypto_sign_encode          (SIGNATURE *sig, void *dest, size_t *length);
+SIGNATURE *      crypto_sign_decode          (const void *sigData, size_t length);
+void             crypto_sign_free            (SIGNATURE *sig);
+X509_KEYPAIR *   crypto_keypair_new          (void);
+int              crypto_keypair_load_cert    (X509_KEYPAIR *keypair, const char *file);
+int              crypto_keypair_load_key     (X509_KEYPAIR *keypair, const char *file, CRYPTO_PEM_PASSWD_CB *pem_callback, const void *pem_userdata);
+void             crypto_keypair_free         (X509_KEYPAIR *keypair);
+int              crypto_default_pem_callback (char *buf, int size, const void *userdata);
+const char *     crypto_digest_name          (DIGEST *digest);
+crypto_digest_t  crypto_digest_stream_type   (int stream);
+const char *     crypto_strerror             (crypto_error_t error);
+
 /* daemon.c */
 void     daemon_start            ();
 
@@ -209,14 +232,11 @@ int             bsscanf(const char *buf, const char *fmt, ...);
 
 
 /* tls.c */
-int              init_tls                (void);
-int              cleanup_tls             (void);
-
 TLS_CONTEXT      *new_tls_context        (const char *ca_certfile,
                                           const char *ca_certdir,
                                           const char *certfile,
                                           const char *keyfile,
-                                          TLS_PEM_PASSWD_CB *pem_callback,
+                                          CRYPTO_PEM_PASSWD_CB *pem_callback,
                                           const void *pem_userdata,
                                           const char *dhfile,
                                           bool verify_peer);
index c660505f3c6f8ffec89176e37a475f94c0effb54..d9d3b510027adf54527fe7e7588f1242e59f0a47 100644 (file)
@@ -36,6 +36,7 @@
 
  */
 
+
 #include "bacula.h"
 #include <assert.h>
 
@@ -48,21 +49,10 @@ extern time_t watchdog_time;
 /* No anonymous ciphers, no <128 bit ciphers, no export ciphers, no MD5 ciphers */
 #define TLS_DEFAULT_CIPHERS "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"
 
-/* Array of mutexes for use with OpenSSL static locking */
-static pthread_mutex_t *mutexes;
-
-/* OpenSSL dynamic locking structure */
-struct CRYPTO_dynlock_value {
-   pthread_mutex_t mutex;
-};
-
-/* Are we initialized? */
-static int tls_initialized = false;
-
 /* TLS Context Structure */
 struct TLS_Context {
    SSL_CTX *openssl;
-   TLS_PEM_PASSWD_CB *pem_callback;
+   CRYPTO_PEM_PASSWD_CB *pem_callback;
    const void *pem_userdata;
 };
 
@@ -70,20 +60,6 @@ struct TLS_Connection {
    SSL *openssl;
 };
 
-/* post all per-thread openssl errors */
-static void openssl_post_errors(int code, const char *errstring)
-{
-   char buf[512];
-   unsigned long sslerr;
-
-   /* Pop errors off of the per-thread queue */
-   while((sslerr = ERR_get_error()) != 0) {
-      /* Acquire the human readable string */
-      ERR_error_string_n(sslerr, (char *) &buf, sizeof(buf));
-      Emsg2(M_ERROR, 0, "%s: ERR=%s\n", errstring, buf);
-   }
-}
-
 /*
  * OpenSSL certificate verification callback.
  * OpenSSL has already performed internal certificate verification.
@@ -111,18 +87,8 @@ static int openssl_verify_peer(int ok, X509_STORE_CTX *store)
    return ok;
 }
 
-/*
- * Default PEM encryption passphrase callback.
- * Returns an empty password.
- */
-static int tls_default_pem_callback(char *buf, int size, const void *userdata)
-{
-   bstrncpy(buf, "", size);
-   return (strlen(buf));
-}
-
 /* Dispatch user PEM encryption callbacks */
-static int openssl_pem_callback_dispatch (char *buf, int size, int rwflag, void *userdata)
+static int tls_pem_callback_dispatch (char *buf, int size, int rwflag, void *userdata)
 {
    TLS_CONTEXT *ctx = (TLS_CONTEXT *) userdata;
    return (ctx->pem_callback(buf, size, ctx->pem_userdata));
@@ -135,7 +101,7 @@ static int openssl_pem_callback_dispatch (char *buf, int size, int rwflag, void
  */
 TLS_CONTEXT *new_tls_context(const char *ca_certfile, const char *ca_certdir,
                              const char *certfile, const char *keyfile,
-                             TLS_PEM_PASSWD_CB *pem_callback,
+                             CRYPTO_PEM_PASSWD_CB *pem_callback,
                              const void *pem_userdata, const char *dhfile,
                              bool verify_peer)
 {
@@ -158,10 +124,10 @@ TLS_CONTEXT *new_tls_context(const char *ca_certfile, const char *ca_certdir,
       ctx->pem_callback = pem_callback;
       ctx->pem_userdata = pem_userdata;
    } else {
-      ctx->pem_callback = tls_default_pem_callback;
+      ctx->pem_callback = crypto_default_pem_callback;
       ctx->pem_userdata = NULL;
    }
-   SSL_CTX_set_default_passwd_cb(ctx->openssl, openssl_pem_callback_dispatch);
+   SSL_CTX_set_default_passwd_cb(ctx->openssl, tls_pem_callback_dispatch);
    SSL_CTX_set_default_passwd_cb_userdata(ctx->openssl, (void *) ctx);
 
    /*
@@ -367,7 +333,7 @@ bool tls_postconnect_verify_host(TLS_CONNECTION *tls, const char *host)
             for (j = 0; j < sk_CONF_VALUE_num(val); j++) {
                nval = sk_CONF_VALUE_value(val, j);
                if (strcmp(nval->name, "DNS") == 0) {
-                  if (strcasecmp(nval->name, host) == 0) {
+                  if (strcasecmp(nval->value, host) == 0) {
                      auth_success = true;
                      goto success;
                   }
@@ -692,234 +658,6 @@ int tls_bsock_readn(BSOCK *bsock, char *ptr, int32_t nbytes) {
    return (openssl_bsock_readwrite(bsock, ptr, nbytes, false));
 }
 
-/*
- * Return an OpenSSL thread ID
- *  Returns: thread ID
- *
- */
-static unsigned long get_openssl_thread_id (void)
-{
-   /* Comparison without use of pthread_equal() is mandated by the OpenSSL API */
-   return ((unsigned long) pthread_self());
-}
-
-/*
- * Allocate a dynamic OpenSSL mutex
- */
-static struct CRYPTO_dynlock_value *openssl_create_dynamic_mutex (const char *file, int line)
-{
-   struct CRYPTO_dynlock_value *dynlock;
-   int stat;
-
-   dynlock = (struct CRYPTO_dynlock_value *) malloc(sizeof(struct CRYPTO_dynlock_value));
-
-   if ((stat = pthread_mutex_init(&dynlock->mutex, NULL)) != 0) {
-      Emsg1(M_ABORT, 0, _("Unable to init mutex: ERR=%s\n"), strerror(stat));
-   }
-
-   return dynlock;
-}
-
-static void openssl_update_dynamic_mutex (int mode, struct CRYPTO_dynlock_value *dynlock, const char *file, int line)
-{
-   if (mode & CRYPTO_LOCK) {
-      P(dynlock->mutex);
-   } else {
-      V(dynlock->mutex);
-   }
-}
-
-static void openssl_destroy_dynamic_mutex (struct CRYPTO_dynlock_value *dynlock, const char *file, int line)
-{
-   int stat;
-
-   if ((stat = pthread_mutex_destroy(&dynlock->mutex)) != 0) {
-      Emsg1(M_ABORT, 0, _("Unable to destroy mutex: ERR=%s\n"), strerror(stat));
-   }
-
-   free(dynlock);
-}
-
-/*
- * (Un)Lock a static OpenSSL mutex
- */
-static void openssl_update_static_mutex (int mode, int i, const char *file, int line)
-{
-   if (mode & CRYPTO_LOCK) {
-      P(mutexes[i]);
-   } else {
-      V(mutexes[i]);
-   }
-}
-
-/*
- * Initialize OpenSSL thread support
- *  Returns: 0 on success
- *           errno on failure
- */
-static int openssl_init_threads (void)
-{
-   int i, numlocks;
-   int stat;
-
-
-   /* Set thread ID callback */
-   CRYPTO_set_id_callback(get_openssl_thread_id);
-
-   /* Initialize static locking */
-   numlocks = CRYPTO_num_locks();
-   mutexes = (pthread_mutex_t *) malloc(numlocks * sizeof(pthread_mutex_t));
-   for (i = 0; i < numlocks; i++) {
-      if ((stat = pthread_mutex_init(&mutexes[i], NULL)) != 0) {
-         Emsg1(M_ERROR, 0, _("Unable to init mutex: ERR=%s\n"), strerror(stat));
-         return stat;
-      }
-   }
-
-   /* Set static locking callback */
-   CRYPTO_set_locking_callback(openssl_update_static_mutex);
-
-   /* Initialize dyanmic locking */
-   CRYPTO_set_dynlock_create_callback(openssl_create_dynamic_mutex);
-   CRYPTO_set_dynlock_lock_callback(openssl_update_dynamic_mutex);
-   CRYPTO_set_dynlock_destroy_callback(openssl_destroy_dynamic_mutex);
-
-   return 0;
-}
-
-/*
- * Clean up OpenSSL threading support
- */
-static void openssl_cleanup_threads (void)
-{
-   int i, numlocks;
-   int stat;
-
-   /* Unset thread ID callback */
-   CRYPTO_set_id_callback(NULL);
-  
-   /* Deallocate static lock mutexes */
-   numlocks = CRYPTO_num_locks();
-   for (i = 0; i < numlocks; i++) {
-      if ((stat = pthread_mutex_destroy(&mutexes[i])) != 0) {
-         /* We don't halt execution, reporting the error should be sufficient */
-         Emsg1(M_ERROR, 0, _("Unable to destroy mutex: ERR=%s\n"), strerror(stat));
-      }
-   }
-
-   /* Unset static locking callback */
-   CRYPTO_set_locking_callback(NULL);
-
-   /* Free static lock array */
-   free(mutexes);
-
-   /* Unset dynamic locking callbacks */
-   CRYPTO_set_dynlock_create_callback(NULL);
-   CRYPTO_set_dynlock_lock_callback(NULL);
-   CRYPTO_set_dynlock_destroy_callback(NULL);
-}
-
-
-/*
- * Seed TLS PRNG
- *  Returns: 1 on success
- *           0 on failure
- */
-static int seed_tls_prng (void)
-{
-   const char *names[]  = { "/dev/urandom", "/dev/random", NULL };
-   int i;
-
-   // ***FIXME***
-   // Win32 Support
-   // Read saved entropy?
-
-   for (i = 0; names[i]; i++) {
-      if (RAND_load_file(names[i], 1024) != -1) {
-         /* Success */
-         return 1;
-      }
-   }
-
-   /* Fail */
-   return 0;
-}
-
-/*
- * Save TLS Entropy
- *  Returns: 1 on success
- *           0 on failure
- */
-static int save_tls_prng (void)
-{
-   // ***FIXME***
-   // Implement PRNG state save
-   return 1;
-}
-
-/*
- * Perform global initialization of TLS
- * This function is not thread safe.
- *  Returns: 0 on success
- *           errno on failure
- */
-int init_tls (void)
-{
-   int stat;
-
-   if ((stat = openssl_init_threads()) != 0) {
-      Emsg1(M_ABORT, 0, _("Unable to init OpenSSL threading: ERR=%s\n"), strerror(stat));
-   }
-
-   /* Load libssl and libcrypto human-readable error strings */
-   SSL_load_error_strings();
-
-   /* Register OpenSSL ciphers */
-   SSL_library_init();
-
-   if (!seed_tls_prng()) {
-      Emsg0(M_ERROR_TERM, 0, _("Failed to seed OpenSSL PRNG\n"));
-   }
-
-   tls_initialized = true;
-
-   return stat;
-}
-
-/*
- * Perform global cleanup of TLS
- * All TLS connections must be closed before calling this function.
- * This function is not thread safe.
- *  Returns: 0 on success
- *           errno on failure
- */
-int cleanup_tls (void)
-{
-   /*
-    * Ensure that we've actually been initialized; Doing this here decreases the
-    * complexity of client's termination/cleanup code.
-    */
-   if (!tls_initialized) {
-      return 0;
-   }
-
-   if (!save_tls_prng()) {
-      Emsg0(M_ERROR, 0, _("Failed to save OpenSSL PRNG\n"));
-   }
-
-   openssl_cleanup_threads();
-
-   /* Free libssl and libcrypto error strings */
-   ERR_free_strings();
-
-   /* Free memory used by PRNG */
-   RAND_cleanup();
-
-   tls_initialized = false;
-
-   return 0;
-}
-
 #else /* HAVE_OPENSSL */
 # error No TLS implementation available.
 #endif /* !HAVE_OPENSSL */
@@ -927,11 +665,9 @@ int cleanup_tls (void)
 #else
 
 /* Dummy routines */
-int init_tls(void) { return 0; }
-int cleanup_tls (void) { return 0; }
 TLS_CONTEXT *new_tls_context(const char *ca_certfile, const char *ca_certdir,
                              const char *certfile, const char *keyfile,
-                             TLS_PEM_PASSWD_CB *pem_callback,
+                             CRYPTO_PEM_PASSWD_CB *pem_callback,
                              const void *pem_userdata, const char *dhfile,
                              bool verify_peer)
 {
index 13595dd17faa99ad34c7410e28ad5e3e2e0076e2..28d6fd6111e8e73f545c5a6edbca7f7ab995dbc8 100644 (file)
@@ -50,7 +50,4 @@ typedef struct TLS_Context TLS_CONTEXT;
 /* Opaque TLS Connection Structure */
 typedef struct TLS_Connection TLS_CONNECTION;
 
-/* PEM Decryption Passphrase Callback */
-typedef int (TLS_PEM_PASSWD_CB) (char *buf, int size, const void *userdata);
-
 #endif /* __TLS_H_ */
index be4d23a0e69d5a8692713421e5a7418378d135b2..39ec6d3903659859db0bbb052d3d3b535ef4f3f2 100644 (file)
@@ -208,9 +208,9 @@ bool do_append_data(JCR *jcr)
             FI_to_ascii(buf1, rec.FileIndex), rec.VolSessionId,
             stream_to_ascii(buf2, rec.Stream, rec.FileIndex), rec.data_len);
 
-         /* Send attributes and MD5 to Director for Catalog */
-         if (stream == STREAM_UNIX_ATTRIBUTES    || stream == STREAM_MD5_SIGNATURE ||
-             stream == STREAM_UNIX_ATTRIBUTES_EX || stream == STREAM_SHA1_SIGNATURE) {
+         /* Send attributes and digest to Director for Catalog */
+         if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_UNIX_ATTRIBUTES_EX ||
+             crypto_digest_stream_type(stream) != CRYPTO_DIGEST_NONE) {
             if (!jcr->no_attributes) {
                if (are_attributes_spooled(jcr)) {
                   jcr->dir_bsock->spool = true;
index addb74bbdc3c7ed88f51b112ff53828defa602b4..c7717a4b6c8a60bd23e2bd78a1a7f8ccd67b4f00 100644 (file)
@@ -425,8 +425,14 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec)
 #endif
       break;
 
-   case STREAM_MD5_SIGNATURE:
-   case STREAM_SHA1_SIGNATURE:
+   case STREAM_MD5_DIGEST:
+   case STREAM_SHA1_DIGEST:
+   case STREAM_SHA256_DIGEST:
+   case STREAM_SHA512_DIGEST:
+      break;
+
+   case STREAM_SIGNED_DIGEST:
+      // TODO landonf: Investigate signed digest support in the storage daemon
       break;
 
    case STREAM_PROGRAM_NAMES:
index bd9b310e925deb1768660749715fc3ee45b7310d..de44728abcf80e117b1caa90c6e4b213a1581377 100644 (file)
@@ -48,7 +48,7 @@ static int  create_client_record(B_DB *db, CLIENT_DBR *cr);
 static int  create_fileset_record(B_DB *db, FILESET_DBR *fsr);
 static int  create_jobmedia_record(B_DB *db, JCR *jcr);
 static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId);
-static int update_SIG_record(B_DB *db, char *SIGbuf, DEV_RECORD *rec, int type);
+static int update_digest_record(B_DB *db, char *digest, DEV_RECORD *rec, int type);
 
 
 /* Global variables */
@@ -372,6 +372,7 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec)
    DEVICE *dev = dcr->dev;
    JCR *bjcr = dcr->jcr;
    DEV_BLOCK *block = dcr->block;
+   char digest[BASE64_SIZE(CRYPTO_DIGEST_MAX_SIZE)];
 
    if (rec->data_len > 0) {
       mr.VolBytes += rec->data_len + WRITE_RECHDR_LENGTH; /* Accumulate Volume bytes */
@@ -699,24 +700,44 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec)
       free_jcr(mjcr);                 /* done using JCR */
       break;
 
-   case STREAM_MD5_SIGNATURE:
-      char MD5buf[50];
-      bin_to_base64(MD5buf, (char *)rec->data, 16); /* encode 16 bytes */
+   case STREAM_MD5_DIGEST:
+      bin_to_base64(digest, (char *)rec->data, CRYPTO_DIGEST_MD5_SIZE);
       if (verbose > 1) {
-         Pmsg1(000, _("Got MD5 record: %s\n"), MD5buf);
+         Pmsg1(000, _("Got MD5 record: %s\n"), digest);
       }
-      update_SIG_record(db, MD5buf, rec, MD5_SIG);
+      update_digest_record(db, digest, rec, CRYPTO_DIGEST_MD5);
       break;
 
-   case STREAM_SHA1_SIGNATURE:
-      char SIGbuf[50];
-      bin_to_base64(SIGbuf, (char *)rec->data, 20); /* encode 20 bytes */
+   case STREAM_SHA1_DIGEST:
+      bin_to_base64(digest, (char *)rec->data, CRYPTO_DIGEST_SHA1_SIZE);
       if (verbose > 1) {
-         Pmsg1(000, _("Got SHA1 record: %s\n"), SIGbuf);
+         Pmsg1(000, _("Got SHA1 record: %s\n"), digest);
       }
-      update_SIG_record(db, SIGbuf, rec, SHA1_SIG);
+      update_digest_record(db, digest, rec, CRYPTO_DIGEST_SHA1);
       break;
 
+   case STREAM_SHA256_DIGEST:
+      bin_to_base64(digest, (char *)rec->data, CRYPTO_DIGEST_SHA256_SIZE);
+      if (verbose > 1) {
+         Pmsg1(000, _("Got SHA256 record: %s\n"), digest);
+      }
+      update_digest_record(db, digest, rec, CRYPTO_DIGEST_SHA256);
+      break;
+
+   case STREAM_SHA512_DIGEST:
+      bin_to_base64(digest, (char *)rec->data, CRYPTO_DIGEST_SHA512_SIZE);
+      if (verbose > 1) {
+         Pmsg1(000, _("Got SHA512 record: %s\n"), digest);
+      }
+      update_digest_record(db, digest, rec, CRYPTO_DIGEST_SHA512);
+      break;
+
+   case STREAM_SIGNED_DIGEST:
+      // TODO landonf: Investigate signed digest support in bscan
+      if (verbose > 1) {
+         Pmsg0(000, _("Got signed digest record\n"));
+      }
+      break;
 
    case STREAM_PROGRAM_NAMES:
       if (verbose) {
@@ -1148,7 +1169,7 @@ static int create_jobmedia_record(B_DB *db, JCR *mjcr)
 /*
  * Simulate the database call that updates the MD5/SHA1 record
  */
-static int update_SIG_record(B_DB *db, char *SIGbuf, DEV_RECORD *rec, int type)
+static int update_digest_record(B_DB *db, char *digest, DEV_RECORD *rec, int type)
 {
    JCR *mjcr;
 
@@ -1168,7 +1189,7 @@ static int update_SIG_record(B_DB *db, char *SIGbuf, DEV_RECORD *rec, int type)
       return 1;
    }
 
-   if (!db_add_SIG_to_file_record(bjcr, db, mjcr->FileId, SIGbuf, type)) {
+   if (!db_add_digest_to_file_record(bjcr, db, mjcr->FileId, digest, type)) {
       Pmsg1(0, _("Could not add MD5/SHA1 to File record. ERR=%s\n"), db_strerror(db));
       free_jcr(mjcr);
       return 0;
index c17be35dceb75bf4c49ace0ae4696b0ddd8a5fc1..3f8f9a386bccb1f20b146448ff76a3dcfe080a5e 100644 (file)
@@ -222,7 +222,7 @@ bool read_records(DCR *dcr,
             break;                    /* read second part of record */
          }
          ok = record_cb(dcr, rec);
-         if (rec->Stream == STREAM_MD5_SIGNATURE || rec->Stream == STREAM_SHA1_SIGNATURE) {
+         if (crypto_digest_stream_type(rec->Stream) != CRYPTO_DIGEST_NONE) {
             Dmsg3(300, "Done FI=%u before set_eof pos %u:%u\n", rec->FileIndex,
                   dev->file, dev->block_num);
             if (match_set_eof(jcr->bsr, rec) && try_repositioning(jcr, rec, dev)) {
index 3228fa7331ee93cf60e42f3f2223c57eea762902..522c50a49bb1da48c3fe543a7a747a09be1c3935 100644 (file)
@@ -89,9 +89,9 @@ const char *stream_to_ascii(char *buf, int stream, int fi)
        return "WIN32-DATA";
     case STREAM_WIN32_GZIP_DATA:
        return "WIN32-GZIP";
-    case STREAM_MD5_SIGNATURE:
+    case STREAM_MD5_DIGEST:
        return "MD5";
-    case STREAM_SHA1_SIGNATURE:
+    case STREAM_SHA1_DIGEST:
        return "SHA1";
     case STREAM_GZIP_DATA:
        return "GZIP";
@@ -109,6 +109,12 @@ const char *stream_to_ascii(char *buf, int stream, int fi)
        return "MACOS-RSRC";
     case STREAM_HFSPLUS_ATTRIBUTES:
        return "HFSPLUS-ATTR";
+    case STREAM_SHA256_DIGEST:
+       return "SHA256";
+    case STREAM_SHA512_DIGEST:
+       return "SHA512";
+    case STREAM_SIGNED_DIGEST:
+       return "SIGNED-DIGEST";
     case -STREAM_UNIX_ATTRIBUTES:
        return "contUATTR";
     case -STREAM_FILE_DATA:
@@ -117,9 +123,9 @@ const char *stream_to_ascii(char *buf, int stream, int fi)
        return "contWIN32-DATA";
     case -STREAM_WIN32_GZIP_DATA:
        return "contWIN32-GZIP";
-    case -STREAM_MD5_SIGNATURE:
+    case -STREAM_MD5_DIGEST:
        return "contMD5";
-    case -STREAM_SHA1_SIGNATURE:
+    case -STREAM_SHA1_DIGEST:
        return "contSHA1";
     case -STREAM_GZIP_DATA:
        return "contGZIP";
@@ -137,6 +143,12 @@ const char *stream_to_ascii(char *buf, int stream, int fi)
        return "contMACOS-RSRC";
     case -STREAM_HFSPLUS_ATTRIBUTES:
        return "contHFSPLUS-ATTR";
+    case -STREAM_SHA256_DIGEST:
+       return "contSHA256";
+    case -STREAM_SHA512_DIGEST:
+       return "contSHA512";
+    case -STREAM_SIGNED_DIGEST:
+       return "contSIGNED-DIGEST";
     default:
        sprintf(buf, "%d", stream);
        return buf;
index 9b0ab92f4f3e88682ff4e0e3587688dfd0741730..01561aa46c8f01ed6d276c422094e2125215d853 100644 (file)
@@ -185,8 +185,8 @@ int main (int argc, char *argv[])
 
    parse_config(configfile);
 
-   if (init_tls() != 0) {
-      Jmsg((JCR *)NULL, M_ERROR_TERM, 0, _("TLS library initialization failed.\n"));
+   if (init_crypto() != 0) {
+      Jmsg((JCR *)NULL, M_ERROR_TERM, 0, _("Cryptography library initialization failed.\n"));
    }
 
    if (!check_resources()) {
@@ -565,7 +565,7 @@ void terminate_stored(int sig)
    }
    term_msg();
    stop_watchdog();
-   cleanup_tls();
+   cleanup_crypto();
    free_volume_list();
    close_memory_pool();
 
index 3f2e908420fd886a4de7b726d2714ed6a4f1bf7a..0f98b5a01bf64dd06ee6f1c7570e093cc80bdd91 100644 (file)
@@ -223,8 +223,8 @@ wxString console_thread::LoadConfig(wxString configfile) {
       return errmsg;
    }
    
-   if (init_tls() != 0) {
-      Jmsg(NULL, M_ERROR_TERM, 0, wxString(_("TLS library initialization failed.\n")).mb_str(*wxConvCurrent));
+   if (init_crypto() != 0) {
+      Jmsg(NULL, M_ERROR_TERM, 0, wxString(_("Cryptographic library initialization failed.\n")).mb_str(*wxConvCurrent));
    }
 
    if (!check_resources()) {