+ 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;