Back to index

lightning-sunbird  0.9+nobinonly
pk11nobj.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 /*
00037  * This file manages Netscape specific PKCS #11 objects (CRLs, Trust objects,
00038  * etc).
00039  */
00040 
00041 #include "secport.h"
00042 #include "seccomon.h"
00043 #include "secmod.h"
00044 #include "secmodi.h"
00045 #include "secmodti.h"
00046 #include "pkcs11.h"
00047 #include "pk11func.h"
00048 #include "cert.h"
00049 #include "certi.h" 
00050 #include "secitem.h"
00051 #include "sechash.h" 
00052 #include "secoid.h"
00053 
00054 #include "certdb.h" 
00055 #include "secerr.h"
00056 #include "sslerr.h"
00057 
00058 #include "pki3hack.h"
00059 #include "dev3hack.h" 
00060 
00061 #include "devm.h" 
00062 #include "pki.h"
00063 #include "pkim.h" 
00064 
00065 extern const NSSError NSS_ERROR_NOT_FOUND;
00066 
00067 CK_TRUST
00068 pk11_GetTrustField(PK11SlotInfo *slot, PRArenaPool *arena, 
00069                    CK_OBJECT_HANDLE id, CK_ATTRIBUTE_TYPE type)
00070 {
00071   CK_TRUST rv = 0;
00072   SECItem item;
00073 
00074   item.data = NULL;
00075   item.len = 0;
00076 
00077   if( SECSuccess == PK11_ReadAttribute(slot, id, type, arena, &item) ) {
00078     PORT_Assert(item.len == sizeof(CK_TRUST));
00079     PORT_Memcpy(&rv, item.data, sizeof(CK_TRUST));
00080     /* Damn, is there an endian problem here? */
00081     return rv;
00082   }
00083 
00084   return 0;
00085 }
00086 
00087 PRBool
00088 pk11_HandleTrustObject(PK11SlotInfo *slot, CERTCertificate *cert, CERTCertTrust *trust)
00089 {
00090   PRArenaPool *arena;
00091 
00092   CK_ATTRIBUTE tobjTemplate[] = {
00093     { CKA_CLASS, NULL, 0 },
00094     { CKA_CERT_SHA1_HASH, NULL, 0 },
00095   };
00096 
00097   CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST;
00098   CK_OBJECT_HANDLE tobjID;
00099   unsigned char sha1_hash[SHA1_LENGTH];
00100 
00101   CK_TRUST serverAuth, codeSigning, emailProtection, clientAuth;
00102 
00103   PK11_HashBuf(SEC_OID_SHA1, sha1_hash, cert->derCert.data, cert->derCert.len);
00104 
00105   PK11_SETATTRS(&tobjTemplate[0], CKA_CLASS, &tobjc, sizeof(tobjc));
00106   PK11_SETATTRS(&tobjTemplate[1], CKA_CERT_SHA1_HASH, sha1_hash, 
00107                 SHA1_LENGTH);
00108 
00109   tobjID = pk11_FindObjectByTemplate(slot, tobjTemplate, 
00110                                      sizeof(tobjTemplate)/sizeof(tobjTemplate[0]));
00111   if( CK_INVALID_HANDLE == tobjID ) {
00112     return PR_FALSE;
00113   }
00114 
00115   arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00116   if( NULL == arena ) return PR_FALSE;
00117 
00118   /* Unfortunately, it seems that PK11_GetAttributes doesn't deal
00119    * well with nonexistant attributes.  I guess we have to check 
00120    * the trust info fields one at a time.
00121    */
00122 
00123   /* We could verify CKA_CERT_HASH here */
00124 
00125   /* We could verify CKA_EXPIRES here */
00126 
00127 
00128   /* "Purpose" trust information */
00129   serverAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_SERVER_AUTH);
00130   clientAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CLIENT_AUTH);
00131   codeSigning = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CODE_SIGNING);
00132   emailProtection = pk11_GetTrustField(slot, arena, tobjID, 
00133                                           CKA_TRUST_EMAIL_PROTECTION);
00134   /* Here's where the fun logic happens.  We have to map back from the 
00135    * key usage, extended key usage, purpose, and possibly other trust values 
00136    * into the old trust-flags bits.  */
00137 
00138   /* First implementation: keep it simple for testing.  We can study what other
00139    * mappings would be appropriate and add them later.. fgmr 20000724 */
00140 
00141   if ( serverAuth ==  CKT_NETSCAPE_TRUSTED ) {
00142     trust->sslFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED;
00143   }
00144 
00145   if ( serverAuth == CKT_NETSCAPE_TRUSTED_DELEGATOR ) {
00146     trust->sslFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | 
00147                                                  CERTDB_NS_TRUSTED_CA;
00148   }
00149   if ( clientAuth == CKT_NETSCAPE_TRUSTED_DELEGATOR ) {
00150     trust->sslFlags |=  CERTDB_TRUSTED_CLIENT_CA ;
00151   }
00152 
00153   if ( emailProtection == CKT_NETSCAPE_TRUSTED ) {
00154     trust->emailFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED;
00155   }
00156 
00157   if ( emailProtection == CKT_NETSCAPE_TRUSTED_DELEGATOR ) {
00158     trust->emailFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA;
00159   }
00160 
00161   if( codeSigning == CKT_NETSCAPE_TRUSTED ) {
00162     trust->objectSigningFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED;
00163   }
00164 
00165   if( codeSigning == CKT_NETSCAPE_TRUSTED_DELEGATOR ) {
00166     trust->objectSigningFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA;
00167   }
00168 
00169   /* There's certainly a lot more logic that can go here.. */
00170 
00171   PORT_FreeArena(arena, PR_FALSE);
00172 
00173   return PR_TRUE;
00174 }
00175 
00176 static SECStatus
00177 pk11_CollectCrls(PK11SlotInfo *slot, CK_OBJECT_HANDLE crlID, void *arg)
00178 {
00179     SECItem derCrl;
00180     CERTCrlHeadNode *head = (CERTCrlHeadNode *) arg;
00181     CERTCrlNode *new_node = NULL;
00182     CK_ATTRIBUTE fetchCrl[3] = {
00183         { CKA_VALUE, NULL, 0},
00184         { CKA_NETSCAPE_KRL, NULL, 0},
00185         { CKA_NETSCAPE_URL, NULL, 0},
00186     };
00187     const int fetchCrlSize = sizeof(fetchCrl)/sizeof(fetchCrl[2]);
00188     CK_RV crv;
00189     SECStatus rv = SECFailure;
00190 
00191     crv = PK11_GetAttributes(head->arena,slot,crlID,fetchCrl,fetchCrlSize);
00192     if (CKR_OK != crv) {
00193        PORT_SetError(PK11_MapError(crv));
00194        goto loser;
00195     }
00196 
00197     if (!fetchCrl[1].pValue) {
00198        PORT_SetError(SEC_ERROR_CRL_INVALID);
00199        goto loser;
00200     }
00201 
00202     new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena, sizeof(CERTCrlNode));
00203     if (new_node == NULL) {
00204         goto loser;
00205     }
00206 
00207     if (*((CK_BBOOL *)fetchCrl[1].pValue))
00208         new_node->type = SEC_KRL_TYPE;
00209     else
00210         new_node->type = SEC_CRL_TYPE;
00211 
00212     derCrl.type = siBuffer;
00213     derCrl.data = (unsigned char *)fetchCrl[0].pValue;
00214     derCrl.len = fetchCrl[0].ulValueLen;
00215     new_node->crl=CERT_DecodeDERCrl(head->arena,&derCrl,new_node->type);
00216     if (new_node->crl == NULL) {
00217        goto loser;
00218     }
00219 
00220     if (fetchCrl[2].pValue) {
00221         int nnlen = fetchCrl[2].ulValueLen;
00222         new_node->crl->url  = (char *)PORT_ArenaAlloc(head->arena, nnlen+1);
00223         if ( !new_node->crl->url ) {
00224             goto loser;
00225         }
00226         PORT_Memcpy(new_node->crl->url, fetchCrl[2].pValue, nnlen);
00227         new_node->crl->url[nnlen] = 0;
00228     } else {
00229         new_node->crl->url = NULL;
00230     }
00231 
00232 
00233     new_node->next = NULL;
00234     if (head->last) {
00235         head->last->next = new_node;
00236         head->last = new_node;
00237     } else {
00238         head->first = head->last = new_node;
00239     }
00240     rv = SECSuccess;
00241 
00242 loser:
00243     return(rv);
00244 }
00245 
00246 /*
00247  * Return a list of all the CRLs .
00248  * CRLs are allocated in the list's arena.
00249  */
00250 SECStatus
00251 PK11_LookupCrls(CERTCrlHeadNode *nodes, int type, void *wincx) {
00252     pk11TraverseSlot creater;
00253     CK_ATTRIBUTE theTemplate[2];
00254     CK_ATTRIBUTE *attrs;
00255     CK_OBJECT_CLASS certClass = CKO_NETSCAPE_CRL;
00256     CK_BBOOL isKrl = CK_FALSE;
00257 
00258     attrs = theTemplate;
00259     PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass)); attrs++;
00260     if (type != -1) {
00261        isKrl = (CK_BBOOL) (type == SEC_KRL_TYPE);
00262         PK11_SETATTRS(attrs, CKA_NETSCAPE_KRL, &isKrl, sizeof(isKrl)); attrs++;
00263     }
00264 
00265     creater.callback = pk11_CollectCrls;
00266     creater.callbackArg = (void *) nodes;
00267     creater.findTemplate = theTemplate;
00268     creater.templateCount = (attrs - theTemplate);
00269 
00270     return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, PR_FALSE, wincx);
00271 }
00272 
00273 struct crlOptionsStr {
00274     CERTCrlHeadNode* head;
00275     PRInt32 decodeOptions;
00276 };
00277 
00278 typedef struct crlOptionsStr crlOptions;
00279 
00280 static SECStatus
00281 pk11_RetrieveCrlsCallback(PK11SlotInfo *slot, CK_OBJECT_HANDLE crlID,
00282                           void *arg)
00283 {
00284     SECItem* derCrl = NULL;
00285     crlOptions* options = (crlOptions*) arg;
00286     CERTCrlHeadNode *head = options->head;
00287     CERTCrlNode *new_node = NULL;
00288     CK_ATTRIBUTE fetchCrl[3] = {
00289         { CKA_VALUE, NULL, 0},
00290         { CKA_NETSCAPE_KRL, NULL, 0},
00291         { CKA_NETSCAPE_URL, NULL, 0},
00292     };
00293     const int fetchCrlSize = sizeof(fetchCrl)/sizeof(fetchCrl[2]);
00294     CK_RV crv;
00295     SECStatus rv = SECFailure;
00296     PRBool adopted = PR_FALSE; /* whether the CRL adopted the DER memory
00297                                   successfully */
00298     int i;
00299 
00300     crv = PK11_GetAttributes(NULL,slot,crlID,fetchCrl,fetchCrlSize);
00301     if (CKR_OK != crv) {
00302        PORT_SetError(PK11_MapError(crv));
00303        goto loser;
00304     }
00305 
00306     if (!fetchCrl[1].pValue) {
00307         /* reject KRLs */
00308        PORT_SetError(SEC_ERROR_CRL_INVALID);
00309        goto loser;
00310     }
00311 
00312     new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena,
00313                                               sizeof(CERTCrlNode));
00314     if (new_node == NULL) {
00315         goto loser;
00316     }
00317 
00318     new_node->type = SEC_CRL_TYPE;
00319 
00320     derCrl = SECITEM_AllocItem(NULL, NULL, 0);
00321     if (!derCrl) {
00322         goto loser;
00323     }
00324     derCrl->type = siBuffer;
00325     derCrl->data = (unsigned char *)fetchCrl[0].pValue;
00326     derCrl->len = fetchCrl[0].ulValueLen;
00327     new_node->crl = CERT_DecodeDERCrlWithFlags(NULL, derCrl,new_node->type,
00328                                                options->decodeOptions);
00329     if (new_node->crl == NULL) {
00330        goto loser;
00331     }    
00332     adopted = PR_TRUE; /* now that the CRL has adopted the DER memory,
00333                           we won't need to free it upon exit */
00334 
00335     if (fetchCrl[2].pValue && fetchCrl[2].ulValueLen) {
00336         /* copy the URL if there is one */
00337         int nnlen = fetchCrl[2].ulValueLen;
00338         new_node->crl->url  = (char *)PORT_ArenaAlloc(new_node->crl->arena,
00339                                                       nnlen+1);
00340         if ( !new_node->crl->url ) {
00341             goto loser;
00342         }
00343         PORT_Memcpy(new_node->crl->url, fetchCrl[2].pValue, nnlen);
00344         new_node->crl->url[nnlen] = 0;
00345     } else {
00346         new_node->crl->url = NULL;
00347     }
00348 
00349     new_node->next = NULL;
00350     if (head->last) {
00351         head->last->next = new_node;
00352         head->last = new_node;
00353     } else {
00354         head->first = head->last = new_node;
00355     }
00356     rv = SECSuccess;
00357     new_node->crl->slot = PK11_ReferenceSlot(slot);
00358     new_node->crl->pkcs11ID = crlID;
00359 
00360 loser:
00361     /* free attributes that weren't adopted by the CRL */
00362     for (i=1;i<fetchCrlSize;i++) {
00363         if (fetchCrl[i].pValue) {
00364             PORT_Free(fetchCrl[i].pValue);
00365         }
00366     }
00367     /* free the DER if the CRL object didn't adopt it */
00368     if (fetchCrl[0].pValue && PR_FALSE == adopted) {
00369         PORT_Free(fetchCrl[0].pValue);
00370     }
00371     if (derCrl && !adopted) {
00372         /* clear the data fields, which we already took care of above */
00373         derCrl->data = NULL;
00374         derCrl->len = 0;
00375         /* free the memory for the SECItem structure itself */
00376         SECITEM_FreeItem(derCrl, PR_TRUE);
00377     }
00378     return(rv);
00379 }
00380 
00381 /*
00382  * Return a list of CRLs matching specified issuer and type
00383  * CRLs are not allocated in the list's arena, but rather in their own,
00384  * arena, so that they can be used individually in the CRL cache .
00385  * CRLs are always partially decoded for efficiency.
00386  */
00387 SECStatus pk11_RetrieveCrls(CERTCrlHeadNode *nodes, SECItem* issuer,
00388                             void *wincx)
00389 {
00390     pk11TraverseSlot creater;
00391     CK_ATTRIBUTE theTemplate[2];
00392     CK_ATTRIBUTE *attrs;
00393     CK_OBJECT_CLASS crlClass = CKO_NETSCAPE_CRL;
00394     crlOptions options;
00395 
00396     attrs = theTemplate;
00397     PK11_SETATTRS(attrs, CKA_CLASS, &crlClass, sizeof(crlClass)); attrs++;
00398 
00399     options.head = nodes;
00400 
00401     /* - do a partial decoding - we don't need to decode the entries while
00402        fetching
00403        - don't copy the DER for optimal performance - CRL can be very large
00404        - have the CRL objects adopt the DER, so SEC_DestroyCrl will free it
00405        - keep bad CRL objects. The CRL cache is interested in them, for
00406          security purposes. Bad CRL objects are a sign of something amiss.
00407     */
00408 
00409     options.decodeOptions = CRL_DECODE_SKIP_ENTRIES | CRL_DECODE_DONT_COPY_DER |
00410                             CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_KEEP_BAD_CRL;
00411     if (issuer)
00412     {
00413         PK11_SETATTRS(attrs, CKA_SUBJECT, issuer->data, issuer->len); attrs++;
00414     }
00415 
00416     creater.callback = pk11_RetrieveCrlsCallback;
00417     creater.callbackArg = (void *) &options;
00418     creater.findTemplate = theTemplate;
00419     creater.templateCount = (attrs - theTemplate);
00420 
00421     return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, PR_FALSE, wincx);
00422 }
00423 
00424 /*
00425  * return the crl associated with a derSubjectName 
00426  */
00427 SECItem *
00428 PK11_FindCrlByName(PK11SlotInfo **slot, CK_OBJECT_HANDLE *crlHandle,
00429                                     SECItem *name, int type, char **pUrl)
00430 {
00431     NSSCRL **crls, **crlp, *crl = NULL;
00432     NSSDER subject;
00433     SECItem *rvItem;
00434     NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
00435     char * url = NULL;
00436 
00437     PORT_SetError(0);
00438     NSSITEM_FROM_SECITEM(&subject, name);
00439     if (*slot) {
00440        nssCryptokiObject **instances;
00441        nssPKIObjectCollection *collection;
00442        nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
00443        NSSToken *token = PK11Slot_GetNSSToken(*slot);
00444        collection = nssCRLCollection_Create(td, NULL);
00445        if (!collection) {
00446            goto loser;
00447        }
00448        instances = nssToken_FindCRLsBySubject(token, NULL, &subject, 
00449                                               tokenOnly, 0, NULL);
00450        nssPKIObjectCollection_AddInstances(collection, instances, 0);
00451        nss_ZFreeIf(instances);
00452        crls = nssPKIObjectCollection_GetCRLs(collection, NULL, 0, NULL);
00453        nssPKIObjectCollection_Destroy(collection);
00454     } else {
00455        crls = nssTrustDomain_FindCRLsBySubject(td, &subject);
00456     }
00457     if ((!crls) || (*crls == NULL)) {
00458        if (crls) {
00459            nssCRLArray_Destroy(crls);
00460        }
00461        if (NSS_GetError() == NSS_ERROR_NOT_FOUND) {
00462            PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
00463        }
00464        goto loser;
00465     }
00466     for (crlp = crls; *crlp; crlp++) {
00467        if ((!(*crlp)->isKRL && type == SEC_CRL_TYPE) ||
00468            ((*crlp)->isKRL && type != SEC_CRL_TYPE)) 
00469        {
00470            crl = nssCRL_AddRef(*crlp);
00471            break;
00472        }
00473     }
00474     nssCRLArray_Destroy(crls);
00475     if (!crl) { 
00476        /* CRL collection was found, but no interesting CRL's were on it.
00477         * Not an error */
00478        PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
00479        goto loser;
00480     }
00481     if (crl->url) {
00482        url = PORT_Strdup(crl->url);
00483        if (!url) {
00484            goto loser;
00485        }
00486     }
00487     rvItem = SECITEM_AllocItem(NULL, NULL, crl->encoding.size);
00488     if (!rvItem) {
00489        goto loser;
00490     }
00491     memcpy(rvItem->data, crl->encoding.data, crl->encoding.size);
00492     *slot = PK11_ReferenceSlot(crl->object.instances[0]->token->pk11slot);
00493     *crlHandle = crl->object.instances[0]->handle;
00494     *pUrl = url;
00495     nssCRL_Destroy(crl);
00496     return rvItem;
00497 
00498 loser:
00499     if (url)
00500        PORT_Free(url);
00501     if (crl)
00502        nssCRL_Destroy(crl);
00503     if (PORT_GetError() == 0) {
00504        PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
00505     }
00506     return NULL;
00507 }
00508 
00509 CK_OBJECT_HANDLE
00510 PK11_PutCrl(PK11SlotInfo *slot, SECItem *crl, SECItem *name, 
00511                                                  char *url, int type)
00512 {
00513     NSSItem derCRL, derSubject;
00514     NSSToken *token = PK11Slot_GetNSSToken(slot);
00515     nssCryptokiObject *object;
00516     PRBool isKRL = (type == SEC_CRL_TYPE) ? PR_FALSE : PR_TRUE;
00517     CK_OBJECT_HANDLE rvH;
00518 
00519     NSSITEM_FROM_SECITEM(&derSubject, name);
00520     NSSITEM_FROM_SECITEM(&derCRL, crl);
00521 
00522     object = nssToken_ImportCRL(token, NULL, 
00523                                 &derSubject, &derCRL, isKRL, url, PR_TRUE);
00524 
00525     if (object) {
00526        rvH = object->handle;
00527        nssCryptokiObject_Destroy(object);
00528     } else {
00529        rvH = CK_INVALID_HANDLE;
00530     }
00531     return rvH;
00532 }
00533 
00534 
00535 /*
00536  * delete a crl.
00537  */
00538 SECStatus
00539 SEC_DeletePermCRL(CERTSignedCrl *crl)
00540 {
00541     PRStatus status;
00542     NSSToken *token;
00543     nssCryptokiObject *object;
00544     PK11SlotInfo *slot = crl->slot;
00545 
00546     if (slot == NULL) {
00547         PORT_Assert(slot);
00548        /* shouldn't happen */
00549        PORT_SetError( SEC_ERROR_CRL_INVALID);
00550        return SECFailure;
00551     }
00552     token = PK11Slot_GetNSSToken(slot);
00553 
00554     object = nss_ZNEW(NULL, nssCryptokiObject);
00555     object->token = nssToken_AddRef(token);
00556     object->handle = crl->pkcs11ID;
00557     object->isTokenObject = PR_TRUE;
00558 
00559     status = nssToken_DeleteStoredObject(object);
00560 
00561     nssCryptokiObject_Destroy(object);
00562     return (status == PR_SUCCESS) ? SECSuccess : SECFailure;
00563 }
00564 
00565 /*
00566  * return the certificate associated with a derCert 
00567  */
00568 SECItem *
00569 PK11_FindSMimeProfile(PK11SlotInfo **slot, char *emailAddr,
00570                              SECItem *name, SECItem **profileTime)
00571 {
00572     CK_OBJECT_CLASS smimeClass = CKO_NETSCAPE_SMIME;
00573     CK_ATTRIBUTE theTemplate[] = {
00574        { CKA_SUBJECT, NULL, 0 },
00575        { CKA_CLASS, NULL, 0 },
00576        { CKA_NETSCAPE_EMAIL, NULL, 0 },
00577     };
00578     CK_ATTRIBUTE smimeData[] =  {
00579        { CKA_SUBJECT, NULL, 0 },
00580        { CKA_VALUE, NULL, 0 },
00581     };
00582     /* if you change the array, change the variable below as well */
00583     int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
00584     CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE;
00585     CK_ATTRIBUTE *attrs = theTemplate;
00586     CK_RV crv;
00587     SECItem *emailProfile = NULL;
00588 
00589     if (!emailAddr || !emailAddr[0]) {
00590        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00591        return NULL;
00592     }
00593 
00594     PK11_SETATTRS(attrs, CKA_SUBJECT, name->data, name->len); attrs++;
00595     PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass)); attrs++;
00596     PK11_SETATTRS(attrs, CKA_NETSCAPE_EMAIL, emailAddr, strlen(emailAddr)); 
00597                                                             attrs++;
00598 
00599     if (*slot) {
00600        smimeh = pk11_FindObjectByTemplate(*slot,theTemplate,tsize);
00601     } else {
00602        PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
00603                                                  PR_FALSE,PR_TRUE,NULL);
00604        PK11SlotListElement *le;
00605 
00606        /* loop through all the slots */
00607        for (le = list->head; le; le = le->next) {
00608            smimeh = pk11_FindObjectByTemplate(le->slot,theTemplate,tsize);
00609            if (smimeh != CK_INVALID_HANDLE) {
00610               *slot = PK11_ReferenceSlot(le->slot);
00611               break;
00612            }
00613        }
00614        PK11_FreeSlotList(list);
00615     }
00616     
00617     if (smimeh == CK_INVALID_HANDLE) {
00618        PORT_SetError(SEC_ERROR_NO_KRL);
00619        return NULL;
00620     }
00621 
00622     if (profileTime) {
00623        PK11_SETATTRS(smimeData, CKA_NETSCAPE_SMIME_TIMESTAMP, NULL, 0);
00624     } 
00625     
00626     crv = PK11_GetAttributes(NULL,*slot,smimeh,smimeData,2);
00627     if (crv != CKR_OK) {
00628        PORT_SetError(PK11_MapError (crv));
00629        goto loser;
00630     }
00631 
00632     if (!profileTime) {
00633        SECItem profileSubject;
00634 
00635        profileSubject.data = (unsigned char*) smimeData[0].pValue;
00636        profileSubject.len = smimeData[0].ulValueLen;
00637        if (!SECITEM_ItemsAreEqual(&profileSubject,name)) {
00638            goto loser;
00639        }
00640     }
00641 
00642     emailProfile = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    
00643     if (emailProfile == NULL) {
00644        goto loser;
00645     }
00646 
00647     emailProfile->data = (unsigned char*) smimeData[1].pValue;
00648     emailProfile->len = smimeData[1].ulValueLen;
00649 
00650     if (profileTime) {
00651        *profileTime = (SECItem *)PORT_ZAlloc(sizeof(SECItem));    
00652        if (*profileTime) {
00653            (*profileTime)->data = (unsigned char*) smimeData[0].pValue;
00654            (*profileTime)->len = smimeData[0].ulValueLen;
00655        }
00656     }
00657 
00658 loser:
00659     if (emailProfile == NULL) {
00660        if (smimeData[1].pValue) {
00661            PORT_Free(smimeData[1].pValue);
00662        }
00663     }
00664     if (profileTime == NULL || *profileTime == NULL) {
00665        if (smimeData[0].pValue) {
00666            PORT_Free(smimeData[0].pValue);
00667        }
00668     }
00669     return emailProfile;
00670 }
00671 
00672 
00673 SECStatus
00674 PK11_SaveSMimeProfile(PK11SlotInfo *slot, char *emailAddr, SECItem *derSubj,
00675                              SECItem *emailProfile,  SECItem *profileTime)
00676 {
00677     CK_OBJECT_CLASS smimeClass = CKO_NETSCAPE_SMIME;
00678     CK_BBOOL ck_true = CK_TRUE;
00679     CK_ATTRIBUTE theTemplate[] = {
00680        { CKA_CLASS, NULL, 0 },
00681        { CKA_TOKEN, NULL, 0 },
00682        { CKA_SUBJECT, NULL, 0 },
00683        { CKA_NETSCAPE_EMAIL, NULL, 0 },
00684        { CKA_NETSCAPE_SMIME_TIMESTAMP, NULL, 0 },
00685        { CKA_VALUE, NULL, 0 }
00686     };
00687     /* if you change the array, change the variable below as well */
00688     int realSize = 0;
00689     CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE;
00690     CK_ATTRIBUTE *attrs = theTemplate;
00691     CK_SESSION_HANDLE rwsession;
00692     PK11SlotInfo *free_slot = NULL;
00693     CK_RV crv;
00694 #ifdef DEBUG
00695     int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
00696 #endif
00697 
00698     PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass)); attrs++;
00699     PK11_SETATTRS(attrs, CKA_TOKEN, &ck_true, sizeof(ck_true)); attrs++;
00700     PK11_SETATTRS(attrs, CKA_SUBJECT, derSubj->data, derSubj->len); attrs++;
00701     PK11_SETATTRS(attrs, CKA_NETSCAPE_EMAIL, 
00702                             emailAddr, PORT_Strlen(emailAddr)+1); attrs++;
00703     if (profileTime) {
00704        PK11_SETATTRS(attrs, CKA_NETSCAPE_SMIME_TIMESTAMP, profileTime->data,
00705                                                    profileTime->len); attrs++;
00706        PK11_SETATTRS(attrs, CKA_VALUE,emailProfile->data,
00707                                                    emailProfile->len); attrs++;
00708     }
00709     realSize = attrs - theTemplate;
00710     PORT_Assert (realSize <= tsize);
00711 
00712     if (slot == NULL) {
00713        free_slot = slot = PK11_GetInternalKeySlot();
00714        /* we need to free the key slot in the end!!! */
00715     }
00716 
00717     rwsession = PK11_GetRWSession(slot);
00718     if (rwsession == CK_INVALID_SESSION) {
00719        PORT_SetError(SEC_ERROR_READ_ONLY);
00720        if (free_slot) {
00721            PK11_FreeSlot(free_slot);
00722        }
00723        return SECFailure;
00724     }
00725 
00726     crv = PK11_GETTAB(slot)->
00727                         C_CreateObject(rwsession,theTemplate,realSize,&smimeh);
00728     if (crv != CKR_OK) {
00729         PORT_SetError( PK11_MapError(crv) );
00730     }
00731 
00732     PK11_RestoreROSession(slot,rwsession);
00733 
00734     if (free_slot) {
00735        PK11_FreeSlot(free_slot);
00736     }
00737     return SECSuccess;
00738 }
00739 
00740 
00741 CERTSignedCrl * crl_storeCRL (PK11SlotInfo *slot,char *url,
00742                   CERTSignedCrl *newCrl, SECItem *derCrl, int type);
00743 
00744 /* import the CRL into the token */
00745 
00746 CERTSignedCrl* PK11_ImportCRL(PK11SlotInfo * slot, SECItem *derCRL, char *url,
00747     int type, void *wincx, PRInt32 importOptions, PRArenaPool* arena,
00748     PRInt32 decodeoptions)
00749 {
00750     CERTSignedCrl *newCrl, *crl;
00751     SECStatus rv;
00752     CERTCertificate *caCert = NULL;
00753 
00754     newCrl = crl = NULL;
00755 
00756     do {
00757         newCrl = CERT_DecodeDERCrlWithFlags(arena, derCRL, type,
00758                                             decodeoptions);
00759         if (newCrl == NULL) {
00760             if (type == SEC_CRL_TYPE) {
00761                 /* only promote error when the error code is too generic */
00762                 if (PORT_GetError () == SEC_ERROR_BAD_DER)
00763                     PORT_SetError(SEC_ERROR_CRL_INVALID);
00764                } else {
00765                 PORT_SetError(SEC_ERROR_KRL_INVALID);
00766             }
00767             break;          
00768         }
00769 
00770         if (0 == (importOptions & CRL_IMPORT_BYPASS_CHECKS)){
00771             CERTCertDBHandle* handle = CERT_GetDefaultCertDB();
00772             PR_ASSERT(handle != NULL);
00773             caCert = CERT_FindCertByName (handle,
00774                                           &newCrl->crl.derName);
00775             if (caCert == NULL) {
00776                 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);           
00777                 break;
00778             }
00779 
00780             /* If caCert is a v3 certificate, make sure that it can be used for
00781                crl signing purpose */
00782             rv = CERT_CheckCertUsage (caCert, KU_CRL_SIGN);
00783             if (rv != SECSuccess) {
00784                 break;
00785             }
00786 
00787             rv = CERT_VerifySignedData(&newCrl->signatureWrap, caCert,
00788                                        PR_Now(), wincx);
00789             if (rv != SECSuccess) {
00790                 if (type == SEC_CRL_TYPE) {
00791                     PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE);
00792                 } else {
00793                     PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE);
00794                 }
00795                 break;
00796             }
00797         }
00798 
00799        crl = crl_storeCRL(slot, url, newCrl, derCRL, type);
00800 
00801     } while (0);
00802 
00803     if (crl == NULL) {
00804        SEC_DestroyCrl (newCrl);
00805     }
00806     if (caCert) {
00807         CERT_DestroyCertificate(caCert);
00808     }
00809     return (crl);
00810 }