]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/lib/crypto.c
Add missing cast
[bacula/bacula] / bacula / src / lib / crypto.c
index d2a2d4a4d3562d77490315f51cd5fd679da67e13..598dcf72aa110ca881b0506e9a8d3cbf170d2653 100644 (file)
@@ -73,7 +73,8 @@
  *
  * 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
@@ -160,6 +165,7 @@ typedef struct {
 typedef struct {
    ASN1_INTEGER *version;
    ASN1_OBJECT *contentEncryptionAlgorithm;
+   ASN1_OCTET_STRING *iv;
    STACK_OF(RecipientInfo) *recipientInfo;
 } CryptoData;
 
@@ -170,10 +176,12 @@ ASN1_SEQUENCE(SignatureData) = {
 
 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)
@@ -204,13 +212,13 @@ 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))
+        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)
@@ -234,13 +242,13 @@ 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))
+        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 */
@@ -261,6 +269,14 @@ struct Signature {
    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;
@@ -344,6 +360,49 @@ X509_KEYPAIR *crypto_keypair_new (void) {
    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
@@ -512,7 +571,7 @@ err:
  * 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 { 
@@ -527,8 +586,8 @@ int crypto_digest_update (DIGEST *digest, const void *data, size_t length) {
  * Returns: true on success
  *          false on failure
  */
-int crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
-   if (!EVP_DigestFinal(&digest->ctx, (unsigned char *) dest, length)) {
+bool crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
+   if (!EVP_DigestFinal(&digest->ctx, (unsigned char *) dest, (unsigned int *) length)) {
       return false;
    } else {
       return true;
@@ -815,6 +874,169 @@ void crypto_sign_free(SIGNATURE *sig)
    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.
@@ -925,7 +1147,7 @@ DIGEST *crypto_digest_new (crypto_digest_t type)
    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 ... */
@@ -934,10 +1156,10 @@ int crypto_digest_update (DIGEST *digest, const void *data, size_t length) {
    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:
@@ -945,7 +1167,7 @@ int crypto_digest_update (DIGEST *digest, const void *data, size_t length) {
    }
 }
 
-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:
@@ -962,9 +1184,9 @@ int crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
       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:
@@ -996,10 +1218,14 @@ void crypto_sign_free (SIGNATURE *sig) { }
 
 
 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 */