/* 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
support_gnome=no
support_wx_console=no
support_tls=no
+support_crypto=no
gnome_version=
wx_version=
support_static_tools=no
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
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}
support_gnome=no
support_wx_console=no
support_tls=no
+support_crypto=no
gnome_version=
wx_version=
support_static_tools=no
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
#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
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}
*
* 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
*/
#include <openssl/x509v3.h>
#include <openssl/rand.h>
#include <openssl/err.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
#undef STORE
#endif
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;
}
DBId_t PathId;
DBId_t FilenameId;
FileId_t FileId;
- char *Sig;
- int SigType;
+ char *Digest;
+ int DigestType;
};
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 */
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);
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 */
"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"),
} 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 {
*
* -----------------------------------------------------------------------
*/
-/* 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);
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()) {
exit(1);
}
already_here = true;
- cleanup_tls();
+ cleanup_crypto();
free_pool_memory(args);
con_term();
(void)WSACleanup(); /* Cleanup Windows sockets */
#include "bacula.h"
#include "dird.h"
+#include "findlib/find.h"
/*
* Handle catalog request
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);
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));
}
}
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()) {
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);
#include "bacula.h"
#include "dird.h"
+#include "findlib/find.h"
/* Commands sent to File daemon */
static char filesetcmd[] = "fileset%s\n"; /* set full fileset */
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
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);
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);
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);
}
enum {
INC_KW_NONE,
INC_KW_COMPRESSION,
- INC_KW_SIGNATURE,
+ INC_KW_DIGEST,
INC_KW_ENCRYPTION,
INC_KW_VERIFY,
INC_KW_ONEFS,
*/
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},
* 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"},
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)) {
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));
* We expect:
* FileIndex
* Stream
- * Options or SIG (MD5/SHA1)
+ * Options or Digest (MD5/SHA1)
* Filename
* Attributes
* Link name ???
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"
* 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) {
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 */
}
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 */
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':
}
}
/*
- * 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) {
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;
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
/* 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);
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;
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() */
}
}
- 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.
*
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;
}
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) {
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);
}
}
}
- /* 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;
* 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 */
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 */
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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
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);
}
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);
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;
+ }
+ }
+ }
+ }
}
#define FILE_DAEMON 1
#include "filed_conf.h"
-#include "chksum.h"
#include "findlib/find.h"
#include "jcr.h"
#include "acl.h"
{"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}
};
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);
}
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:
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 */
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 */
};
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 */);
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;
*/
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);
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);
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;
* 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:
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)) {
}
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"));
#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:
}
#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.
#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
{
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;
* 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;
}
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;
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);
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:
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;
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;
}
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:
#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;
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()) {
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);
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 */
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 \
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 \
--- /dev/null
+/*
+ * 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)
--- /dev/null
+/*
+ * 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";
+ }
+}
--- /dev/null
+/*
+ * 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_ */
#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(
#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"
#ifndef __BMD5_H
#define __BMD5_H
+#define MD5HashSize 16
+
struct MD5Context {
uint32_t buf[4];
uint32_t bits[2];
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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_ */
{
unsigned int i, j;
struct MD5Context md5c;
- unsigned char signature[16];
+ unsigned char digest[CRYPTO_DIGEST_MD5_SIZE];
char sig[100];
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);
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 ();
/* 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);
*/
+
#include "bacula.h"
#include <assert.h>
/* 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;
};
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.
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));
*/
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)
{
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);
/*
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;
}
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 */
#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)
{
/* 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_ */
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;
#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:
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 */
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 */
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) {
/*
* 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;
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;
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)) {
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";
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:
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";
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;
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()) {
}
term_msg();
stop_watchdog();
- cleanup_tls();
+ cleanup_crypto();
free_volume_list();
close_memory_pool();
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()) {