/*
- Bacula® - The Network Backup Solution
-
- Copyright (C) 2005-2007 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.
- This program is Free Software; you can redistribute it and/or
- modify it under the terms of version two of the GNU General Public
- License as published by the Free Software Foundation and included
- in the file LICENSE.
-
- 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., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
- Bacula® is a registered trademark of Kern Sibbald.
- The licensor of Bacula is the Free Software Foundation Europe
- (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
- Switzerland, email:ftf@fsfeurope.org.
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2016 Kern Sibbald
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
*/
/*
* crypto.c Encryption support functions
*
* Author: Landon Fuller <landonf@opendarwin.org>
*
- * Version $Id$
- *
* This file was contributed to the Bacula project by Landon Fuller.
*
* Landon Fuller has been granted a perpetual, worldwide, non-exclusive,
#include "jcr.h"
#include <assert.h>
+/**
+ * For OpenSSL version 1.x, EVP_PKEY_encrypt no longer
+ * exists. It was not an official API.
+ */
+#ifdef HAVE_OPENSSLv1
+#define EVP_PKEY_encrypt EVP_PKEY_encrypt_old
+#define EVP_PKEY_decrypt EVP_PKEY_decrypt_old
+#endif
+
/*
* Bacula ASN.1 Syntax
*
#ifdef HAVE_CRYPTO /* Is encryption enabled? */
#ifdef HAVE_OPENSSL /* How about OpenSSL? */
-/* Are we initialized? */
-static int crypto_initialized = false;
+#include "openssl-compat.h"
/* ASN.1 Declarations */
#define BACULA_ASN1_VERSION 0
#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))
+ 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) \
#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))
+ 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) \
*/
static ASN1_OCTET_STRING *openssl_cert_keyid(X509 *cert) {
X509_EXTENSION *ext;
- X509V3_EXT_METHOD *method;
+ const 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);
ext_value_data = ext->value->data;
-#if (OPENSSL_VERSION_NUMBER > 0x00907000L)
if (method->it) {
/* New style ASN1 */
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;
}
* Returns: A pointer to a X509 KEYPAIR object on success.
* NULL on failure.
*/
-X509_KEYPAIR *crypto_keypair_new(void)
+X509_KEYPAIR *crypto_keypair_new(void)
{
X509_KEYPAIR *keypair;
/* Validate the public key type (only RSA is supported) */
if (EVP_PKEY_type(keypair->pubkey->type) != EVP_PKEY_RSA) {
- Jmsg1(NULL, M_ERROR, 0,
+ Jmsg1(NULL, M_ERROR, 0,
_("Unsupported key type provided: %d\n"), EVP_PKEY_type(keypair->pubkey->type));
goto err;
}
digest = (DIGEST *)malloc(sizeof(DIGEST));
digest->type = type;
digest->jcr = jcr;
- Dmsg1(50, "crypto_digest_new jcr=%p\n", jcr);
+ Dmsg1(150, "crypto_digest_new jcr=%p\n", jcr);
/* Initialize the OpenSSL message digest context */
EVP_MD_CTX_init(&digest->ctx);
err:
/* This should not happen, but never say never ... */
- Dmsg0(50, "Digest init failed.\n");
+ Dmsg0(150, "Digest init failed.\n");
openssl_post_errors(jcr, M_ERROR, _("OpenSSL digest initialization failed"));
crypto_digest_free(digest);
return NULL;
bool crypto_digest_update(DIGEST *digest, const uint8_t *data, uint32_t length)
{
if (EVP_DigestUpdate(&digest->ctx, data, length) == 0) {
- Dmsg0(50, "digest update failed\n");
+ Dmsg0(150, "digest update failed\n");
openssl_post_errors(digest->jcr, M_ERROR, _("OpenSSL digest update failed"));
return false;
- } else {
+ } else {
return true;
}
}
bool crypto_digest_finalize(DIGEST *digest, uint8_t *dest, uint32_t *length)
{
if (!EVP_DigestFinal(&digest->ctx, dest, (unsigned int *)length)) {
- Dmsg0(50, "digest finalize failed\n");
+ Dmsg0(150, "digest finalize failed\n");
openssl_post_errors(digest->jcr, M_ERROR, _("OpenSSL digest finalize failed"));
return false;
} else {
sig->sigData = SignatureData_new();
sig->jcr = jcr;
- Dmsg1(50, "crypto_sign_new jcr=%p\n", jcr);
+ Dmsg1(150, "crypto_sign_new jcr=%p\n", jcr);
if (!sig->sigData) {
/* Allocation failed in OpenSSL */
* 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,
+crypto_error_t crypto_sign_get_digest(SIGNATURE *sig, X509_KEYPAIR *keypair,
crypto_digest_t &type, DIGEST **digest)
{
STACK_OF(SignerInfo) *signers;
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 */
- Dmsg1(50, "crypto_sign_get_digest jcr=%p\n", sig->jcr);
+ Dmsg1(150, "crypto_sign_get_digest jcr=%p\n", sig->jcr);
switch (OBJ_obj2nid(si->digestAlgorithm)) {
case NID_md5:
Dmsg0(100, "sign digest algorithm is MD5\n");
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;
SIGNATURE *crypto_sign_decode(JCR *jcr, const uint8_t *sigData, uint32_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) {
X509_KEYPAIR *keypair;
STACK_OF(RecipientInfo) *recipients;
crypto_error_t retval = CRYPTO_ERROR_NONE;
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800FL)
const unsigned char *p = (const unsigned char *)data;
-#else
- unsigned char *p = (unsigned char *)data;
-#endif
/* bacula-fd.conf doesn't contains any key */
if (!keypairs) {
/* Match against the subjectKeyIdentifier */
if (M_ASN1_OCTET_STRING_cmp(keypair->keyid, ri->subjectKeyIdentifier) == 0) {
/* Match found, extract symmetric encryption session data */
-
+
/* RSA is required. */
assert(EVP_PKEY_type(keypair->privkey->type) == EVP_PKEY_RSA);
* Acquire a cipher instance for the given ASN.1 cipher NID
*/
if ((ec = EVP_get_cipherbyobj(cs->cryptoData->contentEncryptionAlgorithm)) == NULL) {
- Jmsg1(NULL, M_ERROR, 0,
+ Jmsg1(NULL, M_ERROR, 0,
_("Unsupported contentEncryptionAlgorithm: %d\n"), OBJ_obj2nid(cs->cryptoData->contentEncryptionAlgorithm));
free(cipher_ctx);
return NULL;
openssl_post_errors(M_ERROR, _("Encryption session provided an invalid IV"));
goto err;
}
-
+
/* Add the key and IV to the cipher context */
if (!EVP_CipherInit_ex(&cipher_ctx->ctx, NULL, NULL, cs->session_key, M_ASN1_STRING_data(cs->cryptoData->iv), -1)) {
openssl_post_errors(M_ERROR, _("OpenSSL cipher context key/IV initialization failed"));
}
-/*
- * 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) {
- berrno be;
- Jmsg1(NULL, M_ABORT, 0,
- _("Unable to init OpenSSL threading: ERR=%s\n"), be.bstrerror(stat));
- }
-
- /* Load libssl and libcrypto human-readable error strings */
- SSL_load_error_strings();
-
- /* Initialize OpenSSL SSL library */
- SSL_library_init();
-
- /* Register OpenSSL ciphers and digests */
- OpenSSL_add_all_algorithms();
-
- if (!openssl_seed_prng()) {
- Jmsg0(NULL, 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()) {
- Jmsg0(NULL, M_ERROR, 0, _("Failed to save OpenSSL PRNG\n"));
- }
-
- openssl_cleanup_threads();
-
- /* Free libssl and libcrypto error strings */
- ERR_free_strings();
-
- /* Free all ciphers and digests */
- EVP_cleanup();
-
- /* Free memory used by PRNG */
- RAND_cleanup();
-
- crypto_initialized = false;
-
- return 0;
-}
-
#else /* HAVE_OPENSSL */
# error No encryption library available
}
}
-bool crypto_digest_finalize(DIGEST *digest, uint8_t *dest, uint32_t *length)
+bool crypto_digest_finalize(DIGEST *digest, uint8_t *dest, uint32_t *length)
{
switch (digest->type) {
case CRYPTO_DIGEST_MD5:
free(digest);
}
-/* Dummy routines */
-int init_crypto (void) { return 0; }
-int cleanup_crypto (void) { return 0; }
-
SIGNATURE *crypto_sign_new(JCR *jcr) { return NULL; }
-crypto_error_t crypto_sign_get_digest (SIGNATURE *sig, X509_KEYPAIR *keypair,
- crypto_digest_t &type, DIGEST **digest)
+crypto_error_t crypto_sign_get_digest (SIGNATURE *sig, X509_KEYPAIR *keypair,
+ crypto_digest_t &type, DIGEST **digest)
{ return CRYPTO_ERROR_INTERNAL; }
crypto_error_t crypto_sign_verify (SIGNATURE *sig, X509_KEYPAIR *keypair, DIGEST *digest) { return CRYPTO_ERROR_INTERNAL; }
* Returns the ASCII name of the digest type.
* Returns: ASCII name of digest type.
*/
-const char *crypto_digest_name(DIGEST *digest)
+const char *crypto_digest_name(DIGEST *digest)
{
switch (digest->type) {
case CRYPTO_DIGEST_MD5: