*
* CryptoData ::= SEQUENCE {
* version Version DEFAULT v0,
- * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier
+ * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+ * iv InitializationVector,
* recipientInfo RecipientInfo
* }
*
*
* KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
*
+ * ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * InitializationVector ::= OCTET STRING
+ *
* SignatureValue ::= OCTET STRING
*
* EncryptedKey ::= OCTET STRING
typedef struct {
ASN1_INTEGER *version;
ASN1_OBJECT *contentEncryptionAlgorithm;
+ ASN1_OCTET_STRING *iv;
STACK_OF(RecipientInfo) *recipientInfo;
} CryptoData;
ASN1_SEQUENCE(CryptoData) = {
ASN1_SIMPLE(CryptoData, version, ASN1_INTEGER),
+ ASN1_SIMPLE(CryptoData, iv, ASN1_OCTET_STRING),
ASN1_SET_OF(CryptoData, recipientInfo, RecipientInfo)
} ASN1_SEQUENCE_END(CryptoData);
IMPLEMENT_ASN1_FUNCTIONS(SignerInfo)
+IMPLEMENT_ASN1_FUNCTIONS(RecipientInfo)
IMPLEMENT_ASN1_FUNCTIONS(SignatureData)
IMPLEMENT_ASN1_FUNCTIONS(CryptoData)
IMPLEMENT_STACK_OF(SignerInfo)
#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))
+ 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) \
- SKM_ASN1_seq_pack(SignerInfo, (st), (i2d_func), (buf), (len))
+ SKM_ASN1_seq_pack(SignerInfo, (st), (i2d_func), (buf), (len))
#define ASN1_seq_unpack_SignerInfo(buf, len, d2i_func, free_func) \
- SKM_ASN1_seq_unpack(SignerInfo, (buf), (len), (d2i_func), (free_func))
+ SKM_ASN1_seq_unpack(SignerInfo, (buf), (len), (d2i_func), (free_func))
#define sk_RecipientInfo_new(st) SKM_sk_new(RecipientInfo, (st))
#define sk_RecipientInfo_new_null() SKM_sk_new_null(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))
+ 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) \
- SKM_ASN1_seq_pack(RecipientInfo, (st), (i2d_func), (buf), (len))
+ SKM_ASN1_seq_pack(RecipientInfo, (st), (i2d_func), (buf), (len))
#define ASN1_seq_unpack_RecipientInfo(buf, len, d2i_func, free_func) \
- SKM_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 */
/* X509 Public/Private Key Pair Structure */
SignatureData *sigData;
};
+/* Encryption Key Data */
+struct Crypto_Recipients {
+ CryptoData *cryptoData; /* ASN.1 Structure */
+ EVP_CIPHER *openssl_cipher; /* OpenSSL Cipher Object */
+ unsigned char session_key[EVP_MAX_KEY_LENGTH]; /* Private symmetric session key */
+ size_t session_key_len; /* Symmetric session key length */
+};
+
/* PEM Password Dispatch Context */
typedef struct PEM_CB_Context {
CRYPTO_PEM_PASSWD_CB *pem_callback;
return keypair;
}
+/*
+ * Create a copy of a keypair object. The underlying
+ * EVP objects are not duplicated, as no EVP_PKEY_dup()
+ * API is available. Instead, the reference count is
+ * incremented.
+ */
+X509_KEYPAIR *crypto_keypair_dup (X509_KEYPAIR *keypair)
+{
+ X509_KEYPAIR *newpair;
+
+ newpair = crypto_keypair_new();
+
+ if (!newpair) {
+ /* Allocation failed */
+ return NULL;
+ }
+
+ /* Increment the public key ref count */
+ if (keypair->pubkey) {
+ CRYPTO_add(&(keypair->pubkey->references), 1, CRYPTO_LOCK_EVP_PKEY);
+ newpair->pubkey = keypair->pubkey;
+ }
+
+ /* Increment the private key ref count */
+ if (keypair->privkey) {
+ CRYPTO_add(&(keypair->privkey->references), 1, CRYPTO_LOCK_EVP_PKEY);
+ 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;
+ }
+ }
+
+ return newpair;
+}
+
+
/*
* Load a public key from a PEM-encoded x509 certificate.
* Returns: true on success
* Returns: true on success
* false on failure
*/
-int crypto_digest_update (DIGEST *digest, const void *data, size_t length) {
+bool crypto_digest_update (DIGEST *digest, const void *data, size_t length) {
if (EVP_DigestUpdate(&digest->ctx, data, length) == 0) {
return true;
} else {
* Returns: true on success
* false on failure
*/
-int crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
+bool crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
if (!EVP_DigestFinal(&digest->ctx, (unsigned char *) dest, length)) {
return false;
} else {
free (sig);
}
+/*
+ * Create a new encryption recipient.
+ * Returns: A pointer to a CRYPTO_RECIPIENTS object on success.
+ * NULL on failure.
+ */
+CRYPTO_RECIPIENTS *crypto_recipients_new (crypto_cipher_t cipher, alist *pubkeys)
+{
+ CRYPTO_RECIPIENTS *cr;
+ X509_KEYPAIR *keypair;
+ const EVP_CIPHER *ec;
+ unsigned char *iv;
+ int iv_len;
+
+ /* Allocate our recipient description structures */
+ cr = (CRYPTO_RECIPIENTS *) malloc(sizeof(CRYPTO_RECIPIENTS));
+ if (!cr) {
+ return NULL;
+ }
+
+ cr->cryptoData = CryptoData_new();
+
+ if (!cr->cryptoData) {
+ /* Allocation failed in OpenSSL */
+ free(cr);
+ return NULL;
+ }
+
+ /* Set the ASN.1 structure version number */
+ ASN1_INTEGER_set(cr->cryptoData->version, BACULA_ASN1_VERSION);
+
+ /*
+ * Acquire a cipher instance and set the ASN.1 cipher NID
+ */
+ switch (cipher) {
+ case CRYPTO_CIPHER_AES_128_CBC:
+ /* AES 128 bit CBC */
+ cr->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_aes_128_cbc);
+ ec = EVP_aes_128_cbc();
+ break;
+ case CRYPTO_CIPHER_AES_192_CBC:
+ /* AES 192 bit CBC */
+ cr->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_aes_192_cbc);
+ ec = EVP_aes_192_cbc();
+ break;
+ case CRYPTO_CIPHER_AES_256_CBC:
+ /* AES 256 bit CBC */
+ cr->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_aes_256_cbc);
+ ec = EVP_aes_256_cbc();
+ break;
+ case CRYPTO_CIPHER_BLOWFISH_CBC:
+ /* Blowfish CBC */
+ cr->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_bf_cbc);
+ ec = EVP_bf_cbc();
+ break;
+ default:
+ Emsg0(M_ERROR, 0, _("Unsupported cipher type specified\n"));
+ crypto_recipients_free(cr);
+ return NULL;
+ }
+
+ /* Generate a symmetric session key */
+ cr->session_key_len = EVP_CIPHER_key_length(ec);
+ if (RAND_bytes(cr->session_key, cr->session_key_len) <= 0) {
+ /* OpenSSL failure */
+ crypto_recipients_free(cr);
+ return NULL;
+ }
+
+ /* Generate an IV if possible */
+ if ((iv_len = EVP_CIPHER_iv_length(ec))) {
+ iv = (unsigned char *) malloc(iv_len);
+ if (!iv) {
+ /* Malloc failure */
+ crypto_recipients_free(cr);
+ return NULL;
+ }
+
+ /* Generate random IV */
+ if (RAND_bytes(iv, iv_len) <= 0) {
+ /* OpenSSL failure */
+ crypto_recipients_free(cr);
+ return NULL;
+ }
+
+ /* Store it in our ASN.1 structure */
+ if (!M_ASN1_OCTET_STRING_set(cr->cryptoData->iv, iv, iv_len)) {
+ /* Allocation failed in OpenSSL */
+ crypto_recipients_free(cr);
+ return NULL;
+ }
+ }
+
+ /*
+ * Create RecipientInfo structures for supplied
+ * public keys.
+ */
+ foreach_alist(keypair, pubkeys) {
+ RecipientInfo *ri;
+ unsigned char *ekey;
+ int ekey_len;
+
+ ri = RecipientInfo_new();
+ if (!ri) {
+ /* Allocation failed in OpenSSL */
+ crypto_recipients_free(cr);
+ return NULL;
+ }
+
+ /* Set the ASN.1 structure version number */
+ 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);
+
+ /* Set our key encryption algorithm. We currently require RSA */
+ assert(keypair->pubkey && EVP_PKEY_type(keypair->pubkey->type) == EVP_PKEY_RSA);
+ 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_recipients_free(cr);
+ return NULL;
+ }
+
+ if ((ekey_len = EVP_PKEY_encrypt(ekey, cr->session_key, cr->session_key_len, keypair->pubkey)) <= 0) {
+ /* OpenSSL failure */
+ RecipientInfo_free(ri);
+ crypto_recipients_free(cr);
+ free(ekey);
+ return NULL;
+ }
+
+ /* Store it in our ASN.1 structure */
+ if (!M_ASN1_OCTET_STRING_set(ri->encryptedKey, ekey, ekey_len)) {
+ /* Allocation failed in OpenSSL */
+ RecipientInfo_free(ri);
+ crypto_recipients_free(cr);
+ free(ekey);
+ return NULL;
+ }
+
+ /* Free the encrypted key buffer */
+ free(ekey);
+
+ /* Push the new RecipientInfo structure onto the stack */
+ sk_RecipientInfo_push(cr->cryptoData->recipientInfo, ri);
+ }
+
+ return cr;
+}
+
+/*
+ * Free memory associated with a crypto recipient object.
+ */
+void crypto_recipients_free (CRYPTO_RECIPIENTS *cr)
+{
+ CryptoData_free(cr->cryptoData);
+ free(cr);
+}
+
/*
* Perform global initialization of OpenSSL
* This function is not thread safe.
return (digest);
}
-int crypto_digest_update (DIGEST *digest, const void *data, size_t length) {
+bool crypto_digest_update (DIGEST *digest, const void *data, size_t length) {
switch (digest->type) {
case CRYPTO_DIGEST_MD5:
/* Doesn't return anything ... */
case CRYPTO_DIGEST_SHA1:
int ret;
if ((ret = SHA1Update(&digest->sha1, (const u_int8_t *) data, length)) == shaSuccess) {
- return true;
+ return true;
} else {
Emsg1(M_ERROR, 0, _("SHA1Update() returned an error: %d\n"), ret);
- return false;
+ return false;
}
break;
default:
}
}
-int crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
+bool crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
switch (digest->type) {
case CRYPTO_DIGEST_MD5:
assert(*length >= CRYPTO_DIGEST_SHA1_SIZE);
*length = CRYPTO_DIGEST_SHA1_SIZE;
if (SHA1Final(&digest->sha1, (u_int8_t *) dest) == shaSuccess) {
- return true;
+ return true;
} else {
- return false;
+ return false;
}
break;
default:
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; }
int crypto_keypair_load_key (X509_KEYPAIR *keypair, const char *file, CRYPTO_PEM_PASSWD_CB *pem_callback, const void *pem_userdata) { return false; }
void crypto_keypair_free (X509_KEYPAIR *keypair) { }
+CRYPTO_RECIPIENTS *crypto_recipients_new (crypto_cipher_t cipher, alist *pubkeys) { return NULL; }
+void crypto_recipients_free (CRYPTO_RECIPIENTS *cr) { }
+
#endif /* HAVE_CRYPTO */
/* Shared Code */