#include "cmslocal.h"
#include "secasn1.h"
#include "secitem.h"
#include "secoid.h"
#include "secerr.h"
#include "cryptohi.h"
#include <Security/SecCertificatePriv.h>
#include <Security/SecKeyPriv.h>
OSStatus
SecCmsUtilEncryptSymKeyRSA(PLArenaPool *poolp, SecCertificateRef cert,
SecSymmetricKeyRef bulkkey,
CSSM_DATA *encKey)
{
OSStatus rv;
SecPublicKeyRef publickey;
rv = SecCertificateCopyPublicKey(cert,&publickey);
if (publickey == NULL)
return SECFailure;
rv = SecCmsUtilEncryptSymKeyRSAPubKey(poolp, publickey, bulkkey, encKey);
CFRelease(publickey);
return rv;
}
OSStatus
SecCmsUtilEncryptSymKeyRSAPubKey(PLArenaPool *poolp,
SecPublicKeyRef publickey,
SecSymmetricKeyRef bulkkey, CSSM_DATA *encKey)
{
OSStatus rv;
unsigned int data_len;
void *mark = NULL;
mark = PORT_ArenaMark(poolp);
if (!mark)
goto loser;
#if 0
keyType = SECKEY_GetPublicKeyType(publickey);
PORT_Assert(keyType == rsaKey);
if (keyType != rsaKey) {
goto loser;
}
#endif
rv = SecKeyGetStrengthInBits(publickey, NULL, &data_len);
if (rv)
goto loser;
data_len >>= 2;
encKey->Data = (unsigned char*)PORT_ArenaAlloc(poolp, data_len);
encKey->Length = data_len;
if (encKey->Data == NULL)
goto loser;
rv = WRAP_PubWrapSymKey(publickey, bulkkey, encKey);
if (rv != SECSuccess)
goto loser;
PORT_ArenaUnmark(poolp, mark);
return SECSuccess;
loser:
if (mark) {
PORT_ArenaRelease(poolp, mark);
}
return SECFailure;
}
SecSymmetricKeyRef
SecCmsUtilDecryptSymKeyRSA(SecPrivateKeyRef privkey, CSSM_DATA *encKey, SECOidTag bulkalgtag)
{
return WRAP_PubUnwrapSymKey(privkey, encKey, bulkalgtag);
}
#if 0
extern const SEC_ASN1Template NSS_SMIMEKEAParamTemplateAllParams[];
OSStatus
SecCmsUtilEncryptSymKeyMISSI(PLArenaPool *poolp, SecCertificateRef cert, SecSymmetricKeyRef bulkkey,
SECOidTag symalgtag, CSSM_DATA *encKey, CSSM_DATA **pparams, void *pwfn_arg)
{
SECOidTag certalgtag;
SECOidTag encalgtag;
OSStatus rv = SECFailure;
CSSM_DATA *params = NULL;
OSStatus err;
SecSymmetricKeyRef tek;
SecCertificateRef ourCert;
SecPublicKeyRef ourPubKey, *publickey = NULL;
SecPrivateKeyRef ourPrivKey = NULL;
SecCmsKEATemplateSelector whichKEA = SecCmsKEAInvalid;
SecCmsSMIMEKEAParameters keaParams;
PLArenaPool *arena = NULL;
extern const SEC_ASN1Template *nss_cms_get_kea_template(SecCmsKEATemplateSelector whichTemplate);
const SECAlgorithmID *algid;
(void) memset(&keaParams, 0, sizeof(keaParams));
SecCertificateGetAlgorithmID(cert,&algid);
certalgtag = SECOID_GetAlgorithmTag(algid);
PORT_Assert(certalgtag == SEC_OID_MISSI_KEA_DSS_OLD ||
certalgtag == SEC_OID_MISSI_KEA_DSS ||
certalgtag == SEC_OID_MISSI_KEA);
#define SMIME_FORTEZZA_RA_LENGTH 128
#define SMIME_FORTEZZA_IV_LENGTH 24
#define SMIME_FORTEZZA_MAX_KEY_SIZE 256
encalgtag = SEC_OID_NETSCAPE_SMIME_KEA;
publickey = CERT_ExtractPublicKey(cert);
if (publickey == NULL) goto loser;
ourCert = PK11_FindBestKEAMatch(cert, pwfn_arg);
if (ourCert == NULL) goto loser;
arena = PORT_NewArena(1024);
if (arena == NULL)
goto loser;
ourPubKey = CERT_ExtractPublicKey(ourCert);
if (ourPubKey == NULL) {
CERT_DestroyCertificate(ourCert);
goto loser;
}
SECITEM_CopyItem(arena, &(keaParams.originatorKEAKey), &(ourPubKey->u.fortezza.KEAKey));
SECKEY_DestroyPublicKey(ourPubKey);
ourPubKey = NULL;
ourPrivKey = PK11_FindKeyByAnyCert(ourCert, pwfn_arg);
CERT_DestroyCertificate(ourCert);
if (!ourPrivKey)
goto loser;
keaParams.originatorRA.Data = (unsigned char *)PORT_ArenaAlloc(arena,SMIME_FORTEZZA_RA_LENGTH);
keaParams.originatorRA.Length = SMIME_FORTEZZA_RA_LENGTH;
tek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE,
&keaParams.originatorRA, NULL,
CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
CKA_WRAP, 0, pwfn_arg);
SECKEY_DestroyPublicKey(publickey);
SECKEY_DestroyPrivateKey(ourPrivKey);
publickey = NULL;
ourPrivKey = NULL;
if (!tek)
goto loser;
encKey->Data = (unsigned char *)PORT_ArenaAlloc(poolp, SMIME_FORTEZZA_MAX_KEY_SIZE);
encKey->Length = SMIME_FORTEZZA_MAX_KEY_SIZE;
if (encKey->Data == NULL) {
CFRelease(tek);
goto loser;
}
switch (PK11_AlgtagToMechanism(symalgtag)) {
case CKM_SKIPJACK_CBC64:
case CKM_SKIPJACK_ECB64:
case CKM_SKIPJACK_OFB64:
case CKM_SKIPJACK_CFB64:
case CKM_SKIPJACK_CFB32:
case CKM_SKIPJACK_CFB16:
case CKM_SKIPJACK_CFB8:
err = PK11_WrapSymKey(CKM_SKIPJACK_WRAP, NULL, tek, bulkkey, encKey);
whichKEA = SecCmsKEAUsesSkipjack;
break;
default:
keaParams.nonSkipjackIV.Data =
(unsigned char *)PORT_ArenaAlloc(arena, SMIME_FORTEZZA_IV_LENGTH);
keaParams.nonSkipjackIV.Length = SMIME_FORTEZZA_IV_LENGTH;
err = PK11_WrapSymKey(CKM_SKIPJACK_CBC64, &keaParams.nonSkipjackIV, tek, bulkkey, encKey);
if (err != SECSuccess)
goto loser;
if (encKey->Length != PK11_GetKeyLength(bulkkey)) {
if (SEC_ASN1EncodeInteger(arena, &keaParams.bulkKeySize, PK11_GetKeyLength(bulkkey)) == NULL)
err = (OSStatus)PORT_GetError();
else
whichKEA = SecCmsKEAUsesNonSkipjackWithPaddedEncKey;
}
else
whichKEA = SecCmsKEAUsesNonSkipjack;
break;
}
CFRelease(tek);
if (err != SECSuccess)
goto loser;
PORT_Assert(whichKEA != SecCmsKEAInvalid);
params = SEC_ASN1EncodeItem(poolp, NULL, &keaParams, nss_cms_get_kea_template(whichKEA));
if (params == NULL)
goto loser;
*pparams = params;
rv = SECSuccess;
loser:
if (arena)
PORT_FreeArena(arena, PR_FALSE);
if (publickey)
SECKEY_DestroyPublicKey(publickey);
if (ourPrivKey)
SECKEY_DestroyPrivateKey(ourPrivKey);
return rv;
}
SecSymmetricKeyRef
SecCmsUtilDecryptSymKeyMISSI(SecPrivateKeyRef privkey, CSSM_DATA *encKey, SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag, void *pwfn_arg)
{
OSStatus err;
CK_MECHANISM_TYPE bulkType;
SecSymmetricKeyRef tek;
SecPublicKeyRef originatorPubKey;
SecCmsSMIMEKEAParameters keaParams;
SecSymmetricKeyRef bulkkey;
int bulkLength;
(void) memset(&keaParams, 0, sizeof(keaParams));
err = SEC_ASN1DecodeItem(NULL, &keaParams, NSS_SMIMEKEAParamTemplateAllParams,
&(keyEncAlg->parameters));
if (err != SECSuccess)
goto loser;
originatorPubKey = PK11_MakeKEAPubKey(keaParams.originatorKEAKey.Data,
keaParams.originatorKEAKey.Length);
if (originatorPubKey == NULL)
goto loser;
tek = PK11_PubDerive(privkey, originatorPubKey, PR_FALSE,
&keaParams.originatorRA, NULL,
CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
CKA_WRAP, 0, pwfn_arg);
SECKEY_DestroyPublicKey(originatorPubKey);
if (tek == NULL)
goto loser;
bulkType = PK11_AlgtagToMechanism(bulkalgtag);
switch (bulkType) {
case CKM_SKIPJACK_CBC64:
case CKM_SKIPJACK_ECB64:
case CKM_SKIPJACK_OFB64:
case CKM_SKIPJACK_CFB64:
case CKM_SKIPJACK_CFB32:
case CKM_SKIPJACK_CFB16:
case CKM_SKIPJACK_CFB8:
bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_WRAP, NULL,
encKey, CKM_SKIPJACK_CBC64, CKA_DECRYPT, 0);
break;
default:
if (keaParams.bulkKeySize.Length > 0) {
err = SEC_ASN1DecodeItem(NULL, &bulkLength,
SEC_ASN1_GET(SEC_IntegerTemplate),
&keaParams.bulkKeySize);
if (err != SECSuccess)
goto loser;
}
bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_CBC64, &keaParams.nonSkipjackIV,
encKey, bulkType, CKA_DECRYPT, bulkLength);
break;
}
return bulkkey;
loser:
return NULL;
}
OSStatus
SecCmsUtilEncryptSymKeyESDH(PLArenaPool *poolp, SecCertificateRef cert, SecSymmetricKeyRef key,
CSSM_DATA *encKey, CSSM_DATA **ukm, SECAlgorithmID *keyEncAlg,
CSSM_DATA *pubKey)
{
#if 0
SECOidTag certalgtag;
SECOidTag encalgtag;
OSStatus rv;
CSSM_DATA *params = NULL;
int data_len;
OSStatus err;
SecSymmetricKeyRef tek;
SecCertificateRef ourCert;
SecPublicKeyRef ourPubKey;
SecCmsKEATemplateSelector whichKEA = SecCmsKEAInvalid;
certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
PORT_Assert(certalgtag == SEC_OID_X942_DIFFIE_HELMAN_KEY);
encalgtag = SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN;
publickey = CERT_ExtractPublicKey(cert);
if (publickey == NULL) goto loser;
ourCert = PK11_FindBestKEAMatch(cert, wincx);
if (ourCert == NULL) goto loser;
arena = PORT_NewArena(1024);
if (arena == NULL) goto loser;
ourPubKey = CERT_ExtractPublicKey(ourCert);
if (ourPubKey == NULL)
{
goto loser;
}
SECITEM_CopyItem(arena, pubKey, &(ourPubKey->u.fortezza.KEAKey));
SECKEY_DestroyPublicKey(ourPubKey);
ourPubKey = NULL;
ourPrivKey = PK11_FindKeyByAnyCert(ourCert,wincx);
CERT_DestroyCertificate(ourCert);
if (!ourPrivKey) goto loser;
if (ukm) {
ukm->Data = (unsigned char*)PORT_ArenaZAlloc(arena,);
ukm->Length = ;
}
kek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE,
ukm, NULL,
CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
CKA_WRAP, 0, wincx);
SECKEY_DestroyPublicKey(publickey);
SECKEY_DestroyPrivateKey(ourPrivKey);
publickey = NULL;
ourPrivKey = NULL;
if (!kek)
goto loser;
encKey->Data = (unsigned char*)PORT_ArenaAlloc(poolp, SMIME_FORTEZZA_MAX_KEY_SIZE);
encKey->Length = SMIME_FORTEZZA_MAX_KEY_SIZE;
if (encKey->Data == NULL)
{
CFRelease(kek);
goto loser;
}
switch (PK11_AlgtagToMechanism(enccinfo->encalg))
{
case CKM_SKIPJACK_CFB8:
err = PK11_WrapSymKey(CKM_CMS3DES_WRAP, NULL, kek, bulkkey, encKey);
whichKEA = SecCmsKEAUsesSkipjack;
break;
case CKM_SKIPJACK_CFB8:
err = PK11_WrapSymKey(CKM_CMSRC2_WRAP, NULL, kek, bulkkey, encKey);
whichKEA = SecCmsKEAUsesSkipjack;
break;
default:
err = SECFailure;
break;
}
CFRelease(kek);
if (err != SECSuccess)
goto loser;
PORT_Assert(whichKEA != SecCmsKEAInvalid);
params = SEC_ASN1EncodeItem(arena, NULL, &keaParams, sec_pkcs7_get_kea_template(whichKEA));
if (params == NULL)
goto loser;
rv = SECOID_SetAlgorithmID(poolp, keyEncAlg, SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN, params);
if (rv != SECSuccess)
goto loser;
loser:
if (arena) {
PORT_FreeArena(arena, PR_FALSE);
}
if (publickey) {
SECKEY_DestroyPublicKey(publickey);
}
if (ourPrivKey) {
SECKEY_DestroyPrivateKey(ourPrivKey);
}
#endif
return SECFailure;
}
SecSymmetricKeyRef
SecCmsUtilDecryptSymKeyESDH(SecPrivateKeyRef privkey, CSSM_DATA *encKey, SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag, void *pwfn_arg)
{
#if 0
OSStatus err;
CK_MECHANISM_TYPE bulkType;
SecSymmetricKeyRef tek;
SecPublicKeyRef originatorPubKey;
SecCmsSMIMEKEAParameters keaParams;
originatorPubKey = PK11_MakeKEAPubKey(keaParams.originatorKEAKey.Data,
keaParams.originatorKEAKey.Length);
if (originatorPubKey == NULL)
goto loser;
tek = PK11_PubDerive(privkey, originatorPubKey, PR_FALSE,
&keaParams.originatorRA, NULL,
CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
CKA_WRAP, 0, pwfn_arg);
SECKEY_DestroyPublicKey(originatorPubKey);
if (tek == NULL)
goto loser;
bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_WRAP, NULL,
encKey, CKM_SKIPJACK_CBC64, CKA_DECRYPT, 0);
return bulkkey;
loser:
#endif
return NULL;
}
#endif