]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/crypto.c
Backport from Bacula Enterprise
[bacula/bacula] / bacula / src / filed / crypto.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 Kern Sibbald
5    Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
6
7    The original author of Bacula is Kern Sibbald, with contributions
8    from many others, a complete list can be found in the file AUTHORS.
9
10    You may use this file and others of this release according to the
11    license defined in the LICENSE file, which includes the Affero General
12    Public License, v3.0 ("AGPLv3") and some additional permissions and
13    terms pursuant to its AGPLv3 Section 7.
14
15    This notice must be preserved when any source code is 
16    conveyed and/or propagated.
17
18    Bacula(R) is a registered trademark of Kern Sibbald.
19  */
20 /*
21  *  Crypto subroutines used in backup.c
22  *
23  * Split from backup.c August 2014
24  *
25  *    Kern Sibbald, August MMXIV
26  *
27  */
28
29 #include "bacula.h"
30 #include "filed.h"
31 #include "ch.h"
32 #include "backup.h"
33
34
35 bool crypto_allocate_ctx(bctx_t &bctx)
36 {
37    JCR *jcr = bctx.jcr;
38
39    if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
40       Jmsg0(jcr, M_FATAL, 0, _("Encrypting sparse or offset data not supported.\n"));
41       return false;
42    }
43    /** Allocate the cipher context */
44    if ((bctx.cipher_ctx = crypto_cipher_new(jcr->crypto.pki_session, true,
45         &bctx.cipher_block_size)) == NULL) {
46       /* Shouldn't happen! */
47       Jmsg0(jcr, M_FATAL, 0, _("Failed to initialize encryption context.\n"));
48       return false;
49    }
50
51    /**
52     * Grow the crypto buffer, if necessary.
53     * crypto_cipher_update() will buffer up to (cipher_block_size - 1).
54     * We grow crypto_buf to the maximum number of blocks that
55     * could be returned for the given read buffer size.
56     * (Using the larger of either rsize or max_compress_len)
57     */
58    jcr->crypto.crypto_buf = check_pool_memory_size(jcr->crypto.crypto_buf,
59         (MAX(bctx.rsize + (int)sizeof(uint32_t), (int32_t)bctx.max_compress_len) +
60          bctx.cipher_block_size - 1) / bctx.cipher_block_size * bctx.cipher_block_size);
61
62    bctx.wbuf = jcr->crypto.crypto_buf; /* Encrypted, possibly compressed output here. */
63    return true;
64 }
65
66
67 bool crypto_setup_digests(bctx_t &bctx)
68 {
69    JCR *jcr = bctx.jcr;
70    FF_PKT *ff_pkt = bctx.ff_pkt;
71
72    crypto_digest_t signing_algorithm = (crypto_digest_t)me->pki_digest;
73
74    /**
75     * Setup for digest handling. If this fails, the digest will be set to NULL
76     * and not used. Note, the digest (file hash) can be any one of the four
77     * algorithms below.
78     *
79     * The signing digest is a single algorithm depending on
80     * whether or not we have SHA2.
81     *   ****FIXME****  the signing algoritm should really be
82     *   determined a different way!!!!!!  What happens if
83     *   sha2 was available during backup but not restore?
84     */
85    if (ff_pkt->flags & FO_MD5) {
86       bctx.digest = crypto_digest_new(jcr, CRYPTO_DIGEST_MD5);
87       bctx.digest_stream = STREAM_MD5_DIGEST;
88
89    } else if (ff_pkt->flags & FO_SHA1) {
90       bctx.digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA1);
91       bctx.digest_stream = STREAM_SHA1_DIGEST;
92
93    } else if (ff_pkt->flags & FO_SHA256) {
94       bctx.digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA256);
95       bctx.digest_stream = STREAM_SHA256_DIGEST;
96
97    } else if (ff_pkt->flags & FO_SHA512) {
98       bctx.digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA512);
99       bctx.digest_stream = STREAM_SHA512_DIGEST;
100    }
101
102    /** Did digest initialization fail? */
103    if (bctx.digest_stream != STREAM_NONE && bctx.digest == NULL) {
104       Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"),
105          stream_to_ascii(bctx.digest_stream));
106    }
107
108    /**
109     * Set up signature digest handling. If this fails, the signature digest
110     * will be set to NULL and not used.
111     */
112    /* TODO landonf: We should really only calculate the digest once, for
113     * both verification and signing.
114     */
115    if (jcr->crypto.pki_sign) {
116       bctx.signing_digest = crypto_digest_new(jcr, signing_algorithm);
117
118       /** Full-stop if a failure occurred initializing the signature digest */
119       if (bctx.signing_digest == NULL) {
120          Jmsg(jcr, M_NOTSAVED, 0, _("%s signature digest initialization failed\n"),
121             stream_to_ascii(signing_algorithm));
122          jcr->JobErrors++;
123          return false;
124       }
125    }
126
127    /** Enable encryption */
128    if (jcr->crypto.pki_encrypt) {
129       ff_pkt->flags |= FO_ENCRYPT;
130    }
131    return true;
132 }
133
134
135 bool crypto_session_start(JCR *jcr)
136 {
137    crypto_cipher_t cipher = (crypto_cipher_t) me->pki_cipher;
138
139    /**
140     * Create encryption session data and a cached, DER-encoded session data
141     * structure. We use a single session key for each backup, so we'll encode
142     * the session data only once.
143     */
144    if (jcr->crypto.pki_encrypt) {
145       uint32_t size = 0;
146
147       /** Create per-job session encryption context */
148       jcr->crypto.pki_session = crypto_session_new(cipher, jcr->crypto.pki_recipients);
149       if (!jcr->crypto.pki_session) {
150          Jmsg(jcr, M_FATAL, 0, _("Unsupported cipher on this system.\n"));
151          return false;
152       }
153
154       /** Get the session data size */
155       if (!crypto_session_encode(jcr->crypto.pki_session, (uint8_t *)0, &size)) {
156          Jmsg(jcr, M_FATAL, 0, _("An error occurred while encrypting the stream.\n"));
157          return false;
158       }
159
160       /** Allocate buffer */
161       jcr->crypto.pki_session_encoded = get_memory(size);
162
163       /** Encode session data */
164       if (!crypto_session_encode(jcr->crypto.pki_session, (uint8_t *)jcr->crypto.pki_session_encoded, &size)) {
165          Jmsg(jcr, M_FATAL, 0, _("An error occurred while encrypting the stream.\n"));
166          return false;
167       }
168
169       /** ... and store the encoded size */
170       jcr->crypto.pki_session_encoded_size = size;
171
172       /** Allocate the encryption/decryption buffer */
173       jcr->crypto.crypto_buf = get_memory(CRYPTO_CIPHER_MAX_BLOCK_SIZE);
174    }
175    return true;
176 }
177
178 void crypto_session_end(JCR *jcr)
179 {
180    if (jcr->crypto.crypto_buf) {
181       free_pool_memory(jcr->crypto.crypto_buf);
182       jcr->crypto.crypto_buf = NULL;
183    }
184    if (jcr->crypto.pki_session) {
185       crypto_session_free(jcr->crypto.pki_session);
186    }
187    if (jcr->crypto.pki_session_encoded) {
188       free_pool_memory(jcr->crypto.pki_session_encoded);
189       jcr->crypto.pki_session_encoded = NULL;
190    }
191 }
192
193 bool crypto_session_send(JCR *jcr, BSOCK *sd)
194 {
195    POOLMEM *msgsave;
196
197    /** Send our header */
198    Dmsg2(100, "Send hdr fi=%ld stream=%d\n", jcr->JobFiles, STREAM_ENCRYPTED_SESSION_DATA);
199    sd->fsend("%ld %d %lld", jcr->JobFiles, STREAM_ENCRYPTED_SESSION_DATA,
200       (int64_t)jcr->ff->statp.st_size);
201    msgsave = sd->msg;
202    sd->msg = jcr->crypto.pki_session_encoded;
203    sd->msglen = jcr->crypto.pki_session_encoded_size;
204    jcr->JobBytes += sd->msglen;
205
206    Dmsg1(100, "Send data len=%d\n", sd->msglen);
207    sd->send();
208    sd->msg = msgsave;
209    sd->signal(BNET_EOD);
210    return true;
211 }
212
213 bool crypto_terminate_digests(bctx_t &bctx)
214 {
215    JCR *jcr;
216    BSOCK *sd;
217    FF_PKT *ff_pkt;
218
219    jcr = bctx.jcr;
220    sd = bctx.sd;
221    ff_pkt = bctx.ff_pkt;
222
223    /** Terminate the signing digest and send it to the Storage daemon */
224    if (bctx.signing_digest) {
225       uint32_t size = 0;
226
227       if ((bctx.sig = crypto_sign_new(jcr)) == NULL) {
228          Jmsg(jcr, M_FATAL, 0, _("Failed to allocate memory for crypto signature.\n"));
229          return false;
230       }
231
232       if (!crypto_sign_add_signer(bctx.sig, bctx.signing_digest, jcr->crypto.pki_keypair)) {
233          Jmsg(jcr, M_FATAL, 0, _("An error occurred while adding signer the stream.\n"));
234          return false;
235       }
236
237       /** Get signature size */
238       if (!crypto_sign_encode(bctx.sig, NULL, &size)) {
239          Jmsg(jcr, M_FATAL, 0, _("An error occurred while signing the stream.\n"));
240          return false;
241       }
242
243       /** Grow the bsock buffer to fit our message if necessary */
244       if (sizeof_pool_memory(sd->msg) < (int32_t)size) {
245          sd->msg = realloc_pool_memory(sd->msg, size);
246       }
247
248       /** Send our header */
249       sd->fsend("%ld %ld 0", jcr->JobFiles, STREAM_SIGNED_DIGEST);
250       Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
251
252       /** Encode signature data */
253       if (!crypto_sign_encode(bctx.sig, (uint8_t *)sd->msg, &size)) {
254          Jmsg(jcr, M_FATAL, 0, _("An error occurred while signing the stream.\n"));
255          return false;
256       }
257
258       sd->msglen = size;
259       sd->send();
260       sd->signal(BNET_EOD);              /* end of checksum */
261    }
262
263    /** Terminate any digest and send it to Storage daemon */
264    if (bctx.digest) {
265       uint32_t size;
266
267       sd->fsend("%ld %d 0", jcr->JobFiles, bctx.digest_stream);
268       Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
269
270       size = CRYPTO_DIGEST_MAX_SIZE;
271
272       /** Grow the bsock buffer to fit our message if necessary */
273       if (sizeof_pool_memory(sd->msg) < (int32_t)size) {
274          sd->msg = realloc_pool_memory(sd->msg, size);
275       }
276
277       if (!crypto_digest_finalize(bctx.digest, (uint8_t *)sd->msg, &size)) {
278          Jmsg(jcr, M_FATAL, 0, _("An error occurred finalizing signing the stream.\n"));
279          return false;
280       }
281
282       /* Keep the checksum if this file is a hardlink */
283       if (ff_pkt->linked) {
284          ff_pkt_set_link_digest(ff_pkt, bctx.digest_stream, sd->msg, size);
285       }
286
287       sd->msglen = size;
288       sd->send();
289       sd->signal(BNET_EOD);              /* end of checksum */
290    }
291
292    /* Check if original file has a digest, and send it */
293    if (ff_pkt->type == FT_LNKSAVED && ff_pkt->digest) {
294       Dmsg2(300, "Link %s digest %d\n", ff_pkt->fname, ff_pkt->digest_len);
295       sd->fsend("%ld %d 0", jcr->JobFiles, ff_pkt->digest_stream);
296
297       sd->msg = check_pool_memory_size(sd->msg, ff_pkt->digest_len);
298       memcpy(sd->msg, ff_pkt->digest, ff_pkt->digest_len);
299       sd->msglen = ff_pkt->digest_len;
300       sd->send();
301
302       sd->signal(BNET_EOD);              /* end of hardlink record */
303    }
304
305    return true;
306 }
307
308 void crypto_free(bctx_t &bctx)
309 {
310    if (bctx.digest) {
311       crypto_digest_free(bctx.digest);
312       bctx.digest = NULL;
313    }
314    if (bctx.signing_digest) {
315       crypto_digest_free(bctx.signing_digest);
316       bctx.signing_digest = NULL;
317    }
318    if (bctx.sig) {
319       crypto_sign_free(bctx.sig);
320       bctx.sig = NULL;
321    }
322 }