security/nss/lib/pkcs7/p7common.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/pkcs7/p7common.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,691 @@
     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 + * PKCS7 implementation -- the exported parts that are used whether
    1.10 + * creating or decoding.
    1.11 + */
    1.12 +
    1.13 +#include "p7local.h"
    1.14 +
    1.15 +#include "cert.h"
    1.16 +#include "secitem.h"
    1.17 +#include "secoid.h"
    1.18 +#include "pk11func.h"
    1.19 +
    1.20 +/*
    1.21 + * Find out (saving pointer to lookup result for future reference)
    1.22 + * and return the inner content type.
    1.23 + */
    1.24 +SECOidTag
    1.25 +SEC_PKCS7ContentType (SEC_PKCS7ContentInfo *cinfo)
    1.26 +{
    1.27 +    if (cinfo->contentTypeTag == NULL)
    1.28 +	cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
    1.29 +
    1.30 +    if (cinfo->contentTypeTag == NULL)
    1.31 +	return SEC_OID_UNKNOWN;
    1.32 +
    1.33 +    return cinfo->contentTypeTag->offset;
    1.34 +}
    1.35 +
    1.36 +
    1.37 +/*
    1.38 + * Destroy a PKCS7 contentInfo and all of its sub-pieces.
    1.39 + */
    1.40 +void
    1.41 +SEC_PKCS7DestroyContentInfo(SEC_PKCS7ContentInfo *cinfo)
    1.42 +{
    1.43 +    SECOidTag kind;
    1.44 +    CERTCertificate **certs;
    1.45 +    CERTCertificateList **certlists;
    1.46 +    SEC_PKCS7SignerInfo **signerinfos;
    1.47 +    SEC_PKCS7RecipientInfo **recipientinfos;
    1.48 +
    1.49 +    PORT_Assert (cinfo->refCount > 0);
    1.50 +    if (cinfo->refCount <= 0)
    1.51 +	return;
    1.52 +
    1.53 +    cinfo->refCount--;
    1.54 +    if (cinfo->refCount > 0)
    1.55 +	return;
    1.56 +
    1.57 +    certs = NULL;
    1.58 +    certlists = NULL;
    1.59 +    recipientinfos = NULL;
    1.60 +    signerinfos = NULL;
    1.61 +
    1.62 +    kind = SEC_PKCS7ContentType (cinfo);
    1.63 +    switch (kind) {
    1.64 +      case SEC_OID_PKCS7_ENVELOPED_DATA:
    1.65 +	{
    1.66 +	    SEC_PKCS7EnvelopedData *edp;
    1.67 +
    1.68 +	    edp = cinfo->content.envelopedData;
    1.69 +	    if (edp != NULL) {
    1.70 +		recipientinfos = edp->recipientInfos;
    1.71 +	    }
    1.72 +	}
    1.73 +	break;
    1.74 +      case SEC_OID_PKCS7_SIGNED_DATA:
    1.75 +	{
    1.76 +	    SEC_PKCS7SignedData *sdp;
    1.77 +
    1.78 +	    sdp = cinfo->content.signedData;
    1.79 +	    if (sdp != NULL) {
    1.80 +		certs = sdp->certs;
    1.81 +		certlists = sdp->certLists;
    1.82 +		signerinfos = sdp->signerInfos;
    1.83 +	    }
    1.84 +	}
    1.85 +	break;
    1.86 +      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
    1.87 +	{
    1.88 +	    SEC_PKCS7SignedAndEnvelopedData *saedp;
    1.89 +
    1.90 +	    saedp = cinfo->content.signedAndEnvelopedData;
    1.91 +	    if (saedp != NULL) {
    1.92 +		certs = saedp->certs;
    1.93 +		certlists = saedp->certLists;
    1.94 +		recipientinfos = saedp->recipientInfos;
    1.95 +		signerinfos = saedp->signerInfos;
    1.96 +		if (saedp->sigKey != NULL)
    1.97 +		    PK11_FreeSymKey (saedp->sigKey);
    1.98 +	    }
    1.99 +	}
   1.100 +	break;
   1.101 +      default:
   1.102 +	/* XXX Anything else that needs to be "manually" freed/destroyed? */
   1.103 +	break;
   1.104 +    }
   1.105 +
   1.106 +    if (certs != NULL) {
   1.107 +	CERTCertificate *cert;
   1.108 +
   1.109 +	while ((cert = *certs++) != NULL) {
   1.110 +	    CERT_DestroyCertificate (cert);
   1.111 +	}
   1.112 +    }
   1.113 +
   1.114 +    if (certlists != NULL) {
   1.115 +	CERTCertificateList *certlist;
   1.116 +
   1.117 +	while ((certlist = *certlists++) != NULL) {
   1.118 +	    CERT_DestroyCertificateList (certlist);
   1.119 +	}
   1.120 +    }
   1.121 +
   1.122 +    if (recipientinfos != NULL) {
   1.123 +	SEC_PKCS7RecipientInfo *ri;
   1.124 +
   1.125 +	while ((ri = *recipientinfos++) != NULL) {
   1.126 +	    if (ri->cert != NULL)
   1.127 +		CERT_DestroyCertificate (ri->cert);
   1.128 +	}
   1.129 +    }
   1.130 +
   1.131 +    if (signerinfos != NULL) {
   1.132 +	SEC_PKCS7SignerInfo *si;
   1.133 +
   1.134 +	while ((si = *signerinfos++) != NULL) {
   1.135 +	    if (si->cert != NULL)
   1.136 +		CERT_DestroyCertificate (si->cert);
   1.137 +	    if (si->certList != NULL)
   1.138 +		CERT_DestroyCertificateList (si->certList);
   1.139 +	}
   1.140 +    }
   1.141 +
   1.142 +    if (cinfo->poolp != NULL) {
   1.143 +	PORT_FreeArena (cinfo->poolp, PR_FALSE);	/* XXX clear it? */
   1.144 +    }
   1.145 +}
   1.146 +
   1.147 +
   1.148 +/*
   1.149 + * Return a copy of the given contentInfo.  The copy may be virtual
   1.150 + * or may be real -- either way, the result needs to be passed to
   1.151 + * SEC_PKCS7DestroyContentInfo later (as does the original).
   1.152 + */
   1.153 +SEC_PKCS7ContentInfo *
   1.154 +SEC_PKCS7CopyContentInfo(SEC_PKCS7ContentInfo *cinfo)
   1.155 +{
   1.156 +    if (cinfo == NULL)
   1.157 +	return NULL;
   1.158 +
   1.159 +    PORT_Assert (cinfo->refCount > 0);
   1.160 +
   1.161 +    if (cinfo->created) {
   1.162 +	/*
   1.163 +	 * Want to do a real copy of these; otherwise subsequent
   1.164 +	 * changes made to either copy are likely to be a surprise.
   1.165 +	 * XXX I suspect that this will not actually be called for yet,
   1.166 +	 * which is why the assert, so to notice if it is...
   1.167 +	 */
   1.168 +	PORT_Assert (0);
   1.169 +	/*
   1.170 +	 * XXX Create a new pool here, and copy everything from
   1.171 +	 * within.  For cert stuff, need to call the appropriate
   1.172 +	 * copy functions, etc.
   1.173 +	 */
   1.174 +    }
   1.175 +
   1.176 +    cinfo->refCount++;
   1.177 +    return cinfo;
   1.178 +}
   1.179 +
   1.180 +
   1.181 +/*
   1.182 + * Return a pointer to the actual content.  In the case of those types
   1.183 + * which are encrypted, this returns the *plain* content.
   1.184 + * XXX Needs revisiting if/when we handle nested encrypted types.
   1.185 + */
   1.186 +SECItem *
   1.187 +SEC_PKCS7GetContent(SEC_PKCS7ContentInfo *cinfo)
   1.188 +{
   1.189 +    SECOidTag kind;
   1.190 +
   1.191 +    kind = SEC_PKCS7ContentType (cinfo);
   1.192 +    switch (kind) {
   1.193 +      case SEC_OID_PKCS7_DATA:
   1.194 +	return cinfo->content.data;
   1.195 +      case SEC_OID_PKCS7_DIGESTED_DATA:
   1.196 +	{
   1.197 +	    SEC_PKCS7DigestedData *digd;
   1.198 +
   1.199 +	    digd = cinfo->content.digestedData;
   1.200 +	    if (digd == NULL)
   1.201 +		break;
   1.202 +	    return SEC_PKCS7GetContent (&(digd->contentInfo));
   1.203 +	}
   1.204 +      case SEC_OID_PKCS7_ENCRYPTED_DATA:
   1.205 +	{
   1.206 +	    SEC_PKCS7EncryptedData *encd;
   1.207 +
   1.208 +	    encd = cinfo->content.encryptedData;
   1.209 +	    if (encd == NULL)
   1.210 +		break;
   1.211 +	    return &(encd->encContentInfo.plainContent);
   1.212 +	}
   1.213 +      case SEC_OID_PKCS7_ENVELOPED_DATA:
   1.214 +	{
   1.215 +	    SEC_PKCS7EnvelopedData *envd;
   1.216 +
   1.217 +	    envd = cinfo->content.envelopedData;
   1.218 +	    if (envd == NULL)
   1.219 +		break;
   1.220 +	    return &(envd->encContentInfo.plainContent);
   1.221 +	}
   1.222 +      case SEC_OID_PKCS7_SIGNED_DATA:
   1.223 +	{
   1.224 +	    SEC_PKCS7SignedData *sigd;
   1.225 +
   1.226 +	    sigd = cinfo->content.signedData;
   1.227 +	    if (sigd == NULL)
   1.228 +		break;
   1.229 +	    return SEC_PKCS7GetContent (&(sigd->contentInfo));
   1.230 +	}
   1.231 +      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
   1.232 +	{
   1.233 +	    SEC_PKCS7SignedAndEnvelopedData *saed;
   1.234 +
   1.235 +	    saed = cinfo->content.signedAndEnvelopedData;
   1.236 +	    if (saed == NULL)
   1.237 +		break;
   1.238 +	    return &(saed->encContentInfo.plainContent);
   1.239 +	}
   1.240 +      default:
   1.241 +	PORT_Assert(0);
   1.242 +	break;
   1.243 +    }
   1.244 +
   1.245 +    return NULL;
   1.246 +}
   1.247 +
   1.248 +
   1.249 +/*
   1.250 + * XXX Fix the placement and formatting of the
   1.251 + * following routines (i.e. make them consistent with the rest of
   1.252 + * the pkcs7 code -- I think some/many belong in other files and
   1.253 + * they all need a formatting/style rehaul)
   1.254 + */
   1.255 +
   1.256 +/* retrieve the algorithm identifier for encrypted data.  
   1.257 + * the identifier returned is a copy of the algorithm identifier
   1.258 + * in the content info and needs to be freed after being used.
   1.259 + *
   1.260 + *   cinfo is the content info for which to retrieve the
   1.261 + *     encryption algorithm.
   1.262 + *
   1.263 + * if the content info is not encrypted data or an error 
   1.264 + * occurs NULL is returned.
   1.265 + */
   1.266 +SECAlgorithmID *
   1.267 +SEC_PKCS7GetEncryptionAlgorithm(SEC_PKCS7ContentInfo *cinfo)
   1.268 +{
   1.269 +  SECAlgorithmID *alg = 0;
   1.270 +  switch (SEC_PKCS7ContentType(cinfo))
   1.271 +    {
   1.272 +    case SEC_OID_PKCS7_ENCRYPTED_DATA:
   1.273 +      alg = &cinfo->content.encryptedData->encContentInfo.contentEncAlg;
   1.274 +      break;
   1.275 +    case SEC_OID_PKCS7_ENVELOPED_DATA:
   1.276 +      alg = &cinfo->content.envelopedData->encContentInfo.contentEncAlg;
   1.277 +      break;
   1.278 +    case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
   1.279 +      alg = &cinfo->content.signedAndEnvelopedData
   1.280 +	->encContentInfo.contentEncAlg;
   1.281 +      break;
   1.282 +    default:
   1.283 +      alg = 0;
   1.284 +      break;
   1.285 +    }
   1.286 +
   1.287 +    return alg;
   1.288 +}
   1.289 +
   1.290 +/* set the content of the content info.  For data content infos,
   1.291 + * the data is set.  For encrytped content infos, the plainContent
   1.292 + * is set, and is expected to be encrypted later.
   1.293 + *  
   1.294 + * cinfo is the content info where the data will be set
   1.295 + *
   1.296 + * buf is a buffer of the data to set
   1.297 + *
   1.298 + * len is the length of the data being set.
   1.299 + *
   1.300 + * in the event of an error, SECFailure is returned.  SECSuccess 
   1.301 + * indicates the content was successfully set.
   1.302 + */
   1.303 +SECStatus 
   1.304 +SEC_PKCS7SetContent(SEC_PKCS7ContentInfo *cinfo,
   1.305 +		    const char *buf, 
   1.306 +		    unsigned long len)
   1.307 +{
   1.308 +    SECOidTag cinfo_type;
   1.309 +    SECStatus rv;
   1.310 +    SECItem content;
   1.311 +    SECOidData *contentTypeTag = NULL;
   1.312 +
   1.313 +    content.type = siBuffer;
   1.314 +    content.data = (unsigned char *)buf;
   1.315 +    content.len = len;
   1.316 +
   1.317 +    cinfo_type = SEC_PKCS7ContentType(cinfo);
   1.318 +
   1.319 +    /* set inner content */
   1.320 +    switch(cinfo_type)
   1.321 +    {
   1.322 +	case SEC_OID_PKCS7_SIGNED_DATA:
   1.323 +	    if(content.len > 0) {
   1.324 +		/* we "leak" the old content here, but as it's all in the pool */
   1.325 +		/* it does not really matter */
   1.326 +
   1.327 +		/* create content item if necessary */
   1.328 +		if (cinfo->content.signedData->contentInfo.content.data == NULL)
   1.329 +		    cinfo->content.signedData->contentInfo.content.data = SECITEM_AllocItem(cinfo->poolp, NULL, 0);
   1.330 +		rv = SECITEM_CopyItem(cinfo->poolp, 
   1.331 +			cinfo->content.signedData->contentInfo.content.data,
   1.332 +			&content);
   1.333 +	    } else {
   1.334 +		cinfo->content.signedData->contentInfo.content.data->data = NULL;
   1.335 +		cinfo->content.signedData->contentInfo.content.data->len = 0;
   1.336 +		rv = SECSuccess;
   1.337 +	    }
   1.338 +	    if(rv == SECFailure)
   1.339 +		goto loser;
   1.340 +	    
   1.341 +	    break;
   1.342 +	case SEC_OID_PKCS7_ENCRYPTED_DATA:
   1.343 +	    /* XXX this forces the inner content type to be "data" */
   1.344 +	    /* do we really want to override without asking or reason? */
   1.345 +	    contentTypeTag = SECOID_FindOIDByTag(SEC_OID_PKCS7_DATA);
   1.346 +	    if(contentTypeTag == NULL)
   1.347 +		goto loser;
   1.348 +	    rv = SECITEM_CopyItem(cinfo->poolp, 
   1.349 +		&(cinfo->content.encryptedData->encContentInfo.contentType),
   1.350 +		&(contentTypeTag->oid));
   1.351 +	    if(rv == SECFailure)
   1.352 +		goto loser;
   1.353 +	    if(content.len > 0) {
   1.354 +		rv = SECITEM_CopyItem(cinfo->poolp, 
   1.355 +			&(cinfo->content.encryptedData->encContentInfo.plainContent),
   1.356 +			&content);
   1.357 +	    } else {
   1.358 +		cinfo->content.encryptedData->encContentInfo.plainContent.data = NULL;
   1.359 +		cinfo->content.encryptedData->encContentInfo.encContent.data = NULL;
   1.360 +		cinfo->content.encryptedData->encContentInfo.plainContent.len = 0;
   1.361 +		cinfo->content.encryptedData->encContentInfo.encContent.len = 0;
   1.362 +		rv = SECSuccess;
   1.363 +	    }
   1.364 +	    if(rv == SECFailure)
   1.365 +		goto loser;
   1.366 +	    break;
   1.367 +	case SEC_OID_PKCS7_DATA:
   1.368 +	    cinfo->content.data = (SECItem *)PORT_ArenaZAlloc(cinfo->poolp,
   1.369 +		sizeof(SECItem));
   1.370 +	    if(cinfo->content.data == NULL)
   1.371 +		goto loser;
   1.372 +	    if(content.len > 0) {
   1.373 +		rv = SECITEM_CopyItem(cinfo->poolp,
   1.374 +			cinfo->content.data, &content);
   1.375 +	    } else {
   1.376 +	    	/* handle case with NULL content */
   1.377 +		rv = SECSuccess;
   1.378 +	    }
   1.379 +	    if(rv == SECFailure)
   1.380 +		goto loser;
   1.381 +	    break;
   1.382 +	default:
   1.383 +	    goto loser;
   1.384 +    }
   1.385 +
   1.386 +    return SECSuccess;
   1.387 +
   1.388 +loser:
   1.389 +	
   1.390 +    return SECFailure;
   1.391 +}
   1.392 +
   1.393 +/* the content of an encrypted data content info is encrypted.
   1.394 + * it is assumed that for encrypted data, that the data has already
   1.395 + * been set and is in the "plainContent" field of the content info.
   1.396 + *
   1.397 + * cinfo is the content info to encrypt
   1.398 + *
   1.399 + * key is the key with which to perform the encryption.  if the
   1.400 + *     algorithm is a password based encryption algorithm, the
   1.401 + *     key is actually a password which will be processed per
   1.402 + *     PKCS #5.
   1.403 + * 
   1.404 + * in the event of an error, SECFailure is returned.  SECSuccess
   1.405 + * indicates a success.
   1.406 + */
   1.407 +SECStatus 
   1.408 +SEC_PKCS7EncryptContents(PLArenaPool *poolp,
   1.409 +			 SEC_PKCS7ContentInfo *cinfo,
   1.410 +			 SECItem *key,
   1.411 +			 void *wincx)
   1.412 +{
   1.413 +    SECAlgorithmID *algid 	= NULL;
   1.414 +    SECItem *       result 	= NULL;
   1.415 +    SECItem *       src;
   1.416 +    SECItem *       dest;
   1.417 +    SECItem *       blocked_data = NULL;
   1.418 +    void *          mark;
   1.419 +    void *          cx;
   1.420 +    PK11SymKey *    eKey 	= NULL;
   1.421 +    PK11SlotInfo *  slot 	= NULL;
   1.422 +
   1.423 +    CK_MECHANISM_TYPE cryptoMechType;
   1.424 +    int             bs;
   1.425 +    SECStatus       rv 		= SECFailure;
   1.426 +    SECItem         *c_param = NULL;
   1.427 +
   1.428 +    if((cinfo == NULL) || (key == NULL))
   1.429 +	return SECFailure;
   1.430 +
   1.431 +    if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA)
   1.432 +	return SECFailure;
   1.433 +
   1.434 +    algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo);	
   1.435 +    if(algid == NULL)
   1.436 +	return SECFailure;
   1.437 +
   1.438 +    if(poolp == NULL)
   1.439 +	poolp = cinfo->poolp;
   1.440 +
   1.441 +    mark = PORT_ArenaMark(poolp);
   1.442 +    
   1.443 +    src = &cinfo->content.encryptedData->encContentInfo.plainContent;
   1.444 +    dest = &cinfo->content.encryptedData->encContentInfo.encContent;
   1.445 +    dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64));
   1.446 +    dest->len = (src->len + 64);
   1.447 +    if(dest->data == NULL) {
   1.448 +	rv = SECFailure;
   1.449 +	goto loser;
   1.450 +    }
   1.451 +
   1.452 +    slot = PK11_GetInternalKeySlot();
   1.453 +    if(slot == NULL) {
   1.454 +	rv = SECFailure;
   1.455 +	goto loser;
   1.456 +    }
   1.457 +
   1.458 +    eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx);
   1.459 +    if(eKey == NULL) {
   1.460 +	rv = SECFailure;
   1.461 +	goto loser;
   1.462 +    }
   1.463 +    
   1.464 +    cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key);
   1.465 +    if (cryptoMechType == CKM_INVALID_MECHANISM) {
   1.466 +	rv = SECFailure;
   1.467 +	goto loser;
   1.468 +    }
   1.469 +
   1.470 +    /* block according to PKCS 8 */
   1.471 +    bs = PK11_GetBlockSize(cryptoMechType, c_param);
   1.472 +    rv = SECSuccess;
   1.473 +    if(bs) {
   1.474 +	char pad_char;
   1.475 +	pad_char = (char)(bs - (src->len % bs));
   1.476 +	if(src->len % bs) {
   1.477 +	    rv = SECSuccess;
   1.478 +	    blocked_data = PK11_BlockData(src, bs);
   1.479 +	    if(blocked_data) {
   1.480 +		PORT_Memset((blocked_data->data + blocked_data->len 
   1.481 +			    - (int)pad_char), 
   1.482 +			    pad_char, (int)pad_char);
   1.483 +	    } else {
   1.484 +		rv = SECFailure;
   1.485 +		goto loser;
   1.486 +	    }
   1.487 +	} else {
   1.488 +	    blocked_data = SECITEM_DupItem(src);
   1.489 +	    if(blocked_data) {
   1.490 +		blocked_data->data = (unsigned char*)PORT_Realloc(
   1.491 +						  blocked_data->data,
   1.492 +						  blocked_data->len + bs);
   1.493 +		if(blocked_data->data) {
   1.494 +		    blocked_data->len += bs;
   1.495 +		    PORT_Memset((blocked_data->data + src->len), (char)bs, bs);
   1.496 +		} else {
   1.497 +		    rv = SECFailure;
   1.498 +		    goto loser;
   1.499 +		}
   1.500 +	    } else {
   1.501 +		rv = SECFailure;
   1.502 +		goto loser;
   1.503 +	    }
   1.504 +	 }
   1.505 +    } else {
   1.506 +	blocked_data = SECITEM_DupItem(src);
   1.507 +	if(!blocked_data) {
   1.508 +	    rv = SECFailure;
   1.509 +	    goto loser;
   1.510 +	}
   1.511 +    }
   1.512 +
   1.513 +    cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT,
   1.514 +		    		    eKey, c_param);
   1.515 +    if(cx == NULL) {
   1.516 +	rv = SECFailure;
   1.517 +	goto loser;
   1.518 +    }
   1.519 +
   1.520 +    rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len), 
   1.521 +		       (int)(src->len + 64), blocked_data->data, 
   1.522 +		       (int)blocked_data->len);
   1.523 +    PK11_DestroyContext((PK11Context*)cx, PR_TRUE);
   1.524 +
   1.525 +loser:
   1.526 +    /* let success fall through */
   1.527 +    if(blocked_data != NULL)
   1.528 +	SECITEM_ZfreeItem(blocked_data, PR_TRUE);
   1.529 +
   1.530 +    if(result != NULL)
   1.531 +	SECITEM_ZfreeItem(result, PR_TRUE);
   1.532 +
   1.533 +    if(rv == SECFailure)
   1.534 +	PORT_ArenaRelease(poolp, mark);
   1.535 +    else 
   1.536 +	PORT_ArenaUnmark(poolp, mark);
   1.537 +
   1.538 +    if(eKey != NULL)
   1.539 +	PK11_FreeSymKey(eKey);
   1.540 +
   1.541 +    if(slot != NULL)
   1.542 +	PK11_FreeSlot(slot);
   1.543 +
   1.544 +    if(c_param != NULL) 
   1.545 +	SECITEM_ZfreeItem(c_param, PR_TRUE);
   1.546 +	
   1.547 +    return rv;
   1.548 +}
   1.549 +
   1.550 +/* the content of an encrypted data content info is decrypted.
   1.551 + * it is assumed that for encrypted data, that the data has already
   1.552 + * been set and is in the "encContent" field of the content info.
   1.553 + *
   1.554 + * cinfo is the content info to decrypt
   1.555 + *
   1.556 + * key is the key with which to perform the decryption.  if the
   1.557 + *     algorithm is a password based encryption algorithm, the
   1.558 + *     key is actually a password which will be processed per
   1.559 + *     PKCS #5.
   1.560 + * 
   1.561 + * in the event of an error, SECFailure is returned.  SECSuccess
   1.562 + * indicates a success.
   1.563 + */
   1.564 +SECStatus 
   1.565 +SEC_PKCS7DecryptContents(PLArenaPool *poolp,
   1.566 +			 SEC_PKCS7ContentInfo *cinfo,
   1.567 +			 SECItem *key,
   1.568 +			 void *wincx)
   1.569 +{
   1.570 +    SECAlgorithmID *algid = NULL;
   1.571 +    SECStatus rv = SECFailure;
   1.572 +    SECItem *result = NULL, *dest, *src;
   1.573 +    void *mark;
   1.574 +
   1.575 +    PK11SymKey *eKey = NULL;
   1.576 +    PK11SlotInfo *slot = NULL;
   1.577 +    CK_MECHANISM_TYPE cryptoMechType;
   1.578 +    void *cx;
   1.579 +    SECItem *c_param = NULL;
   1.580 +    int bs;
   1.581 +
   1.582 +    if((cinfo == NULL) || (key == NULL))
   1.583 +	return SECFailure;
   1.584 +
   1.585 +    if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA)
   1.586 +	return SECFailure;
   1.587 +
   1.588 +    algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo);	
   1.589 +    if(algid == NULL)
   1.590 +	return SECFailure;
   1.591 +
   1.592 +    if(poolp == NULL)
   1.593 +	poolp = cinfo->poolp;
   1.594 +
   1.595 +    mark = PORT_ArenaMark(poolp);
   1.596 +    
   1.597 +    src = &cinfo->content.encryptedData->encContentInfo.encContent;
   1.598 +    dest = &cinfo->content.encryptedData->encContentInfo.plainContent;
   1.599 +    dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64));
   1.600 +    dest->len = (src->len + 64);
   1.601 +    if(dest->data == NULL) {
   1.602 +	rv = SECFailure;
   1.603 +	goto loser;
   1.604 +    }
   1.605 +
   1.606 +    slot = PK11_GetInternalKeySlot();
   1.607 +    if(slot == NULL) {
   1.608 +	rv = SECFailure;
   1.609 +	goto loser;
   1.610 +    }
   1.611 +
   1.612 +    eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx);
   1.613 +    if(eKey == NULL) {
   1.614 +	rv = SECFailure;
   1.615 +	goto loser;
   1.616 +    }
   1.617 +    
   1.618 +    cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key);
   1.619 +    if (cryptoMechType == CKM_INVALID_MECHANISM) {
   1.620 +	rv = SECFailure;
   1.621 +	goto loser;
   1.622 +    }
   1.623 +
   1.624 +    cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT,
   1.625 +		    		    eKey, c_param);
   1.626 +    if(cx == NULL) {
   1.627 +	rv = SECFailure;
   1.628 +	goto loser;
   1.629 +    }
   1.630 +
   1.631 +    rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len), 
   1.632 +		       (int)(src->len + 64), src->data, (int)src->len);
   1.633 +    PK11_DestroyContext((PK11Context *)cx, PR_TRUE);
   1.634 +
   1.635 +    bs = PK11_GetBlockSize(cryptoMechType, c_param);
   1.636 +    if(bs) {
   1.637 +	/* check for proper badding in block algorithms.  this assumes
   1.638 +	 * RC2 cbc or a DES cbc variant.  and the padding is thus defined
   1.639 +	 */
   1.640 +	if(((int)dest->data[dest->len-1] <= bs) && 
   1.641 +	   ((int)dest->data[dest->len-1] > 0)) {
   1.642 +	    dest->len -= (int)dest->data[dest->len-1];
   1.643 +	} else {
   1.644 +	    rv = SECFailure;
   1.645 +	    /* set an error ? */
   1.646 +	}
   1.647 +    } 
   1.648 +
   1.649 +loser:
   1.650 +    /* let success fall through */
   1.651 +    if(result != NULL)
   1.652 +	SECITEM_ZfreeItem(result, PR_TRUE);
   1.653 +
   1.654 +    if(rv == SECFailure)
   1.655 +	PORT_ArenaRelease(poolp, mark);
   1.656 +    else
   1.657 +	PORT_ArenaUnmark(poolp, mark);
   1.658 +
   1.659 +    if(eKey != NULL)
   1.660 +	PK11_FreeSymKey(eKey);
   1.661 +
   1.662 +    if(slot != NULL)
   1.663 +	PK11_FreeSlot(slot);
   1.664 +
   1.665 +    if(c_param != NULL) 
   1.666 +	SECITEM_ZfreeItem(c_param, PR_TRUE);
   1.667 +	
   1.668 +    return rv;
   1.669 +}
   1.670 +
   1.671 +SECItem **
   1.672 +SEC_PKCS7GetCertificateList(SEC_PKCS7ContentInfo *cinfo)
   1.673 +{
   1.674 +    switch(SEC_PKCS7ContentType(cinfo))
   1.675 +    {
   1.676 +	case SEC_OID_PKCS7_SIGNED_DATA:
   1.677 +	    return cinfo->content.signedData->rawCerts;
   1.678 +	    break;
   1.679 +	default:
   1.680 +	    return NULL;
   1.681 +	    break;
   1.682 +    }
   1.683 +}
   1.684 +
   1.685 +
   1.686 +int
   1.687 +SEC_PKCS7GetKeyLength(SEC_PKCS7ContentInfo *cinfo)
   1.688 +{
   1.689 +  if (cinfo->contentTypeTag->offset == SEC_OID_PKCS7_ENVELOPED_DATA)
   1.690 +    return cinfo->content.envelopedData->encContentInfo.keysize;
   1.691 +  else
   1.692 +    return 0;
   1.693 +}
   1.694 +

mercurial