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, ¶ms, 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 + -
显示快捷键?