/*
Bacula(R) - The Network Backup Solution
- Copyright (C) 2000-2015 Kern Sibbald
- Copyright (C) 2005-2014 Free Software Foundation Europe e.V.
+ 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.
#ifdef HAVE_CRYPTO /* Is encryption enabled? */
#ifdef HAVE_OPENSSL /* How about OpenSSL? */
+#include "openssl-compat.h"
+
/* ASN.1 Declarations */
#define BACULA_ASN1_VERSION 0
IMPLEMENT_ASN1_FUNCTIONS(RecipientInfo)
IMPLEMENT_ASN1_FUNCTIONS(SignatureData)
IMPLEMENT_ASN1_FUNCTIONS(CryptoData)
-IMPLEMENT_STACK_OF(SignerInfo)
-IMPLEMENT_STACK_OF(RecipientInfo)
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+DEFINE_STACK_OF(SignerInfo);
+DEFINE_STACK_OF(RecipientInfo);
+#else
/*
* SignerInfo and RecipientInfo stack macros, generated by OpenSSL's util/mkstack.pl.
*/
#define ASN1_seq_unpack_RecipientInfo(buf, len, d2i_func, free_func) \
SKM_ASN1_seq_unpack(RecipientInfo, (buf), (len), (d2i_func), (free_func))
/* End of util/mkstack.pl block */
+#endif
/* X509 Public/Private Key Pair Structure */
struct X509_Keypair {
struct Digest {
crypto_digest_t type;
JCR *jcr;
- EVP_MD_CTX ctx;
+ EVP_MD_CTX *ctx;
};
/* Message Signature Structure */
/* Symmetric Cipher Context */
struct Cipher_Context {
- EVP_CIPHER_CTX ctx;
+ EVP_CIPHER_CTX *ctx;
};
/* PEM Password Dispatch Context */
/*
* Extract subjectKeyIdentifier from x509 certificate.
- * Returns: On success, an ASN1_OCTET_STRING that must be freed via M_ASN1_OCTET_STRING_free().
+ * Returns: On success, an ASN1_OCTET_STRING that must be freed via ASN1_OCTET_STRING_free().
* NULL on failure.
*/
static ASN1_OCTET_STRING *openssl_cert_keyid(X509 *cert) {
const X509V3_EXT_METHOD *method;
ASN1_OCTET_STRING *keyid;
int i;
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800FL)
+ const ASN1_STRING *asn1_ext_val;
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);
return NULL;
}
- ext_value_data = ext->value->data;
+ asn1_ext_val = X509_EXTENSION_get_data(ext);
+ ext_value_data = ASN1_STRING_get0_data(asn1_ext_val);
-#if (OPENSSL_VERSION_NUMBER > 0x00907000L)
if (method->it) {
/* New style ASN1 */
/* Decode ASN1 item in data */
- keyid = (ASN1_OCTET_STRING *) ASN1_item_d2i(NULL, &ext_value_data, ext->value->length,
+ keyid = (ASN1_OCTET_STRING *) ASN1_item_d2i(NULL, &ext_value_data, ASN1_STRING_length(asn1_ext_val),
ASN1_ITEM_ptr(method->it));
} else {
/* Old style ASN1 */
/* Decode ASN1 item in data */
- keyid = (ASN1_OCTET_STRING *) method->d2i(NULL, &ext_value_data, ext->value->length);
+ keyid = (ASN1_OCTET_STRING *) method->d2i(NULL, &ext_value_data, ASN1_STRING_length(asn1_ext_val));
}
-#else
- keyid = (ASN1_OCTET_STRING *) method->d2i(NULL, &ext_value_data, ext->value->length);
-#endif
-
return keyid;
}
X509_KEYPAIR *crypto_keypair_dup(X509_KEYPAIR *keypair)
{
X509_KEYPAIR *newpair;
+ int ret;
newpair = crypto_keypair_new();
/* Increment the public key ref count */
if (keypair->pubkey) {
- CRYPTO_add(&(keypair->pubkey->references), 1, CRYPTO_LOCK_EVP_PKEY);
+ ret = EVP_PKEY_up_ref(keypair->pubkey);
+ if (ret == 0)
+ goto out_free_new;
newpair->pubkey = keypair->pubkey;
}
/* Increment the private key ref count */
if (keypair->privkey) {
- CRYPTO_add(&(keypair->privkey->references), 1, CRYPTO_LOCK_EVP_PKEY);
+ ret = EVP_PKEY_up_ref(keypair->privkey);
+ if (ret == 0)
+ goto out_free_new;
newpair->privkey = keypair->privkey;
}
/* Duplicate the keyid */
if (keypair->keyid) {
- newpair->keyid = M_ASN1_OCTET_STRING_dup(keypair->keyid);
- if (!newpair->keyid) {
- /* Allocation failed */
- crypto_keypair_free(newpair);
- return NULL;
- }
+ newpair->keyid = ASN1_OCTET_STRING_dup(keypair->keyid);
+ if (!newpair->keyid)
+ goto out_free_new;
}
return newpair;
+
+out_free_new:
+ crypto_keypair_free(newpair);
+ return NULL;
}
}
/* Validate the public key type (only RSA is supported) */
- if (EVP_PKEY_type(keypair->pubkey->type) != EVP_PKEY_RSA) {
+ if (EVP_PKEY_base_id(keypair->pubkey) != EVP_PKEY_RSA) {
Jmsg1(NULL, M_ERROR, 0,
- _("Unsupported key type provided: %d\n"), EVP_PKEY_type(keypair->pubkey->type));
+ _("Unsupported key type provided: %d\n"), EVP_PKEY_id(keypair->pubkey));
goto err;
}
EVP_PKEY_free(keypair->privkey);
}
if (keypair->keyid) {
- M_ASN1_OCTET_STRING_free(keypair->keyid);
+ ASN1_OCTET_STRING_free(keypair->keyid);
}
free(keypair);
}
Dmsg1(150, "crypto_digest_new jcr=%p\n", jcr);
/* Initialize the OpenSSL message digest context */
- EVP_MD_CTX_init(&digest->ctx);
+ digest->ctx = EVP_MD_CTX_new();
+ if (!digest->ctx)
+ goto err;
+ EVP_MD_CTX_reset(digest->ctx);
/* Determine the correct OpenSSL message digest type */
switch (type) {
}
/* Initialize the backing OpenSSL context */
- if (EVP_DigestInit_ex(&digest->ctx, md, NULL) == 0) {
+ if (EVP_DigestInit_ex(digest->ctx, md, NULL) == 0) {
goto err;
}
*/
bool crypto_digest_update(DIGEST *digest, const uint8_t *data, uint32_t length)
{
- if (EVP_DigestUpdate(&digest->ctx, data, length) == 0) {
+ if (EVP_DigestUpdate(digest->ctx, data, length) == 0) {
Dmsg0(150, "digest update failed\n");
openssl_post_errors(digest->jcr, M_ERROR, _("OpenSSL digest update failed"));
return false;
*/
bool crypto_digest_finalize(DIGEST *digest, uint8_t *dest, uint32_t *length)
{
- if (!EVP_DigestFinal(&digest->ctx, dest, (unsigned int *)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;
*/
void crypto_digest_free(DIGEST *digest)
{
- EVP_MD_CTX_cleanup(&digest->ctx);
+ EVP_MD_CTX_free(digest->ctx);
free(digest);
}
for (i = 0; i < sk_SignerInfo_num(signers); i++) {
si = sk_SignerInfo_value(signers, i);
- if (M_ASN1_OCTET_STRING_cmp(keypair->keyid, si->subjectKeyIdentifier) == 0) {
+ if (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)) {
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;
/* Find the signer */
for (i = 0; i < sk_SignerInfo_num(signers); i++) {
si = sk_SignerInfo_value(signers, i);
- if (M_ASN1_OCTET_STRING_cmp(keypair->keyid, si->subjectKeyIdentifier) == 0) {
+ if (ASN1_OCTET_STRING_cmp(keypair->keyid, si->subjectKeyIdentifier) == 0) {
/* Extract the signature data */
- sigLen = M_ASN1_STRING_length(si->signature);
- sigData = M_ASN1_STRING_data(si->signature);
+ sigLen = ASN1_STRING_length(si->signature);
+ sigData = ASN1_STRING_get0_data(si->signature);
- ok = EVP_VerifyFinal(&digest->ctx, sigData, sigLen, keypair->pubkey);
+ ok = EVP_VerifyFinal(digest->ctx, sigData, sigLen, keypair->pubkey);
if (ok >= 1) {
return CRYPTO_ERROR_NONE;
} else if (ok == 0) {
}
/* Drop the string allocated by OpenSSL, and add our subjectKeyIdentifier */
- M_ASN1_OCTET_STRING_free(si->subjectKeyIdentifier);
- si->subjectKeyIdentifier = M_ASN1_OCTET_STRING_dup(keypair->keyid);
+ ASN1_OCTET_STRING_free(si->subjectKeyIdentifier);
+ si->subjectKeyIdentifier = ASN1_OCTET_STRING_dup(keypair->keyid);
/* Set our signature algorithm. We currently require RSA */
- assert(EVP_PKEY_type(keypair->pubkey->type) == EVP_PKEY_RSA);
+ assert(EVP_PKEY_base_id(keypair->pubkey) == EVP_PKEY_RSA);
/* This is slightly evil. Reach into the MD structure and grab the key type */
- si->signatureAlgorithm = OBJ_nid2obj(digest->ctx.digest->pkey_type);
+ si->signatureAlgorithm = OBJ_nid2obj(EVP_MD_pkey_type(EVP_MD_CTX_md(digest->ctx)));
/* Finalize/Sign our Digest */
len = EVP_PKEY_size(keypair->privkey);
buf = (unsigned char *) malloc(len);
- if (!EVP_SignFinal(&digest->ctx, buf, &len, keypair->privkey)) {
+ if (!EVP_SignFinal(digest->ctx, buf, &len, keypair->privkey)) {
openssl_post_errors(M_ERROR, _("Signature creation failed"));
goto err;
}
/* Add the signature to the SignerInfo structure */
- if (!M_ASN1_OCTET_STRING_set(si->signature, buf, len)) {
+ if (!ASN1_OCTET_STRING_set(si->signature, buf, len)) {
/* Allocation failed in OpenSSL */
goto err;
}
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) {
}
/* Store it in our ASN.1 structure */
- if (!M_ASN1_OCTET_STRING_set(cs->cryptoData->iv, iv, iv_len)) {
+ if (!ASN1_OCTET_STRING_set(cs->cryptoData->iv, iv, iv_len)) {
/* Allocation failed in OpenSSL */
crypto_session_free(cs);
free(iv);
ASN1_INTEGER_set(ri->version, BACULA_ASN1_VERSION);
/* Drop the string allocated by OpenSSL, and add our subjectKeyIdentifier */
- M_ASN1_OCTET_STRING_free(ri->subjectKeyIdentifier);
- ri->subjectKeyIdentifier = M_ASN1_OCTET_STRING_dup(keypair->keyid);
+ ASN1_OCTET_STRING_free(ri->subjectKeyIdentifier);
+ ri->subjectKeyIdentifier = ASN1_OCTET_STRING_dup(keypair->keyid);
/* Set our key encryption algorithm. We currently require RSA */
- assert(keypair->pubkey && EVP_PKEY_type(keypair->pubkey->type) == EVP_PKEY_RSA);
+ assert(keypair->pubkey && EVP_PKEY_base_id(keypair->pubkey) == EVP_PKEY_RSA);
ri->keyEncryptionAlgorithm = OBJ_nid2obj(NID_rsaEncryption);
/* Encrypt the session key */
}
/* Store it in our ASN.1 structure */
- if (!M_ASN1_OCTET_STRING_set(ri->encryptedKey, ekey, ekey_len)) {
+ if (!ASN1_OCTET_STRING_set(ri->encryptedKey, ekey, ekey_len)) {
/* Allocation failed in OpenSSL */
RecipientInfo_free(ri);
crypto_session_free(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
/* bacula-fd.conf doesn't contains any key */
if (!keypairs) {
ri = sk_RecipientInfo_value(recipients, i);
/* Match against the subjectKeyIdentifier */
- if (M_ASN1_OCTET_STRING_cmp(keypair->keyid, ri->subjectKeyIdentifier) == 0) {
+ if (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);
+ assert(EVP_PKEY_base_id(keypair->privkey) == EVP_PKEY_RSA);
/* If we recieve a RecipientInfo structure that does not use
* RSA, return an error */
/* 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_len = EVP_PKEY_decrypt(cs->session_key, M_ASN1_STRING_data(ri->encryptedKey),
- M_ASN1_STRING_length(ri->encryptedKey), keypair->privkey);
+ cs->session_key_len = EVP_PKEY_decrypt(cs->session_key, ASN1_STRING_get0_data(ri->encryptedKey),
+ ASN1_STRING_length(ri->encryptedKey), keypair->privkey);
if (cs->session_key_len <= 0) {
openssl_post_errors(M_ERROR, _("Failure decrypting the session key"));
const EVP_CIPHER *ec;
cipher_ctx = (CIPHER_CONTEXT *)malloc(sizeof(CIPHER_CONTEXT));
+ if (!cipher_ctx)
+ return NULL;
+
+ cipher_ctx->ctx = EVP_CIPHER_CTX_new();
+ if (!cipher_ctx->ctx)
+ goto err;
/*
* Acquire a cipher instance for the given ASN.1 cipher NID
}
/* Initialize the OpenSSL cipher context */
- EVP_CIPHER_CTX_init(&cipher_ctx->ctx);
+ EVP_CIPHER_CTX_reset(cipher_ctx->ctx);
if (encrypt) {
/* Initialize for encryption */
- if (!EVP_CipherInit_ex(&cipher_ctx->ctx, ec, NULL, NULL, NULL, 1)) {
+ if (!EVP_CipherInit_ex(cipher_ctx->ctx, ec, NULL, NULL, NULL, 1)) {
openssl_post_errors(M_ERROR, _("OpenSSL cipher context initialization failed"));
goto err;
}
} else {
/* Initialize for decryption */
- if (!EVP_CipherInit_ex(&cipher_ctx->ctx, ec, NULL, NULL, NULL, 0)) {
+ if (!EVP_CipherInit_ex(cipher_ctx->ctx, ec, NULL, NULL, NULL, 0)) {
openssl_post_errors(M_ERROR, _("OpenSSL cipher context initialization failed"));
goto err;
}
}
/* Set the key size */
- if (!EVP_CIPHER_CTX_set_key_length(&cipher_ctx->ctx, cs->session_key_len)) {
+ if (!EVP_CIPHER_CTX_set_key_length(cipher_ctx->ctx, cs->session_key_len)) {
openssl_post_errors(M_ERROR, _("Encryption session provided an invalid symmetric key"));
goto err;
}
/* Validate the IV length */
- if (EVP_CIPHER_iv_length(ec) != M_ASN1_STRING_length(cs->cryptoData->iv)) {
+ if (EVP_CIPHER_iv_length(ec) != ASN1_STRING_length(cs->cryptoData->iv)) {
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)) {
+ if (!EVP_CipherInit_ex(cipher_ctx->ctx, NULL, NULL, cs->session_key, ASN1_STRING_get0_data(cs->cryptoData->iv), -1)) {
openssl_post_errors(M_ERROR, _("OpenSSL cipher context key/IV initialization failed"));
goto err;
}
- *blocksize = EVP_CIPHER_CTX_block_size(&cipher_ctx->ctx);
+ *blocksize = EVP_CIPHER_CTX_block_size(cipher_ctx->ctx);
return cipher_ctx;
err:
*/
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)) {
+ if (!EVP_CipherUpdate(cipher_ctx->ctx, (unsigned char *)dest, (int *)written, (const unsigned char *)data, length)) {
/* This really shouldn't fail */
return false;
} else {
*/
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)) {
+ if (!EVP_CipherFinal_ex(cipher_ctx->ctx, (unsigned char *)dest, (int *) written)) {
/* This really shouldn't fail */
return false;
} else {
*/
void crypto_cipher_free (CIPHER_CONTEXT *cipher_ctx)
{
- EVP_CIPHER_CTX_cleanup(&cipher_ctx->ctx);
+ EVP_CIPHER_CTX_free(cipher_ctx->ctx);
free (cipher_ctx);
}
-
-
#else /* HAVE_OPENSSL */
# error No encryption library available
#endif /* HAVE_OPENSSL */