1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/smime/cmsrecinfo.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,680 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/* 1.9 + * CMS recipientInfo methods. 1.10 + */ 1.11 + 1.12 +#include "cmslocal.h" 1.13 + 1.14 +#include "cert.h" 1.15 +#include "key.h" 1.16 +#include "secasn1.h" 1.17 +#include "secitem.h" 1.18 +#include "secoid.h" 1.19 +#include "pk11func.h" 1.20 +#include "secerr.h" 1.21 + 1.22 +PRBool 1.23 +nss_cmsrecipientinfo_usessubjectkeyid(NSSCMSRecipientInfo *ri) 1.24 +{ 1.25 + if (ri->recipientInfoType == NSSCMSRecipientInfoID_KeyTrans) { 1.26 + NSSCMSRecipientIdentifier *rid; 1.27 + rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier; 1.28 + if (rid->identifierType == NSSCMSRecipientID_SubjectKeyID) { 1.29 + return PR_TRUE; 1.30 + } 1.31 + } 1.32 + return PR_FALSE; 1.33 +} 1.34 + 1.35 +/* 1.36 + * NOTE: fakeContent marks CMSMessage structure which is only used as a carrier 1.37 + * of pwfn_arg and arena pools. In an ideal world, NSSCMSMessage would not have 1.38 + * been exported, and we would have added an ordinary enum to handle this 1.39 + * check. Unfortunatly wo don't have that luxury so we are overloading the 1.40 + * contentTypeTag field. NO code should every try to interpret this content tag 1.41 + * as a real OID tag, or use any fields other than pwfn_arg or poolp of this 1.42 + * CMSMessage for that matter */ 1.43 +static const SECOidData fakeContent; 1.44 +NSSCMSRecipientInfo * 1.45 +nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg, 1.46 + NSSCMSRecipientIDSelector type, 1.47 + CERTCertificate *cert, 1.48 + SECKEYPublicKey *pubKey, 1.49 + SECItem *subjKeyID, 1.50 + void* pwfn_arg, 1.51 + SECItem* DERinput) 1.52 +{ 1.53 + NSSCMSRecipientInfo *ri; 1.54 + void *mark; 1.55 + SECOidTag certalgtag; 1.56 + SECStatus rv = SECSuccess; 1.57 + NSSCMSRecipientEncryptedKey *rek; 1.58 + NSSCMSOriginatorIdentifierOrKey *oiok; 1.59 + unsigned long version; 1.60 + SECItem *dummy; 1.61 + PLArenaPool *poolp; 1.62 + CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL; 1.63 + NSSCMSRecipientIdentifier *rid; 1.64 + extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[]; 1.65 + 1.66 + if (!cmsg) { 1.67 + /* a CMSMessage wasn't supplied, create a fake one to hold the pwfunc 1.68 + * and a private arena pool */ 1.69 + cmsg = NSS_CMSMessage_Create(NULL); 1.70 + cmsg->pwfn_arg = pwfn_arg; 1.71 + /* mark it as a special cms message */ 1.72 + cmsg->contentInfo.contentTypeTag = (SECOidData *)&fakeContent; 1.73 + } 1.74 + 1.75 + poolp = cmsg->poolp; 1.76 + 1.77 + mark = PORT_ArenaMark(poolp); 1.78 + 1.79 + ri = (NSSCMSRecipientInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSRecipientInfo)); 1.80 + if (ri == NULL) 1.81 + goto loser; 1.82 + 1.83 + ri->cmsg = cmsg; 1.84 + 1.85 + if (DERinput) { 1.86 + /* decode everything from DER */ 1.87 + SECItem newinput; 1.88 + SECStatus rv = SECITEM_CopyItem(poolp, &newinput, DERinput); 1.89 + if (SECSuccess != rv) 1.90 + goto loser; 1.91 + rv = SEC_QuickDERDecodeItem(poolp, ri, NSSCMSRecipientInfoTemplate, &newinput); 1.92 + if (SECSuccess != rv) 1.93 + goto loser; 1.94 + } 1.95 + 1.96 + switch (type) { 1.97 + case NSSCMSRecipientID_IssuerSN: 1.98 + { 1.99 + ri->cert = CERT_DupCertificate(cert); 1.100 + if (NULL == ri->cert) 1.101 + goto loser; 1.102 + spki = &(cert->subjectPublicKeyInfo); 1.103 + break; 1.104 + } 1.105 + 1.106 + case NSSCMSRecipientID_SubjectKeyID: 1.107 + { 1.108 + PORT_Assert(pubKey); 1.109 + spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(pubKey); 1.110 + break; 1.111 + } 1.112 + 1.113 + case NSSCMSRecipientID_BrandNew: 1.114 + goto done; 1.115 + break; 1.116 + 1.117 + default: 1.118 + /* unkown type */ 1.119 + goto loser; 1.120 + break; 1.121 + } 1.122 + 1.123 + certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm)); 1.124 + 1.125 + rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier; 1.126 + switch (certalgtag) { 1.127 + case SEC_OID_PKCS1_RSA_ENCRYPTION: 1.128 + ri->recipientInfoType = NSSCMSRecipientInfoID_KeyTrans; 1.129 + rid->identifierType = type; 1.130 + if (type == NSSCMSRecipientID_IssuerSN) { 1.131 + rid->id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert); 1.132 + if (rid->id.issuerAndSN == NULL) { 1.133 + break; 1.134 + } 1.135 + } else if (type == NSSCMSRecipientID_SubjectKeyID){ 1.136 + NSSCMSKeyTransRecipientInfoEx *riExtra; 1.137 + 1.138 + rid->id.subjectKeyID = PORT_ArenaNew(poolp, SECItem); 1.139 + if (rid->id.subjectKeyID == NULL) { 1.140 + rv = SECFailure; 1.141 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.142 + break; 1.143 + } 1.144 + SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID); 1.145 + if (rid->id.subjectKeyID->data == NULL) { 1.146 + rv = SECFailure; 1.147 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.148 + break; 1.149 + } 1.150 + riExtra = &ri->ri.keyTransRecipientInfoEx; 1.151 + riExtra->version = 0; 1.152 + riExtra->pubKey = SECKEY_CopyPublicKey(pubKey); 1.153 + if (riExtra->pubKey == NULL) { 1.154 + rv = SECFailure; 1.155 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.156 + break; 1.157 + } 1.158 + } else { 1.159 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.160 + rv = SECFailure; 1.161 + } 1.162 + break; 1.163 + case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ 1.164 + PORT_Assert(type == NSSCMSRecipientID_IssuerSN); 1.165 + if (type != NSSCMSRecipientID_IssuerSN) { 1.166 + rv = SECFailure; 1.167 + break; 1.168 + } 1.169 + /* a key agreement op */ 1.170 + ri->recipientInfoType = NSSCMSRecipientInfoID_KeyAgree; 1.171 + 1.172 + if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) { 1.173 + rv = SECFailure; 1.174 + break; 1.175 + } 1.176 + /* we do not support the case where multiple recipients 1.177 + * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys 1.178 + * in this case, we would need to walk all the recipientInfos, take the 1.179 + * ones that do KeyAgreement algorithms and join them, algorithm by algorithm 1.180 + * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */ 1.181 + 1.182 + /* only epheremal-static Diffie-Hellman is supported for now 1.183 + * this is the only form of key agreement that provides potential anonymity 1.184 + * of the sender, plus we do not have to include certs in the message */ 1.185 + 1.186 + /* force single recipientEncryptedKey for now */ 1.187 + if ((rek = NSS_CMSRecipientEncryptedKey_Create(poolp)) == NULL) { 1.188 + rv = SECFailure; 1.189 + break; 1.190 + } 1.191 + 1.192 + /* hardcoded IssuerSN choice for now */ 1.193 + rek->recipientIdentifier.identifierType = NSSCMSKeyAgreeRecipientID_IssuerSN; 1.194 + if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) { 1.195 + rv = SECFailure; 1.196 + break; 1.197 + } 1.198 + 1.199 + oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); 1.200 + 1.201 + /* see RFC2630 12.3.1.1 */ 1.202 + oiok->identifierType = NSSCMSOriginatorIDOrKey_OriginatorPublicKey; 1.203 + 1.204 + rv = NSS_CMSArray_Add(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys, 1.205 + (void *)rek); 1.206 + 1.207 + break; 1.208 + default: 1.209 + /* other algorithms not supported yet */ 1.210 + /* NOTE that we do not support any KEK algorithm */ 1.211 + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 1.212 + rv = SECFailure; 1.213 + break; 1.214 + } 1.215 + 1.216 + if (rv == SECFailure) 1.217 + goto loser; 1.218 + 1.219 + /* set version */ 1.220 + switch (ri->recipientInfoType) { 1.221 + case NSSCMSRecipientInfoID_KeyTrans: 1.222 + if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == NSSCMSRecipientID_IssuerSN) 1.223 + version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN; 1.224 + else 1.225 + version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY; 1.226 + dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version); 1.227 + if (dummy == NULL) 1.228 + goto loser; 1.229 + break; 1.230 + case NSSCMSRecipientInfoID_KeyAgree: 1.231 + dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version), 1.232 + NSS_CMS_KEYAGREE_RECIPIENT_INFO_VERSION); 1.233 + if (dummy == NULL) 1.234 + goto loser; 1.235 + break; 1.236 + case NSSCMSRecipientInfoID_KEK: 1.237 + /* NOTE: this cannot happen as long as we do not support any KEK algorithm */ 1.238 + dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version), 1.239 + NSS_CMS_KEK_RECIPIENT_INFO_VERSION); 1.240 + if (dummy == NULL) 1.241 + goto loser; 1.242 + break; 1.243 + 1.244 + } 1.245 + 1.246 +done: 1.247 + PORT_ArenaUnmark (poolp, mark); 1.248 + if (freeSpki) 1.249 + SECKEY_DestroySubjectPublicKeyInfo(freeSpki); 1.250 + return ri; 1.251 + 1.252 +loser: 1.253 + if (ri && ri->cert) { 1.254 + CERT_DestroyCertificate(ri->cert); 1.255 + } 1.256 + if (freeSpki) { 1.257 + SECKEY_DestroySubjectPublicKeyInfo(freeSpki); 1.258 + } 1.259 + PORT_ArenaRelease (poolp, mark); 1.260 + if (cmsg->contentInfo.contentTypeTag == &fakeContent) { 1.261 + NSS_CMSMessage_Destroy(cmsg); 1.262 + } 1.263 + return NULL; 1.264 +} 1.265 + 1.266 +/* 1.267 + * NSS_CMSRecipientInfo_Create - create a recipientinfo 1.268 + * 1.269 + * we currently do not create KeyAgreement recipientinfos with multiple 1.270 + * recipientEncryptedKeys the certificate is supposed to have been 1.271 + * verified by the caller 1.272 + */ 1.273 +NSSCMSRecipientInfo * 1.274 +NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert) 1.275 +{ 1.276 + return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_IssuerSN, cert, 1.277 + NULL, NULL, NULL, NULL); 1.278 +} 1.279 + 1.280 +NSSCMSRecipientInfo * 1.281 +NSS_CMSRecipientInfo_CreateNew(void* pwfn_arg) 1.282 +{ 1.283 + return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL, 1.284 + NULL, NULL, pwfn_arg, NULL); 1.285 +} 1.286 + 1.287 +NSSCMSRecipientInfo * 1.288 +NSS_CMSRecipientInfo_CreateFromDER(SECItem* input, void* pwfn_arg) 1.289 +{ 1.290 + return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL, 1.291 + NULL, NULL, pwfn_arg, input); 1.292 +} 1.293 + 1.294 + 1.295 +NSSCMSRecipientInfo * 1.296 +NSS_CMSRecipientInfo_CreateWithSubjKeyID(NSSCMSMessage *cmsg, 1.297 + SECItem *subjKeyID, 1.298 + SECKEYPublicKey *pubKey) 1.299 +{ 1.300 + return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_SubjectKeyID, 1.301 + NULL, pubKey, subjKeyID, NULL, NULL); 1.302 +} 1.303 + 1.304 +NSSCMSRecipientInfo * 1.305 +NSS_CMSRecipientInfo_CreateWithSubjKeyIDFromCert(NSSCMSMessage *cmsg, 1.306 + CERTCertificate *cert) 1.307 +{ 1.308 + SECKEYPublicKey *pubKey = NULL; 1.309 + SECItem subjKeyID = {siBuffer, NULL, 0}; 1.310 + NSSCMSRecipientInfo *retVal = NULL; 1.311 + 1.312 + if (!cmsg || !cert) { 1.313 + return NULL; 1.314 + } 1.315 + pubKey = CERT_ExtractPublicKey(cert); 1.316 + if (!pubKey) { 1.317 + goto done; 1.318 + } 1.319 + if (CERT_FindSubjectKeyIDExtension(cert, &subjKeyID) != SECSuccess || 1.320 + subjKeyID.data == NULL) { 1.321 + goto done; 1.322 + } 1.323 + retVal = NSS_CMSRecipientInfo_CreateWithSubjKeyID(cmsg, &subjKeyID, pubKey); 1.324 +done: 1.325 + if (pubKey) 1.326 + SECKEY_DestroyPublicKey(pubKey); 1.327 + 1.328 + if (subjKeyID.data) 1.329 + SECITEM_FreeItem(&subjKeyID, PR_FALSE); 1.330 + 1.331 + return retVal; 1.332 +} 1.333 + 1.334 +void 1.335 +NSS_CMSRecipientInfo_Destroy(NSSCMSRecipientInfo *ri) 1.336 +{ 1.337 + if (!ri) { 1.338 + return; 1.339 + } 1.340 + /* version was allocated on the pool, so no need to destroy it */ 1.341 + /* issuerAndSN was allocated on the pool, so no need to destroy it */ 1.342 + if (ri->cert != NULL) 1.343 + CERT_DestroyCertificate(ri->cert); 1.344 + 1.345 + if (nss_cmsrecipientinfo_usessubjectkeyid(ri)) { 1.346 + NSSCMSKeyTransRecipientInfoEx *extra; 1.347 + extra = &ri->ri.keyTransRecipientInfoEx; 1.348 + if (extra->pubKey) 1.349 + SECKEY_DestroyPublicKey(extra->pubKey); 1.350 + } 1.351 + if (ri->cmsg && ri->cmsg->contentInfo.contentTypeTag == &fakeContent) { 1.352 + NSS_CMSMessage_Destroy(ri->cmsg); 1.353 + } 1.354 + 1.355 + /* we're done. */ 1.356 +} 1.357 + 1.358 +int 1.359 +NSS_CMSRecipientInfo_GetVersion(NSSCMSRecipientInfo *ri) 1.360 +{ 1.361 + unsigned long version; 1.362 + SECItem *versionitem = NULL; 1.363 + 1.364 + switch (ri->recipientInfoType) { 1.365 + case NSSCMSRecipientInfoID_KeyTrans: 1.366 + /* ignore subIndex */ 1.367 + versionitem = &(ri->ri.keyTransRecipientInfo.version); 1.368 + break; 1.369 + case NSSCMSRecipientInfoID_KEK: 1.370 + /* ignore subIndex */ 1.371 + versionitem = &(ri->ri.kekRecipientInfo.version); 1.372 + break; 1.373 + case NSSCMSRecipientInfoID_KeyAgree: 1.374 + versionitem = &(ri->ri.keyAgreeRecipientInfo.version); 1.375 + break; 1.376 + } 1.377 + 1.378 + PORT_Assert(versionitem); 1.379 + if (versionitem == NULL) 1.380 + return 0; 1.381 + 1.382 + /* always take apart the SECItem */ 1.383 + if (SEC_ASN1DecodeInteger(versionitem, &version) != SECSuccess) 1.384 + return 0; 1.385 + else 1.386 + return (int)version; 1.387 +} 1.388 + 1.389 +SECItem * 1.390 +NSS_CMSRecipientInfo_GetEncryptedKey(NSSCMSRecipientInfo *ri, int subIndex) 1.391 +{ 1.392 + SECItem *enckey = NULL; 1.393 + 1.394 + switch (ri->recipientInfoType) { 1.395 + case NSSCMSRecipientInfoID_KeyTrans: 1.396 + /* ignore subIndex */ 1.397 + enckey = &(ri->ri.keyTransRecipientInfo.encKey); 1.398 + break; 1.399 + case NSSCMSRecipientInfoID_KEK: 1.400 + /* ignore subIndex */ 1.401 + enckey = &(ri->ri.kekRecipientInfo.encKey); 1.402 + break; 1.403 + case NSSCMSRecipientInfoID_KeyAgree: 1.404 + enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey); 1.405 + break; 1.406 + } 1.407 + return enckey; 1.408 +} 1.409 + 1.410 + 1.411 +SECOidTag 1.412 +NSS_CMSRecipientInfo_GetKeyEncryptionAlgorithmTag(NSSCMSRecipientInfo *ri) 1.413 +{ 1.414 + SECOidTag encalgtag = SEC_OID_UNKNOWN; /* an invalid encryption alg */ 1.415 + 1.416 + switch (ri->recipientInfoType) { 1.417 + case NSSCMSRecipientInfoID_KeyTrans: 1.418 + encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg)); 1.419 + break; 1.420 + case NSSCMSRecipientInfoID_KeyAgree: 1.421 + encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg)); 1.422 + break; 1.423 + case NSSCMSRecipientInfoID_KEK: 1.424 + encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg)); 1.425 + break; 1.426 + } 1.427 + return encalgtag; 1.428 +} 1.429 + 1.430 +SECStatus 1.431 +NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey, 1.432 + SECOidTag bulkalgtag) 1.433 +{ 1.434 + CERTCertificate *cert; 1.435 + SECOidTag certalgtag; 1.436 + SECStatus rv = SECSuccess; 1.437 + NSSCMSRecipientEncryptedKey *rek; 1.438 + NSSCMSOriginatorIdentifierOrKey *oiok; 1.439 + CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL; 1.440 + PLArenaPool *poolp; 1.441 + NSSCMSKeyTransRecipientInfoEx *extra = NULL; 1.442 + PRBool usesSubjKeyID; 1.443 + 1.444 + poolp = ri->cmsg->poolp; 1.445 + cert = ri->cert; 1.446 + usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri); 1.447 + if (cert) { 1.448 + spki = &cert->subjectPublicKeyInfo; 1.449 + certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm)); 1.450 + } else if (usesSubjKeyID) { 1.451 + extra = &ri->ri.keyTransRecipientInfoEx; 1.452 + /* sanity check */ 1.453 + PORT_Assert(extra->pubKey); 1.454 + if (!extra->pubKey) { 1.455 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.456 + return SECFailure; 1.457 + } 1.458 + spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(extra->pubKey); 1.459 + certalgtag = SECOID_GetAlgorithmTag(&spki->algorithm); 1.460 + } else { 1.461 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.462 + return SECFailure; 1.463 + } 1.464 + 1.465 + /* XXX set ri->recipientInfoType to the proper value here */ 1.466 + /* or should we look if it's been set already ? */ 1.467 + 1.468 + certalgtag = SECOID_GetAlgorithmTag(&spki->algorithm); 1.469 + switch (certalgtag) { 1.470 + case SEC_OID_PKCS1_RSA_ENCRYPTION: 1.471 + /* wrap the symkey */ 1.472 + if (cert) { 1.473 + rv = NSS_CMSUtil_EncryptSymKey_RSA(poolp, cert, bulkkey, 1.474 + &ri->ri.keyTransRecipientInfo.encKey); 1.475 + if (rv != SECSuccess) 1.476 + break; 1.477 + } else if (usesSubjKeyID) { 1.478 + PORT_Assert(extra != NULL); 1.479 + rv = NSS_CMSUtil_EncryptSymKey_RSAPubKey(poolp, extra->pubKey, 1.480 + bulkkey, &ri->ri.keyTransRecipientInfo.encKey); 1.481 + if (rv != SECSuccess) 1.482 + break; 1.483 + } 1.484 + 1.485 + rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL); 1.486 + break; 1.487 + case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ 1.488 + rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0]; 1.489 + if (rek == NULL) { 1.490 + rv = SECFailure; 1.491 + break; 1.492 + } 1.493 + 1.494 + oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); 1.495 + PORT_Assert(oiok->identifierType == NSSCMSOriginatorIDOrKey_OriginatorPublicKey); 1.496 + 1.497 + /* see RFC2630 12.3.1.1 */ 1.498 + if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier, 1.499 + SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) { 1.500 + rv = SECFailure; 1.501 + break; 1.502 + } 1.503 + 1.504 + /* this will generate a key pair, compute the shared secret, */ 1.505 + /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */ 1.506 + /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */ 1.507 + rv = NSS_CMSUtil_EncryptSymKey_ESDH(poolp, cert, bulkkey, 1.508 + &rek->encKey, 1.509 + &ri->ri.keyAgreeRecipientInfo.ukm, 1.510 + &ri->ri.keyAgreeRecipientInfo.keyEncAlg, 1.511 + &oiok->id.originatorPublicKey.publicKey); 1.512 + 1.513 + break; 1.514 + default: 1.515 + /* other algorithms not supported yet */ 1.516 + /* NOTE that we do not support any KEK algorithm */ 1.517 + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 1.518 + rv = SECFailure; 1.519 + break; 1.520 + } 1.521 + if (freeSpki) 1.522 + SECKEY_DestroySubjectPublicKeyInfo(freeSpki); 1.523 + 1.524 + return rv; 1.525 +} 1.526 + 1.527 +PK11SymKey * 1.528 +NSS_CMSRecipientInfo_UnwrapBulkKey(NSSCMSRecipientInfo *ri, int subIndex, 1.529 + CERTCertificate *cert, SECKEYPrivateKey *privkey, SECOidTag bulkalgtag) 1.530 +{ 1.531 + PK11SymKey *bulkkey = NULL; 1.532 + SECAlgorithmID *encalg; 1.533 + SECOidTag encalgtag; 1.534 + SECItem *enckey; 1.535 + int error; 1.536 + 1.537 + ri->cert = CERT_DupCertificate(cert); 1.538 + /* mark the recipientInfo so we can find it later */ 1.539 + 1.540 + switch (ri->recipientInfoType) { 1.541 + case NSSCMSRecipientInfoID_KeyTrans: 1.542 + encalg = &(ri->ri.keyTransRecipientInfo.keyEncAlg); 1.543 + encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg)); 1.544 + enckey = &(ri->ri.keyTransRecipientInfo.encKey); /* ignore subIndex */ 1.545 + switch (encalgtag) { 1.546 + case SEC_OID_PKCS1_RSA_ENCRYPTION: 1.547 + /* RSA encryption algorithm: */ 1.548 + /* get the symmetric (bulk) key by unwrapping it using our private key */ 1.549 + bulkkey = NSS_CMSUtil_DecryptSymKey_RSA(privkey, enckey, bulkalgtag); 1.550 + break; 1.551 + default: 1.552 + error = SEC_ERROR_UNSUPPORTED_KEYALG; 1.553 + goto loser; 1.554 + } 1.555 + break; 1.556 + case NSSCMSRecipientInfoID_KeyAgree: 1.557 + encalg = &(ri->ri.keyAgreeRecipientInfo.keyEncAlg); 1.558 + encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg)); 1.559 + enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey); 1.560 + switch (encalgtag) { 1.561 + case SEC_OID_X942_DIFFIE_HELMAN_KEY: 1.562 + /* Diffie-Helman key exchange */ 1.563 + /* XXX not yet implemented */ 1.564 + /* XXX problem: SEC_OID_X942_DIFFIE_HELMAN_KEY points to a PKCS3 mechanism! */ 1.565 + /* we support ephemeral-static DH only, so if the recipientinfo */ 1.566 + /* has originator stuff in it, we punt (or do we? shouldn't be that hard...) */ 1.567 + /* first, we derive the KEK (a symkey!) using a Derive operation, then we get the */ 1.568 + /* content encryption key using a Unwrap op */ 1.569 + /* the derive operation has to generate the key using the algorithm in RFC2631 */ 1.570 + error = SEC_ERROR_UNSUPPORTED_KEYALG; 1.571 + goto loser; 1.572 + break; 1.573 + default: 1.574 + error = SEC_ERROR_UNSUPPORTED_KEYALG; 1.575 + goto loser; 1.576 + } 1.577 + break; 1.578 + case NSSCMSRecipientInfoID_KEK: 1.579 + encalg = &(ri->ri.kekRecipientInfo.keyEncAlg); 1.580 + encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg)); 1.581 + enckey = &(ri->ri.kekRecipientInfo.encKey); 1.582 + /* not supported yet */ 1.583 + error = SEC_ERROR_UNSUPPORTED_KEYALG; 1.584 + goto loser; 1.585 + break; 1.586 + } 1.587 + /* XXXX continue here */ 1.588 + return bulkkey; 1.589 + 1.590 +loser: 1.591 + PORT_SetError(error); 1.592 + return NULL; 1.593 +} 1.594 + 1.595 +SECStatus NSS_CMSRecipientInfo_GetCertAndKey(NSSCMSRecipientInfo *ri, 1.596 + CERTCertificate** retcert, 1.597 + SECKEYPrivateKey** retkey) 1.598 +{ 1.599 + CERTCertificate* cert = NULL; 1.600 + NSSCMSRecipient** recipients = NULL; 1.601 + NSSCMSRecipientInfo* recipientInfos[2]; 1.602 + SECStatus rv = SECSuccess; 1.603 + SECKEYPrivateKey* key = NULL; 1.604 + 1.605 + if (!ri) 1.606 + return SECFailure; 1.607 + 1.608 + if (!retcert && !retkey) { 1.609 + /* nothing requested, nothing found, success */ 1.610 + return SECSuccess; 1.611 + } 1.612 + 1.613 + if (retcert) { 1.614 + *retcert = NULL; 1.615 + } 1.616 + if (retkey) { 1.617 + *retkey = NULL; 1.618 + } 1.619 + 1.620 + if (ri->cert) { 1.621 + cert = CERT_DupCertificate(ri->cert); 1.622 + if (!cert) { 1.623 + rv = SECFailure; 1.624 + } 1.625 + } 1.626 + if (SECSuccess == rv && !cert) { 1.627 + /* we don't have the cert, we have to look for it */ 1.628 + /* first build an NSS_CMSRecipient */ 1.629 + recipientInfos[0] = ri; 1.630 + recipientInfos[1] = NULL; 1.631 + 1.632 + recipients = nss_cms_recipient_list_create(recipientInfos); 1.633 + if (recipients) { 1.634 + /* now look for the cert and key */ 1.635 + if (0 == PK11_FindCertAndKeyByRecipientListNew(recipients, 1.636 + ri->cmsg->pwfn_arg)) { 1.637 + cert = CERT_DupCertificate(recipients[0]->cert); 1.638 + key = SECKEY_CopyPrivateKey(recipients[0]->privkey); 1.639 + } else { 1.640 + rv = SECFailure; 1.641 + } 1.642 + 1.643 + nss_cms_recipient_list_destroy(recipients); 1.644 + } 1.645 + else { 1.646 + rv = SECFailure; 1.647 + } 1.648 + } else if (SECSuccess == rv && cert && retkey) { 1.649 + /* we have the cert, we just need the key now */ 1.650 + key = PK11_FindPrivateKeyFromCert(cert->slot, cert, ri->cmsg->pwfn_arg); 1.651 + } 1.652 + if (retcert) { 1.653 + *retcert = cert; 1.654 + } else { 1.655 + if (cert) { 1.656 + CERT_DestroyCertificate(cert); 1.657 + } 1.658 + } 1.659 + if (retkey) { 1.660 + *retkey = key; 1.661 + } else { 1.662 + if (key) { 1.663 + SECKEY_DestroyPrivateKey(key); 1.664 + } 1.665 + } 1.666 + 1.667 + return rv; 1.668 +} 1.669 + 1.670 +SECStatus NSS_CMSRecipientInfo_Encode(PLArenaPool* poolp, 1.671 + const NSSCMSRecipientInfo *src, 1.672 + SECItem* returned) 1.673 +{ 1.674 + extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[]; 1.675 + SECStatus rv = SECFailure; 1.676 + if (!src || !returned) { 1.677 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.678 + } else if (SEC_ASN1EncodeItem(poolp, returned, src, 1.679 + NSSCMSRecipientInfoTemplate)) { 1.680 + rv = SECSuccess; 1.681 + } 1.682 + return rv; 1.683 +}