]> git.sur5r.net Git - bacula/bacula/commitdiff
Add PKE recipient structure creation w/ symmetric key & IV generation.
authorLandon Fuller <landonf@opendarwin.org>
Mon, 12 Dec 2005 03:27:12 +0000 (03:27 +0000)
committerLandon Fuller <landonf@opendarwin.org>
Mon, 12 Dec 2005 03:27:12 +0000 (03:27 +0000)
Fix NULL dereference when no additional PKI Trusted Signers are specified.

git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@2661 91ce42f0-d328-0410-95d8-f526ca767f89

bacula/src/filed/backup.c
bacula/src/filed/filed.c
bacula/src/filed/filed_conf.c
bacula/src/filed/filed_conf.h
bacula/src/filed/job.c
bacula/src/jcr.h
bacula/src/lib/crypto.c
bacula/src/lib/crypto.h
bacula/src/lib/protos.h

index 0431a0fc0a0bab1598e82e5d305a4976cf02510e..fe9d2e7d0de72739d9af8fe5a4bac2097d023024 100644 (file)
@@ -47,6 +47,8 @@ bool blast_data_to_storage_daemon(JCR *jcr, char *addr)
 {
    BSOCK *sd;
    bool ok = true;
+   // TODO landonf: Allow user to specify encryption algorithm
+   crypto_cipher_t cipher = CRYPTO_CIPHER_AES_128_CBC;
 
    sd = jcr->store_bsock;
 
@@ -79,6 +81,11 @@ bool blast_data_to_storage_daemon(JCR *jcr, char *addr)
    jcr->compress_buf_size = jcr->buf_size + ((jcr->buf_size+999) / 1000) + 30;
    jcr->compress_buf = get_memory(jcr->compress_buf_size);
 
+   if (jcr->pki_encrypt) {
+      /* Create per-job session encryption context */
+      jcr->pki_recipients = crypto_recipients_new(cipher, jcr->pki_readers);
+   }
+
    Dmsg1(300, "set_find_options ff=%p\n", jcr->ff);
    set_find_options((FF_PKT *)jcr->ff, jcr->incremental, jcr->mtime);
    Dmsg0(300, "start find files\n");
@@ -108,6 +115,11 @@ bool blast_data_to_storage_daemon(JCR *jcr, char *addr)
       free_pool_memory(jcr->compress_buf);
       jcr->compress_buf = NULL;
    }
+
+   if (jcr->pki_recipients) {
+      crypto_recipients_free(jcr->pki_recipients);
+   }
+
    Dmsg1(100, "end blast_data ok=%d\n", ok);
    return ok;
 }
index fe6b33c37d61760f3cdc4e30dce0484388e66c53..7bb2a3a2f8c829bfafca083a20bdffa3cdfa8d37 100644 (file)
@@ -372,27 +372,59 @@ static int check_resources()
          }
 
          /*
-          * Trusted Signers. We're always trusted. me->pki_keypair
-          * will be deallocated when me->pki_signers is deallocated.
+          * Trusted Signers. We're always trusted.
           */
          me->pki_signers = New(alist(10, not_owned_by_alist));
-         me->pki_signers->append(me->pki_keypair);
+         me->pki_signers->append(crypto_keypair_dup(me->pki_keypair));
 
          /* If additional trusted keys have been specified, load them up */
-         foreach_alist(filepath, me->pki_trustedkeys) {
-            X509_KEYPAIR *keypair;
+        if (me->pki_trustedkeys) {
+            foreach_alist(filepath, me->pki_trustedkeys) {
+               X509_KEYPAIR *keypair;
 
-            keypair = crypto_keypair_new();
-            if (!keypair) {
-               Emsg0(M_FATAL, 0, _("Failed to allocate a new keypair object.\n"));
-               OK = false;
-            } else {
-               if (crypto_keypair_load_cert(keypair, filepath)) {
-                  me->pki_signers->append(keypair);
-               } else {
-                  Emsg3(M_FATAL, 0, _("Failed to load trusted signer certificate"
-                     " from file %s for File daemon \"%s\" in %s.\n"), filepath, me->hdr.name, configfile);
+               keypair = crypto_keypair_new();
+               if (!keypair) {
+                  Emsg0(M_FATAL, 0, _("Failed to allocate a new keypair object.\n"));
                   OK = false;
+               } else {
+                  if (crypto_keypair_load_cert(keypair, filepath)) {
+                     me->pki_signers->append(keypair);
+                  } else {
+                     Emsg3(M_FATAL, 0, _("Failed to load trusted signer certificate"
+                        " from file %s for File daemon \"%s\" in %s.\n"), filepath, me->hdr.name, configfile);
+                     OK = false;
+                  }
+               }
+            }
+        }
+
+         if (me->pki_encrypt) {
+            /*
+             * Trusted readers. We're always trusted.
+             * The symmetric session key will be encrypted for each of these readers.
+             */
+            me->pki_readers = New(alist(10, not_owned_by_alist));
+            me->pki_readers->append(crypto_keypair_dup(me->pki_keypair));
+
+
+            /* If additional keys have been specified, load them up */
+            if (me->pki_masterkeys) {
+               foreach_alist(filepath, me->pki_masterkeys) {
+                  X509_KEYPAIR *keypair;
+
+                  keypair = crypto_keypair_new();
+                  if (!keypair) {
+                     Emsg0(M_FATAL, 0, _("Failed to allocate a new keypair object.\n"));
+                     OK = false;
+                  } else {
+                     if (crypto_keypair_load_cert(keypair, filepath)) {
+                        me->pki_signers->append(keypair);
+                     } else {
+                        Emsg3(M_FATAL, 0, _("Failed to load master key certificate"
+                           " from file %s for File daemon \"%s\" in %s.\n"), filepath, me->hdr.name, configfile);
+                        OK = false;
+                     }
+                  }
                }
             }
          }
index 242eab9ab8ee3ccd49d2db6eab69ed1fae8eb31c..442e6dd63c5ec1eff8fd542db84991c1cca83e69 100644 (file)
@@ -93,6 +93,7 @@ static RES_ITEM cli_items[] = {
    {"pkiencryption",         store_yesno,     ITEM(res_client.pki_encrypt), 1, ITEM_DEFAULT, 0},
    {"pkikeypair",            store_dir,       ITEM(res_client.pki_keypairfile), 0, 0, 0},
    {"pkitrustedsigner",      store_alist_str, ITEM(res_client.pki_trustedkeys), 0, 0, 0},
+   {"pkimasterkey",          store_alist_str, ITEM(res_client.pki_masterkeys), 0, 0, 0},
    {"tlsenable",             store_yesno,     ITEM(res_client.tls_enable),  1, 0, 0},
    {"tlsrequire",            store_yesno,     ITEM(res_client.tls_require), 1, 0, 0},
    {"tlscacertificatefile",  store_dir,       ITEM(res_client.tls_ca_certfile), 0, 0, 0},
@@ -247,6 +248,9 @@ void free_resource(RES *sres, int type)
       if (res->res_client.pki_keypairfile) { 
          free(res->res_client.pki_keypairfile);
       }
+      if (res->res_client.pki_keypair) {
+        crypto_keypair_free(res->res_client.pki_keypair);
+      }
       /* Also frees res_client.pki_keypair */
       if (res->res_client.pki_trustedkeys) {
          delete res->res_client.pki_trustedkeys;
@@ -258,6 +262,17 @@ void free_resource(RES *sres, int type)
          }
          delete res->res_client.pki_signers;
       }
+      if (res->res_client.pki_masterkeys) {
+         delete res->res_client.pki_masterkeys;
+      }
+      if (res->res_client.pki_readers) {
+         X509_KEYPAIR *keypair;
+         foreach_alist(keypair, res->res_client.pki_readers) {
+            crypto_keypair_free(keypair);
+         }
+         delete res->res_client.pki_signers;
+      }
+
       if (res->res_client.tls_ctx) { 
          free_tls_context(res->res_client.tls_ctx);
       }
index 396fae14a7ea800c2574ff5bfcf78ea4333e36a1..5ba1737598ebb90605b5b42e989aae937c6ea505 100644 (file)
@@ -75,6 +75,7 @@ struct CLIENT {
    int pki_encrypt;                   /* Enable Data Encryption */
    char *pki_keypairfile;             /* PKI Key Pair File */
    alist *pki_trustedkeys;            /* PKI Trusted Public Keys */
+   alist *pki_masterkeys;             /* PKI Master Keys */
    int tls_enable;                    /* Enable TLS */
    int tls_require;                   /* Require TLS */
    char *tls_ca_certfile;             /* TLS CA Certificate File */
@@ -84,6 +85,7 @@ struct CLIENT {
 
    X509_KEYPAIR *pki_keypair;         /* Shared PKI Public/Private Keypair */
    alist *pki_signers;                /* Shared PKI Trusted Signers */
+   alist *pki_readers;                /* Shared PKI Recipients */
    TLS_CONTEXT *tls_ctx;              /* Shared TLS Context */
 };
 
index 7af7ce10b06e0a12486f198ddb1620f5f4a93eca..57dd05eca242d3a5fa5f96ccb0c95a4cf2b45de6 100644 (file)
@@ -177,6 +177,7 @@ void *handle_client_request(void *dirp)
    jcr->pki_encrypt = me->pki_encrypt;
    jcr->pki_keypair = me->pki_keypair;
    jcr->pki_signers = me->pki_signers;
+   jcr->pki_readers = me->pki_readers;
    dir->jcr = jcr;
    enable_backup_privileges(NULL, 1 /* ignore_errors */);
 
index 65d176357c80ae4b6ca458fb7b49089b7534a668..1907f633f983320a97f91d998a1446c0eaa05dd6 100644 (file)
@@ -234,6 +234,8 @@ public:
    DIGEST *digest;                    /* Last file's digest context */
    X509_KEYPAIR *pki_keypair;         /* Encryption key pair */
    alist *pki_signers;                /* Trusted Signers */
+   alist *pki_readers;                /* Trusted Readers */
+   CRYPTO_RECIPIENTS *pki_recipients; /* PKE Public Keys + Symmetric Session Keys */
    DIRRES* director;                  /* Director resource */
 #endif /* FILE_DAEMON */
 
index 9860a4b1a9c8c47c99775175d8c45a60cf699b4e..327b1269b12fbd0c9cbf7139a5046d9b59b0cbe3 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)
@@ -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
@@ -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.
index 1519cf426c3b8da06ee1e35883454f72aafeb1dc..d9cafe794e7d7747173f48454ee9f5e54b84c519 100644 (file)
@@ -45,6 +45,9 @@ typedef struct Digest DIGEST;
 /* Opaque Message Signature Structure */
 typedef struct Signature SIGNATURE;
 
+/* Opaque PKI Symmetric Key Data Structure */
+typedef struct Crypto_Recipients CRYPTO_RECIPIENTS;
+
 /* PEM Decryption Passphrase Callback */
 typedef int (CRYPTO_PEM_PASSWD_CB) (char *buf, int size, const void *userdata);
 
@@ -58,6 +61,15 @@ typedef enum {
    CRYPTO_DIGEST_SHA512 = 4
 } crypto_digest_t;
 
+/* Cipher Types */
+typedef enum {
+   /* These are not stored on disk */
+   CRYPTO_CIPHER_AES_128_CBC,
+   CRYPTO_CIPHER_AES_192_CBC,
+   CRYPTO_CIPHER_AES_256_CBC,
+   CRYPTO_CIPHER_BLOWFISH_CBC
+} crypto_cipher_t;
+
 /* Crypto API Errors */
 typedef enum {
    CRYPTO_ERROR_NONE           = 0, /* No error */
index 130189729f1bd09621362f64bf8e969c1e7de896..3d5601fe2877e40577ec4af6d7a1f503e169b1e7 100644 (file)
@@ -114,27 +114,30 @@ void hmac_md5(uint8_t* text, int text_len, uint8_t*  key,
 uint32_t bcrc32(uint8_t *buf, int len);
 
 /* crypto.c */
-int              init_crypto                 (void);
-int              cleanup_crypto              (void);
-DIGEST *         crypto_digest_new           (crypto_digest_t type);
-bool             crypto_digest_update        (DIGEST *digest, const void *data, size_t length);
-bool             crypto_digest_finalize      (DIGEST *digest, void *dest, size_t *length);
-void             crypto_digest_free          (DIGEST *digest);
-SIGNATURE *      crypto_sign_new             (void);
-crypto_error_t   crypto_sign_get_digest      (SIGNATURE *sig, X509_KEYPAIR *keypair, DIGEST **digest);
-crypto_error_t   crypto_sign_verify          (SIGNATURE *sig, X509_KEYPAIR *keypair, DIGEST *digest);
-int              crypto_sign_add_signer      (SIGNATURE *sig, DIGEST *digest, X509_KEYPAIR *keypair);
-int              crypto_sign_encode          (SIGNATURE *sig, void *dest, size_t *length);
-SIGNATURE *      crypto_sign_decode          (const void *sigData, size_t length);
-void             crypto_sign_free            (SIGNATURE *sig);
-X509_KEYPAIR *   crypto_keypair_new          (void);
-int              crypto_keypair_load_cert    (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);
-void             crypto_keypair_free         (X509_KEYPAIR *keypair);
-int              crypto_default_pem_callback (char *buf, int size, const void *userdata);
-const char *     crypto_digest_name          (DIGEST *digest);
-crypto_digest_t  crypto_digest_stream_type   (int stream);
-const char *     crypto_strerror             (crypto_error_t error);
+int                init_crypto                 (void);
+int                cleanup_crypto              (void);
+DIGEST *           crypto_digest_new           (crypto_digest_t type);
+bool               crypto_digest_update        (DIGEST *digest, const void *data, size_t length);
+bool               crypto_digest_finalize      (DIGEST *digest, void *dest, size_t *length);
+void               crypto_digest_free          (DIGEST *digest);
+SIGNATURE *        crypto_sign_new             (void);
+crypto_error_t     crypto_sign_get_digest      (SIGNATURE *sig, X509_KEYPAIR *keypair, DIGEST **digest);
+crypto_error_t     crypto_sign_verify          (SIGNATURE *sig, X509_KEYPAIR *keypair, DIGEST *digest);
+int                crypto_sign_add_signer      (SIGNATURE *sig, DIGEST *digest, X509_KEYPAIR *keypair);
+int                crypto_sign_encode          (SIGNATURE *sig, void *dest, size_t *length);
+SIGNATURE *        crypto_sign_decode          (const void *sigData, size_t length);
+void               crypto_sign_free            (SIGNATURE *sig);
+CRYPTO_RECIPIENTS *crypto_recipients_new       (crypto_cipher_t cipher, alist *pubkeys);
+void               crypto_recipients_free      (CRYPTO_RECIPIENTS *cr);
+X509_KEYPAIR *     crypto_keypair_new          (void);
+X509_KEYPAIR *     crypto_keypair_dup          (X509_KEYPAIR *keypair);
+int                crypto_keypair_load_cert    (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);
+void               crypto_keypair_free         (X509_KEYPAIR *keypair);
+int                crypto_default_pem_callback (char *buf, int size, const void *userdata);
+const char *       crypto_digest_name          (DIGEST *digest);
+crypto_digest_t    crypto_digest_stream_type   (int stream);
+const char *       crypto_strerror             (crypto_error_t error);
 
 /* daemon.c */
 void     daemon_start            ();