#include "cmslocal.h"
#include "SecAsn1Item.h"
#include "secoid.h"
#include "cryptohi.h"
#include <security_asn1/secasn1.h>
#include <security_asn1/secerr.h>
#include <security_asn1/secport.h>
#include <Security/SecCertificateInternal.h>
#include <Security/SecKeyPriv.h>
OSStatus
SecCmsUtilEncryptSymKeyRSA(PLArenaPool *poolp, SecCertificateRef cert,
SecSymmetricKeyRef bulkkey,
SecAsn1Item * encKey)
{
OSStatus rv;
SecPublicKeyRef publickey;
#if USE_CDSA_CRYPTO
rv = SecCertificateCopyPublicKey(cert,&publickey);
#else
publickey = SecCertificateCopyPublicKey(cert);
#endif
if (publickey == NULL)
return SECFailure;
rv = SecCmsUtilEncryptSymKeyRSAPubKey(poolp, publickey, bulkkey, encKey);
CFRelease(publickey);
return rv;
}
OSStatus
SecCmsUtilEncryptSymKeyRSAPubKey(PLArenaPool *poolp,
SecPublicKeyRef publickey,
SecSymmetricKeyRef bulkkey, SecAsn1Item * encKey)
{
OSStatus rv;
size_t 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
#if USE_CDSA_CRYPTO
rv = SecKeyGetStrengthInBits(publickey, NULL, &data_len);
if (rv)
goto loser;
data_len >>= 2;
#else
data_len = SecKeyGetSize(publickey, kSecKeyEncryptedDataSize);
#endif
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, SecAsn1Item * encKey, SECOidTag bulkalgtag)
{
return WRAP_PubUnwrapSymKey(privkey, encKey, bulkalgtag);
}
#if 0
extern const SecAsn1Template NSS_SMIMEKEAParamTemplateAllParams[];
OSStatus
SecCmsUtilEncryptSymKeyMISSI(PLArenaPool *poolp, SecCertificateRef cert, SecSymmetricKeyRef bulkkey,
SECOidTag symalgtag, SecAsn1Item * encKey, SecAsn1Item * *pparams, void *pwfn_arg)
{
SECOidTag certalgtag;
SECOidTag encalgtag;
OSStatus rv = SECFailure;
SecAsn1Item * params = NULL;
OSStatus err;
SecSymmetricKeyRef tek;
SecCertificateRef ourCert;
SecPublicKeyRef ourPubKey, *publickey = NULL;
SecPrivateKeyRef ourPrivKey = NULL;
SecCmsKEATemplateSelector whichKEA = SecCmsKEAInvalid;
SecCmsSMIMEKEAParameters keaParams;
PLArenaPool *arena = NULL;
const SECAlgorithmID *algid;
(void) memset(&keaParams, 0, sizeof(keaParams));
#if USE_CDSA_CRYPTO
SecCertificateGetAlgorithmID(cert,&algid);
#endif
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, SecAsn1Item * 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,
SecAsn1Item * encKey, SecAsn1Item * *ukm, SECAlgorithmID *keyEncAlg,
SecAsn1Item * pubKey)
{
#if 0
SECOidTag certalgtag;
SECOidTag encalgtag;
OSStatus rv;
SecAsn1Item * 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, SecAsn1Item * 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