Ejemplo n.º 1
0
/*
 * SecCmsEncryptedDataEncodeBeforeStart - do all the necessary things to a EncryptedData
 *     before encoding begins.
 *
 * In particular:
 *  - set the correct version value.
 *  - get the encryption key
 */
OSStatus
SecCmsEncryptedDataEncodeBeforeStart(SecCmsEncryptedDataRef encd)
{
    int version;
    SecSymmetricKeyRef bulkkey = NULL;
    CSSM_DATA_PTR dummy;
    SecCmsContentInfoRef cinfo = &(encd->contentInfo);

    if (SecCmsArrayIsEmpty((void **)encd->unprotectedAttr))
	version = SEC_CMS_ENCRYPTED_DATA_VERSION;
    else
	version = SEC_CMS_ENCRYPTED_DATA_VERSION_UPATTR;
    
    dummy = SEC_ASN1EncodeInteger (encd->cmsg->poolp, &(encd->version), version);
    if (dummy == NULL)
	return SECFailure;

    /* now get content encryption key (bulk key) by using our cmsg callback */
    if (encd->cmsg->decrypt_key_cb)
	bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, 
		    SecCmsContentInfoGetContentEncAlg(cinfo));
    if (bulkkey == NULL)
	return SECFailure;

    /* store the bulk key in the contentInfo so that the encoder can find it */
    SecCmsContentInfoSetBulkKey(cinfo, bulkkey);
    CFRelease(bulkkey); /* This assumes the decrypt_key_cb hands us a copy of the key --mb */

    return SECSuccess;
}
Ejemplo n.º 2
0
/*
 * SecCmsEncryptedDataDecodeBeforeData - find bulk key & set up decryption
 */
OSStatus
SecCmsEncryptedDataDecodeBeforeData(SecCmsEncryptedDataRef encd)
{
    SecSymmetricKeyRef bulkkey = NULL;
    SecCmsContentInfoRef cinfo;
    SECAlgorithmID *bulkalg;
    OSStatus rv = SECFailure;

    cinfo = &(encd->contentInfo);

    bulkalg = SecCmsContentInfoGetContentEncAlg(cinfo);

    if (encd->cmsg->decrypt_key_cb == NULL)	/* no callback? no key../ */
	goto loser;

    bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, bulkalg);
    if (bulkkey == NULL)
	/* no success finding a bulk key */
	goto loser;

    SecCmsContentInfoSetBulkKey(cinfo, bulkkey);

    cinfo->ciphcx = SecCmsCipherContextStartDecrypt(bulkkey, bulkalg);
    if (cinfo->ciphcx == NULL)
	goto loser;		/* error has been set by SecCmsCipherContextStartDecrypt */

#if 1
    // @@@ Not done yet
#else
    /* 
     * HACK ALERT!!
     * For PKCS5 Encryption Algorithms, the bulkkey is actually a different
     * structure.  Therefore, we need to set the bulkkey to the actual key 
     * prior to freeing it.
     */
    if (SEC_PKCS5IsAlgorithmPBEAlg(bulkalg)) {
	SEC_PKCS5KeyAndPassword *keyPwd = (SEC_PKCS5KeyAndPassword *)bulkkey;
	bulkkey = keyPwd->key;
    }
#endif

    /* we are done with (this) bulkkey now. */
    CFRelease(bulkkey);

    rv = SECSuccess;

loser:
    return rv;
}
Ejemplo n.º 3
0
/*
 * SecCmsEnvelopedDataDecodeBeforeData - find our recipientinfo, 
 * derive bulk key & set up our contentinfo
 */
OSStatus
SecCmsEnvelopedDataDecodeBeforeData(SecCmsEnvelopedData *envd)
{
    SecCmsRecipientInfo *ri;
    SecSymmetricKeyRef bulkkey = NULL;
    SECOidTag bulkalgtag;
    SECAlgorithmID *bulkalg;
    OSStatus rv = SECFailure;
    SecCmsContentInfo *cinfo;
    SecCmsRecipient **recipient_list = NULL;
    SecCmsRecipient *recipient;
    int rlIndex;

    if (SecCmsArrayCount((void **)envd->recipientInfos) == 0) {
	PORT_SetError(SEC_ERROR_BAD_DATA);
#if 0
	PORT_SetErrorString("No recipient data in envelope.");
#endif
	goto loser;
    }

    /* look if one of OUR cert's issuerSN is on the list of recipients, and if so,  */
    /* get the cert and private key for it right away */
    recipient_list = nss_cms_recipient_list_create(envd->recipientInfos);
    if (recipient_list == NULL)
	goto loser;

    /* what about multiple recipientInfos that match?
     * especially if, for some reason, we could not produce a bulk key with the first match?!
     * we could loop & feed partial recipient_list to PK11_FindCertAndKeyByRecipientList...
     * maybe later... */
    rlIndex = nss_cms_FindCertAndKeyByRecipientList(recipient_list, envd->cmsg->pwfn_arg);

    /* if that fails, then we're not an intended recipient and cannot decrypt */
    if (rlIndex < 0) {
	PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT);
#if 0
	PORT_SetErrorString("Cannot decrypt data because proper key cannot be found.");
#endif
	goto loser;
    }

    recipient = recipient_list[rlIndex];
    if (!recipient->cert || !recipient->privkey) {
	/* XXX should set an error code ?!? */
	goto loser;
    }
    /* get a pointer to "our" recipientinfo */
    ri = envd->recipientInfos[recipient->riIndex];

    cinfo = &(envd->contentInfo);
    bulkalgtag = SecCmsContentInfoGetContentEncAlgTag(cinfo);
    bulkkey = SecCmsRecipientInfoUnwrapBulkKey(ri,recipient->subIndex,
						    recipient->cert,
						    recipient->privkey,
						    bulkalgtag);
    if (bulkkey == NULL) {
	/* no success finding a bulk key */
	goto loser;
    }

    SecCmsContentInfoSetBulkKey(cinfo, bulkkey);
    // @@@ See 3401088 for details.  We need to CFRelease cinfo->bulkkey before recipient->privkey gets CFReleased. It's created with SecKeyCreate which is not safe currently.  If the private key's SecKeyRef from which we extracted the CSP gets CFRelease before the builkkey does we crash.  We should really fix SecKeyCreate which is a huge hack currently.  To work around this we add recipient->privkey to the cinfo so it gets when cinfo is destroyed.
    CFRetain(recipient->privkey);
    cinfo->privkey = recipient->privkey;

    bulkalg = SecCmsContentInfoGetContentEncAlg(cinfo);

    cinfo->ciphcx = SecCmsCipherContextStartDecrypt(bulkkey, bulkalg);
    if (cinfo->ciphcx == NULL)
	goto loser;		/* error has been set by SecCmsCipherContextStartDecrypt */

#if 1
    // @@@ Fix me
#else
    /* 
     * HACK ALERT!!
     * For PKCS5 Encryption Algorithms, the bulkkey is actually a different
     * structure.  Therefore, we need to set the bulkkey to the actual key 
     * prior to freeing it.
     */
    if (SEC_PKCS5IsAlgorithmPBEAlg(bulkalg)) {
	SEC_PKCS5KeyAndPassword *keyPwd = (SEC_PKCS5KeyAndPassword *)bulkkey;
	bulkkey = keyPwd->key;
    }
#endif

    rv = SECSuccess;

loser:
    if (bulkkey)
	CFRelease(bulkkey);
    if (recipient_list != NULL)
	nss_cms_recipient_list_destroy(recipient_list);
    return rv;
}
Ejemplo n.º 4
0
/*
 * SecCmsEnvelopedDataEncodeBeforeStart - prepare this envelopedData for encoding
 *
 * at this point, we need
 * - recipientinfos set up with recipient's certificates
 * - a content encryption algorithm (if none, 3DES will be used)
 *
 * this function will generate a random content encryption key (aka bulk key),
 * initialize the recipientinfos with certificate identification and wrap the bulk key
 * using the proper algorithm for every certificiate.
 * it will finally set the bulk algorithm and key so that the encode step can find it.
 */
OSStatus
SecCmsEnvelopedDataEncodeBeforeStart(SecCmsEnvelopedData *envd)
{
    int version;
    SecCmsRecipientInfo **recipientinfos;
    SecCmsContentInfo *cinfo;
    SecSymmetricKeyRef bulkkey = NULL;
    CSSM_ALGORITHMS algorithm;
    SECOidTag bulkalgtag;
    //CK_MECHANISM_TYPE type;
    //PK11SlotInfo *slot;
    OSStatus rv;
    CSSM_DATA *dummy;
    PLArenaPool *poolp;
    extern const SEC_ASN1Template SecCmsRecipientInfoTemplate[];
    void *mark = NULL;
    int i;

    poolp = envd->cmsg->poolp;
    cinfo = &(envd->contentInfo);

    recipientinfos = envd->recipientInfos;
    if (recipientinfos == NULL) {
	PORT_SetError(SEC_ERROR_BAD_DATA);
#if 0
	PORT_SetErrorString("Cannot find recipientinfos to encode.");
#endif
	goto loser;
    }

    version = SEC_CMS_ENVELOPED_DATA_VERSION_REG;
    if (envd->originatorInfo != NULL || envd->unprotectedAttr != NULL) {
	version = SEC_CMS_ENVELOPED_DATA_VERSION_ADV;
    } else {
	for (i = 0; recipientinfos[i] != NULL; i++) {
	    if (SecCmsRecipientInfoGetVersion(recipientinfos[i]) != 0) {
		version = SEC_CMS_ENVELOPED_DATA_VERSION_ADV;
		break;
	    }
	}
    }
    dummy = SEC_ASN1EncodeInteger(poolp, &(envd->version), version);
    if (dummy == NULL)
	goto loser;

    /* now we need to have a proper content encryption algorithm
     * on the SMIME level, we would figure one out by looking at SMIME capabilities
     * we cannot do that on our level, so if none is set already, we'll just go
     * with one of the mandatory algorithms (3DES) */
    if ((bulkalgtag = SecCmsContentInfoGetContentEncAlgTag(cinfo)) == SEC_OID_UNKNOWN) {
	rv = SecCmsContentInfoSetContentEncAlg(poolp, cinfo, SEC_OID_DES_EDE3_CBC, NULL, 168);
	if (rv != SECSuccess)
	    goto loser;
	bulkalgtag = SEC_OID_DES_EDE3_CBC;
    }

    algorithm = SECOID_FindyCssmAlgorithmByTag(bulkalgtag);
    if (!algorithm)
	goto loser;
    rv = SecKeyGenerate(NULL,	/* keychainRef */
		algorithm,
		SecCmsContentInfoGetBulkKeySize(cinfo),
		0,		/* contextHandle */
		CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
		CSSM_KEYATTR_EXTRACTABLE,
		NULL,		/* initialAccess */
		&bulkkey);
    if (rv)
	goto loser;

    mark = PORT_ArenaMark(poolp);

    /* Encrypt the bulk key with the public key of each recipient.  */
    for (i = 0; recipientinfos[i] != NULL; i++) {
	rv = SecCmsRecipientInfoWrapBulkKey(recipientinfos[i], bulkkey, bulkalgtag);
	if (rv != SECSuccess)
	    goto loser;	/* error has been set by SecCmsRecipientInfoEncryptBulkKey */
	    		/* could be: alg not supported etc. */
    }

    /* the recipientinfos are all finished. now sort them by DER for SET OF encoding */
    rv = SecCmsArraySortByDER((void **)envd->recipientInfos, SecCmsRecipientInfoTemplate, NULL);
    if (rv != SECSuccess)
	goto loser;	/* error has been set by SecCmsArraySortByDER */

    /* store the bulk key in the contentInfo so that the encoder can find it */
    SecCmsContentInfoSetBulkKey(cinfo, bulkkey);

    PORT_ArenaUnmark(poolp, mark);

    CFRelease(bulkkey);

    return SECSuccess;

loser:
    if (mark != NULL)
	PORT_ArenaRelease (poolp, mark);
    if (bulkkey)
	CFRelease(bulkkey);

    return SECFailure;
}