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