]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/lib/crypto.c
crypto: Add a tiny OpenSSL compat level
[bacula/bacula] / bacula / src / lib / crypto.c
index 7cc359c2a375f1591d355b443978a6a205c41c76..c172efb2b5d9a4e8b671a597835ffb665505d329 100644 (file)
@@ -1,12 +1,26 @@
+/*
+   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$
- *
- * 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,
  * 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 "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
@@ -213,7 +222,7 @@ IMPLEMENT_STACK_OF(RecipientInfo)
 #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) \
@@ -243,7 +252,7 @@ IMPLEMENT_STACK_OF(RecipientInfo)
 #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) \
@@ -262,12 +271,14 @@ struct X509_Keypair {
 /* Message Digest Structure */
 struct Digest {
    crypto_digest_t type;
+   JCR *jcr;
    EVP_MD_CTX ctx;
 };
 
 /* Message Signature Structure */
 struct Signature {
    SignatureData *sigData;
+   JCR *jcr;
 };
 
 /* Encryption Session Data */
@@ -293,17 +304,12 @@ typedef struct PEM_CB_Context {
  * 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){
+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);
@@ -322,7 +328,6 @@ static ASN1_OCTET_STRING *openssl_cert_keyid(X509 *cert){
 
    ext_value_data = ext->value->data;
 
-#if (OPENSSL_VERSION_NUMBER > 0x00907000L)
    if (method->it) {
       /* New style ASN1 */
 
@@ -336,10 +341,6 @@ static ASN1_OCTET_STRING *openssl_cert_keyid(X509 *cert){
       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;
 }
 
@@ -348,14 +349,12 @@ static ASN1_OCTET_STRING *openssl_cert_keyid(X509 *cert){
  *  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;
 
    /* Allocate our keypair structure */
-   keypair = (X509_KEYPAIR *) malloc(sizeof(X509_KEYPAIR));
-   if (!keypair) {
-      return NULL;
-   }
+   keypair = (X509_KEYPAIR *)malloc(sizeof(X509_KEYPAIR));
 
    /* Initialize our keypair structure */
    keypair->keyid = NULL;
@@ -371,7 +370,7 @@ X509_KEYPAIR *crypto_keypair_new (void) {
  * API is available. Instead, the reference count is
  * incremented.
  */
-X509_KEYPAIR *crypto_keypair_dup (X509_KEYPAIR *keypair)
+X509_KEYPAIR *crypto_keypair_dup(X509_KEYPAIR *keypair)
 {
    X509_KEYPAIR *newpair;
 
@@ -413,7 +412,7 @@ X509_KEYPAIR *crypto_keypair_dup (X509_KEYPAIR *keypair)
  *  Returns: true on success
  *           false on failure
  */
-int crypto_keypair_load_cert (X509_KEYPAIR *keypair, const char *file)
+int crypto_keypair_load_cert(X509_KEYPAIR *keypair, const char *file)
 {
    BIO *bio;
    X509 *cert;
@@ -439,13 +438,15 @@ int crypto_keypair_load_cert (X509_KEYPAIR *keypair, const char *file)
 
    /* 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."));
+      Jmsg0(NULL, 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));
+       Jmsg1(NULL, M_ERROR, 0,
+             _("Unsupported key type provided: %d\n"), EVP_PKEY_type(keypair->pubkey->type));
        goto err;
    }
 
@@ -473,7 +474,7 @@ static int crypto_pem_callback_dispatch (char *buf, int size, int rwflag, void *
  * Returns: true if a private key is found
  *          false otherwise
  */
-bool crypto_keypair_has_key (const char *file) {
+bool crypto_keypair_has_key(const char *file) {
    BIO *bio;
    char *name = NULL;
    char *header = NULL;
@@ -521,7 +522,7 @@ bool crypto_keypair_has_key (const char *file) {
  *  Returns: true on success
  *           false on failure
  */
-int crypto_keypair_load_key (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)
 {
@@ -556,7 +557,7 @@ int crypto_keypair_load_key (X509_KEYPAIR *keypair, const char *file,
 /*
  * Free memory associated with a keypair object.
  */
-void crypto_keypair_free (X509_KEYPAIR *keypair)
+void crypto_keypair_free(X509_KEYPAIR *keypair)
 {
    if (keypair->pubkey) {
       EVP_PKEY_free(keypair->pubkey);
@@ -575,13 +576,15 @@ void crypto_keypair_free (X509_KEYPAIR *keypair)
  *  Returns: A pointer to a DIGEST object on success.
  *           NULL on failure.
  */
-DIGEST *crypto_digest_new (crypto_digest_t type)
+DIGEST *crypto_digest_new(JCR *jcr, crypto_digest_t type)
 {
    DIGEST *digest;
    const EVP_MD *md = NULL; /* Quell invalid uninitialized warnings */
 
-   digest = (DIGEST *) malloc(sizeof(DIGEST));
+   digest = (DIGEST *)malloc(sizeof(DIGEST));
    digest->type = type;
+   digest->jcr = jcr;
+   Dmsg1(150, "crypto_digest_new jcr=%p\n", jcr);
 
    /* Initialize the OpenSSL message digest context */
    EVP_MD_CTX_init(&digest->ctx);
@@ -603,7 +606,7 @@ DIGEST *crypto_digest_new (crypto_digest_t type)
       break;
 #endif
    default:
-      Emsg1(M_ERROR, 0, _("Unsupported digest type: %d\n"), type);
+      Jmsg1(jcr, M_ERROR, 0, _("Unsupported digest type: %d\n"), type);
       goto err;
    }
 
@@ -616,7 +619,8 @@ DIGEST *crypto_digest_new (crypto_digest_t type)
 
 err:
    /* This should not happen, but never say never ... */
-   openssl_post_errors(M_ERROR, _("OpenSSL digest initialization failed"));
+   Dmsg0(150, "Digest init failed.\n");
+   openssl_post_errors(jcr, M_ERROR, _("OpenSSL digest initialization failed"));
    crypto_digest_free(digest);
    return NULL;
 }
@@ -626,11 +630,14 @@ err:
  * Returns: true on success
  *          false on failure
  */
-bool crypto_digest_update (DIGEST *digest, const void *data, size_t length) {
+bool crypto_digest_update(DIGEST *digest, const uint8_t *data, uint32_t length)
+{
    if (EVP_DigestUpdate(&digest->ctx, data, length) == 0) {
-      return true;
-   } else { 
+      Dmsg0(150, "digest update failed\n");
+      openssl_post_errors(digest->jcr, M_ERROR, _("OpenSSL digest update failed"));
       return false;
+   } else {
+      return true;
    }
 }
 
@@ -641,8 +648,11 @@ bool crypto_digest_update (DIGEST *digest, const void *data, size_t length) {
  * Returns: true on success
  *          false on failure
  */
-bool crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
-   if (!EVP_DigestFinal(&digest->ctx, (unsigned char *) dest, (unsigned int *) length)) {
+bool crypto_digest_finalize(DIGEST *digest, uint8_t *dest, uint32_t *length)
+{
+   if (!EVP_DigestFinal(&digest->ctx, dest, (unsigned int *)length)) {
+      Dmsg0(150, "digest finalize failed\n");
+      openssl_post_errors(digest->jcr, M_ERROR, _("OpenSSL digest finalize failed"));
       return false;
    } else {
       return true;
@@ -652,10 +662,10 @@ bool crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
 /*
  * Free memory associated with a digest object.
  */
-void crypto_digest_free (DIGEST *digest)
+void crypto_digest_free(DIGEST *digest)
 {
   EVP_MD_CTX_cleanup(&digest->ctx);
-  free (digest);
+  free(digest);
 }
 
 /*
@@ -663,16 +673,18 @@ void crypto_digest_free (DIGEST *digest)
  *  Returns: A pointer to a SIGNATURE object on success.
  *           NULL on failure.
  */
-SIGNATURE *crypto_sign_new (void)
+SIGNATURE *crypto_sign_new(JCR *jcr)
 {
    SIGNATURE *sig;
 
-   sig = (SIGNATURE *) malloc(sizeof(SIGNATURE));
+   sig = (SIGNATURE *)malloc(sizeof(SIGNATURE));
    if (!sig) {
       return NULL;
    }
 
    sig->sigData = SignatureData_new();
+   sig->jcr = jcr;
+   Dmsg1(150, "crypto_sign_new jcr=%p\n", jcr);
 
    if (!sig->sigData) {
       /* Allocation failed in OpenSSL */
@@ -688,11 +700,13 @@ SIGNATURE *crypto_sign_new (void)
 
 /*
  * For a given public key, find the associated SignatureInfo record
- * and create a digest context for signature validation
+ *   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)
+crypto_error_t crypto_sign_get_digest(SIGNATURE *sig, X509_KEYPAIR *keypair,
+                                      crypto_digest_t &type, DIGEST **digest)
 {
    STACK_OF(SignerInfo) *signers;
    SignerInfo *si;
@@ -704,33 +718,47 @@ crypto_error_t crypto_sign_get_digest(SIGNATURE *sig, X509_KEYPAIR *keypair, DIG
       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(150, "crypto_sign_get_digest jcr=%p\n", sig->jcr);
          switch (OBJ_obj2nid(si->digestAlgorithm)) {
          case NID_md5:
-            *digest = crypto_digest_new(CRYPTO_DIGEST_MD5);
+            Dmsg0(100, "sign digest algorithm is MD5\n");
+            type = CRYPTO_DIGEST_MD5;
+            *digest = crypto_digest_new(sig->jcr, CRYPTO_DIGEST_MD5);
             break;
          case NID_sha1:
-            *digest = crypto_digest_new(CRYPTO_DIGEST_SHA1);
+            Dmsg0(100, "sign digest algorithm is SHA1\n");
+            type = CRYPTO_DIGEST_SHA1;
+            *digest = crypto_digest_new(sig->jcr, CRYPTO_DIGEST_SHA1);
             break;
 #ifdef HAVE_SHA2
          case NID_sha256:
-            *digest = crypto_digest_new(CRYPTO_DIGEST_SHA256);
+            Dmsg0(100, "sign digest algorithm is SHA256\n");
+            type = CRYPTO_DIGEST_SHA256;
+            *digest = crypto_digest_new(sig->jcr, CRYPTO_DIGEST_SHA256);
             break;
          case NID_sha512:
-            *digest = crypto_digest_new(CRYPTO_DIGEST_SHA512);
+            Dmsg0(100, "sign digest algorithm is SHA512\n");
+            type = CRYPTO_DIGEST_SHA512;
+            *digest = crypto_digest_new(sig->jcr, CRYPTO_DIGEST_SHA512);
             break;
 #endif
          default:
+            type = CRYPTO_DIGEST_NONE;
             *digest = NULL;
             return CRYPTO_ERROR_INVALID_DIGEST;
          }
 
          /* Shouldn't happen */
          if (*digest == NULL) {
+            openssl_post_errors(sig->jcr, M_ERROR, _("OpenSSL digest_new failed"));
             return CRYPTO_ERROR_INVALID_DIGEST;
          } else {
             return CRYPTO_ERROR_NONE;
          }
+      } else {
+         openssl_post_errors(sig->jcr, M_ERROR, _("OpenSSL sign get digest failed"));
       }
+
    }
 
    return CRYPTO_ERROR_NOSIGNER;
@@ -747,11 +775,7 @@ crypto_error_t crypto_sign_verify(SIGNATURE *sig, X509_KEYPAIR *keypair, DIGEST
    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;
 
@@ -767,15 +791,16 @@ crypto_error_t crypto_sign_verify(SIGNATURE *sig, X509_KEYPAIR *keypair, DIGEST
          if (ok >= 1) {
             return CRYPTO_ERROR_NONE;
          } else if (ok == 0) {
+            openssl_post_errors(sig->jcr, M_ERROR, _("OpenSSL digest Verify final failed"));
             return CRYPTO_ERROR_BAD_SIGNATURE;
          } else if (ok < 0) {
             /* Shouldn't happen */
-            openssl_post_errors(M_ERROR, _("OpenSSL error occured"));
+            openssl_post_errors(sig->jcr, M_ERROR, _("OpenSSL digest Verify final failed"));
             return CRYPTO_ERROR_INTERNAL;
          }
       }
    }
-
+   Jmsg(sig->jcr, M_ERROR, 0, _("No signers found for crypto verify.\n"));
    /* Signer wasn't found. */
    return CRYPTO_ERROR_NOSIGNER;
 }
@@ -874,14 +899,14 @@ err:
  * 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)
+int crypto_sign_encode(SIGNATURE *sig, uint8_t *dest, uint32_t *length)
 {
    if (*length == 0) {
       *length = i2d_SignatureData(sig->sigData, NULL);
       return true;
    }
 
-   *length = i2d_SignatureData(sig->sigData, (unsigned char **) &dest);
+   *length = i2d_SignatureData(sig->sigData, (unsigned char **)&dest);
    return true;
 }
 
@@ -894,26 +919,23 @@ int crypto_sign_encode(SIGNATURE *sig, void *dest, size_t *length)
 
  */
 
-SIGNATURE *crypto_sign_decode(const void *sigData, size_t length)
+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));
+   sig = (SIGNATURE *)malloc(sizeof(SIGNATURE));
    if (!sig) {
       return NULL;
    }
+   sig->jcr = jcr;
 
    /* 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"));
+      openssl_post_errors(jcr, M_ERROR, _("Signature decoding failed"));
       free(sig);
       return NULL;
    }
@@ -934,6 +956,8 @@ void crypto_sign_free(SIGNATURE *sig)
  * Create a new encryption session.
  *  Returns: A pointer to a CRYPTO_SESSION object on success.
  *           NULL on failure.
+ *
+ *  Note! Bacula malloc() fails if out of memory.
  */
 CRYPTO_SESSION *crypto_session_new (crypto_cipher_t cipher, alist *pubkeys)
 {
@@ -944,10 +968,7 @@ CRYPTO_SESSION *crypto_session_new (crypto_cipher_t cipher, alist *pubkeys)
    int iv_len;
 
    /* Allocate our session description structures */
-   cs = (CRYPTO_SESSION *) malloc(sizeof(CRYPTO_SESSION));
-   if (!cs) {
-      return NULL;
-   }
+   cs = (CRYPTO_SESSION *)malloc(sizeof(CRYPTO_SESSION));
 
    /* Initialize required fields */
    cs->session_key = NULL;
@@ -973,6 +994,7 @@ CRYPTO_SESSION *crypto_session_new (crypto_cipher_t cipher, alist *pubkeys)
       cs->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_aes_128_cbc);
       ec = EVP_aes_128_cbc();
       break;
+#ifndef HAVE_OPENSSL_EXPORT_LIBRARY
    case CRYPTO_CIPHER_AES_192_CBC:
       /* AES 192 bit CBC */
       cs->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_aes_192_cbc);
@@ -983,13 +1005,14 @@ CRYPTO_SESSION *crypto_session_new (crypto_cipher_t cipher, alist *pubkeys)
       cs->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_aes_256_cbc);
       ec = EVP_aes_256_cbc();
       break;
+#endif
    case CRYPTO_CIPHER_BLOWFISH_CBC:
       /* Blowfish CBC */
       cs->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_bf_cbc);
       ec = EVP_bf_cbc();
       break;
    default:
-      Emsg0(M_ERROR, 0, _("Unsupported cipher type specified\n"));
+      Jmsg0(NULL, M_ERROR, 0, _("Unsupported cipher type specified\n"));
       crypto_session_free(cs);
       return NULL;
    }
@@ -1005,12 +1028,7 @@ CRYPTO_SESSION *crypto_session_new (crypto_cipher_t cipher, alist *pubkeys)
 
    /* Generate an IV if possible */
    if ((iv_len = EVP_CIPHER_iv_length(ec))) {
-      iv = (unsigned char *) malloc(iv_len);
-      if (!iv) {
-         /* Malloc failure */
-         crypto_session_free(cs);
-         return NULL;
-      }
+      iv = (unsigned char *)malloc(iv_len);
 
       /* Generate random IV */
       if (RAND_bytes(iv, iv_len) <= 0) {
@@ -1058,12 +1076,7 @@ CRYPTO_SESSION *crypto_session_new (crypto_cipher_t cipher, alist *pubkeys)
       ri->keyEncryptionAlgorithm = OBJ_nid2obj(NID_rsaEncryption);
 
       /* Encrypt the session key */
-      ekey = (unsigned char *) malloc(EVP_PKEY_size(keypair->pubkey));
-      if (!ekey) {
-         RecipientInfo_free(ri);
-         crypto_session_free(cs);
-         return NULL;
-      }
+      ekey = (unsigned char *)malloc(EVP_PKEY_size(keypair->pubkey));
 
       if ((ekey_len = EVP_PKEY_encrypt(ekey, cs->session_key, cs->session_key_len, keypair->pubkey)) <= 0) {
          /* OpenSSL failure */
@@ -1101,14 +1114,14 @@ CRYPTO_SESSION *crypto_session_new (crypto_cipher_t cipher, alist *pubkeys)
  * Returns: true on success, stores the encoded data in dest, and the size in length.
  *          false on failure.
  */
-bool crypto_session_encode(CRYPTO_SESSION *cs, void *dest, size_t *length)
+bool crypto_session_encode(CRYPTO_SESSION *cs, uint8_t *dest, uint32_t *length)
 {
    if (*length == 0) {
       *length = i2d_CryptoData(cs->cryptoData, NULL);
       return true;
    }
 
-   *length = i2d_CryptoData(cs->cryptoData, (unsigned char **) &dest);
+   *length = i2d_CryptoData(cs->cryptoData, &dest);
    return true;
 }
 
@@ -1121,23 +1134,21 @@ bool crypto_session_encode(CRYPTO_SESSION *cs, void *dest, size_t *length)
  * Returns: CRYPTO_ERROR_NONE and a pointer to a newly allocated CRYPTO_SESSION structure in *session on success.
  *          A crypto_error_t value on failure.
  */
-crypto_error_t crypto_session_decode(const void *data, size_t length, alist *keypairs, CRYPTO_SESSION **session)
+crypto_error_t crypto_session_decode(const uint8_t *data, uint32_t length, alist *keypairs, CRYPTO_SESSION **session)
 {
    CRYPTO_SESSION *cs;
    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
+   const unsigned char *p = (const unsigned char *)data;
 
-   cs = (CRYPTO_SESSION *) malloc(sizeof(CRYPTO_SESSION));
-   if (!cs) {
-      return CRYPTO_ERROR_INTERNAL;
+   /* bacula-fd.conf doesn't contains any key */
+   if (!keypairs) {
+      return CRYPTO_ERROR_NORECIPIENT;
    }
 
+   cs = (CRYPTO_SESSION *)malloc(sizeof(CRYPTO_SESSION));
+
    /* Initialize required fields */
    cs->session_key = NULL;
 
@@ -1172,7 +1183,7 @@ crypto_error_t crypto_session_decode(const void *data, size_t length, alist *key
          /* 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);
 
@@ -1185,7 +1196,7 @@ crypto_error_t crypto_session_decode(const void *data, size_t length, alist *key
 
             /* Decrypt the session key */
             /* Allocate sufficient space for the largest possible decrypted data */
-            cs->session_key = (unsigned char *) malloc(EVP_PKEY_size(keypair->privkey));
+            cs->session_key = (unsigned char *)malloc(EVP_PKEY_size(keypair->privkey));
             cs->session_key_len = EVP_PKEY_decrypt(cs->session_key, M_ASN1_STRING_data(ri->encryptedKey),
                                   M_ASN1_STRING_length(ri->encryptedKey), keypair->privkey);
 
@@ -1213,7 +1224,7 @@ err:
 /*
  * Free memory associated with a crypto session object.
  */
-void crypto_session_free (CRYPTO_SESSION *cs)
+void crypto_session_free(CRYPTO_SESSION *cs)
 {
    if (cs->cryptoData) {
       CryptoData_free(cs->cryptoData);
@@ -1229,21 +1240,19 @@ void crypto_session_free (CRYPTO_SESSION *cs)
  *  Returns: A pointer to a CIPHER_CONTEXT object on success. The cipher block size is returned in blocksize.
  *           NULL on failure.
  */
-CIPHER_CONTEXT *crypto_cipher_new (CRYPTO_SESSION *cs, bool encrypt, size_t *blocksize)
+CIPHER_CONTEXT *crypto_cipher_new(CRYPTO_SESSION *cs, bool encrypt, uint32_t *blocksize)
 {
    CIPHER_CONTEXT *cipher_ctx;
    const EVP_CIPHER *ec;
 
-   cipher_ctx = (CIPHER_CONTEXT *) malloc(sizeof(CIPHER_CONTEXT));
-   if (!cipher_ctx) {
-      return NULL;
-   }
+   cipher_ctx = (CIPHER_CONTEXT *)malloc(sizeof(CIPHER_CONTEXT));
 
    /*
     * Acquire a cipher instance for the given ASN.1 cipher NID
     */
    if ((ec = EVP_get_cipherbyobj(cs->cryptoData->contentEncryptionAlgorithm)) == NULL) {
-      Emsg1(M_ERROR, 0, _("Unsupported contentEncryptionAlgorithm: %d\n"), OBJ_obj2nid(cs->cryptoData->contentEncryptionAlgorithm));
+      Jmsg1(NULL, M_ERROR, 0,
+         _("Unsupported contentEncryptionAlgorithm: %d\n"), OBJ_obj2nid(cs->cryptoData->contentEncryptionAlgorithm));
       free(cipher_ctx);
       return NULL;
    }
@@ -1275,7 +1284,7 @@ CIPHER_CONTEXT *crypto_cipher_new (CRYPTO_SESSION *cs, bool encrypt, size_t *blo
       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"));
@@ -1296,8 +1305,9 @@ err:
  * Returns: true on success, number of bytes output in written
  *          false on failure
  */
-bool crypto_cipher_update (CIPHER_CONTEXT *cipher_ctx, const void *data, size_t length, const void *dest, size_t *written) {
-   if (!EVP_CipherUpdate(&cipher_ctx->ctx, (unsigned char *) dest, (int *) written, (const unsigned char *) data, length)) {
+bool crypto_cipher_update(CIPHER_CONTEXT *cipher_ctx, const uint8_t *data, uint32_t length, const uint8_t *dest, uint32_t *written)
+{
+   if (!EVP_CipherUpdate(&cipher_ctx->ctx, (unsigned char *)dest, (int *)written, (const unsigned char *)data, length)) {
       /* This really shouldn't fail */
       return false;
    } else {
@@ -1313,8 +1323,9 @@ bool crypto_cipher_update (CIPHER_CONTEXT *cipher_ctx, const void *data, size_t
  * Returns: true on success
  *          false on failure
  */
-bool crypto_cipher_finalize (CIPHER_CONTEXT *cipher_ctx, void *dest, size_t *written) {
-   if (!EVP_CipherFinal_ex(&cipher_ctx->ctx, (unsigned char *) dest, (int *) written)) {
+bool crypto_cipher_finalize (CIPHER_CONTEXT *cipher_ctx, uint8_t *dest, uint32_t *written)
+{
+   if (!EVP_CipherFinal_ex(&cipher_ctx->ctx, (unsigned char *)dest, (int *) written)) {
       /* This really shouldn't fail */
       return false;
    } else {
@@ -1333,75 +1344,6 @@ void crypto_cipher_free (CIPHER_CONTEXT *cipher_ctx)
 }
 
 
-/*
- * 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();
-
-   /* Initialize OpenSSL SSL  library */
-   SSL_library_init();
-
-   /* Register OpenSSL ciphers and digests */
-   OpenSSL_add_all_algorithms();
-
-   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 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
@@ -1416,6 +1358,7 @@ int cleanup_crypto (void)
 /* Message Digest Structure */
 struct Digest {
    crypto_digest_t type;
+   JCR *jcr;
    union {
       SHA1Context sha1;
       MD5Context md5;
@@ -1424,14 +1367,16 @@ struct Digest {
 
 /* Dummy Signature Structure */
 struct Signature {
+   JCR *jcr;
 };
 
-DIGEST *crypto_digest_new (crypto_digest_t type)
+DIGEST *crypto_digest_new(JCR *jcr, crypto_digest_t type)
 {
    DIGEST *digest;
 
-   digest = (DIGEST *) malloc(sizeof(DIGEST));
+   digest = (DIGEST *)malloc(sizeof(DIGEST));
    digest->type = type;
+   digest->jcr = jcr;
 
    switch (type) {
    case CRYPTO_DIGEST_MD5:
@@ -1441,7 +1386,7 @@ DIGEST *crypto_digest_new (crypto_digest_t type)
       SHA1Init(&digest->sha1);
       break;
    default:
-      Emsg0(M_ERROR, 0, _("Unsupported digest type specified\n"));
+      Jmsg1(jcr, M_ERROR, 0, _("Unsupported digest type=%d specified\n"), type);
       free(digest);
       return NULL;
    }
@@ -1449,7 +1394,8 @@ DIGEST *crypto_digest_new (crypto_digest_t type)
    return (digest);
 }
 
-bool crypto_digest_update (DIGEST *digest, const void *data, size_t length) {
+bool crypto_digest_update(DIGEST *digest, const uint8_t *data, uint32_t length)
+{
    switch (digest->type) {
    case CRYPTO_DIGEST_MD5:
       /* Doesn't return anything ... */
@@ -1460,7 +1406,7 @@ bool crypto_digest_update (DIGEST *digest, const void *data, size_t length) {
       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);
+         Jmsg1(NULL, M_ERROR, 0, _("SHA1Update() returned an error: %d\n"), ret);
          return false;
       }
       break;
@@ -1469,8 +1415,8 @@ bool crypto_digest_update (DIGEST *digest, const void *data, size_t length) {
    }
 }
 
-bool crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
-
+bool crypto_digest_finalize(DIGEST *digest, uint8_t *dest, uint32_t *length)
+{
    switch (digest->type) {
    case CRYPTO_DIGEST_MD5:
       /* Guard against programmer error by either the API client or
@@ -1478,7 +1424,7 @@ bool crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
       assert(*length >= CRYPTO_DIGEST_MD5_SIZE);
       *length = CRYPTO_DIGEST_MD5_SIZE;
       /* Doesn't return anything ... */
-      MD5Final((unsigned char *) dest, &digest->md5);
+      MD5Final((unsigned char *)dest, &digest->md5);
       return true;
    case CRYPTO_DIGEST_SHA1:
       /* Guard against programmer error by either the API client or
@@ -1498,28 +1444,27 @@ bool crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
    return false;
 }
 
-void crypto_digest_free (DIGEST *digest)
+void crypto_digest_free(DIGEST *digest)
 {
-   free (digest);
+   free(digest);
 }
 
-/* Dummy routines */
-int init_crypto (void) { return 0; }
-int cleanup_crypto (void) { return 0; }
+SIGNATURE *crypto_sign_new(JCR *jcr) { return NULL; }
 
-SIGNATURE *crypto_sign_new (void) { return NULL; }
+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_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; }
+int crypto_sign_encode (SIGNATURE *sig, uint8_t *dest, uint32_t *length) { return false; }
 
-SIGNATURE *crypto_sign_decode (const void *sigData, size_t length) { return NULL; }
+SIGNATURE *crypto_sign_decode (JCR *jcr, const uint8_t *sigData, uint32_t length) { return NULL; }
 void crypto_sign_free (SIGNATURE *sig) { }
 
 
-X509_KEYPAIR *crypto_keypair_new (void) { return NULL; }
+X509_KEYPAIR *crypto_keypair_new(void) { return NULL; }
 X509_KEYPAIR *crypto_keypair_dup (X509_KEYPAIR *keypair) { return NULL; }
 int crypto_keypair_load_cert (X509_KEYPAIR *keypair, const char *file) { return false; }
 bool crypto_keypair_has_key (const char *file) { return false; }
@@ -1528,12 +1473,12 @@ void crypto_keypair_free (X509_KEYPAIR *keypair) { }
 
 CRYPTO_SESSION *crypto_session_new (crypto_cipher_t cipher, alist *pubkeys) { return NULL; }
 void crypto_session_free (CRYPTO_SESSION *cs) { }
-bool crypto_session_encode (CRYPTO_SESSION *cs, void *dest, size_t *length) { return false; }
-crypto_error_t crypto_session_decode (const void *data, size_t length, alist *keypairs, CRYPTO_SESSION **session) { return CRYPTO_ERROR_INTERNAL; }
+bool crypto_session_encode (CRYPTO_SESSION *cs, uint8_t *dest, uint32_t *length) { return false; }
+crypto_error_t crypto_session_decode(const uint8_t *data, uint32_t length, alist *keypairs, CRYPTO_SESSION **session) { return CRYPTO_ERROR_INTERNAL; }
 
-CIPHER_CONTEXT *crypto_cipher_new (CRYPTO_SESSION *cs, bool encrypt, size_t *blocksize) { return NULL; }
-bool crypto_cipher_update (CIPHER_CONTEXT *cipher_ctx, const void *data, size_t length, const void *dest, size_t *written) { return false; }
-bool crypto_cipher_finalize (CIPHER_CONTEXT *cipher_ctx, void *dest, size_t *written) { return false; }
+CIPHER_CONTEXT *crypto_cipher_new (CRYPTO_SESSION *cs, bool encrypt, uint32_t *blocksize) { return NULL; }
+bool crypto_cipher_update (CIPHER_CONTEXT *cipher_ctx, const uint8_t *data, uint32_t length, const uint8_t *dest, uint32_t *written) { return false; }
+bool crypto_cipher_finalize (CIPHER_CONTEXT *cipher_ctx, uint8_t *dest, uint32_t *written) { return false; }
 void crypto_cipher_free (CIPHER_CONTEXT *cipher_ctx) { }
 
 #endif /* HAVE_CRYPTO */
@@ -1554,7 +1499,8 @@ int crypto_default_pem_callback(char *buf, int size, const void *userdata)
  * 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:
       return "MD5";
@@ -1576,7 +1522,8 @@ const char *crypto_digest_name (DIGEST *digest) {
  * Given a stream type, returns the associated
  * crypto_digest_t value.
  */
-crypto_digest_t crypto_digest_stream_type (int stream) {
+crypto_digest_t crypto_digest_stream_type(int stream)
+{
    switch (stream) {
    case STREAM_MD5_DIGEST:
       return CRYPTO_DIGEST_MD5;
@@ -1598,23 +1545,23 @@ crypto_digest_t crypto_digest_stream_type (int stream) {
 const char *crypto_strerror(crypto_error_t error) {
    switch (error) {
    case CRYPTO_ERROR_NONE:
-      return "No error";
+      return _("No error");
    case CRYPTO_ERROR_NOSIGNER:
-      return "Signer not found";
+      return _("Signer not found");
    case CRYPTO_ERROR_NORECIPIENT:
-      return "Recipient not found";
+      return _("Recipient not found");
    case CRYPTO_ERROR_INVALID_DIGEST:
-      return "Unsupported digest algorithm";
+      return _("Unsupported digest algorithm");
    case CRYPTO_ERROR_INVALID_CRYPTO:
-      return "Unsupported encryption algorithm";
+      return _("Unsupported encryption algorithm");
    case CRYPTO_ERROR_BAD_SIGNATURE:
-      return "Signature is invalid";
+      return _("Signature is invalid");
    case CRYPTO_ERROR_DECRYPTION:
-      return "Decryption error";
+      return _("Decryption error");
    case CRYPTO_ERROR_INTERNAL:
       /* This shouldn't happen */
-      return "Internal error";
+      return _("Internal error");
    default:
-      return "Unknown error";
+      return _("Unknown error");
    }
 }