From cdfaee3ae4ac1997e5fcb4651a7a12533b8d3d5f Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Mon, 28 Jan 2008 11:46:46 +0000 Subject: [PATCH] A bit of crypto cleanup. More later. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@6332 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/filed/backup.c | 172 ++++++++++++++++++++--------------- bacula/src/filed/job.c | 12 +-- bacula/src/filed/restore.c | 46 +++++----- bacula/src/findlib/attribs.c | 2 +- bacula/src/jcr.h | 26 ++++-- bacula/src/version.h | 4 +- bacula/technotes-2.3 | 2 + 7 files changed, 149 insertions(+), 115 deletions(-) diff --git a/bacula/src/filed/backup.c b/bacula/src/filed/backup.c index 6009b1bce5..a42ad87049 100644 --- a/bacula/src/filed/backup.c +++ b/bacula/src/filed/backup.c @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2000-2007 Free Software Foundation Europe e.V. + Copyright (C) 2000-2008 Free Software Foundation Europe e.V. The main author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. @@ -45,6 +45,9 @@ static void unstrip_path(FF_PKT *ff_pkt); 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 bool crypto_session_start(JCR *jcr); +static void crypto_session_end(JCR *jcr); +static bool crypto_session_send(JCR *jcr, BSOCK *sd); /* * Find all the requested files and send them @@ -63,8 +66,6 @@ bool blast_data_to_storage_daemon(JCR *jcr, char *addr) BSOCK *sd; bool ok = true; // TODO landonf: Allow user to specify encryption algorithm - crypto_cipher_t cipher = CRYPTO_CIPHER_AES_128_CBC; - sd = jcr->store_bsock; @@ -108,42 +109,16 @@ bool blast_data_to_storage_daemon(JCR *jcr, char *addr) pZlibStream->opaque = Z_NULL; pZlibStream->state = Z_NULL; - if (deflateInit(pZlibStream, Z_DEFAULT_COMPRESSION) == Z_OK) + if (deflateInit(pZlibStream, Z_DEFAULT_COMPRESSION) == Z_OK) { jcr->pZLIB_compress_workset = pZlibStream; - else + } else { free (pZlibStream); + } } #endif - /* Create encryption session data and a cached, DER-encoded session data - * structure. We use a single session key for each backup, so we'll encode - * the session data only once. */ - if (jcr->pki_encrypt) { - uint32_t size = 0; - - /* Create per-job session encryption context */ - jcr->pki_session = crypto_session_new(cipher, jcr->pki_recipients); - - /* Get the session data size */ - if (crypto_session_encode(jcr->pki_session, (uint8_t *)0, &size) == false) { - Jmsg(jcr, M_FATAL, 0, _("An error occurred while encrypting the stream.\n")); - return 0; - } - - /* Allocate buffer */ - jcr->pki_session_encoded = (uint8_t *)malloc(size); - - /* Encode session data */ - if (crypto_session_encode(jcr->pki_session, jcr->pki_session_encoded, &size) == false) { - Jmsg(jcr, M_FATAL, 0, _("An error occurred while encrypting the stream.\n")); - return 0; - } - - /* ... and store the encoded size */ - jcr->pki_session_encoded_size = size; - - /* Allocate the encryption/decryption buffer */ - jcr->crypto_buf = get_memory(CRYPTO_CIPHER_MAX_BLOCK_SIZE); + if (!crypto_session_start(jcr)) { + return false; } Dmsg1(300, "set_find_options ff=%p\n", jcr->ff); @@ -182,20 +157,85 @@ bool blast_data_to_storage_daemon(JCR *jcr, char *addr) free (jcr->pZLIB_compress_workset); jcr->pZLIB_compress_workset = NULL; } - if (jcr->crypto_buf) { - free_pool_memory(jcr->crypto_buf); - jcr->crypto_buf = NULL; + crypto_session_end(jcr); + + + Dmsg1(100, "end blast_data ok=%d\n", ok); + return ok; +} + +static bool crypto_session_start(JCR *jcr) +{ + crypto_cipher_t cipher = CRYPTO_CIPHER_AES_128_CBC; + + /* + * Create encryption session data and a cached, DER-encoded session data + * structure. We use a single session key for each backup, so we'll encode + * the session data only once. + */ + if (jcr->crypto.pki_encrypt) { + uint32_t size = 0; + + /* Create per-job session encryption context */ + jcr->crypto.pki_session = crypto_session_new(cipher, jcr->crypto.pki_recipients); + + /* Get the session data size */ + if (!crypto_session_encode(jcr->crypto.pki_session, (uint8_t *)0, &size)) { + Jmsg(jcr, M_FATAL, 0, _("An error occurred while encrypting the stream.\n")); + return false; + } + + /* Allocate buffer */ + jcr->crypto.pki_session_encoded = get_memory(size); + + /* Encode session data */ + if (!crypto_session_encode(jcr->crypto.pki_session, (uint8_t *)jcr->crypto.pki_session_encoded, &size)) { + Jmsg(jcr, M_FATAL, 0, _("An error occurred while encrypting the stream.\n")); + return false; + } + + /* ... and store the encoded size */ + jcr->crypto.pki_session_encoded_size = size; + + /* Allocate the encryption/decryption buffer */ + jcr->crypto.crypto_buf = get_memory(CRYPTO_CIPHER_MAX_BLOCK_SIZE); } - if (jcr->pki_session) { - crypto_session_free(jcr->pki_session); + return true; +} + +static void crypto_session_end(JCR *jcr) +{ + if (jcr->crypto.crypto_buf) { + free_pool_memory(jcr->crypto.crypto_buf); + jcr->crypto.crypto_buf = NULL; } - if (jcr->pki_session_encoded) { - free(jcr->pki_session_encoded); - jcr->pki_session_encoded = NULL; + if (jcr->crypto.pki_session) { + crypto_session_free(jcr->crypto.pki_session); } + if (jcr->crypto.pki_session_encoded) { + free_pool_memory(jcr->crypto.pki_session_encoded); + jcr->crypto.pki_session_encoded = NULL; + } +} - Dmsg1(100, "end blast_data ok=%d\n", ok); - return ok; +static bool crypto_session_send(JCR *jcr, BSOCK *sd) +{ + POOLMEM *msgsave; + + /* Send our header */ + Dmsg2(100, "Send hdr fi=%ld stream=%d\n", jcr->JobFiles, STREAM_ENCRYPTED_SESSION_DATA); + sd->fsend("%ld %d 0", jcr->JobFiles, STREAM_ENCRYPTED_SESSION_DATA); + + msgsave = sd->msg; + sd->msg = jcr->crypto.pki_session_encoded; + sd->msglen = jcr->crypto.pki_session_encoded_size; + jcr->JobBytes += sd->msglen; + + Dmsg1(100, "Send data len=%d\n", sd->msglen); + sd->send(); + sd->msg = msgsave; + sd->signal(BNET_EOD); + return true; } /* @@ -376,7 +416,7 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level) * NULL and not used. */ // TODO landonf: We should really only calculate the digest once, for both verification and signing. - if (jcr->pki_sign) { + if (jcr->crypto.pki_sign) { signing_digest = crypto_digest_new(jcr, signing_algorithm); /* Full-stop if a failure occurred initializing the signature digest */ @@ -389,12 +429,12 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level) } /* Enable encryption */ - if (jcr->pki_encrypt) { + if (jcr->crypto.pki_encrypt) { ff_pkt->flags |= FO_ENCRYPT; } } - /* Initialise the file descriptor we use for data and other streams. */ + /* Initialize 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() */ @@ -413,24 +453,10 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level) } /* Set up the encryption context and send the session data to the SD */ - if (has_file_data && jcr->pki_encrypt) { - /* Send our header */ - Dmsg2(100, "Send hdr fi=%ld stream=%d\n", jcr->JobFiles, STREAM_ENCRYPTED_SESSION_DATA); - sd->fsend("%ld %d 0", jcr->JobFiles, STREAM_ENCRYPTED_SESSION_DATA); - - /* Grow the bsock buffer to fit our message if necessary */ - if (sizeof_pool_memory(sd->msg) < jcr->pki_session_encoded_size) { - sd->msg = realloc_pool_memory(sd->msg, jcr->pki_session_encoded_size); + if (has_file_data && jcr->crypto.pki_encrypt) { + if (!crypto_session_send(jcr, sd)) { + goto bail_out; } - - /* Copy our message over and send it */ - memcpy(sd->msg, jcr->pki_session_encoded, jcr->pki_session_encoded_size); - sd->msglen = jcr->pki_session_encoded_size; - jcr->JobBytes += sd->msglen; - - Dmsg1(100, "Send data len=%d\n", sd->msglen); - sd->send(); - sd->signal(BNET_EOD); } /* @@ -561,7 +587,7 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level) goto bail_out; } - if (!crypto_sign_add_signer(sig, signing_digest, jcr->pki_keypair)) { + if (!crypto_sign_add_signer(sig, signing_digest, jcr->crypto.pki_keypair)) { Jmsg(jcr, M_FATAL, 0, _("An error occurred while signing the stream.\n")); goto bail_out; } @@ -592,7 +618,7 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level) sd->signal(BNET_EOD); /* end of checksum */ } - /* Terminate any digest and send it to Storage daemon and the Director */ + /* Terminate any digest and send it to Storage daemon */ if (digest) { uint32_t size; @@ -710,7 +736,7 @@ int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, DIGEST *digest, goto err; } /* Allocate the cipher context */ - if ((cipher_ctx = crypto_cipher_new(jcr->pki_session, true, + if ((cipher_ctx = crypto_cipher_new(jcr->crypto.pki_session, true, &cipher_block_size)) == NULL) { /* Shouldn't happen! */ Jmsg0(jcr, M_FATAL, 0, _("Failed to initialize encryption context.\n")); @@ -724,11 +750,11 @@ int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, DIGEST *digest, * could be returned for the given read buffer size. * (Using the larger of either rsize or max_compress_len) */ - jcr->crypto_buf = check_pool_memory_size(jcr->crypto_buf, + jcr->crypto.crypto_buf = check_pool_memory_size(jcr->crypto.crypto_buf, (MAX(rsize + (int)sizeof(uint32_t), (int32_t)max_compress_len) + cipher_block_size - 1) / cipher_block_size * cipher_block_size); - wbuf = jcr->crypto_buf; /* Encrypted, possibly compressed output here. */ + wbuf = jcr->crypto.crypto_buf; /* Encrypted, possibly compressed output here. */ } /* @@ -863,7 +889,7 @@ int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, DIGEST *digest, Dmsg1(20, "Encrypt len=%d\n", cipher_input_len); if (!crypto_cipher_update(cipher_ctx, packet_len, sizeof(packet_len), - (u_int8_t *)jcr->crypto_buf, &initial_len)) { + (uint8_t *)jcr->crypto.crypto_buf, &initial_len)) { /* Encryption failed. Shouldn't happen. */ Jmsg(jcr, M_FATAL, 0, _("Encryption error\n")); goto err; @@ -871,7 +897,7 @@ int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, DIGEST *digest, /* Encrypt the input block */ if (crypto_cipher_update(cipher_ctx, cipher_input, cipher_input_len, - (u_int8_t *)&jcr->crypto_buf[initial_len], &encrypted_len)) { + (uint8_t *)&jcr->crypto.crypto_buf[initial_len], &encrypted_len)) { if ((initial_len + encrypted_len) == 0) { /* No full block of data available, read more data */ continue; @@ -915,7 +941,7 @@ int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, DIGEST *digest, * For encryption, we must call finalize to push out any * buffered data. */ - if (!crypto_cipher_finalize(cipher_ctx, (uint8_t *)jcr->crypto_buf, + if (!crypto_cipher_finalize(cipher_ctx, (uint8_t *)jcr->crypto.crypto_buf, &encrypted_len)) { /* Padding failed. Shouldn't happen. */ Jmsg(jcr, M_FATAL, 0, _("Encryption padding error\n")); @@ -925,7 +951,7 @@ int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, DIGEST *digest, /* Note, on SSL pre-0.9.7, there is always some output */ if (encrypted_len > 0) { sd->msglen = encrypted_len; /* set encrypted length */ - sd->msg = jcr->crypto_buf; /* set correct write buffer */ + sd->msg = jcr->crypto.crypto_buf; /* set correct write buffer */ if (!sd->send()) { Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror()); diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c index c6e1891801..ef74a313c5 100644 --- a/bacula/src/filed/job.c +++ b/bacula/src/filed/job.c @@ -214,11 +214,11 @@ void *handle_client_request(void *dirp) jcr->client_name = get_memory(strlen(my_name) + 1); new_plugins(jcr); /* instantiate plugins for this jcr */ 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; - jcr->pki_recipients = me->pki_recipients; + jcr->crypto.pki_sign = me->pki_sign; + jcr->crypto.pki_encrypt = me->pki_encrypt; + jcr->crypto.pki_keypair = me->pki_keypair; + jcr->crypto.pki_signers = me->pki_signers; + jcr->crypto.pki_recipients = me->pki_recipients; dir->set_jcr(jcr); enable_backup_privileges(NULL, 1 /* ignore_errors */); @@ -276,7 +276,7 @@ void *handle_client_request(void *dirp) bnet_fsend(dir, EndJob, jcr->JobStatus, jcr->JobFiles, edit_uint64(jcr->ReadBytes, ed1), edit_uint64(jcr->JobBytes, ed2), jcr->Errors, jcr->VSS, - jcr->pki_encrypt); + jcr->crypto.pki_encrypt); Dmsg1(110, "End FD msg: %s\n", dir->msg); } diff --git a/bacula/src/filed/restore.c b/bacula/src/filed/restore.c index 7c094462ef..30fb4dc4da 100644 --- a/bacula/src/filed/restore.c +++ b/bacula/src/filed/restore.c @@ -395,18 +395,18 @@ void do_restore(JCR *jcr) } /* Do we have any keys at all? */ - if (!jcr->pki_recipients) { + if (!jcr->crypto.pki_recipients) { Jmsg(jcr, M_ERROR, 0, _("No private decryption keys have been defined to decrypt encrypted backup data.\n")); extract = false; bclose(&rctx.bfd); break; } - if (jcr->digest) { - crypto_digest_free(jcr->digest); + if (jcr->crypto.digest) { + crypto_digest_free(jcr->crypto.digest); } - jcr->digest = crypto_digest_new(jcr, signing_algorithm); - if (!jcr->digest) { + jcr->crypto.digest = crypto_digest_new(jcr, signing_algorithm); + if (!jcr->crypto.digest) { Jmsg0(jcr, M_FATAL, 0, _("Could not create digest.\n")); extract = false; bclose(&rctx.bfd); @@ -415,7 +415,7 @@ void do_restore(JCR *jcr) /* Decode and save session keys. */ cryptoerr = crypto_session_decode((uint8_t *)sd->msg, (uint32_t)sd->msglen, - jcr->pki_recipients, &rctx.cs); + jcr->crypto.pki_recipients, &rctx.cs); switch(cryptoerr) { case CRYPTO_ERROR_NONE: /* Success */ @@ -692,9 +692,9 @@ ok_out: /* Free Signature & Crypto Data */ free_signature(rctx); free_session(rctx); - if (jcr->digest) { - crypto_digest_free(jcr->digest); - jcr->digest = NULL; + if (jcr->crypto.digest) { + crypto_digest_free(jcr->crypto.digest); + jcr->crypto.digest = NULL; } /* Free file cipher restore context */ @@ -779,7 +779,7 @@ static int do_file_digest(FF_PKT *ff_pkt, void *pkt, bool top_level) { JCR *jcr = (JCR *)pkt; Dmsg1(50, "do_file_digest jcr=%p\n", jcr); - return (digest_file(jcr, ff_pkt, jcr->digest)); + return (digest_file(jcr, ff_pkt, jcr->crypto.digest)); } /* @@ -801,7 +801,7 @@ static bool verify_signature(JCR *jcr, r_ctx &rctx) SIGNATURE *sig = rctx.sig; - if (!jcr->pki_sign) { + if (!jcr->crypto.pki_sign) { return true; /* no signature OK */ } if (!sig) { @@ -814,26 +814,26 @@ static bool verify_signature(JCR *jcr, r_ctx &rctx) } /* Iterate through the trusted signers */ - foreach_alist(keypair, jcr->pki_signers) { - err = crypto_sign_get_digest(sig, jcr->pki_keypair, algorithm, &digest); + foreach_alist(keypair, jcr->crypto.pki_signers) { + err = crypto_sign_get_digest(sig, jcr->crypto.pki_keypair, algorithm, &digest); switch (err) { case CRYPTO_ERROR_NONE: Dmsg0(50, "== Got digest\n"); /* - * We computed jcr->digest using signing_algorithm while writing + * We computed jcr->crypto.digest using signing_algorithm while writing * the file. If it is not the same as the algorithm used for * this file, punt by releasing the computed algorithm and * computing by re-reading the file. */ if (algorithm != signing_algorithm) { - if (jcr->digest) { - crypto_digest_free(jcr->digest); - jcr->digest = NULL; + if (jcr->crypto.digest) { + crypto_digest_free(jcr->crypto.digest); + jcr->crypto.digest = NULL; } } - if (jcr->digest) { + if (jcr->crypto.digest) { /* Use digest computed while writing the file to verify the signature */ - if ((err = crypto_sign_verify(sig, keypair, jcr->digest)) != CRYPTO_ERROR_NONE) { + if ((err = crypto_sign_verify(sig, keypair, jcr->crypto.digest)) != CRYPTO_ERROR_NONE) { Dmsg1(50, "Bad signature on %s\n", jcr->last_fname); Jmsg2(jcr, M_ERROR, 0, _("Signature validation failed for file %s: ERR=%s\n"), jcr->last_fname, crypto_strerror(err)); @@ -843,7 +843,7 @@ static bool verify_signature(JCR *jcr, r_ctx &rctx) /* Signature found, digest allocated. Old method, * re-read the file and compute the digest */ - jcr->digest = digest; + jcr->crypto.digest = digest; /* Checksum the entire file */ /* Make sure we don't modify JobBytes by saving and restoring it */ @@ -863,7 +863,7 @@ static bool verify_signature(JCR *jcr, r_ctx &rctx) jcr->last_fname, crypto_strerror(err)); goto bail_out; } - jcr->digest = NULL; + jcr->crypto.digest = NULL; } /* Valid signature */ @@ -959,8 +959,8 @@ static void unser_crypto_packet_len(RESTORE_CIPHER_CTX *ctx) bool store_data(JCR *jcr, BFILE *bfd, char *data, const int32_t length, bool win32_decomp) { - if (jcr->digest) { - crypto_digest_update(jcr->digest, (uint8_t *)data, length); + if (jcr->crypto.digest) { + crypto_digest_update(jcr->crypto.digest, (uint8_t *)data, length); } if (win32_decomp) { if (!processWin32BackupAPIBlock(bfd, data, length)) { diff --git a/bacula/src/findlib/attribs.c b/bacula/src/findlib/attribs.c index 3d1978ad0e..275d196393 100644 --- a/bacula/src/findlib/attribs.c +++ b/bacula/src/findlib/attribs.c @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2002-2007 Free Software Foundation Europe e.V. + Copyright (C) 2002-2008 Free Software Foundation Europe e.V. The main author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index 017acdb5eb..3a0c959d56 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -123,6 +123,21 @@ struct FF_PKT; struct B_DB; struct ATTR_DBR; +#ifdef FILE_DAEMON +struct CRYPTO_CTX { + 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 */ + alist *pki_recipients; /* Trusted Recipients */ + CRYPTO_SESSION *pki_session; /* PKE Public Keys + Symmetric Session Keys */ + POOLMEM *pki_session_encoded; /* Cached DER-encoded copy of pki_session */ + int32_t pki_session_encoded_size; /* Size of DER-encoded pki_session */ + POOLMEM *crypto_buf; /* Encryption/Decryption buffer */ +}; +#endif + typedef void (JCR_free_HANDLER)(JCR *jcr); /* Job Control Record (JCR) */ @@ -294,16 +309,7 @@ public: BSOCK *hb_bsock; /* duped SD socket */ BSOCK *hb_dir_bsock; /* duped DIR socket */ alist *RunScripts; /* Commands to run before and 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 */ - alist *pki_recipients; /* Trusted Recipients */ - CRYPTO_SESSION *pki_session; /* PKE Public Keys + Symmetric Session Keys */ - uint8_t *pki_session_encoded; /* Cached DER-encoded copy of pki_session */ - int32_t pki_session_encoded_size; /* Size of DER-encoded pki_session */ - POOLMEM *crypto_buf; /* Encryption/Decryption buffer */ + CRYPTO_CTX crypto; /* Crypto ctx */ DIRRES* director; /* Director resource */ bool VSS; /* VSS used by FD */ #endif /* FILE_DAEMON */ diff --git a/bacula/src/version.h b/bacula/src/version.h index 9883f98195..4227ca72d2 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -4,8 +4,8 @@ #undef VERSION #define VERSION "2.3.8" -#define BDATE "25 January 2008" -#define LSMDATE "25Jan08" +#define BDATE "28 January 2008" +#define LSMDATE "28Jan08" #define PROG_COPYRIGHT "Copyright (C) %d-2008 Free Software Foundation Europe e.V.\n" #define BYEAR "2008" /* year for copyright messages in progs */ diff --git a/bacula/technotes-2.3 b/bacula/technotes-2.3 index 76b8887de4..158057f5a5 100644 --- a/bacula/technotes-2.3 +++ b/bacula/technotes-2.3 @@ -1,6 +1,8 @@ Technical notes on version 2.3 General: +28Jan08 +kes A bit of crypto cleanup. More later. 25Jan08 kes Apply patch from Martin to correct bug #1040, bscan sets existing ClientId to zero. -- 2.39.5