security/nss/lib/smime/cmsrecinfo.c

changeset 0
6474c204b198
     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 +}

mercurial