security/nss/lib/smime/cmsrecinfo.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6 * CMS recipientInfo methods.
michael@0 7 */
michael@0 8
michael@0 9 #include "cmslocal.h"
michael@0 10
michael@0 11 #include "cert.h"
michael@0 12 #include "key.h"
michael@0 13 #include "secasn1.h"
michael@0 14 #include "secitem.h"
michael@0 15 #include "secoid.h"
michael@0 16 #include "pk11func.h"
michael@0 17 #include "secerr.h"
michael@0 18
michael@0 19 PRBool
michael@0 20 nss_cmsrecipientinfo_usessubjectkeyid(NSSCMSRecipientInfo *ri)
michael@0 21 {
michael@0 22 if (ri->recipientInfoType == NSSCMSRecipientInfoID_KeyTrans) {
michael@0 23 NSSCMSRecipientIdentifier *rid;
michael@0 24 rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier;
michael@0 25 if (rid->identifierType == NSSCMSRecipientID_SubjectKeyID) {
michael@0 26 return PR_TRUE;
michael@0 27 }
michael@0 28 }
michael@0 29 return PR_FALSE;
michael@0 30 }
michael@0 31
michael@0 32 /*
michael@0 33 * NOTE: fakeContent marks CMSMessage structure which is only used as a carrier
michael@0 34 * of pwfn_arg and arena pools. In an ideal world, NSSCMSMessage would not have
michael@0 35 * been exported, and we would have added an ordinary enum to handle this
michael@0 36 * check. Unfortunatly wo don't have that luxury so we are overloading the
michael@0 37 * contentTypeTag field. NO code should every try to interpret this content tag
michael@0 38 * as a real OID tag, or use any fields other than pwfn_arg or poolp of this
michael@0 39 * CMSMessage for that matter */
michael@0 40 static const SECOidData fakeContent;
michael@0 41 NSSCMSRecipientInfo *
michael@0 42 nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg,
michael@0 43 NSSCMSRecipientIDSelector type,
michael@0 44 CERTCertificate *cert,
michael@0 45 SECKEYPublicKey *pubKey,
michael@0 46 SECItem *subjKeyID,
michael@0 47 void* pwfn_arg,
michael@0 48 SECItem* DERinput)
michael@0 49 {
michael@0 50 NSSCMSRecipientInfo *ri;
michael@0 51 void *mark;
michael@0 52 SECOidTag certalgtag;
michael@0 53 SECStatus rv = SECSuccess;
michael@0 54 NSSCMSRecipientEncryptedKey *rek;
michael@0 55 NSSCMSOriginatorIdentifierOrKey *oiok;
michael@0 56 unsigned long version;
michael@0 57 SECItem *dummy;
michael@0 58 PLArenaPool *poolp;
michael@0 59 CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL;
michael@0 60 NSSCMSRecipientIdentifier *rid;
michael@0 61 extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[];
michael@0 62
michael@0 63 if (!cmsg) {
michael@0 64 /* a CMSMessage wasn't supplied, create a fake one to hold the pwfunc
michael@0 65 * and a private arena pool */
michael@0 66 cmsg = NSS_CMSMessage_Create(NULL);
michael@0 67 cmsg->pwfn_arg = pwfn_arg;
michael@0 68 /* mark it as a special cms message */
michael@0 69 cmsg->contentInfo.contentTypeTag = (SECOidData *)&fakeContent;
michael@0 70 }
michael@0 71
michael@0 72 poolp = cmsg->poolp;
michael@0 73
michael@0 74 mark = PORT_ArenaMark(poolp);
michael@0 75
michael@0 76 ri = (NSSCMSRecipientInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSRecipientInfo));
michael@0 77 if (ri == NULL)
michael@0 78 goto loser;
michael@0 79
michael@0 80 ri->cmsg = cmsg;
michael@0 81
michael@0 82 if (DERinput) {
michael@0 83 /* decode everything from DER */
michael@0 84 SECItem newinput;
michael@0 85 SECStatus rv = SECITEM_CopyItem(poolp, &newinput, DERinput);
michael@0 86 if (SECSuccess != rv)
michael@0 87 goto loser;
michael@0 88 rv = SEC_QuickDERDecodeItem(poolp, ri, NSSCMSRecipientInfoTemplate, &newinput);
michael@0 89 if (SECSuccess != rv)
michael@0 90 goto loser;
michael@0 91 }
michael@0 92
michael@0 93 switch (type) {
michael@0 94 case NSSCMSRecipientID_IssuerSN:
michael@0 95 {
michael@0 96 ri->cert = CERT_DupCertificate(cert);
michael@0 97 if (NULL == ri->cert)
michael@0 98 goto loser;
michael@0 99 spki = &(cert->subjectPublicKeyInfo);
michael@0 100 break;
michael@0 101 }
michael@0 102
michael@0 103 case NSSCMSRecipientID_SubjectKeyID:
michael@0 104 {
michael@0 105 PORT_Assert(pubKey);
michael@0 106 spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(pubKey);
michael@0 107 break;
michael@0 108 }
michael@0 109
michael@0 110 case NSSCMSRecipientID_BrandNew:
michael@0 111 goto done;
michael@0 112 break;
michael@0 113
michael@0 114 default:
michael@0 115 /* unkown type */
michael@0 116 goto loser;
michael@0 117 break;
michael@0 118 }
michael@0 119
michael@0 120 certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm));
michael@0 121
michael@0 122 rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier;
michael@0 123 switch (certalgtag) {
michael@0 124 case SEC_OID_PKCS1_RSA_ENCRYPTION:
michael@0 125 ri->recipientInfoType = NSSCMSRecipientInfoID_KeyTrans;
michael@0 126 rid->identifierType = type;
michael@0 127 if (type == NSSCMSRecipientID_IssuerSN) {
michael@0 128 rid->id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert);
michael@0 129 if (rid->id.issuerAndSN == NULL) {
michael@0 130 break;
michael@0 131 }
michael@0 132 } else if (type == NSSCMSRecipientID_SubjectKeyID){
michael@0 133 NSSCMSKeyTransRecipientInfoEx *riExtra;
michael@0 134
michael@0 135 rid->id.subjectKeyID = PORT_ArenaNew(poolp, SECItem);
michael@0 136 if (rid->id.subjectKeyID == NULL) {
michael@0 137 rv = SECFailure;
michael@0 138 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 139 break;
michael@0 140 }
michael@0 141 SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID);
michael@0 142 if (rid->id.subjectKeyID->data == NULL) {
michael@0 143 rv = SECFailure;
michael@0 144 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 145 break;
michael@0 146 }
michael@0 147 riExtra = &ri->ri.keyTransRecipientInfoEx;
michael@0 148 riExtra->version = 0;
michael@0 149 riExtra->pubKey = SECKEY_CopyPublicKey(pubKey);
michael@0 150 if (riExtra->pubKey == NULL) {
michael@0 151 rv = SECFailure;
michael@0 152 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 153 break;
michael@0 154 }
michael@0 155 } else {
michael@0 156 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 157 rv = SECFailure;
michael@0 158 }
michael@0 159 break;
michael@0 160 case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
michael@0 161 PORT_Assert(type == NSSCMSRecipientID_IssuerSN);
michael@0 162 if (type != NSSCMSRecipientID_IssuerSN) {
michael@0 163 rv = SECFailure;
michael@0 164 break;
michael@0 165 }
michael@0 166 /* a key agreement op */
michael@0 167 ri->recipientInfoType = NSSCMSRecipientInfoID_KeyAgree;
michael@0 168
michael@0 169 if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) {
michael@0 170 rv = SECFailure;
michael@0 171 break;
michael@0 172 }
michael@0 173 /* we do not support the case where multiple recipients
michael@0 174 * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys
michael@0 175 * in this case, we would need to walk all the recipientInfos, take the
michael@0 176 * ones that do KeyAgreement algorithms and join them, algorithm by algorithm
michael@0 177 * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */
michael@0 178
michael@0 179 /* only epheremal-static Diffie-Hellman is supported for now
michael@0 180 * this is the only form of key agreement that provides potential anonymity
michael@0 181 * of the sender, plus we do not have to include certs in the message */
michael@0 182
michael@0 183 /* force single recipientEncryptedKey for now */
michael@0 184 if ((rek = NSS_CMSRecipientEncryptedKey_Create(poolp)) == NULL) {
michael@0 185 rv = SECFailure;
michael@0 186 break;
michael@0 187 }
michael@0 188
michael@0 189 /* hardcoded IssuerSN choice for now */
michael@0 190 rek->recipientIdentifier.identifierType = NSSCMSKeyAgreeRecipientID_IssuerSN;
michael@0 191 if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) {
michael@0 192 rv = SECFailure;
michael@0 193 break;
michael@0 194 }
michael@0 195
michael@0 196 oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
michael@0 197
michael@0 198 /* see RFC2630 12.3.1.1 */
michael@0 199 oiok->identifierType = NSSCMSOriginatorIDOrKey_OriginatorPublicKey;
michael@0 200
michael@0 201 rv = NSS_CMSArray_Add(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys,
michael@0 202 (void *)rek);
michael@0 203
michael@0 204 break;
michael@0 205 default:
michael@0 206 /* other algorithms not supported yet */
michael@0 207 /* NOTE that we do not support any KEK algorithm */
michael@0 208 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
michael@0 209 rv = SECFailure;
michael@0 210 break;
michael@0 211 }
michael@0 212
michael@0 213 if (rv == SECFailure)
michael@0 214 goto loser;
michael@0 215
michael@0 216 /* set version */
michael@0 217 switch (ri->recipientInfoType) {
michael@0 218 case NSSCMSRecipientInfoID_KeyTrans:
michael@0 219 if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == NSSCMSRecipientID_IssuerSN)
michael@0 220 version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN;
michael@0 221 else
michael@0 222 version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY;
michael@0 223 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version);
michael@0 224 if (dummy == NULL)
michael@0 225 goto loser;
michael@0 226 break;
michael@0 227 case NSSCMSRecipientInfoID_KeyAgree:
michael@0 228 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version),
michael@0 229 NSS_CMS_KEYAGREE_RECIPIENT_INFO_VERSION);
michael@0 230 if (dummy == NULL)
michael@0 231 goto loser;
michael@0 232 break;
michael@0 233 case NSSCMSRecipientInfoID_KEK:
michael@0 234 /* NOTE: this cannot happen as long as we do not support any KEK algorithm */
michael@0 235 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version),
michael@0 236 NSS_CMS_KEK_RECIPIENT_INFO_VERSION);
michael@0 237 if (dummy == NULL)
michael@0 238 goto loser;
michael@0 239 break;
michael@0 240
michael@0 241 }
michael@0 242
michael@0 243 done:
michael@0 244 PORT_ArenaUnmark (poolp, mark);
michael@0 245 if (freeSpki)
michael@0 246 SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
michael@0 247 return ri;
michael@0 248
michael@0 249 loser:
michael@0 250 if (ri && ri->cert) {
michael@0 251 CERT_DestroyCertificate(ri->cert);
michael@0 252 }
michael@0 253 if (freeSpki) {
michael@0 254 SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
michael@0 255 }
michael@0 256 PORT_ArenaRelease (poolp, mark);
michael@0 257 if (cmsg->contentInfo.contentTypeTag == &fakeContent) {
michael@0 258 NSS_CMSMessage_Destroy(cmsg);
michael@0 259 }
michael@0 260 return NULL;
michael@0 261 }
michael@0 262
michael@0 263 /*
michael@0 264 * NSS_CMSRecipientInfo_Create - create a recipientinfo
michael@0 265 *
michael@0 266 * we currently do not create KeyAgreement recipientinfos with multiple
michael@0 267 * recipientEncryptedKeys the certificate is supposed to have been
michael@0 268 * verified by the caller
michael@0 269 */
michael@0 270 NSSCMSRecipientInfo *
michael@0 271 NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert)
michael@0 272 {
michael@0 273 return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_IssuerSN, cert,
michael@0 274 NULL, NULL, NULL, NULL);
michael@0 275 }
michael@0 276
michael@0 277 NSSCMSRecipientInfo *
michael@0 278 NSS_CMSRecipientInfo_CreateNew(void* pwfn_arg)
michael@0 279 {
michael@0 280 return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL,
michael@0 281 NULL, NULL, pwfn_arg, NULL);
michael@0 282 }
michael@0 283
michael@0 284 NSSCMSRecipientInfo *
michael@0 285 NSS_CMSRecipientInfo_CreateFromDER(SECItem* input, void* pwfn_arg)
michael@0 286 {
michael@0 287 return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL,
michael@0 288 NULL, NULL, pwfn_arg, input);
michael@0 289 }
michael@0 290
michael@0 291
michael@0 292 NSSCMSRecipientInfo *
michael@0 293 NSS_CMSRecipientInfo_CreateWithSubjKeyID(NSSCMSMessage *cmsg,
michael@0 294 SECItem *subjKeyID,
michael@0 295 SECKEYPublicKey *pubKey)
michael@0 296 {
michael@0 297 return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_SubjectKeyID,
michael@0 298 NULL, pubKey, subjKeyID, NULL, NULL);
michael@0 299 }
michael@0 300
michael@0 301 NSSCMSRecipientInfo *
michael@0 302 NSS_CMSRecipientInfo_CreateWithSubjKeyIDFromCert(NSSCMSMessage *cmsg,
michael@0 303 CERTCertificate *cert)
michael@0 304 {
michael@0 305 SECKEYPublicKey *pubKey = NULL;
michael@0 306 SECItem subjKeyID = {siBuffer, NULL, 0};
michael@0 307 NSSCMSRecipientInfo *retVal = NULL;
michael@0 308
michael@0 309 if (!cmsg || !cert) {
michael@0 310 return NULL;
michael@0 311 }
michael@0 312 pubKey = CERT_ExtractPublicKey(cert);
michael@0 313 if (!pubKey) {
michael@0 314 goto done;
michael@0 315 }
michael@0 316 if (CERT_FindSubjectKeyIDExtension(cert, &subjKeyID) != SECSuccess ||
michael@0 317 subjKeyID.data == NULL) {
michael@0 318 goto done;
michael@0 319 }
michael@0 320 retVal = NSS_CMSRecipientInfo_CreateWithSubjKeyID(cmsg, &subjKeyID, pubKey);
michael@0 321 done:
michael@0 322 if (pubKey)
michael@0 323 SECKEY_DestroyPublicKey(pubKey);
michael@0 324
michael@0 325 if (subjKeyID.data)
michael@0 326 SECITEM_FreeItem(&subjKeyID, PR_FALSE);
michael@0 327
michael@0 328 return retVal;
michael@0 329 }
michael@0 330
michael@0 331 void
michael@0 332 NSS_CMSRecipientInfo_Destroy(NSSCMSRecipientInfo *ri)
michael@0 333 {
michael@0 334 if (!ri) {
michael@0 335 return;
michael@0 336 }
michael@0 337 /* version was allocated on the pool, so no need to destroy it */
michael@0 338 /* issuerAndSN was allocated on the pool, so no need to destroy it */
michael@0 339 if (ri->cert != NULL)
michael@0 340 CERT_DestroyCertificate(ri->cert);
michael@0 341
michael@0 342 if (nss_cmsrecipientinfo_usessubjectkeyid(ri)) {
michael@0 343 NSSCMSKeyTransRecipientInfoEx *extra;
michael@0 344 extra = &ri->ri.keyTransRecipientInfoEx;
michael@0 345 if (extra->pubKey)
michael@0 346 SECKEY_DestroyPublicKey(extra->pubKey);
michael@0 347 }
michael@0 348 if (ri->cmsg && ri->cmsg->contentInfo.contentTypeTag == &fakeContent) {
michael@0 349 NSS_CMSMessage_Destroy(ri->cmsg);
michael@0 350 }
michael@0 351
michael@0 352 /* we're done. */
michael@0 353 }
michael@0 354
michael@0 355 int
michael@0 356 NSS_CMSRecipientInfo_GetVersion(NSSCMSRecipientInfo *ri)
michael@0 357 {
michael@0 358 unsigned long version;
michael@0 359 SECItem *versionitem = NULL;
michael@0 360
michael@0 361 switch (ri->recipientInfoType) {
michael@0 362 case NSSCMSRecipientInfoID_KeyTrans:
michael@0 363 /* ignore subIndex */
michael@0 364 versionitem = &(ri->ri.keyTransRecipientInfo.version);
michael@0 365 break;
michael@0 366 case NSSCMSRecipientInfoID_KEK:
michael@0 367 /* ignore subIndex */
michael@0 368 versionitem = &(ri->ri.kekRecipientInfo.version);
michael@0 369 break;
michael@0 370 case NSSCMSRecipientInfoID_KeyAgree:
michael@0 371 versionitem = &(ri->ri.keyAgreeRecipientInfo.version);
michael@0 372 break;
michael@0 373 }
michael@0 374
michael@0 375 PORT_Assert(versionitem);
michael@0 376 if (versionitem == NULL)
michael@0 377 return 0;
michael@0 378
michael@0 379 /* always take apart the SECItem */
michael@0 380 if (SEC_ASN1DecodeInteger(versionitem, &version) != SECSuccess)
michael@0 381 return 0;
michael@0 382 else
michael@0 383 return (int)version;
michael@0 384 }
michael@0 385
michael@0 386 SECItem *
michael@0 387 NSS_CMSRecipientInfo_GetEncryptedKey(NSSCMSRecipientInfo *ri, int subIndex)
michael@0 388 {
michael@0 389 SECItem *enckey = NULL;
michael@0 390
michael@0 391 switch (ri->recipientInfoType) {
michael@0 392 case NSSCMSRecipientInfoID_KeyTrans:
michael@0 393 /* ignore subIndex */
michael@0 394 enckey = &(ri->ri.keyTransRecipientInfo.encKey);
michael@0 395 break;
michael@0 396 case NSSCMSRecipientInfoID_KEK:
michael@0 397 /* ignore subIndex */
michael@0 398 enckey = &(ri->ri.kekRecipientInfo.encKey);
michael@0 399 break;
michael@0 400 case NSSCMSRecipientInfoID_KeyAgree:
michael@0 401 enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
michael@0 402 break;
michael@0 403 }
michael@0 404 return enckey;
michael@0 405 }
michael@0 406
michael@0 407
michael@0 408 SECOidTag
michael@0 409 NSS_CMSRecipientInfo_GetKeyEncryptionAlgorithmTag(NSSCMSRecipientInfo *ri)
michael@0 410 {
michael@0 411 SECOidTag encalgtag = SEC_OID_UNKNOWN; /* an invalid encryption alg */
michael@0 412
michael@0 413 switch (ri->recipientInfoType) {
michael@0 414 case NSSCMSRecipientInfoID_KeyTrans:
michael@0 415 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));
michael@0 416 break;
michael@0 417 case NSSCMSRecipientInfoID_KeyAgree:
michael@0 418 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));
michael@0 419 break;
michael@0 420 case NSSCMSRecipientInfoID_KEK:
michael@0 421 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg));
michael@0 422 break;
michael@0 423 }
michael@0 424 return encalgtag;
michael@0 425 }
michael@0 426
michael@0 427 SECStatus
michael@0 428 NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey,
michael@0 429 SECOidTag bulkalgtag)
michael@0 430 {
michael@0 431 CERTCertificate *cert;
michael@0 432 SECOidTag certalgtag;
michael@0 433 SECStatus rv = SECSuccess;
michael@0 434 NSSCMSRecipientEncryptedKey *rek;
michael@0 435 NSSCMSOriginatorIdentifierOrKey *oiok;
michael@0 436 CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL;
michael@0 437 PLArenaPool *poolp;
michael@0 438 NSSCMSKeyTransRecipientInfoEx *extra = NULL;
michael@0 439 PRBool usesSubjKeyID;
michael@0 440
michael@0 441 poolp = ri->cmsg->poolp;
michael@0 442 cert = ri->cert;
michael@0 443 usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri);
michael@0 444 if (cert) {
michael@0 445 spki = &cert->subjectPublicKeyInfo;
michael@0 446 certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm));
michael@0 447 } else if (usesSubjKeyID) {
michael@0 448 extra = &ri->ri.keyTransRecipientInfoEx;
michael@0 449 /* sanity check */
michael@0 450 PORT_Assert(extra->pubKey);
michael@0 451 if (!extra->pubKey) {
michael@0 452 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 453 return SECFailure;
michael@0 454 }
michael@0 455 spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(extra->pubKey);
michael@0 456 certalgtag = SECOID_GetAlgorithmTag(&spki->algorithm);
michael@0 457 } else {
michael@0 458 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 459 return SECFailure;
michael@0 460 }
michael@0 461
michael@0 462 /* XXX set ri->recipientInfoType to the proper value here */
michael@0 463 /* or should we look if it's been set already ? */
michael@0 464
michael@0 465 certalgtag = SECOID_GetAlgorithmTag(&spki->algorithm);
michael@0 466 switch (certalgtag) {
michael@0 467 case SEC_OID_PKCS1_RSA_ENCRYPTION:
michael@0 468 /* wrap the symkey */
michael@0 469 if (cert) {
michael@0 470 rv = NSS_CMSUtil_EncryptSymKey_RSA(poolp, cert, bulkkey,
michael@0 471 &ri->ri.keyTransRecipientInfo.encKey);
michael@0 472 if (rv != SECSuccess)
michael@0 473 break;
michael@0 474 } else if (usesSubjKeyID) {
michael@0 475 PORT_Assert(extra != NULL);
michael@0 476 rv = NSS_CMSUtil_EncryptSymKey_RSAPubKey(poolp, extra->pubKey,
michael@0 477 bulkkey, &ri->ri.keyTransRecipientInfo.encKey);
michael@0 478 if (rv != SECSuccess)
michael@0 479 break;
michael@0 480 }
michael@0 481
michael@0 482 rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL);
michael@0 483 break;
michael@0 484 case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
michael@0 485 rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0];
michael@0 486 if (rek == NULL) {
michael@0 487 rv = SECFailure;
michael@0 488 break;
michael@0 489 }
michael@0 490
michael@0 491 oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
michael@0 492 PORT_Assert(oiok->identifierType == NSSCMSOriginatorIDOrKey_OriginatorPublicKey);
michael@0 493
michael@0 494 /* see RFC2630 12.3.1.1 */
michael@0 495 if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier,
michael@0 496 SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) {
michael@0 497 rv = SECFailure;
michael@0 498 break;
michael@0 499 }
michael@0 500
michael@0 501 /* this will generate a key pair, compute the shared secret, */
michael@0 502 /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */
michael@0 503 /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */
michael@0 504 rv = NSS_CMSUtil_EncryptSymKey_ESDH(poolp, cert, bulkkey,
michael@0 505 &rek->encKey,
michael@0 506 &ri->ri.keyAgreeRecipientInfo.ukm,
michael@0 507 &ri->ri.keyAgreeRecipientInfo.keyEncAlg,
michael@0 508 &oiok->id.originatorPublicKey.publicKey);
michael@0 509
michael@0 510 break;
michael@0 511 default:
michael@0 512 /* other algorithms not supported yet */
michael@0 513 /* NOTE that we do not support any KEK algorithm */
michael@0 514 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
michael@0 515 rv = SECFailure;
michael@0 516 break;
michael@0 517 }
michael@0 518 if (freeSpki)
michael@0 519 SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
michael@0 520
michael@0 521 return rv;
michael@0 522 }
michael@0 523
michael@0 524 PK11SymKey *
michael@0 525 NSS_CMSRecipientInfo_UnwrapBulkKey(NSSCMSRecipientInfo *ri, int subIndex,
michael@0 526 CERTCertificate *cert, SECKEYPrivateKey *privkey, SECOidTag bulkalgtag)
michael@0 527 {
michael@0 528 PK11SymKey *bulkkey = NULL;
michael@0 529 SECAlgorithmID *encalg;
michael@0 530 SECOidTag encalgtag;
michael@0 531 SECItem *enckey;
michael@0 532 int error;
michael@0 533
michael@0 534 ri->cert = CERT_DupCertificate(cert);
michael@0 535 /* mark the recipientInfo so we can find it later */
michael@0 536
michael@0 537 switch (ri->recipientInfoType) {
michael@0 538 case NSSCMSRecipientInfoID_KeyTrans:
michael@0 539 encalg = &(ri->ri.keyTransRecipientInfo.keyEncAlg);
michael@0 540 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));
michael@0 541 enckey = &(ri->ri.keyTransRecipientInfo.encKey); /* ignore subIndex */
michael@0 542 switch (encalgtag) {
michael@0 543 case SEC_OID_PKCS1_RSA_ENCRYPTION:
michael@0 544 /* RSA encryption algorithm: */
michael@0 545 /* get the symmetric (bulk) key by unwrapping it using our private key */
michael@0 546 bulkkey = NSS_CMSUtil_DecryptSymKey_RSA(privkey, enckey, bulkalgtag);
michael@0 547 break;
michael@0 548 default:
michael@0 549 error = SEC_ERROR_UNSUPPORTED_KEYALG;
michael@0 550 goto loser;
michael@0 551 }
michael@0 552 break;
michael@0 553 case NSSCMSRecipientInfoID_KeyAgree:
michael@0 554 encalg = &(ri->ri.keyAgreeRecipientInfo.keyEncAlg);
michael@0 555 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));
michael@0 556 enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
michael@0 557 switch (encalgtag) {
michael@0 558 case SEC_OID_X942_DIFFIE_HELMAN_KEY:
michael@0 559 /* Diffie-Helman key exchange */
michael@0 560 /* XXX not yet implemented */
michael@0 561 /* XXX problem: SEC_OID_X942_DIFFIE_HELMAN_KEY points to a PKCS3 mechanism! */
michael@0 562 /* we support ephemeral-static DH only, so if the recipientinfo */
michael@0 563 /* has originator stuff in it, we punt (or do we? shouldn't be that hard...) */
michael@0 564 /* first, we derive the KEK (a symkey!) using a Derive operation, then we get the */
michael@0 565 /* content encryption key using a Unwrap op */
michael@0 566 /* the derive operation has to generate the key using the algorithm in RFC2631 */
michael@0 567 error = SEC_ERROR_UNSUPPORTED_KEYALG;
michael@0 568 goto loser;
michael@0 569 break;
michael@0 570 default:
michael@0 571 error = SEC_ERROR_UNSUPPORTED_KEYALG;
michael@0 572 goto loser;
michael@0 573 }
michael@0 574 break;
michael@0 575 case NSSCMSRecipientInfoID_KEK:
michael@0 576 encalg = &(ri->ri.kekRecipientInfo.keyEncAlg);
michael@0 577 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg));
michael@0 578 enckey = &(ri->ri.kekRecipientInfo.encKey);
michael@0 579 /* not supported yet */
michael@0 580 error = SEC_ERROR_UNSUPPORTED_KEYALG;
michael@0 581 goto loser;
michael@0 582 break;
michael@0 583 }
michael@0 584 /* XXXX continue here */
michael@0 585 return bulkkey;
michael@0 586
michael@0 587 loser:
michael@0 588 PORT_SetError(error);
michael@0 589 return NULL;
michael@0 590 }
michael@0 591
michael@0 592 SECStatus NSS_CMSRecipientInfo_GetCertAndKey(NSSCMSRecipientInfo *ri,
michael@0 593 CERTCertificate** retcert,
michael@0 594 SECKEYPrivateKey** retkey)
michael@0 595 {
michael@0 596 CERTCertificate* cert = NULL;
michael@0 597 NSSCMSRecipient** recipients = NULL;
michael@0 598 NSSCMSRecipientInfo* recipientInfos[2];
michael@0 599 SECStatus rv = SECSuccess;
michael@0 600 SECKEYPrivateKey* key = NULL;
michael@0 601
michael@0 602 if (!ri)
michael@0 603 return SECFailure;
michael@0 604
michael@0 605 if (!retcert && !retkey) {
michael@0 606 /* nothing requested, nothing found, success */
michael@0 607 return SECSuccess;
michael@0 608 }
michael@0 609
michael@0 610 if (retcert) {
michael@0 611 *retcert = NULL;
michael@0 612 }
michael@0 613 if (retkey) {
michael@0 614 *retkey = NULL;
michael@0 615 }
michael@0 616
michael@0 617 if (ri->cert) {
michael@0 618 cert = CERT_DupCertificate(ri->cert);
michael@0 619 if (!cert) {
michael@0 620 rv = SECFailure;
michael@0 621 }
michael@0 622 }
michael@0 623 if (SECSuccess == rv && !cert) {
michael@0 624 /* we don't have the cert, we have to look for it */
michael@0 625 /* first build an NSS_CMSRecipient */
michael@0 626 recipientInfos[0] = ri;
michael@0 627 recipientInfos[1] = NULL;
michael@0 628
michael@0 629 recipients = nss_cms_recipient_list_create(recipientInfos);
michael@0 630 if (recipients) {
michael@0 631 /* now look for the cert and key */
michael@0 632 if (0 == PK11_FindCertAndKeyByRecipientListNew(recipients,
michael@0 633 ri->cmsg->pwfn_arg)) {
michael@0 634 cert = CERT_DupCertificate(recipients[0]->cert);
michael@0 635 key = SECKEY_CopyPrivateKey(recipients[0]->privkey);
michael@0 636 } else {
michael@0 637 rv = SECFailure;
michael@0 638 }
michael@0 639
michael@0 640 nss_cms_recipient_list_destroy(recipients);
michael@0 641 }
michael@0 642 else {
michael@0 643 rv = SECFailure;
michael@0 644 }
michael@0 645 } else if (SECSuccess == rv && cert && retkey) {
michael@0 646 /* we have the cert, we just need the key now */
michael@0 647 key = PK11_FindPrivateKeyFromCert(cert->slot, cert, ri->cmsg->pwfn_arg);
michael@0 648 }
michael@0 649 if (retcert) {
michael@0 650 *retcert = cert;
michael@0 651 } else {
michael@0 652 if (cert) {
michael@0 653 CERT_DestroyCertificate(cert);
michael@0 654 }
michael@0 655 }
michael@0 656 if (retkey) {
michael@0 657 *retkey = key;
michael@0 658 } else {
michael@0 659 if (key) {
michael@0 660 SECKEY_DestroyPrivateKey(key);
michael@0 661 }
michael@0 662 }
michael@0 663
michael@0 664 return rv;
michael@0 665 }
michael@0 666
michael@0 667 SECStatus NSS_CMSRecipientInfo_Encode(PLArenaPool* poolp,
michael@0 668 const NSSCMSRecipientInfo *src,
michael@0 669 SECItem* returned)
michael@0 670 {
michael@0 671 extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[];
michael@0 672 SECStatus rv = SECFailure;
michael@0 673 if (!src || !returned) {
michael@0 674 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 675 } else if (SEC_ASN1EncodeItem(poolp, returned, src,
michael@0 676 NSSCMSRecipientInfoTemplate)) {
michael@0 677 rv = SECSuccess;
michael@0 678 }
michael@0 679 return rv;
michael@0 680 }

mercurial