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