cmsrecinfo.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 423 行

C
423
字号
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is the Netscape security libraries. *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. *//* * CMS recipientInfo methods. * * $Id: cmsrecinfo.c,v 1.3 2000/10/06 23:26:10 nelsonb%netscape.com Exp $ */#include "cmslocal.h"#include "cert.h"#include "key.h"#include "secasn1.h"#include "secitem.h"#include "secoid.h"#include "pk11func.h"#include "secerr.h"/* * NSS_CMSRecipientInfo_Create - create a recipientinfo * * we currently do not create KeyAgreement recipientinfos with multiple recipientEncryptedKeys * the certificate is supposed to have been verified by the caller */NSSCMSRecipientInfo *NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert){    NSSCMSRecipientInfo *ri;    void *mark;    SECOidTag certalgtag;    SECStatus rv;    NSSCMSRecipientEncryptedKey *rek;    NSSCMSOriginatorIdentifierOrKey *oiok;    unsigned long version;    SECItem *dummy;    PLArenaPool *poolp;    poolp = cmsg->poolp;    mark = PORT_ArenaMark(poolp);    ri = (NSSCMSRecipientInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSRecipientInfo));    if (ri == NULL)	goto loser;    ri->cmsg = cmsg;    ri->cert = CERT_DupCertificate(cert);    if (ri->cert == NULL)	goto loser;    certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));    switch (certalgtag) {    case SEC_OID_PKCS1_RSA_ENCRYPTION:	ri->recipientInfoType = NSSCMSRecipientInfoID_KeyTrans;	/* hardcoded issuerSN choice for now */	ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType = NSSCMSRecipientID_IssuerSN;	ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert);	if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) {	    rv = SECFailure;	    break;	}	break;    case SEC_OID_MISSI_KEA_DSS_OLD:    case SEC_OID_MISSI_KEA_DSS:    case SEC_OID_MISSI_KEA:	/* backward compatibility - this is not really a keytrans operation */	ri->recipientInfoType = NSSCMSRecipientInfoID_KeyTrans;	/* hardcoded issuerSN choice for now */	ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType = NSSCMSRecipientID_IssuerSN;	ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert);	if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) {	    rv = SECFailure;	    break;	}	break;    case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */	/* a key agreement op */	ri->recipientInfoType = NSSCMSRecipientInfoID_KeyAgree;	if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) {	    rv = SECFailure;	    break;	}	/* we do not support the case where multiple recipients 	 * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys	 * in this case, we would need to walk all the recipientInfos, take the	 * ones that do KeyAgreement algorithms and join them, algorithm by algorithm	 * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */	/* only epheremal-static Diffie-Hellman is supported for now	 * this is the only form of key agreement that provides potential anonymity	 * of the sender, plus we do not have to include certs in the message */	/* force single recipientEncryptedKey for now */	if ((rek = NSS_CMSRecipientEncryptedKey_Create(poolp)) == NULL) {	    rv = SECFailure;	    break;	}	/* hardcoded IssuerSN choice for now */	rek->recipientIdentifier.identifierType = NSSCMSKeyAgreeRecipientID_IssuerSN;	if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) {	    rv = SECFailure;	    break;	}	oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);	/* see RFC2630 12.3.1.1 */	oiok->identifierType = NSSCMSOriginatorIDOrKey_OriginatorPublicKey;	rv = NSS_CMSArray_Add(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys,				    (void *)rek);	break;    default:	/* other algorithms not supported yet */	/* NOTE that we do not support any KEK algorithm */	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);	rv = SECFailure;	break;    }    if (rv == SECFailure)	goto loser;    /* set version */    switch (ri->recipientInfoType) {    case NSSCMSRecipientInfoID_KeyTrans:	if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == NSSCMSRecipientID_IssuerSN)	    version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN;	else	    version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY;	dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version);	if (dummy == NULL)	    goto loser;	break;    case NSSCMSRecipientInfoID_KeyAgree:	dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version),						NSS_CMS_KEYAGREE_RECIPIENT_INFO_VERSION);	if (dummy == NULL)	    goto loser;	break;    case NSSCMSRecipientInfoID_KEK:	/* NOTE: this cannot happen as long as we do not support any KEK algorithm */	dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version),						NSS_CMS_KEK_RECIPIENT_INFO_VERSION);	if (dummy == NULL)	    goto loser;	break;        }    PORT_ArenaUnmark (poolp, mark);    return ri;loser:    PORT_ArenaRelease (poolp, mark);    return NULL;}voidNSS_CMSRecipientInfo_Destroy(NSSCMSRecipientInfo *ri){    /* version was allocated on the pool, so no need to destroy it */    /* issuerAndSN was allocated on the pool, so no need to destroy it */    if (ri->cert != NULL)	CERT_DestroyCertificate(ri->cert);    /* recipientInfo structure itself was allocated on the pool, so no need to destroy it */    /* we're done. */}intNSS_CMSRecipientInfo_GetVersion(NSSCMSRecipientInfo *ri){    unsigned long version;    SECItem *versionitem;    switch (ri->recipientInfoType) {    case NSSCMSRecipientInfoID_KeyTrans:	/* ignore subIndex */	versionitem = &(ri->ri.keyTransRecipientInfo.version);	break;    case NSSCMSRecipientInfoID_KEK:	/* ignore subIndex */	versionitem = &(ri->ri.kekRecipientInfo.version);	break;    case NSSCMSRecipientInfoID_KeyAgree:	versionitem = &(ri->ri.keyAgreeRecipientInfo.version);	break;    }    /* always take apart the SECItem */    if (SEC_ASN1DecodeInteger(versionitem, &version) != SECSuccess)	return 0;    else	return (int)version;}SECItem *NSS_CMSRecipientInfo_GetEncryptedKey(NSSCMSRecipientInfo *ri, int subIndex){    SECItem *enckey;    switch (ri->recipientInfoType) {    case NSSCMSRecipientInfoID_KeyTrans:	/* ignore subIndex */	enckey = &(ri->ri.keyTransRecipientInfo.encKey);	break;    case NSSCMSRecipientInfoID_KEK:	/* ignore subIndex */	enckey = &(ri->ri.kekRecipientInfo.encKey);	break;    case NSSCMSRecipientInfoID_KeyAgree:	enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);	break;    }    return enckey;}SECOidTagNSS_CMSRecipientInfo_GetKeyEncryptionAlgorithmTag(NSSCMSRecipientInfo *ri){    SECOidTag encalgtag;    switch (ri->recipientInfoType) {    case NSSCMSRecipientInfoID_KeyTrans:	encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));	break;    case NSSCMSRecipientInfoID_KeyAgree:	encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));	break;    case NSSCMSRecipientInfoID_KEK:	encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg));	break;    }    return encalgtag;}SECStatusNSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey, SECOidTag bulkalgtag){    CERTCertificate *cert;    SECOidTag certalgtag;    SECStatus rv;    SECItem *params = NULL;    NSSCMSRecipientEncryptedKey *rek;    NSSCMSOriginatorIdentifierOrKey *oiok;    PLArenaPool *poolp;    poolp = ri->cmsg->poolp;    cert = ri->cert;    PORT_Assert (cert != NULL);    if (cert == NULL)	return SECFailure;    /* XXX set ri->recipientInfoType to the proper value here */    /* or should we look if it's been set already ? */    certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));    switch (certalgtag) {    case SEC_OID_PKCS1_RSA_ENCRYPTION:	/* wrap the symkey */	if (NSS_CMSUtil_EncryptSymKey_RSA(poolp, cert, bulkkey, &ri->ri.keyTransRecipientInfo.encKey) != SECSuccess) {	    rv = SECFailure;	    break;	}	rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL);	break;    case SEC_OID_MISSI_KEA_DSS_OLD:    case SEC_OID_MISSI_KEA_DSS:    case SEC_OID_MISSI_KEA:	rv = NSS_CMSUtil_EncryptSymKey_MISSI(poolp, cert, bulkkey,					bulkalgtag,					&ri->ri.keyTransRecipientInfo.encKey,					&params, ri->cmsg->pwfn_arg);	if (rv != SECSuccess)	    break;	/* here, we DO need to pass the params to the wrap function because, with	 * RSA, there is no funny stuff going on with generation of IV vectors or so */	rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, params);	break;    case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */	rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0];	if (rek == NULL) {	    rv = SECFailure;	    break;	}	oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);	PORT_Assert(oiok->identifierType == NSSCMSOriginatorIDOrKey_OriginatorPublicKey);	/* see RFC2630 12.3.1.1 */	if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier,				    SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) {	    rv = SECFailure;	    break;	}	/* this will generate a key pair, compute the shared secret, */	/* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */	/* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */	rv = NSS_CMSUtil_EncryptSymKey_ESDH(poolp, cert, bulkkey,					&rek->encKey,					&ri->ri.keyAgreeRecipientInfo.ukm,					&ri->ri.keyAgreeRecipientInfo.keyEncAlg,					&oiok->id.originatorPublicKey.publicKey);	break;    default:	/* other algorithms not supported yet */	/* NOTE that we do not support any KEK algorithm */	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);	rv = SECFailure;	break;    }    return rv;}PK11SymKey *NSS_CMSRecipientInfo_UnwrapBulkKey(NSSCMSRecipientInfo *ri, int subIndex, 	CERTCertificate *cert, SECKEYPrivateKey *privkey, SECOidTag bulkalgtag){    PK11SymKey *bulkkey = NULL;    SECAlgorithmID *encalg;    SECOidTag encalgtag;    SECItem *enckey;    int error;    ri->cert = cert;	/* mark the recipientInfo so we can find it later */    switch (ri->recipientInfoType) {    case NSSCMSRecipientInfoID_KeyTrans:	encalg = &(ri->ri.keyTransRecipientInfo.keyEncAlg);	encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));	enckey = &(ri->ri.keyTransRecipientInfo.encKey); /* ignore subIndex */	switch (encalgtag) {	case SEC_OID_PKCS1_RSA_ENCRYPTION:	    /* RSA encryption algorithm: */	    /* get the symmetric (bulk) key by unwrapping it using our private key */	    bulkkey = NSS_CMSUtil_DecryptSymKey_RSA(privkey, enckey, bulkalgtag);	    break;	case SEC_OID_NETSCAPE_SMIME_KEA:	    /* FORTEZZA key exchange algorithm */	    /* the supplemental data is in the parameters of encalg */	    bulkkey = NSS_CMSUtil_DecryptSymKey_MISSI(privkey, enckey, encalg, bulkalgtag, ri->cmsg->pwfn_arg);	    break;	default:	    error = SEC_ERROR_UNSUPPORTED_KEYALG;	    goto loser;	}	break;    case NSSCMSRecipientInfoID_KeyAgree:	encalg = &(ri->ri.keyAgreeRecipientInfo.keyEncAlg);	encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));	enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);	switch (encalgtag) {	case SEC_OID_X942_DIFFIE_HELMAN_KEY:	    /* Diffie-Helman key exchange */	    /* XXX not yet implemented */	    /* XXX problem: SEC_OID_X942_DIFFIE_HELMAN_KEY points to a PKCS3 mechanism! */	    /* we support ephemeral-static DH only, so if the recipientinfo */	    /* has originator stuff in it, we punt (or do we? shouldn't be that hard...) */	    /* first, we derive the KEK (a symkey!) using a Derive operation, then we get the */	    /* content encryption key using a Unwrap op */	    /* the derive operation has to generate the key using the algorithm in RFC2631 */	    error = SEC_ERROR_UNSUPPORTED_KEYALG;	    break;	default:	    error = SEC_ERROR_UNSUPPORTED_KEYALG;	    goto loser;	}	break;    case NSSCMSRecipientInfoID_KEK:	encalg = &(ri->ri.kekRecipientInfo.keyEncAlg);	encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg));	enckey = &(ri->ri.kekRecipientInfo.encKey);	/* not supported yet */	error = SEC_ERROR_UNSUPPORTED_KEYALG;	goto loser;	break;    }    /* XXXX continue here */    return bulkkey;loser:    return NULL;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?