security/nss/lib/pkcs7/p7decode.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 /*
     6  * PKCS7 decoding, verification.
     7  */
     9 #include "p7local.h"
    11 #include "cert.h"
    12 				/* XXX do not want to have to include */
    13 #include "certdb.h"		/* certdb.h -- the trust stuff needed by */
    14      				/* the add certificate code needs to get */
    15                            	/* rewritten/abstracted and then this */
    16       				/* include should be removed! */
    17 /*#include "cdbhdl.h" */
    18 #include "cryptohi.h"
    19 #include "key.h"
    20 #include "secasn1.h"
    21 #include "secitem.h"
    22 #include "secoid.h"
    23 #include "pk11func.h"
    24 #include "prtime.h"
    25 #include "secerr.h"
    26 #include "sechash.h"	/* for HASH_GetHashObject() */
    27 #include "secder.h"
    28 #include "secpkcs5.h"
    30 struct sec_pkcs7_decoder_worker {
    31     int depth;
    32     int digcnt;
    33     void **digcxs;
    34     const SECHashObject **digobjs;
    35     sec_PKCS7CipherObject *decryptobj;
    36     PRBool saw_contents;
    37 };
    39 struct SEC_PKCS7DecoderContextStr {
    40     SEC_ASN1DecoderContext *dcx;
    41     SEC_PKCS7ContentInfo *cinfo;
    42     SEC_PKCS7DecoderContentCallback cb;
    43     void *cb_arg;
    44     SECKEYGetPasswordKey pwfn;
    45     void *pwfn_arg;
    46     struct sec_pkcs7_decoder_worker worker;
    47     PLArenaPool *tmp_poolp;
    48     int error;
    49     SEC_PKCS7GetDecryptKeyCallback dkcb;
    50     void *dkcb_arg;
    51     SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb;
    52 };
    54 /*
    55  * Handle one worker, decrypting and digesting the data as necessary.
    56  *
    57  * XXX If/when we support nested contents, this probably needs to be
    58  * revised somewhat to get passed the content-info (which unfortunately
    59  * can be two different types depending on whether it is encrypted or not)
    60  * corresponding to the given worker.
    61  */
    62 static void
    63 sec_pkcs7_decoder_work_data (SEC_PKCS7DecoderContext *p7dcx,
    64 			     struct sec_pkcs7_decoder_worker *worker,
    65 			     const unsigned char *data, unsigned long len,
    66 			     PRBool final)
    67 {
    68     unsigned char *buf = NULL;
    69     SECStatus rv;
    70     int i;
    72     /*
    73      * We should really have data to process, or we should be trying
    74      * to finish/flush the last block.  (This is an overly paranoid
    75      * check since all callers are in this file and simple inspection
    76      * proves they do it right.  But it could find a bug in future
    77      * modifications/development, that is why it is here.)
    78      */
    79     PORT_Assert ((data != NULL && len) || final);
    81     /*
    82      * Decrypt this chunk.
    83      *
    84      * XXX If we get an error, we do not want to do the digest or callback,
    85      * but we want to keep decoding.  Or maybe we want to stop decoding
    86      * altogether if there is a callback, because obviously we are not
    87      * sending the data back and they want to know that.
    88      */
    89     if (worker->decryptobj != NULL) {
    90 	/* XXX the following lengths should all be longs? */
    91 	unsigned int inlen;	/* length of data being decrypted */
    92 	unsigned int outlen;	/* length of decrypted data */
    93 	unsigned int buflen;	/* length available for decrypted data */
    94 	SECItem *plain;
    96 	inlen = len;
    97 	buflen = sec_PKCS7DecryptLength (worker->decryptobj, inlen, final);
    98 	if (buflen == 0) {
    99 	    if (inlen == 0)	/* no input and no output */
   100 		return;
   101 	    /*
   102 	     * No output is expected, but the input data may be buffered
   103 	     * so we still have to call Decrypt.
   104 	     */
   105 	    rv = sec_PKCS7Decrypt (worker->decryptobj, NULL, NULL, 0,
   106 				   data, inlen, final);
   107 	    if (rv != SECSuccess) {
   108 		p7dcx->error = PORT_GetError();
   109 		return;		/* XXX indicate error? */
   110 	    }
   111 	    return;
   112 	}
   114 	if (p7dcx->cb != NULL) {
   115 	    buf = (unsigned char *) PORT_Alloc (buflen);
   116 	    plain = NULL;
   117 	} else {
   118 	    unsigned long oldlen;
   120 	    /*
   121 	     * XXX This assumes one level of content only.
   122 	     * See comment above about nested content types.
   123 	     * XXX Also, it should work for signedAndEnvelopedData, too!
   124 	     */
   125 	    plain = &(p7dcx->cinfo->
   126 			content.envelopedData->encContentInfo.plainContent);
   128 	    oldlen = plain->len;
   129 	    if (oldlen == 0) {
   130 		buf = (unsigned char*)PORT_ArenaAlloc (p7dcx->cinfo->poolp, 
   131 						       buflen);
   132 	    } else {
   133 		buf = (unsigned char*)PORT_ArenaGrow (p7dcx->cinfo->poolp, 
   134 				      plain->data,
   135 				      oldlen, oldlen + buflen);
   136 		if (buf != NULL)
   137 		    buf += oldlen;
   138 	    }
   139 	    plain->data = buf;
   140 	}
   141 	if (buf == NULL) {
   142 	    p7dcx->error = SEC_ERROR_NO_MEMORY;
   143 	    return;		/* XXX indicate error? */
   144 	}
   145 	rv = sec_PKCS7Decrypt (worker->decryptobj, buf, &outlen, buflen,
   146 			       data, inlen, final);
   147 	if (rv != SECSuccess) {
   148 	    p7dcx->error = PORT_GetError();
   149 	    return;		/* XXX indicate error? */
   150 	}
   151 	if (plain != NULL) {
   152 	    PORT_Assert (final || outlen == buflen);
   153 	    plain->len += outlen;
   154 	}
   155 	data = buf;
   156 	len = outlen;
   157     }
   159     /*
   160      * Update the running digests.
   161      */
   162     if (len) {
   163 	for (i = 0; i < worker->digcnt; i++) {
   164 	    (* worker->digobjs[i]->update) (worker->digcxs[i], data, len);
   165 	}
   166     }
   168     /*
   169      * Pass back the contents bytes, and free the temporary buffer.
   170      */
   171     if (p7dcx->cb != NULL) {
   172 	if (len)
   173 	    (* p7dcx->cb) (p7dcx->cb_arg, (const char *)data, len);
   174 	if (worker->decryptobj != NULL) {
   175 	    PORT_Assert (buf != NULL);
   176 	    PORT_Free (buf);
   177 	}
   178     }
   179 }
   181 static void
   182 sec_pkcs7_decoder_filter (void *arg, const char *data, unsigned long len,
   183 			  int depth, SEC_ASN1EncodingPart data_kind)
   184 {
   185     SEC_PKCS7DecoderContext *p7dcx;
   186     struct sec_pkcs7_decoder_worker *worker;
   188     /*
   189      * Since we do not handle any nested contents, the only bytes we
   190      * are really interested in are the actual contents bytes (not
   191      * the identifier, length, or end-of-contents bytes).  If we were
   192      * handling nested types we would probably need to do something
   193      * smarter based on depth and data_kind.
   194      */
   195     if (data_kind != SEC_ASN1_Contents)
   196 	return;
   198     /*
   199      * The ASN.1 decoder should not even call us with a length of 0.
   200      * Just being paranoid.
   201      */
   202     PORT_Assert (len);
   203     if (len == 0)
   204 	return;
   206     p7dcx = (SEC_PKCS7DecoderContext*)arg;
   208     /*
   209      * Handling nested contents would mean that there is a chain
   210      * of workers -- one per each level of content.  The following
   211      * would start with the first worker and loop over them.
   212      */
   213     worker = &(p7dcx->worker);
   215     worker->saw_contents = PR_TRUE;
   217     sec_pkcs7_decoder_work_data (p7dcx, worker,
   218 				 (const unsigned char *) data, len, PR_FALSE);
   219 }
   222 /*
   223  * Create digest contexts for each algorithm in "digestalgs".
   224  * No algorithms is not an error, we just do not do anything.
   225  * An error (like trouble allocating memory), marks the error
   226  * in "p7dcx" and returns SECFailure, which means that our caller
   227  * should just give up altogether.
   228  */
   229 static SECStatus
   230 sec_pkcs7_decoder_start_digests (SEC_PKCS7DecoderContext *p7dcx, int depth,
   231 				 SECAlgorithmID **digestalgs)
   232 {
   233     int i, digcnt;
   235     if (digestalgs == NULL)
   236 	return SECSuccess;
   238     /*
   239      * Count the algorithms.
   240      */
   241     digcnt = 0;
   242     while (digestalgs[digcnt] != NULL)
   243 	digcnt++;
   245     /*
   246      * No algorithms means no work to do.
   247      * Just act as if there were no algorithms specified.
   248      */
   249     if (digcnt == 0)
   250 	return SECSuccess;
   252     p7dcx->worker.digcxs = (void**)PORT_ArenaAlloc (p7dcx->tmp_poolp,
   253 					    digcnt * sizeof (void *));
   254     p7dcx->worker.digobjs = (const SECHashObject**)PORT_ArenaAlloc (p7dcx->tmp_poolp,
   255 					     digcnt * sizeof (SECHashObject *));
   256     if (p7dcx->worker.digcxs == NULL || p7dcx->worker.digobjs == NULL) {
   257 	p7dcx->error = SEC_ERROR_NO_MEMORY;
   258 	return SECFailure;
   259     }
   261     p7dcx->worker.depth = depth;
   262     p7dcx->worker.digcnt = 0;
   264     /*
   265      * Create a digest context for each algorithm.
   266      */
   267     for (i = 0; i < digcnt; i++) {
   268 	SECAlgorithmID *     algid  = digestalgs[i];
   269 	SECOidTag            oidTag = SECOID_FindOIDTag(&(algid->algorithm));
   270 	const SECHashObject *digobj = HASH_GetHashObjectByOidTag(oidTag);
   271 	void *digcx;
   273 	/*
   274 	 * Skip any algorithm we do not even recognize; obviously,
   275 	 * this could be a problem, but if it is critical then the
   276 	 * result will just be that the signature does not verify.
   277 	 * We do not necessarily want to error out here, because
   278 	 * the particular algorithm may not actually be important,
   279 	 * but we cannot know that until later.
   280 	 */
   281 	if (digobj == NULL) {
   282 	    p7dcx->worker.digcnt--;
   283 	    continue;
   284 	}
   286 	digcx = (* digobj->create)();
   287 	if (digcx != NULL) {
   288 	    (* digobj->begin) (digcx);
   289 	    p7dcx->worker.digobjs[p7dcx->worker.digcnt] = digobj;
   290 	    p7dcx->worker.digcxs[p7dcx->worker.digcnt] = digcx;
   291 	    p7dcx->worker.digcnt++;
   292 	}
   293     }
   295     if (p7dcx->worker.digcnt != 0)
   296 	SEC_ASN1DecoderSetFilterProc (p7dcx->dcx,
   297 				      sec_pkcs7_decoder_filter,
   298 				      p7dcx,
   299 				      (PRBool)(p7dcx->cb != NULL));
   300     return SECSuccess;
   301 }
   304 /*
   305  * Close out all of the digest contexts, storing the results in "digestsp".
   306  */
   307 static SECStatus
   308 sec_pkcs7_decoder_finish_digests (SEC_PKCS7DecoderContext *p7dcx,
   309 				  PLArenaPool *poolp,
   310 				  SECItem ***digestsp)
   311 {
   312     struct sec_pkcs7_decoder_worker *worker;
   313     const SECHashObject *digobj;
   314     void *digcx;
   315     SECItem **digests, *digest;
   316     int i;
   317     void *mark;
   319     /*
   320      * XXX Handling nested contents would mean that there is a chain
   321      * of workers -- one per each level of content.  The following
   322      * would want to find the last worker in the chain.
   323      */
   324     worker = &(p7dcx->worker);
   326     /*
   327      * If no digests, then we have nothing to do.
   328      */
   329     if (worker->digcnt == 0)
   330 	return SECSuccess;
   332     /*
   333      * No matter what happens after this, we want to stop filtering.
   334      * XXX If we handle nested contents, we only want to stop filtering
   335      * if we are finishing off the *last* worker.
   336      */
   337     SEC_ASN1DecoderClearFilterProc (p7dcx->dcx);
   339     /*
   340      * If we ended up with no contents, just destroy each
   341      * digest context -- they are meaningless and potentially
   342      * confusing, because their presence would imply some content
   343      * was digested.
   344      */
   345     if (! worker->saw_contents) {
   346 	for (i = 0; i < worker->digcnt; i++) {
   347 	    digcx = worker->digcxs[i];
   348 	    digobj = worker->digobjs[i];
   349 	    (* digobj->destroy) (digcx, PR_TRUE);
   350 	}
   351 	return SECSuccess;
   352     }
   354     mark = PORT_ArenaMark (poolp);
   356     /*
   357      * Close out each digest context, saving digest away.
   358      */
   359     digests = 
   360       (SECItem**)PORT_ArenaAlloc (poolp,(worker->digcnt+1)*sizeof(SECItem *));
   361     digest = (SECItem*)PORT_ArenaAlloc (poolp, worker->digcnt*sizeof(SECItem));
   362     if (digests == NULL || digest == NULL) {
   363 	p7dcx->error = PORT_GetError();
   364 	PORT_ArenaRelease (poolp, mark);
   365 	return SECFailure;
   366     }
   368     for (i = 0; i < worker->digcnt; i++, digest++) {
   369 	digcx = worker->digcxs[i];
   370 	digobj = worker->digobjs[i];
   372 	digest->data = (unsigned char*)PORT_ArenaAlloc (poolp, digobj->length);
   373 	if (digest->data == NULL) {
   374 	    p7dcx->error = PORT_GetError();
   375 	    PORT_ArenaRelease (poolp, mark);
   376 	    return SECFailure;
   377 	}
   379 	digest->len = digobj->length;
   380 	(* digobj->end) (digcx, digest->data, &(digest->len), digest->len);
   381 	(* digobj->destroy) (digcx, PR_TRUE);
   383 	digests[i] = digest;
   384     }
   385     digests[i] = NULL;
   386     *digestsp = digests;
   388     PORT_ArenaUnmark (poolp, mark);
   389     return SECSuccess;
   390 }
   392 /*
   393  * XXX Need comment explaining following helper function (which is used
   394  * by sec_pkcs7_decoder_start_decrypt).
   395  */
   397 static PK11SymKey *
   398 sec_pkcs7_decoder_get_recipient_key (SEC_PKCS7DecoderContext *p7dcx,
   399 				     SEC_PKCS7RecipientInfo **recipientinfos,
   400 				     SEC_PKCS7EncryptedContentInfo *enccinfo)
   401 {
   402     SEC_PKCS7RecipientInfo *ri;
   403     CERTCertificate *cert = NULL;
   404     SECKEYPrivateKey *privkey = NULL;
   405     PK11SymKey *bulkkey = NULL;
   406     SECOidTag keyalgtag, bulkalgtag, encalgtag;
   407     PK11SlotInfo *slot = NULL;
   409     if (recipientinfos == NULL || recipientinfos[0] == NULL) {
   410 	p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT;
   411 	goto no_key_found;
   412     }
   414     cert = PK11_FindCertAndKeyByRecipientList(&slot,recipientinfos,&ri,
   415 						&privkey, p7dcx->pwfn_arg);
   416     if (cert == NULL) {
   417 	p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT;
   418 	goto no_key_found;
   419     }
   421     ri->cert = cert;		/* so we can find it later */
   422     PORT_Assert(privkey != NULL);
   424     keyalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
   425     encalgtag = SECOID_GetAlgorithmTag (&(ri->keyEncAlg));
   426     if (keyalgtag != encalgtag) {
   427 	p7dcx->error = SEC_ERROR_PKCS7_KEYALG_MISMATCH;
   428 	goto no_key_found;
   429     }
   430     bulkalgtag = SECOID_GetAlgorithmTag (&(enccinfo->contentEncAlg));
   432     switch (encalgtag) {
   433       case SEC_OID_PKCS1_RSA_ENCRYPTION:
   434 	bulkkey = PK11_PubUnwrapSymKey (privkey, &ri->encKey,
   435 					PK11_AlgtagToMechanism (bulkalgtag),
   436 					CKA_DECRYPT, 0);
   437 	if (bulkkey == NULL) {
   438 	    p7dcx->error = PORT_GetError();
   439 	    PORT_SetError(0);
   440 	    goto no_key_found;
   441 	}
   442 	break;
   443       default:
   444 	p7dcx->error = SEC_ERROR_UNSUPPORTED_KEYALG;
   445 	break;
   446     }
   448 no_key_found:
   449     if (privkey != NULL)
   450 	SECKEY_DestroyPrivateKey (privkey);
   451     if (slot != NULL)
   452 	PK11_FreeSlot(slot);
   454     return bulkkey;
   455 }
   457 /*
   458  * XXX The following comment is old -- the function used to only handle
   459  * EnvelopedData or SignedAndEnvelopedData but now handles EncryptedData
   460  * as well (and it had all of the code of the helper function above
   461  * built into it), though the comment was left as is.  Fix it...
   462  *
   463  * We are just about to decode the content of an EnvelopedData.
   464  * Set up a decryption context so we can decrypt as we go.
   465  * Presumably we are one of the recipients listed in "recipientinfos".
   466  * (XXX And if we are not, or if we have trouble, what should we do?
   467  *  It would be nice to let the decoding still work.  Maybe it should
   468  *  be an error if there is a content callback, but not an error otherwise?)
   469  * The encryption key and related information can be found in "enccinfo".
   470  */
   471 static SECStatus
   472 sec_pkcs7_decoder_start_decrypt (SEC_PKCS7DecoderContext *p7dcx, int depth,
   473 				 SEC_PKCS7RecipientInfo **recipientinfos,
   474 				 SEC_PKCS7EncryptedContentInfo *enccinfo,
   475 				 PK11SymKey **copy_key_for_signature)
   476 {
   477     PK11SymKey *bulkkey = NULL;
   478     sec_PKCS7CipherObject *decryptobj;
   480     /*
   481      * If a callback is supplied to retrieve the encryption key, 
   482      * for instance, for Encrypted Content infos, then retrieve
   483      * the bulkkey from the callback.  Otherwise, assume that
   484      * we are processing Enveloped or SignedAndEnveloped data
   485      * content infos.
   486      *
   487      * XXX Put an assert here?
   488      */
   489     if (SEC_PKCS7ContentType(p7dcx->cinfo) == SEC_OID_PKCS7_ENCRYPTED_DATA) {
   490 	if (p7dcx->dkcb != NULL) {
   491 	    bulkkey = (*p7dcx->dkcb)(p7dcx->dkcb_arg, 
   492 				     &(enccinfo->contentEncAlg));
   493 	}
   494 	enccinfo->keysize = 0;
   495     } else {
   496 	bulkkey = sec_pkcs7_decoder_get_recipient_key (p7dcx, recipientinfos, 
   497 						       enccinfo);
   498 	if (bulkkey == NULL) goto no_decryption;
   499 	enccinfo->keysize = PK11_GetKeyStrength(bulkkey, 
   500 						&(enccinfo->contentEncAlg));
   502     }
   504     /*
   505      * XXX I think following should set error in p7dcx and clear set error
   506      * (as used to be done here, or as is done in get_receipient_key above.
   507      */
   508     if(bulkkey == NULL) {
   509 	goto no_decryption;
   510     }
   512     /* 
   513      * We want to make sure decryption is allowed.  This is done via
   514      * a callback specified in SEC_PKCS7DecoderStart().
   515      */
   516     if (p7dcx->decrypt_allowed_cb) {
   517 	if ((*p7dcx->decrypt_allowed_cb) (&(enccinfo->contentEncAlg), 
   518 					  bulkkey) == PR_FALSE) {
   519 	    p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED;
   520 	    goto no_decryption;
   521 	}
   522     } else {
   523 	    p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED;
   524 	    goto no_decryption;
   525     }
   527     /*
   528      * When decrypting a signedAndEnvelopedData, the signature also has
   529      * to be decrypted with the bulk encryption key; to avoid having to
   530      * get it all over again later (and do another potentially expensive
   531      * RSA operation), copy it for later signature verification to use.
   532      */
   533     if (copy_key_for_signature != NULL)
   534 	*copy_key_for_signature = PK11_ReferenceSymKey (bulkkey);
   536     /*
   537      * Now we have the bulk encryption key (in bulkkey) and the
   538      * the algorithm (in enccinfo->contentEncAlg).  Using those,
   539      * create a decryption context.
   540      */
   541     decryptobj = sec_PKCS7CreateDecryptObject (bulkkey,
   542 					       &(enccinfo->contentEncAlg));
   544     /*
   545      * We are done with (this) bulkkey now.
   546      */
   547     PK11_FreeSymKey (bulkkey);
   549     if (decryptobj == NULL) {
   550 	p7dcx->error = PORT_GetError();
   551 	PORT_SetError(0);
   552 	goto no_decryption;
   553     }
   555     SEC_ASN1DecoderSetFilterProc (p7dcx->dcx,
   556 				  sec_pkcs7_decoder_filter,
   557 				  p7dcx,
   558 				  (PRBool)(p7dcx->cb != NULL));
   560     p7dcx->worker.depth = depth;
   561     p7dcx->worker.decryptobj = decryptobj;
   563     return SECSuccess;
   565 no_decryption:
   566     /*
   567      * For some reason (error set already, if appropriate), we cannot
   568      * decrypt the content.  I am not sure what exactly is the right
   569      * thing to do here; in some cases we want to just stop, and in
   570      * others we want to let the decoding finish even though we cannot
   571      * decrypt the content.  My current thinking is that if the caller
   572      * set up a content callback, then they are really interested in
   573      * getting (decrypted) content, and if they cannot they will want
   574      * to know about it.  However, if no callback was specified, then
   575      * maybe it is not important that the decryption failed.
   576      */
   577     if (p7dcx->cb != NULL)
   578 	return SECFailure;
   579     else
   580 	return SECSuccess;	/* Let the decoding continue. */
   581 }
   584 static SECStatus
   585 sec_pkcs7_decoder_finish_decrypt (SEC_PKCS7DecoderContext *p7dcx,
   586 				  PLArenaPool *poolp,
   587 				  SEC_PKCS7EncryptedContentInfo *enccinfo)
   588 {
   589     struct sec_pkcs7_decoder_worker *worker;
   591     /*
   592      * XXX Handling nested contents would mean that there is a chain
   593      * of workers -- one per each level of content.  The following
   594      * would want to find the last worker in the chain.
   595      */
   596     worker = &(p7dcx->worker);
   598     /*
   599      * If no decryption context, then we have nothing to do.
   600      */
   601     if (worker->decryptobj == NULL)
   602 	return SECSuccess;
   604     /*
   605      * No matter what happens after this, we want to stop filtering.
   606      * XXX If we handle nested contents, we only want to stop filtering
   607      * if we are finishing off the *last* worker.
   608      */
   609     SEC_ASN1DecoderClearFilterProc (p7dcx->dcx);
   611     /*
   612      * Handle the last block.
   613      */
   614     sec_pkcs7_decoder_work_data (p7dcx, worker, NULL, 0, PR_TRUE);
   616     /*
   617      * All done, destroy it.
   618      */
   619     sec_PKCS7DestroyDecryptObject (worker->decryptobj);
   620     worker->decryptobj = NULL;
   622     return SECSuccess;
   623 }
   626 static void
   627 sec_pkcs7_decoder_notify (void *arg, PRBool before, void *dest, int depth)
   628 {
   629     SEC_PKCS7DecoderContext *p7dcx;
   630     SEC_PKCS7ContentInfo *cinfo;
   631     SEC_PKCS7SignedData *sigd;
   632     SEC_PKCS7EnvelopedData *envd;
   633     SEC_PKCS7SignedAndEnvelopedData *saed;
   634     SEC_PKCS7EncryptedData *encd;
   635     SEC_PKCS7DigestedData *digd;
   636     PRBool after;
   637     SECStatus rv;
   639     /*
   640      * Just to make the code easier to read, create an "after" variable
   641      * that is equivalent to "not before".
   642      * (This used to be just the statement "after = !before", but that
   643      * causes a warning on the mac; to avoid that, we do it the long way.)
   644      */
   645     if (before)
   646 	after = PR_FALSE;
   647     else
   648 	after = PR_TRUE;
   650     p7dcx = (SEC_PKCS7DecoderContext*)arg;
   651     cinfo = p7dcx->cinfo;
   653     if (cinfo->contentTypeTag == NULL) {
   654 	if (after && dest == &(cinfo->contentType))
   655 	    cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
   656 	return;
   657     }
   659     switch (cinfo->contentTypeTag->offset) {
   660       case SEC_OID_PKCS7_SIGNED_DATA:
   661 	sigd = cinfo->content.signedData;
   662 	if (sigd == NULL)
   663 	    break;
   665 	if (sigd->contentInfo.contentTypeTag == NULL) {
   666 	    if (after && dest == &(sigd->contentInfo.contentType))
   667 		sigd->contentInfo.contentTypeTag =
   668 			SECOID_FindOID(&(sigd->contentInfo.contentType));
   669 	    break;
   670 	}
   672 	/*
   673 	 * We only set up a filtering digest if the content is
   674 	 * plain DATA; anything else needs more work because a
   675 	 * second pass is required to produce a DER encoding from
   676 	 * an input that can be BER encoded.  (This is a requirement
   677 	 * of PKCS7 that is unfortunate, but there you have it.)
   678 	 *
   679 	 * XXX Also, since we stop here if this is not DATA, the
   680 	 * inner content is not getting processed at all.  Someday
   681 	 * we may want to fix that.
   682 	 */
   683 	if (sigd->contentInfo.contentTypeTag->offset != SEC_OID_PKCS7_DATA) {
   684 	    /* XXX Set an error in p7dcx->error */
   685 	    SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
   686 	    break;
   687 	}
   689 	/*
   690 	 * Just before the content, we want to set up a digest context
   691 	 * for each digest algorithm listed, and start a filter which
   692 	 * will run all of the contents bytes through that digest.
   693 	 */
   694 	if (before && dest == &(sigd->contentInfo.content)) {
   695 	    rv = sec_pkcs7_decoder_start_digests (p7dcx, depth,
   696 						  sigd->digestAlgorithms);
   697 	    if (rv != SECSuccess)
   698 		SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
   700 	    break;
   701 	}
   703 	/*
   704 	 * XXX To handle nested types, here is where we would want
   705 	 * to check for inner boundaries that need handling.
   706 	 */
   708 	/*
   709 	 * Are we done?
   710 	 */
   711 	if (after && dest == &(sigd->contentInfo.content)) {
   712 	    /*
   713 	     * Close out the digest contexts.  We ignore any error
   714 	     * because we are stopping anyway; the error status left
   715 	     * behind in p7dcx will be seen by outer functions.
   716 	     */
   717 	    (void) sec_pkcs7_decoder_finish_digests (p7dcx, cinfo->poolp,
   718 						     &(sigd->digests));
   720 	    /*
   721 	     * XXX To handle nested contents, we would need to remove
   722 	     * the worker from the chain (and free it).
   723 	     */
   725 	    /*
   726 	     * Stop notify.
   727 	     */
   728 	    SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
   729 	}
   730 	break;
   732       case SEC_OID_PKCS7_ENVELOPED_DATA:
   733 	envd = cinfo->content.envelopedData;
   734 	if (envd == NULL)
   735 	    break;
   737 	if (envd->encContentInfo.contentTypeTag == NULL) {
   738 	    if (after && dest == &(envd->encContentInfo.contentType))
   739 		envd->encContentInfo.contentTypeTag =
   740 			SECOID_FindOID(&(envd->encContentInfo.contentType));
   741 	    break;
   742 	}
   744 	/*
   745 	 * Just before the content, we want to set up a decryption
   746 	 * context, and start a filter which will run all of the
   747 	 * contents bytes through it to determine the plain content.
   748 	 */
   749 	if (before && dest == &(envd->encContentInfo.encContent)) {
   750 	    rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth,
   751 						  envd->recipientInfos,
   752 						  &(envd->encContentInfo),
   753 						  NULL);
   754 	    if (rv != SECSuccess)
   755 		SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
   757 	    break;
   758 	}
   760 	/*
   761 	 * Are we done?
   762 	 */
   763 	if (after && dest == &(envd->encContentInfo.encContent)) {
   764 	    /*
   765 	     * Close out the decryption context.  We ignore any error
   766 	     * because we are stopping anyway; the error status left
   767 	     * behind in p7dcx will be seen by outer functions.
   768 	     */
   769 	    (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp,
   770 						     &(envd->encContentInfo));
   772 	    /*
   773 	     * XXX To handle nested contents, we would need to remove
   774 	     * the worker from the chain (and free it).
   775 	     */
   777 	    /*
   778 	     * Stop notify.
   779 	     */
   780 	    SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
   781 	}
   782 	break;
   784       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
   785 	saed = cinfo->content.signedAndEnvelopedData;
   786 	if (saed == NULL)
   787 	    break;
   789 	if (saed->encContentInfo.contentTypeTag == NULL) {
   790 	    if (after && dest == &(saed->encContentInfo.contentType))
   791 		saed->encContentInfo.contentTypeTag =
   792 			SECOID_FindOID(&(saed->encContentInfo.contentType));
   793 	    break;
   794 	}
   796 	/*
   797 	 * Just before the content, we want to set up a decryption
   798 	 * context *and* digest contexts, and start a filter which
   799 	 * will run all of the contents bytes through both.
   800 	 */
   801 	if (before && dest == &(saed->encContentInfo.encContent)) {
   802 	    rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth,
   803 						  saed->recipientInfos,
   804 						  &(saed->encContentInfo),
   805 						  &(saed->sigKey));
   806 	    if (rv == SECSuccess)
   807 		rv = sec_pkcs7_decoder_start_digests (p7dcx, depth,
   808 						      saed->digestAlgorithms);
   809 	    if (rv != SECSuccess)
   810 		SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
   812 	    break;
   813 	}
   815 	/*
   816 	 * Are we done?
   817 	 */
   818 	if (after && dest == &(saed->encContentInfo.encContent)) {
   819 	    /*
   820 	     * Close out the decryption and digests contexts.
   821 	     * We ignore any errors because we are stopping anyway;
   822 	     * the error status left behind in p7dcx will be seen by
   823 	     * outer functions.
   824 	     *
   825 	     * Note that the decrypt stuff must be called first;
   826 	     * it may have a last buffer to do which in turn has
   827 	     * to be added to the digest.
   828 	     */
   829 	    (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp,
   830 						     &(saed->encContentInfo));
   831 	    (void) sec_pkcs7_decoder_finish_digests (p7dcx, cinfo->poolp,
   832 						     &(saed->digests));
   834 	    /*
   835 	     * XXX To handle nested contents, we would need to remove
   836 	     * the worker from the chain (and free it).
   837 	     */
   839 	    /*
   840 	     * Stop notify.
   841 	     */
   842 	    SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
   843 	}
   844 	break;
   846       case SEC_OID_PKCS7_DIGESTED_DATA:
   847 	digd = cinfo->content.digestedData;
   849 	/* 
   850 	 * XXX Want to do the digest or not?  Maybe future enhancement...
   851 	 */
   852 	if (before && dest == &(digd->contentInfo.content.data)) {
   853 	    SEC_ASN1DecoderSetFilterProc (p7dcx->dcx, sec_pkcs7_decoder_filter,
   854 					  p7dcx,
   855 					  (PRBool)(p7dcx->cb != NULL));
   856 	    break;
   857 	}
   859 	/*
   860 	 * Are we done?
   861 	 */
   862 	if (after && dest == &(digd->contentInfo.content.data)) {
   863 	    SEC_ASN1DecoderClearFilterProc (p7dcx->dcx);
   864 	}
   865 	break;
   867       case SEC_OID_PKCS7_ENCRYPTED_DATA:
   868 	encd = cinfo->content.encryptedData;
   870 	/*
   871 	 * XXX If the decryption key callback is set, we want to start
   872 	 * the decryption.  If the callback is not set, we will treat the
   873 	 * content as plain data, since we do not have the key.
   874 	 *
   875 	 * Is this the proper thing to do?
   876 	 */
   877 	if (before && dest == &(encd->encContentInfo.encContent)) {
   878 	    /*
   879 	     * Start the encryption process if the decryption key callback
   880 	     * is present.  Otherwise, treat the content like plain data.
   881 	     */
   882 	    rv = SECSuccess;
   883 	    if (p7dcx->dkcb != NULL) {
   884 		rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth, NULL,
   885 						      &(encd->encContentInfo),
   886 						      NULL);
   887 	    }
   889 	    if (rv != SECSuccess)
   890 		SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
   892 	    break;
   893 	}
   895 	/*
   896 	 * Are we done?
   897 	 */
   898 	if (after && dest == &(encd->encContentInfo.encContent)) {
   899 	    /*
   900 	     * Close out the decryption context.  We ignore any error
   901 	     * because we are stopping anyway; the error status left
   902 	     * behind in p7dcx will be seen by outer functions.
   903 	     */
   904 	    (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp,
   905 						     &(encd->encContentInfo));
   907 	    /*
   908 	     * Stop notify.
   909 	     */
   910 	    SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
   911 	}
   912 	break;
   914       case SEC_OID_PKCS7_DATA:
   915 	/*
   916 	 * If a output callback has been specified, we want to set the filter
   917 	 * to call the callback.  This is taken care of in 
   918 	 * sec_pkcs7_decoder_start_decrypt() or 
   919 	 * sec_pkcs7_decoder_start_digests() for the other content types.
   920 	 */ 
   922 	if (before && dest == &(cinfo->content.data)) {
   924 	    /* 
   925 	     * Set the filter proc up.
   926 	     */
   927 	    SEC_ASN1DecoderSetFilterProc (p7dcx->dcx,
   928 					  sec_pkcs7_decoder_filter,
   929 					  p7dcx,
   930 					  (PRBool)(p7dcx->cb != NULL));
   931 	    break;
   932 	}
   934 	if (after && dest == &(cinfo->content.data)) {
   935 	    /*
   936 	     * Time to clean up after ourself, stop the Notify and Filter
   937 	     * procedures.
   938 	     */
   939 	    SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
   940 	    SEC_ASN1DecoderClearFilterProc (p7dcx->dcx);
   941 	}
   942 	break;
   944       default:
   945 	SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx);
   946 	break;
   947     }
   948 }
   951 SEC_PKCS7DecoderContext *
   952 SEC_PKCS7DecoderStart(SEC_PKCS7DecoderContentCallback cb, void *cb_arg,
   953 		      SECKEYGetPasswordKey pwfn, void *pwfn_arg,
   954 		      SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb, 
   955 		      void *decrypt_key_cb_arg,
   956 		      SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb)
   957 {
   958     SEC_PKCS7DecoderContext *p7dcx;
   959     SEC_ASN1DecoderContext *dcx;
   960     SEC_PKCS7ContentInfo *cinfo;
   961     PLArenaPool *poolp;
   963     poolp = PORT_NewArena (1024);		/* XXX what is right value? */
   964     if (poolp == NULL)
   965 	return NULL;
   967     cinfo = (SEC_PKCS7ContentInfo*)PORT_ArenaZAlloc (poolp, sizeof(*cinfo));
   968     if (cinfo == NULL) {
   969 	PORT_FreeArena (poolp, PR_FALSE);
   970 	return NULL;
   971     }
   973     cinfo->poolp = poolp;
   974     cinfo->pwfn = pwfn;
   975     cinfo->pwfn_arg = pwfn_arg;
   976     cinfo->created = PR_FALSE;
   977     cinfo->refCount = 1;
   979     p7dcx = 
   980       (SEC_PKCS7DecoderContext*)PORT_ZAlloc (sizeof(SEC_PKCS7DecoderContext));
   981     if (p7dcx == NULL) {
   982 	PORT_FreeArena (poolp, PR_FALSE);
   983 	return NULL;
   984     }
   986     p7dcx->tmp_poolp = PORT_NewArena (1024);	/* XXX what is right value? */
   987     if (p7dcx->tmp_poolp == NULL) {
   988 	PORT_Free (p7dcx);
   989 	PORT_FreeArena (poolp, PR_FALSE);
   990 	return NULL;
   991     }
   993     dcx = SEC_ASN1DecoderStart (poolp, cinfo, sec_PKCS7ContentInfoTemplate);
   994     if (dcx == NULL) {
   995 	PORT_FreeArena (p7dcx->tmp_poolp, PR_FALSE);
   996 	PORT_Free (p7dcx);
   997 	PORT_FreeArena (poolp, PR_FALSE);
   998 	return NULL;
   999     }
  1001     SEC_ASN1DecoderSetNotifyProc (dcx, sec_pkcs7_decoder_notify, p7dcx);
  1003     p7dcx->dcx = dcx;
  1004     p7dcx->cinfo = cinfo;
  1005     p7dcx->cb = cb;
  1006     p7dcx->cb_arg = cb_arg;
  1007     p7dcx->pwfn = pwfn;
  1008     p7dcx->pwfn_arg = pwfn_arg;
  1009     p7dcx->dkcb = decrypt_key_cb;
  1010     p7dcx->dkcb_arg = decrypt_key_cb_arg;
  1011     p7dcx->decrypt_allowed_cb = decrypt_allowed_cb;
  1013     return p7dcx;
  1017 /*
  1018  * Do the next chunk of PKCS7 decoding.  If there is a problem, set
  1019  * an error and return a failure status.  Note that in the case of
  1020  * an error, this routine is still prepared to be called again and
  1021  * again in case that is the easiest route for our caller to take.
  1022  * We simply detect it and do not do anything except keep setting
  1023  * that error in case our caller has not noticed it yet...
  1024  */
  1025 SECStatus
  1026 SEC_PKCS7DecoderUpdate(SEC_PKCS7DecoderContext *p7dcx,
  1027 		       const char *buf, unsigned long len)
  1029     if (p7dcx->cinfo != NULL && p7dcx->dcx != NULL) { 
  1030 	PORT_Assert (p7dcx->error == 0);
  1031 	if (p7dcx->error == 0) {
  1032 	    if (SEC_ASN1DecoderUpdate (p7dcx->dcx, buf, len) != SECSuccess) {
  1033 		p7dcx->error = PORT_GetError();
  1034 		PORT_Assert (p7dcx->error);
  1035 		if (p7dcx->error == 0)
  1036 		    p7dcx->error = -1;
  1041     if (p7dcx->error) {
  1042 	if (p7dcx->dcx != NULL) {
  1043 	    (void) SEC_ASN1DecoderFinish (p7dcx->dcx);
  1044 	    p7dcx->dcx = NULL;
  1046 	if (p7dcx->cinfo != NULL) {
  1047 	    SEC_PKCS7DestroyContentInfo (p7dcx->cinfo);
  1048 	    p7dcx->cinfo = NULL;
  1050 	PORT_SetError (p7dcx->error);
  1051 	return SECFailure;
  1054     return SECSuccess;
  1058 SEC_PKCS7ContentInfo *
  1059 SEC_PKCS7DecoderFinish(SEC_PKCS7DecoderContext *p7dcx)
  1061     SEC_PKCS7ContentInfo *cinfo;
  1063     cinfo = p7dcx->cinfo;
  1064     if (p7dcx->dcx != NULL) {
  1065 	if (SEC_ASN1DecoderFinish (p7dcx->dcx) != SECSuccess) {
  1066 	    SEC_PKCS7DestroyContentInfo (cinfo);
  1067 	    cinfo = NULL;
  1070     /* free any NSS data structures */
  1071     if (p7dcx->worker.decryptobj) {
  1072         sec_PKCS7DestroyDecryptObject (p7dcx->worker.decryptobj);
  1074     PORT_FreeArena (p7dcx->tmp_poolp, PR_FALSE);
  1075     PORT_Free (p7dcx);
  1076     return cinfo;
  1080 SEC_PKCS7ContentInfo *
  1081 SEC_PKCS7DecodeItem(SECItem *p7item,
  1082 		    SEC_PKCS7DecoderContentCallback cb, void *cb_arg,
  1083 		    SECKEYGetPasswordKey pwfn, void *pwfn_arg,
  1084 		    SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb, 
  1085 		    void *decrypt_key_cb_arg,
  1086 		    SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb)
  1088     SEC_PKCS7DecoderContext *p7dcx;
  1090     p7dcx = SEC_PKCS7DecoderStart(cb, cb_arg, pwfn, pwfn_arg, decrypt_key_cb,
  1091 				  decrypt_key_cb_arg, decrypt_allowed_cb);
  1092     if (!p7dcx) {
  1093         /* error code is set */
  1094         return NULL;
  1096     (void) SEC_PKCS7DecoderUpdate(p7dcx, (char *) p7item->data, p7item->len);
  1097     return SEC_PKCS7DecoderFinish(p7dcx);
  1100 /*
  1101  * Abort the ASN.1 stream. Used by pkcs 12
  1102  */
  1103 void
  1104 SEC_PKCS7DecoderAbort(SEC_PKCS7DecoderContext *p7dcx, int error)
  1106     PORT_Assert(p7dcx);
  1107     SEC_ASN1DecoderAbort(p7dcx->dcx, error);
  1111 /*
  1112  * If the thing contains any certs or crls return true; false otherwise.
  1113  */
  1114 PRBool
  1115 SEC_PKCS7ContainsCertsOrCrls(SEC_PKCS7ContentInfo *cinfo)
  1117     SECOidTag kind;
  1118     SECItem **certs;
  1119     CERTSignedCrl **crls;
  1121     kind = SEC_PKCS7ContentType (cinfo);
  1122     switch (kind) {
  1123       default:
  1124       case SEC_OID_PKCS7_DATA:
  1125       case SEC_OID_PKCS7_DIGESTED_DATA:
  1126       case SEC_OID_PKCS7_ENVELOPED_DATA:
  1127       case SEC_OID_PKCS7_ENCRYPTED_DATA:
  1128 	return PR_FALSE;
  1129       case SEC_OID_PKCS7_SIGNED_DATA:
  1130 	certs = cinfo->content.signedData->rawCerts;
  1131 	crls = cinfo->content.signedData->crls;
  1132 	break;
  1133       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
  1134 	certs = cinfo->content.signedAndEnvelopedData->rawCerts;
  1135 	crls = cinfo->content.signedAndEnvelopedData->crls;
  1136 	break;
  1139     /*
  1140      * I know this could be collapsed, but I was in a mood to be explicit.
  1141      */
  1142     if (certs != NULL && certs[0] != NULL)
  1143 	return PR_TRUE;
  1144     else if (crls != NULL && crls[0] != NULL)
  1145 	return PR_TRUE;
  1146     else
  1147 	return PR_FALSE;
  1150 /* return the content length...could use GetContent, however we
  1151  * need the encrypted content length 
  1152  */
  1153 PRBool
  1154 SEC_PKCS7IsContentEmpty(SEC_PKCS7ContentInfo *cinfo, unsigned int minLen)
  1156     SECItem *item = NULL;
  1158     if(cinfo == NULL) {
  1159 	return PR_TRUE;
  1162     switch(SEC_PKCS7ContentType(cinfo)) 
  1164 	case SEC_OID_PKCS7_DATA:
  1165 	    item = cinfo->content.data;
  1166 	    break;
  1167 	case SEC_OID_PKCS7_ENCRYPTED_DATA:
  1168 	    item = &cinfo->content.encryptedData->encContentInfo.encContent;
  1169 	    break;
  1170 	default:
  1171 	    /* add other types */
  1172 	    return PR_FALSE;
  1175     if(!item) {
  1176 	return PR_TRUE;
  1177     } else if(item->len <= minLen) {
  1178 	return PR_TRUE;
  1181     return PR_FALSE;
  1185 PRBool
  1186 SEC_PKCS7ContentIsEncrypted(SEC_PKCS7ContentInfo *cinfo)
  1188     SECOidTag kind;
  1190     kind = SEC_PKCS7ContentType (cinfo);
  1191     switch (kind) {
  1192       default:
  1193       case SEC_OID_PKCS7_DATA:
  1194       case SEC_OID_PKCS7_DIGESTED_DATA:
  1195       case SEC_OID_PKCS7_SIGNED_DATA:
  1196 	return PR_FALSE;
  1197       case SEC_OID_PKCS7_ENCRYPTED_DATA:
  1198       case SEC_OID_PKCS7_ENVELOPED_DATA:
  1199       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
  1200 	return PR_TRUE;
  1205 /*
  1206  * If the PKCS7 content has a signature (not just *could* have a signature)
  1207  * return true; false otherwise.  This can/should be called before calling
  1208  * VerifySignature, which will always indicate failure if no signature is
  1209  * present, but that does not mean there even was a signature!
  1210  * Note that the content itself can be empty (detached content was sent
  1211  * another way); it is the presence of the signature that matters.
  1212  */
  1213 PRBool
  1214 SEC_PKCS7ContentIsSigned(SEC_PKCS7ContentInfo *cinfo)
  1216     SECOidTag kind;
  1217     SEC_PKCS7SignerInfo **signerinfos;
  1219     kind = SEC_PKCS7ContentType (cinfo);
  1220     switch (kind) {
  1221       default:
  1222       case SEC_OID_PKCS7_DATA:
  1223       case SEC_OID_PKCS7_DIGESTED_DATA:
  1224       case SEC_OID_PKCS7_ENVELOPED_DATA:
  1225       case SEC_OID_PKCS7_ENCRYPTED_DATA:
  1226 	return PR_FALSE;
  1227       case SEC_OID_PKCS7_SIGNED_DATA:
  1228 	signerinfos = cinfo->content.signedData->signerInfos;
  1229 	break;
  1230       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
  1231 	signerinfos = cinfo->content.signedAndEnvelopedData->signerInfos;
  1232 	break;
  1235     /*
  1236      * I know this could be collapsed; but I kind of think it will get
  1237      * more complicated before I am finished, so...
  1238      */
  1239     if (signerinfos != NULL && signerinfos[0] != NULL)
  1240 	return PR_TRUE;
  1241     else
  1242 	return PR_FALSE;
  1246 /*
  1247  * sec_pkcs7_verify_signature
  1249  *	Look at a PKCS7 contentInfo and check if the signature is good.
  1250  *	The digest was either calculated earlier (and is stored in the
  1251  *	contentInfo itself) or is passed in via "detached_digest".
  1253  *	The verification checks that the signing cert is valid and trusted
  1254  *	for the purpose specified by "certusage" at
  1255  * 	- "*atTime" if "atTime" is not null, or
  1256  * 	- the signing time if the signing time is available in "cinfo", or
  1257  *	- the current time (as returned by PR_Now).
  1259  *	In addition, if "keepcerts" is true, add any new certificates found
  1260  *	into our local database.
  1262  * XXX Each place which returns PR_FALSE should be sure to have a good
  1263  * error set for inspection by the caller.  Alternatively, we could create
  1264  * an enumeration of success and each type of failure and return that
  1265  * instead of a boolean.  For now, the default in a bad situation is to
  1266  * set the error to SEC_ERROR_PKCS7_BAD_SIGNATURE.  But this should be
  1267  * reviewed; better (more specific) errors should be possible (to distinguish
  1268  * a signature failure from a badly-formed pkcs7 signedData, for example).
  1269  * Some of the errors should probably just be SEC_ERROR_BAD_SIGNATURE,
  1270  * but that has a less helpful error string associated with it right now;
  1271  * if/when that changes, review and change these as needed.
  1273  * XXX This is broken wrt signedAndEnvelopedData.  In that case, the
  1274  * message digest is doubly encrypted -- first encrypted with the signer
  1275  * private key but then again encrypted with the bulk encryption key used
  1276  * to encrypt the content.  So before we can pass the digest to VerifyDigest,
  1277  * we need to decrypt it with the bulk encryption key.  Also, in this case,
  1278  * there should be NO authenticatedAttributes (signerinfo->authAttr should
  1279  * be NULL).
  1280  */
  1281 static PRBool
  1282 sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo,
  1283 			   SECCertUsage certusage,
  1284 			   const SECItem *detached_digest,
  1285 			   HASH_HashType digest_type,
  1286 			   PRBool keepcerts,
  1287 			   const PRTime *atTime)
  1289     SECAlgorithmID **digestalgs, *bulkid;
  1290     const SECItem *digest;
  1291     SECItem **digests;
  1292     SECItem **rawcerts;
  1293     CERTSignedCrl **crls;
  1294     SEC_PKCS7SignerInfo **signerinfos, *signerinfo;
  1295     CERTCertificate *cert, **certs;
  1296     PRBool goodsig;
  1297     CERTCertDBHandle *certdb, *defaultdb; 
  1298     SECOidTag encTag,digestTag;
  1299     HASH_HashType found_type;
  1300     int i, certcount;
  1301     SECKEYPublicKey *publickey;
  1302     SECItem *content_type;
  1303     PK11SymKey *sigkey;
  1304     SECItem *encoded_stime;
  1305     PRTime stime;
  1306     PRTime verificationTime;
  1307     SECStatus rv;
  1309     /*
  1310      * Everything needed in order to "goto done" safely.
  1311      */
  1312     goodsig = PR_FALSE;
  1313     certcount = 0;
  1314     cert = NULL;
  1315     certs = NULL;
  1316     certdb = NULL;
  1317     defaultdb = CERT_GetDefaultCertDB();
  1318     publickey = NULL;
  1320     if (! SEC_PKCS7ContentIsSigned(cinfo)) {
  1321 	PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
  1322 	goto done;
  1325     PORT_Assert (cinfo->contentTypeTag != NULL);
  1327     switch (cinfo->contentTypeTag->offset) {
  1328       default:
  1329       case SEC_OID_PKCS7_DATA:
  1330       case SEC_OID_PKCS7_DIGESTED_DATA:
  1331       case SEC_OID_PKCS7_ENVELOPED_DATA:
  1332       case SEC_OID_PKCS7_ENCRYPTED_DATA:
  1333 	/* Could only get here if SEC_PKCS7ContentIsSigned is broken. */
  1334 	PORT_Assert (0);
  1335       case SEC_OID_PKCS7_SIGNED_DATA:
  1337 	    SEC_PKCS7SignedData *sdp;
  1339 	    sdp = cinfo->content.signedData;
  1340 	    digestalgs = sdp->digestAlgorithms;
  1341 	    digests = sdp->digests;
  1342 	    rawcerts = sdp->rawCerts;
  1343 	    crls = sdp->crls;
  1344 	    signerinfos = sdp->signerInfos;
  1345 	    content_type = &(sdp->contentInfo.contentType);
  1346 	    sigkey = NULL;
  1347 	    bulkid = NULL;
  1349 	break;
  1350       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
  1352 	    SEC_PKCS7SignedAndEnvelopedData *saedp;
  1354 	    saedp = cinfo->content.signedAndEnvelopedData;
  1355 	    digestalgs = saedp->digestAlgorithms;
  1356 	    digests = saedp->digests;
  1357 	    rawcerts = saedp->rawCerts;
  1358 	    crls = saedp->crls;
  1359 	    signerinfos = saedp->signerInfos;
  1360 	    content_type = &(saedp->encContentInfo.contentType);
  1361 	    sigkey = saedp->sigKey;
  1362 	    bulkid = &(saedp->encContentInfo.contentEncAlg);
  1364 	break;
  1367     if ((signerinfos == NULL) || (signerinfos[0] == NULL)) {
  1368 	PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
  1369 	goto done;
  1372     /*
  1373      * XXX Need to handle multiple signatures; checking them is easy,
  1374      * but what should be the semantics here (like, return value)?
  1375      */
  1376     if (signerinfos[1] != NULL) {
  1377 	PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
  1378 	goto done;
  1381     signerinfo = signerinfos[0];
  1383     /*
  1384      * XXX I would like to just pass the issuerAndSN, along with the rawcerts
  1385      * and crls, to some function that did all of this certificate stuff
  1386      * (open/close the database if necessary, verifying the certs, etc.)
  1387      * and gave me back a cert pointer if all was good.
  1388      */
  1389     certdb = defaultdb;
  1390     if (certdb == NULL) {
  1391 	goto done;
  1394     certcount = 0;
  1395     if (rawcerts != NULL) {
  1396 	for (; rawcerts[certcount] != NULL; certcount++) {
  1397 	    /* just counting */
  1401     /*
  1402      * Note that the result of this is that each cert in "certs"
  1403      * needs to be destroyed.
  1404      */
  1405     rv = CERT_ImportCerts(certdb, certusage, certcount, rawcerts, &certs,
  1406 			  keepcerts, PR_FALSE, NULL);
  1407     if ( rv != SECSuccess ) {
  1408 	goto done;
  1411     /*
  1412      * This cert will also need to be freed, but since we save it
  1413      * in signerinfo for later, we do not want to destroy it when
  1414      * we leave this function -- we let the clean-up of the entire
  1415      * cinfo structure later do the destroy of this cert.
  1416      */
  1417     cert = CERT_FindCertByIssuerAndSN(certdb, signerinfo->issuerAndSN);
  1418     if (cert == NULL) {
  1419 	goto done;
  1422     signerinfo->cert = cert;
  1424     /*
  1425      * Get and convert the signing time; if available, it will be used
  1426      * both on the cert verification and for importing the sender
  1427      * email profile.
  1428      */
  1429     encoded_stime = SEC_PKCS7GetSigningTime (cinfo);
  1430     if (encoded_stime != NULL) {
  1431 	if (DER_DecodeTimeChoice (&stime, encoded_stime) != SECSuccess)
  1432 	    encoded_stime = NULL;	/* conversion failed, so pretend none */
  1435     /*
  1436      * XXX  This uses the signing time, if available.  Additionally, we
  1437      * might want to, if there is no signing time, get the message time
  1438      * from the mail header itself, and use that.  That would require
  1439      * a change to our interface though, and for S/MIME callers to pass
  1440      * in a time (and for non-S/MIME callers to pass in nothing, or
  1441      * maybe make them pass in the current time, always?).
  1442      */
  1443     if (atTime) {
  1444 	verificationTime = *atTime;
  1445     } else if (encoded_stime != NULL) {
  1446 	verificationTime = stime;
  1447     } else {
  1448 	verificationTime = PR_Now();
  1450     if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, verificationTime,
  1451 			 cinfo->pwfn_arg, NULL) != SECSuccess)
  1453 	/*
  1454 	 * XXX Give the user an option to check the signature anyway?
  1455 	 * If we want to do this, need to give a way to leave and display
  1456 	 * some dialog and get the answer and come back through (or do
  1457 	 * the rest of what we do below elsewhere, maybe by putting it
  1458 	 * in a function that we call below and could call from a dialog
  1459 	 * finish handler).
  1460 	 */
  1461 	goto savecert;
  1464     publickey = CERT_ExtractPublicKey (cert);
  1465     if (publickey == NULL)
  1466 	goto done;
  1468     /*
  1469      * XXX No!  If digests is empty, see if we can create it now by
  1470      * digesting the contents.  This is necessary if we want to allow
  1471      * somebody to do a simple decode (without filtering, etc.) and
  1472      * then later call us here to do the verification.
  1473      * OR, we can just specify that the interface to this routine
  1474      * *requires* that the digest(s) be done before calling and either
  1475      * stashed in the struct itself or passed in explicitly (as would
  1476      * be done for detached contents).
  1477      */
  1478     if ((digests == NULL || digests[0] == NULL)
  1479 	&& (detached_digest == NULL || detached_digest->data == NULL))
  1480 	goto done;
  1482     /*
  1483      * Find and confirm digest algorithm.
  1484      */
  1485     digestTag = SECOID_FindOIDTag(&(signerinfo->digestAlg.algorithm));
  1487     /* make sure we understand the digest type first */
  1488     found_type = HASH_GetHashTypeByOidTag(digestTag);
  1489     if ((digestTag == SEC_OID_UNKNOWN) || (found_type == HASH_AlgNULL)) {
  1490 	PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
  1491 	goto done;
  1494     if (detached_digest != NULL) {
  1495 	unsigned int hashLen     = HASH_ResultLen(found_type);
  1497 	if (digest_type != found_type || 
  1498 	    detached_digest->len != hashLen) {
  1499 	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
  1500 	    goto done;
  1502 	digest = detached_digest;
  1503     } else {
  1504 	PORT_Assert (digestalgs != NULL && digestalgs[0] != NULL);
  1505 	if (digestalgs == NULL || digestalgs[0] == NULL) {
  1506 	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
  1507 	    goto done;
  1510 	/*
  1511 	 * pick digest matching signerinfo->digestAlg from digests
  1512 	 */
  1513 	for (i = 0; digestalgs[i] != NULL; i++) {
  1514 	    if (SECOID_FindOIDTag(&(digestalgs[i]->algorithm)) == digestTag)
  1515 		break;
  1517 	if (digestalgs[i] == NULL) {
  1518 	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
  1519 	    goto done;
  1522 	digest = digests[i];
  1525     encTag = SECOID_FindOIDTag(&(signerinfo->digestEncAlg.algorithm));
  1526     if (encTag == SEC_OID_UNKNOWN) {
  1527 	PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
  1528 	goto done;
  1531     if (signerinfo->authAttr != NULL) {
  1532 	SEC_PKCS7Attribute *attr;
  1533 	SECItem *value;
  1534 	SECItem encoded_attrs;
  1536 	/*
  1537 	 * We have a sigkey only for signedAndEnvelopedData, which is
  1538 	 * not supposed to have any authenticated attributes.
  1539 	 */
  1540 	if (sigkey != NULL) {
  1541 	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
  1542 	    goto done;
  1545 	/*
  1546 	 * PKCS #7 says that if there are any authenticated attributes,
  1547 	 * then there must be one for content type which matches the
  1548 	 * content type of the content being signed, and there must
  1549 	 * be one for message digest which matches our message digest.
  1550 	 * So check these things first.
  1551 	 * XXX Might be nice to have a compare-attribute-value function
  1552 	 * which could collapse the following nicely.
  1553 	 */
  1554 	attr = sec_PKCS7FindAttribute (signerinfo->authAttr,
  1555 				       SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE);
  1556 	value = sec_PKCS7AttributeValue (attr);
  1557 	if (value == NULL || value->len != content_type->len) {
  1558 	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
  1559 	    goto done;
  1561 	if (PORT_Memcmp (value->data, content_type->data, value->len) != 0) {
  1562 	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
  1563 	    goto done;
  1566 	attr = sec_PKCS7FindAttribute (signerinfo->authAttr,
  1567 				       SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE);
  1568 	value = sec_PKCS7AttributeValue (attr);
  1569 	if (value == NULL || value->len != digest->len) {
  1570 	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
  1571 	    goto done;
  1573 	if (PORT_Memcmp (value->data, digest->data, value->len) != 0) {
  1574 	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
  1575 	    goto done;
  1578 	/*
  1579 	 * Okay, we met the constraints of the basic attributes.
  1580 	 * Now check the signature, which is based on a digest of
  1581 	 * the DER-encoded authenticated attributes.  So, first we
  1582 	 * encode and then we digest/verify.
  1583 	 */
  1584 	encoded_attrs.data = NULL;
  1585 	encoded_attrs.len = 0;
  1586 	if (sec_PKCS7EncodeAttributes (NULL, &encoded_attrs,
  1587 				       &(signerinfo->authAttr)) == NULL)
  1588 	    goto done;
  1590 	if (encoded_attrs.data == NULL || encoded_attrs.len == 0) {
  1591 	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
  1592 	    goto done;
  1595 	goodsig = (PRBool)(VFY_VerifyDataDirect(encoded_attrs.data, 
  1596 				   encoded_attrs.len,
  1597 				   publickey, &(signerinfo->encDigest),
  1598 				   encTag, digestTag, NULL,
  1599 				   cinfo->pwfn_arg) == SECSuccess);
  1600 	PORT_Free (encoded_attrs.data);
  1601     } else {
  1602 	SECItem *sig;
  1603 	SECItem holder;
  1604 	SECStatus rv;
  1606 	/*
  1607 	 * No authenticated attributes.
  1608 	 * The signature is based on the plain message digest.
  1609 	 */
  1611 	sig = &(signerinfo->encDigest);
  1612 	if (sig->len == 0) {		/* bad signature */
  1613 	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
  1614 	    goto done;
  1617 	if (sigkey != NULL) {
  1618 	    sec_PKCS7CipherObject *decryptobj;
  1619 	    unsigned int buflen;
  1621 	    /*
  1622 	     * For signedAndEnvelopedData, we first must decrypt the encrypted
  1623 	     * digest with the bulk encryption key.  The result is the normal
  1624 	     * encrypted digest (aka the signature).
  1625 	     */
  1626 	    decryptobj = sec_PKCS7CreateDecryptObject (sigkey, bulkid);
  1627 	    if (decryptobj == NULL)
  1628 		goto done;
  1630 	    buflen = sec_PKCS7DecryptLength (decryptobj, sig->len, PR_TRUE);
  1631 	    PORT_Assert (buflen);
  1632 	    if (buflen == 0) {		/* something is wrong */
  1633 		sec_PKCS7DestroyDecryptObject (decryptobj);
  1634 		goto done;
  1637 	    holder.data = (unsigned char*)PORT_Alloc (buflen);
  1638 	    if (holder.data == NULL) {
  1639 		sec_PKCS7DestroyDecryptObject (decryptobj);
  1640 		goto done;
  1643 	    rv = sec_PKCS7Decrypt (decryptobj, holder.data, &holder.len, buflen,
  1644 				   sig->data, sig->len, PR_TRUE);
  1645 	    sec_PKCS7DestroyDecryptObject (decryptobj);
  1646 	    if (rv != SECSuccess) {
  1647 		goto done;
  1650 	    sig = &holder;
  1653 	goodsig = (PRBool)(VFY_VerifyDigestDirect(digest, publickey, sig,
  1654 				     encTag, digestTag, cinfo->pwfn_arg)
  1655                             == SECSuccess);
  1657 	if (sigkey != NULL) {
  1658 	    PORT_Assert (sig == &holder);
  1659 	    PORT_ZFree (holder.data, holder.len);
  1663     if (! goodsig) {
  1664 	/*
  1665 	 * XXX Change the generic error into our specific one, because
  1666 	 * in that case we get a better explanation out of the Security
  1667 	 * Advisor.  This is really a bug in our error strings (the
  1668 	 * "generic" error has a lousy/wrong message associated with it
  1669 	 * which assumes the signature verification was done for the
  1670 	 * purposes of checking the issuer signature on a certificate)
  1671 	 * but this is at least an easy workaround and/or in the
  1672 	 * Security Advisor, which specifically checks for the error
  1673 	 * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation
  1674 	 * in that case but does not similarly check for
  1675 	 * SEC_ERROR_BAD_SIGNATURE.  It probably should, but then would
  1676 	 * probably say the wrong thing in the case that it *was* the
  1677 	 * certificate signature check that failed during the cert
  1678 	 * verification done above.  Our error handling is really a mess.
  1679 	 */
  1680 	if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE)
  1681 	    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
  1684 savecert:
  1685     /*
  1686      * Only save the smime profile if we are checking an email message and
  1687      * the cert has an email address in it.
  1688      */
  1689     if ( cert->emailAddr && cert->emailAddr[0] &&
  1690 	( ( certusage == certUsageEmailSigner ) ||
  1691 	 ( certusage == certUsageEmailRecipient ) ) ) {
  1692 	SECItem *profile = NULL;
  1693 	int save_error;
  1695 	/*
  1696 	 * Remember the current error set because we do not care about
  1697 	 * anything set by the functions we are about to call.
  1698 	 */
  1699 	save_error = PORT_GetError();
  1701 	if (goodsig && (signerinfo->authAttr != NULL)) {
  1702 	    /*
  1703 	     * If the signature is good, then we can save the S/MIME profile,
  1704 	     * if we have one.
  1705 	     */
  1706 	    SEC_PKCS7Attribute *attr;
  1708 	    attr = sec_PKCS7FindAttribute (signerinfo->authAttr,
  1709 					   SEC_OID_PKCS9_SMIME_CAPABILITIES,
  1710 					   PR_TRUE);
  1711 	    profile = sec_PKCS7AttributeValue (attr);
  1714 	rv = CERT_SaveSMimeProfile (cert, profile, encoded_stime);
  1716 	/*
  1717 	 * Restore the saved error in case the calls above set a new
  1718 	 * one that we do not actually care about.
  1719 	 */
  1720 	PORT_SetError (save_error);
  1722 	/*
  1723 	 * XXX Failure is not indicated anywhere -- the signature
  1724 	 * verification itself is unaffected by whether or not the
  1725 	 * profile was successfully saved.
  1726 	 */
  1730 done:
  1732     /*
  1733      * See comment above about why we do not want to destroy cert
  1734      * itself here.
  1735      */
  1737     if (certs != NULL)
  1738 	CERT_DestroyCertArray (certs, certcount);
  1740     if (publickey != NULL)
  1741 	SECKEY_DestroyPublicKey (publickey);
  1743     return goodsig;
  1746 /*
  1747  * SEC_PKCS7VerifySignature
  1748  *	Look at a PKCS7 contentInfo and check if the signature is good.
  1749  *	The verification checks that the signing cert is valid and trusted
  1750  *	for the purpose specified by "certusage".
  1752  *	In addition, if "keepcerts" is true, add any new certificates found
  1753  *	into our local database.
  1754  */
  1755 PRBool
  1756 SEC_PKCS7VerifySignature(SEC_PKCS7ContentInfo *cinfo,
  1757 			 SECCertUsage certusage,
  1758 			 PRBool keepcerts)
  1760     return sec_pkcs7_verify_signature (cinfo, certusage,
  1761 				       NULL, HASH_AlgNULL, keepcerts, NULL);
  1764 /*
  1765  * SEC_PKCS7VerifyDetachedSignature
  1766  *	Look at a PKCS7 contentInfo and check if the signature matches
  1767  *	a passed-in digest (calculated, supposedly, from detached contents).
  1768  *	The verification checks that the signing cert is valid and trusted
  1769  *	for the purpose specified by "certusage".
  1771  *	In addition, if "keepcerts" is true, add any new certificates found
  1772  *	into our local database.
  1773  */
  1774 PRBool
  1775 SEC_PKCS7VerifyDetachedSignature(SEC_PKCS7ContentInfo *cinfo,
  1776 				 SECCertUsage certusage,
  1777 				 const SECItem *detached_digest,
  1778 				 HASH_HashType digest_type,
  1779 				 PRBool keepcerts)
  1781     return sec_pkcs7_verify_signature (cinfo, certusage,
  1782 				       detached_digest, digest_type,
  1783 				       keepcerts, NULL);
  1786 /*
  1787  * SEC_PKCS7VerifyDetachedSignatureAtTime
  1788  *      Look at a PKCS7 contentInfo and check if the signature matches
  1789  *      a passed-in digest (calculated, supposedly, from detached contents).
  1790  *      The verification checks that the signing cert is valid and trusted
  1791  *      for the purpose specified by "certusage" at time "atTime".
  1793  *	In addition, if "keepcerts" is true, add any new certificates found
  1794  *	into our local database.
  1795  */
  1796 PRBool
  1797 SEC_PKCS7VerifyDetachedSignatureAtTime(SEC_PKCS7ContentInfo *cinfo,
  1798 				       SECCertUsage certusage,
  1799 				       const SECItem *detached_digest,
  1800 				       HASH_HashType digest_type,
  1801 				       PRBool keepcerts,
  1802 				       PRTime atTime)
  1804     return sec_pkcs7_verify_signature (cinfo, certusage,
  1805 				       detached_digest, digest_type,
  1806 				       keepcerts, &atTime);
  1809 /*
  1810  * Return the asked-for portion of the name of the signer of a PKCS7
  1811  * signed object.
  1813  * Returns a pointer to allocated memory, which must be freed.
  1814  * A NULL return value is an error.
  1815  */
  1817 #define sec_common_name 1
  1818 #define sec_email_address 2
  1820 static char *
  1821 sec_pkcs7_get_signer_cert_info(SEC_PKCS7ContentInfo *cinfo, int selector)
  1823     SECOidTag kind;
  1824     SEC_PKCS7SignerInfo **signerinfos;
  1825     CERTCertificate *signercert;
  1826     char *container;
  1828     kind = SEC_PKCS7ContentType (cinfo);
  1829     switch (kind) {
  1830       default:
  1831       case SEC_OID_PKCS7_DATA:
  1832       case SEC_OID_PKCS7_DIGESTED_DATA:
  1833       case SEC_OID_PKCS7_ENVELOPED_DATA:
  1834       case SEC_OID_PKCS7_ENCRYPTED_DATA:
  1835 	PORT_Assert (0);
  1836 	return NULL;
  1837       case SEC_OID_PKCS7_SIGNED_DATA:
  1839 	    SEC_PKCS7SignedData *sdp;
  1841 	    sdp = cinfo->content.signedData;
  1842 	    signerinfos = sdp->signerInfos;
  1844 	break;
  1845       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
  1847 	    SEC_PKCS7SignedAndEnvelopedData *saedp;
  1849 	    saedp = cinfo->content.signedAndEnvelopedData;
  1850 	    signerinfos = saedp->signerInfos;
  1852 	break;
  1855     if (signerinfos == NULL || signerinfos[0] == NULL)
  1856 	return NULL;
  1858     signercert = signerinfos[0]->cert;
  1860     /*
  1861      * No cert there; see if we can find one by calling verify ourselves.
  1862      */
  1863     if (signercert == NULL) {
  1864 	/*
  1865 	 * The cert usage does not matter in this case, because we do not
  1866 	 * actually care about the verification itself, but we have to pick
  1867 	 * some valid usage to pass in.
  1868 	 */
  1869 	(void) sec_pkcs7_verify_signature (cinfo, certUsageEmailSigner,
  1870 					   NULL, HASH_AlgNULL, PR_FALSE, NULL);
  1871 	signercert = signerinfos[0]->cert;
  1872 	if (signercert == NULL)
  1873 	    return NULL;
  1876     switch (selector) {
  1877       case sec_common_name:
  1878 	container = CERT_GetCommonName (&signercert->subject);
  1879 	break;
  1880       case sec_email_address:
  1881 	if(signercert->emailAddr && signercert->emailAddr[0]) {
  1882 	    container = PORT_Strdup(signercert->emailAddr);
  1883 	} else {
  1884 	    container = NULL;
  1886 	break;
  1887       default:
  1888 	PORT_Assert (0);
  1889 	container = NULL;
  1890 	break;
  1893     return container;
  1896 char *
  1897 SEC_PKCS7GetSignerCommonName(SEC_PKCS7ContentInfo *cinfo)
  1899     return sec_pkcs7_get_signer_cert_info(cinfo, sec_common_name);
  1902 char *
  1903 SEC_PKCS7GetSignerEmailAddress(SEC_PKCS7ContentInfo *cinfo)
  1905     return sec_pkcs7_get_signer_cert_info(cinfo, sec_email_address);
  1909 /*
  1910  * Return the signing time, in UTCTime format, of a PKCS7 contentInfo.
  1911  */
  1912 SECItem *
  1913 SEC_PKCS7GetSigningTime(SEC_PKCS7ContentInfo *cinfo)
  1915     SEC_PKCS7SignerInfo **signerinfos;
  1916     SEC_PKCS7Attribute *attr;
  1918     if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
  1919 	return NULL;
  1921     signerinfos = cinfo->content.signedData->signerInfos;
  1923     /*
  1924      * No signature, or more than one, means no deal.
  1925      */
  1926     if (signerinfos == NULL || signerinfos[0] == NULL || signerinfos[1] != NULL)
  1927 	return NULL;
  1929     attr = sec_PKCS7FindAttribute (signerinfos[0]->authAttr,
  1930 				   SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE);
  1931     return sec_PKCS7AttributeValue (attr);

mercurial