]> git.sur5r.net Git - bacula/bacula/commitdiff
- Add support for testing the availability of a PEM-encoded private key
authorLandon Fuller <landonf@opendarwin.org>
Mon, 16 Jan 2006 02:01:47 +0000 (02:01 +0000)
committerLandon Fuller <landonf@opendarwin.org>
Mon, 16 Jan 2006 02:01:47 +0000 (02:01 +0000)
- Load private keys from Master Keys and Signing Keys where possible
- Clarify pki_* variable names in the JCR structure.
- Fix small bugs in RES_CLIENT deallocation and copying.
- Add full support for decoding and decrypting crypto session w/ symmetric keys

git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@2749 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/filed/restore.c
bacula/src/jcr.h
bacula/src/lib/crypto.c
bacula/src/lib/crypto.h
bacula/src/lib/protos.h

index 34fed539da3e5dddd86a99678adaa28a8caad492..6812d8cf7490ee08dcece12d34bcac0bde8c22c7 100644 (file)
@@ -88,7 +88,7 @@ bool blast_data_to_storage_daemon(JCR *jcr, char *addr)
       size_t size = 0;
 
       /* Create per-job session encryption context */
-      jcr->pki_session = crypto_session_new(cipher, jcr->pki_readers);
+      jcr->pki_session = crypto_session_new(cipher, jcr->pki_recipients);
 
       /* Get the session data size */
       if (crypto_session_encode(jcr->pki_session, NULL, &size) == false) {
index c97926d0c75dd2a55fefd91b4b1d36871a438230..f274444fe6ed7bd1405d0115eb6e6e1ec772fef3 100644 (file)
@@ -341,7 +341,7 @@ static int check_resources()
          me->pki_sign = true;
       }
 
-      if ((me->pki_encrypt || me->pki_sign) && !me->pki_keypairfile) {
+      if ((me->pki_encrypt || me->pki_sign) && !me->pki_keypair_file) {
          Emsg2(M_FATAL, 0, _("\"PKI Key Pair\" must be defined for File"
             " daemon \"%s\" in %s if either \"PKI Sign\" or"
             " \"PKI Encrypt\" are enabled.\n"), me->hdr.name, configfile);
@@ -351,20 +351,19 @@ static int check_resources()
       /* If everything is well, attempt to initialize our public/private keys */
       if (OK && (me->pki_encrypt || me->pki_sign)) {
          char *filepath;
-
          /* Load our keypair */
          me->pki_keypair = crypto_keypair_new();
          if (!me->pki_keypair) {
             Emsg0(M_FATAL, 0, _("Failed to allocate a new keypair object.\n"));
             OK = false;
          } else {
-            if (!crypto_keypair_load_cert(me->pki_keypair, me->pki_keypairfile)) {
+            if (!crypto_keypair_load_cert(me->pki_keypair, me->pki_keypair_file)) {
                Emsg2(M_FATAL, 0, _("Failed to load public certificate for File"
                      " daemon \"%s\" in %s.\n"), me->hdr.name, configfile);
                OK = false;
             }
 
-            if (!crypto_keypair_load_key(me->pki_keypair, me->pki_keypairfile, NULL, NULL)) {
+            if (!crypto_keypair_load_key(me->pki_keypair, me->pki_keypair_file, NULL, NULL)) {
                Emsg2(M_FATAL, 0, _("Failed to load private key for File"
                      " daemon \"%s\" in %s.\n"), me->hdr.name, configfile);
                OK = false;
@@ -375,11 +374,13 @@ static int check_resources()
           * Trusted Signers. We're always trusted.
           */
          me->pki_signers = New(alist(10, not_owned_by_alist));
-         me->pki_signers->append(crypto_keypair_dup(me->pki_keypair));
+         if (me->pki_keypair) {
+            me->pki_signers->append(crypto_keypair_dup(me->pki_keypair));
+         }
 
-         /* If additional trusted keys have been specified, load them up */
-         if (me->pki_trustedkeys) {
-            foreach_alist(filepath, me->pki_trustedkeys) {
+         /* If additional signing public keys have been specified, load them up */
+         if (me->pki_signing_key_files) {
+            foreach_alist(filepath, me->pki_signing_key_files) {
                X509_KEYPAIR *keypair;
 
                keypair = crypto_keypair_new();
@@ -389,6 +390,16 @@ static int check_resources()
                } else {
                   if (crypto_keypair_load_cert(keypair, filepath)) {
                      me->pki_signers->append(keypair);
+
+                     /* Attempt to load a private key, if available */
+                     if (crypto_keypair_has_key(filepath)) {
+                        if (!crypto_keypair_load_key(keypair, filepath, NULL, NULL)) {
+                           Emsg3(M_FATAL, 0, _("Failed to load private key from file %s for File"
+                              " daemon \"%s\" in %s.\n"), filepath, me->hdr.name, configfile);
+                           OK = false;
+                        }
+                     }
+
                   } 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);
@@ -398,32 +409,42 @@ static int check_resources()
             }
          }
 
-         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));
+         /*
+          * Crypto recipients. We're always included as a recipient.
+          * The symmetric session key will be encrypted for each of these readers.
+          */
+         me->pki_recipients = New(alist(10, not_owned_by_alist));
+         if (me->pki_keypair) {
+            me->pki_recipients->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;
+         /* If additional keys have been specified, load them up */
+         if (me->pki_master_key_files) {
+            foreach_alist(filepath, me->pki_master_key_files) {
+               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;
+               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_recipients->append(keypair);
+
+                     /* Attempt to load a private key, if available */
+                     if (crypto_keypair_has_key(filepath)) {
+                        if (!crypto_keypair_load_key(keypair, filepath, NULL, NULL)) {
+                           Emsg3(M_FATAL, 0, _("Failed to load private key from file %s for File"
+                              " daemon \"%s\" in %s.\n"), filepath, me->hdr.name, configfile);
+                           OK = false;
+                        }
                      }
+
+                  } 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 442e6dd63c5ec1eff8fd542db84991c1cca83e69..515b7944d20f334932f760066dfa5963d246daba 100644 (file)
@@ -91,9 +91,9 @@ static RES_ITEM cli_items[] = {
    {"maximumnetworkbuffersize", store_pint, ITEM(res_client.max_network_buffer_size), 0, 0, 0},
    {"pkisignatures",         store_yesno,     ITEM(res_client.pki_sign), 1, ITEM_DEFAULT, 0},
    {"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},
+   {"pkikeypair",            store_dir,       ITEM(res_client.pki_keypair_file), 0, 0, 0},
+   {"pkisigner",             store_alist_str, ITEM(res_client.pki_signing_key_files), 0, 0, 0},
+   {"pkimasterkey",          store_alist_str, ITEM(res_client.pki_master_key_files), 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},
@@ -245,15 +245,16 @@ void free_resource(RES *sres, int type)
       if (res->res_client.FDaddrs) {
          free_addresses(res->res_client.FDaddrs);
       }
-      if (res->res_client.pki_keypairfile) { 
-         free(res->res_client.pki_keypairfile);
+
+      if (res->res_client.pki_keypair_file) { 
+         free(res->res_client.pki_keypair_file);
       }
       if (res->res_client.pki_keypair) {
-        crypto_keypair_free(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;
+
+      if (res->res_client.pki_signing_key_files) {
+         delete res->res_client.pki_signing_key_files;
       }
       if (res->res_client.pki_signers) {
          X509_KEYPAIR *keypair;
@@ -262,15 +263,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_master_key_files) {
+         delete res->res_client.pki_master_key_files;
       }
-      if (res->res_client.pki_readers) {
+
+      if (res->res_client.pki_recipients) {
          X509_KEYPAIR *keypair;
-         foreach_alist(keypair, res->res_client.pki_readers) {
+         foreach_alist(keypair, res->res_client.pki_recipients) {
             crypto_keypair_free(keypair);
          }
-         delete res->res_client.pki_signers;
+         delete res->res_client.pki_recipients;
       }
 
       if (res->res_client.tls_ctx) { 
@@ -354,8 +357,12 @@ void save_resource(int type, RES_ITEM *items, int pass)
             if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_dir.hdr.name)) == NULL) {
                Emsg1(M_ABORT, 0, _("Cannot find Client resource %s\n"), res_all.res_dir.hdr.name);
             }
-            res->res_client.pki_trustedkeys = res_all.res_client.pki_trustedkeys;
+            res->res_client.pki_signing_key_files = res_all.res_client.pki_signing_key_files;
+            res->res_client.pki_master_key_files = res_all.res_client.pki_master_key_files;
+
             res->res_client.pki_signers = res_all.res_client.pki_signers;
+            res->res_client.pki_recipients = res_all.res_client.pki_recipients;
+
             res->res_client.messages = res_all.res_client.messages;
             break;
          default:
index 5ba1737598ebb90605b5b42e989aae937c6ea505..e8ea53b27ba342c525493387f9db008a11c21bfd 100644 (file)
@@ -73,9 +73,9 @@ struct CLIENT {
    uint32_t max_network_buffer_size;  /* max network buf size */
    int pki_sign;                      /* Enable Data Integrity Verification via Digital Signatures */
    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 */
+   char *pki_keypair_file;            /* PKI Key Pair File */
+   alist *pki_signing_key_files;      /* PKI Signing Key Files */
+   alist *pki_master_key_files;       /* PKI Master Key Files */
    int tls_enable;                    /* Enable TLS */
    int tls_require;                   /* Require TLS */
    char *tls_ca_certfile;             /* TLS CA Certificate File */
@@ -85,7 +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 */
+   alist *pki_recipients;             /* Shared PKI Recipients */
    TLS_CONTEXT *tls_ctx;              /* Shared TLS Context */
 };
 
index 57dd05eca242d3a5fa5f96ccb0c95a4cf2b45de6..56e43efcbf591481be79782ba591c9e844188fb9 100644 (file)
@@ -177,7 +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;
+   jcr->pki_recipients = me->pki_recipients;
    dir->jcr = jcr;
    enable_backup_privileges(NULL, 1 /* ignore_errors */);
 
index 3ebd3ab4f45bb0640796b5a6714a009ad4293669..f83ea81e41cbd6a4c6deb2c3ee7a275468505ec9 100644 (file)
@@ -83,6 +83,7 @@ void do_restore(JCR *jcr)
    uint64_t alt_addr = 0;             /* Write address for alternative stream */
    intmax_t alt_size = 0;             /* Size of alternate stream */
    SIGNATURE *sig = NULL;             /* Cryptographic signature (if any) for file */
+   CRYPTO_SESSION *cs = NULL;         /* Cryptographic session data (if any) for file */
    int flags;                         /* Options for extract_data() */
    int stat;
    ATTR *attr;
@@ -218,12 +219,22 @@ void do_restore(JCR *jcr)
                   } else {
                      Dmsg1(100, "Signature good on %s\n", jcr->last_fname);
                   }
-                  crypto_sign_free(sig);
-                  sig = NULL;
                } else {
                   Jmsg1(jcr, M_ERROR, 0, _("Missing cryptographic signature for %s\n"), jcr->last_fname);
                }
             }
+
+            /* Free Signature */
+            if (sig) {
+               crypto_sign_free(sig);
+               sig = NULL;
+            }
+
+            if (cs) {
+               crypto_session_free(cs);
+               cs = NULL;
+            }
+
             Dmsg0(30, "Stop extracting.\n");
          } else if (is_bopen(&bfd)) {
             Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n"));
@@ -296,9 +307,24 @@ void do_restore(JCR *jcr)
 
       /* Data stream */
       case STREAM_ENCRYPTED_SESSION_DATA:
-         // TODO landonf: Implement
-         // sig = crypto_sign_decode(sd->msg, (size_t) sd->msglen);
          Dmsg1(30, "Stream=Encrypted Session Data, size: %d\n", sd->msglen);
+         /* Save session keys . */
+         switch(crypto_session_decode(sd->msg, (size_t) sd->msglen, jcr->pki_recipients, &cs)) {
+         case CRYPTO_ERROR_NONE:
+            /* Success */
+            break;
+         case CRYPTO_ERROR_NORECIPIENT:
+            Jmsg(jcr, M_ERROR, 0, _("Missing private key required to decrypt encrypted backup data."));
+            break;
+         case CRYPTO_ERROR_DECRYPTION:
+            Jmsg(jcr, M_ERROR, 0, _("Decrypt of the session key failed."));
+            break;
+         default:
+            /* Shouldn't happen */
+            Jmsg(jcr, M_ERROR, 0, _("An error occured while decoding encrypted session data stream."));
+            break;
+         }
+
          break;
 
       case STREAM_FILE_DATA:
index 152bf6577854c41a21f16b935472149f6368ccc7..413482063966aab5e6c0fbf042c5e5bedf5511a1 100644 (file)
@@ -236,7 +236,7 @@ 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 */
+   alist *pki_recipients;             /* Trusted Recipients */
    CRYPTO_SESSION *pki_session;       /* PKE Public Keys + Symmetric Session Keys */
    void *pki_session_encoded;         /* Cached DER-encoded copy of pki_session */
    size_t pki_session_encoded_size;   /* Size of DER-encoded pki_session */
index fb5efbaa0b75851a37e034ae058363a9ef4c4199..9ce98184570bb22711929cb3f4d07e348e0b5d8e 100644 (file)
@@ -272,8 +272,7 @@ struct Signature {
 /* Encryption Session Data */
 struct Crypto_Session {
    CryptoData *cryptoData;                        /* ASN.1 Structure */
-   EVP_CIPHER *openssl_cipher;                    /* OpenSSL Cipher Object */
-   unsigned char session_key[EVP_MAX_KEY_LENGTH]; /* Private symmetric session key */
+   unsigned char *session_key;                    /* Private symmetric session key */
    size_t session_key_len;                        /* Symmetric session key length */
 };
 
@@ -461,6 +460,55 @@ static int crypto_pem_callback_dispatch (char *buf, int size, int rwflag, void *
    return (ctx->pem_callback(buf, size, ctx->pem_userdata));
 }
 
+/*
+ * Check a PEM-encoded file
+ * for the existence of a private key.
+ * Returns: true if a private key is found
+ *          false otherwise
+ */
+bool crypto_keypair_has_key (const char *file) {
+   BIO *bio;
+   char *name = NULL;
+   char *header = NULL;
+   unsigned char *data = NULL;
+   bool retval = false;
+   long len;
+
+   if (!(bio = BIO_new_file(file, "r"))) {
+      openssl_post_errors(M_ERROR, _("Unable to open private key file"));
+      return false;
+   }
+
+   while (PEM_read_bio(bio, &name, &header, &data, &len)) {
+      /* We don't care what the data is, just that it's there */
+      OPENSSL_free(header);
+      OPENSSL_free(data);
+
+      /*
+       * PEM Header Found, check for a private key
+       * Due to OpenSSL limitations, we must specifically
+       * list supported PEM private key encodings.
+       */
+      if (strcmp(name, PEM_STRING_RSA) == 0
+            || strcmp(name, PEM_STRING_DSA) == 0
+            || strcmp(name, PEM_STRING_PKCS8) == 0
+            || strcmp(name, PEM_STRING_PKCS8INF) == 0) {
+         retval = true;
+         OPENSSL_free(name);
+         break;
+      } else {
+         OPENSSL_free(name);
+      }
+   }
+
+   /* Free our bio */
+   BIO_free(bio);
+
+   /* Post PEM-decoding error messages, if any */
+   openssl_post_errors(M_ERROR, _("Unable to read private key from file"));
+   return retval;
+}
+
 /*
  * Load a PEM-encoded private key.
  *  Returns: true on success
@@ -893,6 +941,10 @@ CRYPTO_SESSION *crypto_session_new (crypto_cipher_t cipher, alist *pubkeys)
       return NULL;
    }
 
+   /* Initialize required fields */
+   cs->session_key = NULL;
+
+   /* Allocate a CryptoData structure */
    cs->cryptoData = CryptoData_new();
 
    if (!cs->cryptoData) {
@@ -936,6 +988,7 @@ CRYPTO_SESSION *crypto_session_new (crypto_cipher_t cipher, alist *pubkeys)
 
    /* Generate a symmetric session key */
    cs->session_key_len = EVP_CIPHER_key_length(ec);
+   cs->session_key = (unsigned char *) malloc(cs->session_key_len);
    if (RAND_bytes(cs->session_key, cs->session_key_len) <= 0) {
       /* OpenSSL failure */
       crypto_session_free(cs);
@@ -955,6 +1008,7 @@ CRYPTO_SESSION *crypto_session_new (crypto_cipher_t cipher, alist *pubkeys)
       if (RAND_bytes(iv, iv_len) <= 0) {
          /* OpenSSL failure */
          crypto_session_free(cs);
+         free(iv);
          return NULL;
       }
 
@@ -962,8 +1016,10 @@ CRYPTO_SESSION *crypto_session_new (crypto_cipher_t cipher, alist *pubkeys)
       if (!M_ASN1_OCTET_STRING_set(cs->cryptoData->iv, iv, iv_len)) {
          /* Allocation failed in OpenSSL */
          crypto_session_free(cs);
+         free(iv);
          return NULL;
       }
+      free(iv);
    }
 
    /*
@@ -1054,11 +1110,15 @@ bool crypto_session_encode(CRYPTO_SESSION *cs, void *dest, size_t *length)
  *
  * Returns: CRYPTO_SESSION instance on success.
  *          NULL on failure.
+ * 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.
  */
-// TODO landonf: Unimplemented, requires a private key to decrypt session key
-CRYPTO_SESSION *crypto_session_decode(const void *data, size_t length)
+crypto_error_t crypto_session_decode(const void *data, size_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
@@ -1067,7 +1127,7 @@ CRYPTO_SESSION *crypto_session_decode(const void *data, size_t length)
 
    cs = (CRYPTO_SESSION *) malloc(sizeof(CRYPTO_SESSION));
    if (!cs) {
-      return NULL;
+      return CRYPTO_ERROR_INTERNAL;
    }
 
    /* d2i_CryptoData modifies the supplied pointer */
@@ -1076,10 +1136,67 @@ CRYPTO_SESSION *crypto_session_decode(const void *data, size_t length)
    if (!cs->cryptoData) {
       /* Allocation / Decoding failed in OpenSSL */
       openssl_post_errors(M_ERROR, _("CryptoData decoding failed"));
-      return NULL;
+      retval = CRYPTO_ERROR_INTERNAL;
+      goto err;
    }
 
-   return cs;
+   recipients = cs->cryptoData->recipientInfo;
+
+   /*
+    * Find a matching RecipientInfo structure for a supplied
+    * public key
+    */
+   foreach_alist(keypair, keypairs) {
+      RecipientInfo *ri;
+      int i;
+
+      /* Private key available? */
+      if (keypair->privkey == NULL) {
+         continue;
+      }
+
+      for (i = 0; i < sk_RecipientInfo_num(recipients); i++) {
+         ri = sk_RecipientInfo_value(recipients, i);
+
+         /* 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);
+
+            /* If we recieve a RecipientInfo structure that does not use
+             * RSA, return an error */
+            if (OBJ_obj2nid(ri->keyEncryptionAlgorithm) != NID_rsaEncryption) {
+               retval = CRYPTO_ERROR_INVALID_CRYPTO;
+               goto err;
+            }
+
+            /* 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);
+
+            if (cs->session_key_len <= 0) {
+               openssl_post_errors(M_ERROR, _("Failure decrypting the session key"));
+               retval = CRYPTO_ERROR_DECRYPTION;
+               goto err;
+            }
+
+            /* Session key successfully extracted, return the CRYPTO_SESSION structure */
+            *session = cs;
+            return CRYPTO_ERROR_NONE;
+         }
+      }
+   }
+
+   /* No matching recipient found */
+   return CRYPTO_ERROR_NORECIPIENT;
+
+err:
+   crypto_session_free(cs);
+   return retval;
 }
 
 /*
@@ -1087,7 +1204,12 @@ CRYPTO_SESSION *crypto_session_decode(const void *data, size_t length)
  */
 void crypto_session_free (CRYPTO_SESSION *cs)
 {
-   CryptoData_free(cs->cryptoData);
+   if (cs->cryptoData) {
+      CryptoData_free(cs->cryptoData);
+   }
+   if (cs->session_key){
+      free(cs->session_key);
+   }
    free(cs);
 }
 
@@ -1274,13 +1396,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; }
+bool crypto_keypair_has_key (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_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_SESSION *crypto_session_decode(const void *data, size_t length) { return NULL; }
+crypto_error_t crypto_session_decode(const void *data, size_t length, alist *keypairs, CRYPTO_SESSION **session) { return CRYPTO_ERROR_INTERNAL; }
 
 #endif /* HAVE_CRYPTO */
 
@@ -1347,10 +1470,16 @@ const char *crypto_strerror(crypto_error_t error) {
       return "No error";
    case CRYPTO_ERROR_NOSIGNER:
       return "Signer not found";
+   case CRYPTO_ERROR_NORECIPIENT:
+      return "Recipient not found";
    case CRYPTO_ERROR_INVALID_DIGEST:
       return "Unsupported digest algorithm";
+   case CRYPTO_ERROR_INVALID_CRYPTO:
+      return "Unsupported encryption algorithm";
    case CRYPTO_ERROR_BAD_SIGNATURE:
       return "Signature is invalid";
+   case CRYPTO_ERROR_DECRYPTION:
+      return "Decryption error";
    case CRYPTO_ERROR_INTERNAL:
       /* This shouldn't happen */
       return "Internal error";
index 04b8f934e8bfbc131750e4dbdecec895852b6d08..f681f349c9165354033b71970cbe419f2a8da12a 100644 (file)
@@ -74,9 +74,12 @@ typedef enum {
 typedef enum {
    CRYPTO_ERROR_NONE           = 0, /* No error */
    CRYPTO_ERROR_NOSIGNER       = 1, /* Signer not found */
-   CRYPTO_ERROR_INVALID_DIGEST = 2, /* Unsupported digest algorithm */
-   CRYPTO_ERROR_BAD_SIGNATURE  = 3, /* Signature is invalid */
-   CRYPTO_ERROR_INTERNAL       = 4  /* Internal Error */
+   CRYPTO_ERROR_NORECIPIENT    = 2, /* Recipient not found */
+   CRYPTO_ERROR_INVALID_DIGEST = 3, /* Unsupported digest algorithm */
+   CRYPTO_ERROR_INVALID_CRYPTO = 4, /* Unsupported encryption algorithm */
+   CRYPTO_ERROR_BAD_SIGNATURE  = 5, /* Signature is invalid */
+   CRYPTO_ERROR_DECRYPTION     = 6, /* Decryption error */
+   CRYPTO_ERROR_INTERNAL       = 7  /* Internal Error */
 } crypto_error_t;
 
 /* Message Digest Sizes */
index 7fdc4c574fb1b5a6bf7934aa52c3e675abb7601b..eb6d186345d08fee9574f232432273afacad13c6 100644 (file)
@@ -130,10 +130,12 @@ void               crypto_sign_free            (SIGNATURE *sig);
 CRYPTO_SESSION *   crypto_session_new          (crypto_cipher_t cipher, alist *pubkeys);
 void               crypto_session_free         (CRYPTO_SESSION *cs);
 bool               crypto_session_encode       (CRYPTO_SESSION *cs, void *dest, size_t *length);
+crypto_error_t     crypto_session_decode       (const void *data, size_t length, alist *keypairs, CRYPTO_SESSION **session); 
 CRYPTO_SESSION *   crypto_session_decode       (const void *data, size_t length);
 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);
+bool               crypto_keypair_has_key      (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);