aboutsummaryrefslogblamecommitdiffstats
path: root/smime/lib/e-cert-db.c
blob: c74ac0a1764783ef7092cddf3dcb056a31f2b5fa (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
                                                                           
                                                                    
                                                           

              
                                    
  



                                                                              
  



                                                                             
  
                                                        
  















                                                                             

   
  
                                           
  
                                                        
   



                    

                       

                        

                                                                                                                      

                                              




                                                         
                      
                         
                     
 

                    
                

                    
                     
                    
                   
                   
                   


                  
                          
                                  



                      

                    
                           
                               




                                            
                                                 
 


























































































































































































































                                                                                                                                                                                                               
                            


                               



                                  
 
                                           

                                         
                                                              
                                                                 
                                          
                                    


                                     
                            
                                                                         
                                     
                                            






                            
                     
                                                     

                                                 


                                               
                                                                                 





                                   
                                              
                                                              
                                                                





                                 
 
             

                                           





                                             


                                                 
      
 
                          


                                  
 

                      









                                                         


                            





                                      
           
                     
 
                                                                
                                                  
 
                                                                    
                                             

                                        






                                                              
             
                                                                        
      




                             


                                                                  
               
 


                                                    
 


                                                              
                                                               


                                                             

                         
 
                                  
         
                                      
 


                                                                       
 







                                                                                                    
                           



                                                                                                     
 
                                                                                        
 



                                                   
 
                           
                  
                                                                  


                                                  
                  
                                                 


                                            

                                           

                                                  
                  
 
                                                                     
                                                                                             
 
                                                                         




                                                                                     
                                                                                          


                                                  
 

                                          





                                                                  
         


           
                                          


                                   
                                              
 
                          
                                                                  
                                  






                                                                          
                                                                         

                                                                              






                                                                                 
                                                                 

                                                              






                                                                                     
                                                                                 

                                                                                              


           

                            

 


                                              
         
















                                                              
       
                                                 

                                                       
 
                                                 

                                     
                                                                              
                                                                    
                    
                                                                                              

         
                   
                                                                       



                                                 
                                      



                            
             
       
                                            

                                                
 
                                                 


                                              
                               


                              
                                      


                            
                                                               
                                                                      
 
                                                                                   

                                                              
 
                                          



                                                                                    

                                                                          

                                                                                




                                                 
                              
                    

 



                                                  


 
       
                                                      

                                                            


 
       
                                                   

                                                         

 
      
 
       
                                                      

                                                         


                                                  
                                  

                               
                                                       
                                                           
 
                        
                                      


                            

                                                               

                                                                       
                                                                    
                                                                  
                        
                                      
                                                   


                            

                                                               
                                      
                                                   
                                                

                            
 
                                                                  
                                      
                                                   
                                                


                            
                                                                                  


                                           




                    




                                                  
 














                                                                    


               


                                          


                          
                              


                                                                    











                                                                      















                                                              



                                               
 








                                                                   
                                                                  
                                                                                      

                                                                                      

                                                                        
                                                                       
                                                                                       
                                                                          

                                           
                                                                                    
                                              




                                           
                                      


                             
                                                                   
                                      


                             
                                      
 

                                                                               

                                                                    
                               
                                                                        



                                                                                   
                                              




                                     
                                                        


                              

                                                                                                          


                             
                                                               
                                
                              
                                    
 


                                                        
                                              


                                     
                                                                                   
 
                                                         
 




                                                                                                


                                                          
 
                                                      
                                                      
                                                     
 
                                                                         












                                                                              
                                        
                                                                        
                                                                                 

                                                                             




                                                                       
                                        
                                              




                                                                                 

                                                                               


                                                             
                                                         


                                              
                                                                      
                                                                                 
 
                                                   
                                                                                                  

                                        
                                                                                              
                                                                                    
                         



                                                                                                  




                            
                                                                                  






                                                                
                                                                       



                                                                     
                                             
                                                                 
                                                      




                             


                                       
                                    
 
                                               
                                                                                      

                              
 






                                                                                





                                                                                


                                                                
                                                                  

         
                    




                                        




                                                

                                               
                                                                   

                                                                                              
               


                              
                                      
                                                 



                                                      
                                                        

                                                                 
 
                                                                                     
                            
                                              
                                                                             
                                            
                                                         





                                                    
                                                                    













                                                                                                                 

                      
                                                                                
                                      
                                                 
                           
         
 
                                                             
                            
                                         




                                             



                                                     
 




                                               

                      
                                                                   
                                                                                              
 
                              
                                      
                                                 
                             

         
                                                                                           
                                                                          
                    
                                      
                           

                           
                                            
                                                                           
                        
                                      
                           

                           
 
                                        
                                                           
         
 
                                                                               

                                                                           
                                
                                      
                           

                           
                                                 






                                                                         
                                                                                             






                                                                                          
                             
       
                 
                                               
                  
                                                
                  

 
              
                                        
 
                                                  




                               
                                    
                                   
                                  

                                   
                                                                   
 
                                                       
                             
                                          
 
                             
                           
 
                                                 
                           
                                        
 
                           
                           
 


                                   
 
                                                           




                                                                              
                                                              


                           
                                      
                                                                                
                                   



                               

                                
                                                                      
                 
 
                                     
                                   
 
                                             
                                                                                       
                                                                                      
 

                          
                                                                                       

                                
                                                                               


                                                                             
                                   
                                                                                                         




                                                                                                     
                                                                            



                                                         
                                      
                                  
 
                                                       

                                                        
                        
                                

       
                       
                                   


                        
                     
                                 
         
                        
                                   

                           
                                     

                                       
                                                     

                                               

                                                                






                                               

                          

 

                                            


                                           
 

                                                 
                                
                            
                        


                                   
                                      
 
                                                      
                            
                                      




                                                                             
                                      


                           
                                                                                        
                                                                          
                    
                                      


                           
                                                        
                           
                                      

                           
                             








                                                                                    
                                                   


                                           
                                                            
                    
                                      

                           
                             


                                               
                                                    
                                                                                         


                                  
 

                    
                                                 
         
                   
                                               

                  



                                              



                                                      
 
                                                                     
                                     
                     



                                                   



                                                          

                    
                
                       

                        






                            
 

                                         
                                      


                             
                                                        
                       
                                      



                                    
                                      


                             
 

                                    
                                      






                                                
 
                                       
                                      


                           
                                                                                 


                                    
                                                                                                                 


                                 
                                                                                                            


                                    
                                                                                                           
                              
 






                                   
                  



                                               

                                                     
 








                                                                 
 
 
             

                                               


                                                     

 
      
 

                                          
                                            




                                               
                                   

                                            
                                                                









                                                                                
                                                                            
                                                     

                 
                                                     
                                                                            
                                                                           
                                                                             





                                     
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* The following is the mozilla license blurb, as the bodies some of
 * these functions were derived from the mozilla source. */
/* e-cert-db.c
 *
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the Netscape security libraries.
 *
 * The Initial Developer of the Original Code is
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 1994-2000
 * the Initial Developer. All Rights Reserved.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 */

/*
 * Author: Chris Toshok (toshok@ximian.com)
 *
 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>

#include <camel/camel.h>        /* FIXME: this is where camel_init is defined; it shouldn't include everything else */

#include <libedataserverui/libedataserverui.h>

/* private NSS defines used by PSM */
/* (must be declated before cert.h) */
#define CERT_NewTempCertificate __CERT_NewTempCertificate
#define CERT_AddTempCertToPerm __CERT_AddTempCertToPerm

#include "e-cert-db.h"
#include "e-cert-trust.h"
#include "e-pkcs12.h"

#include "gmodule.h"

#include "nss.h"
#include "ssl.h"
#include "p12plcy.h"
#include "pk11func.h"
#include "nssckbi.h"
#include <secerr.h>
#include "secmod.h"
#include "certdb.h"
#include "plstr.h"
#include "prprf.h"
#include "prmem.h"
#include "e-util/e-util.h"
#include "e-util/e-util-private.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

enum {
    PK11_PASSWD,
    PK11_CHANGE_PASSWD,
    CONFIRM_CA_CERT_IMPORT,
    LAST_SIGNAL
};

static guint e_cert_db_signals[LAST_SIGNAL];

G_DEFINE_TYPE (ECertDB, e_cert_db, G_TYPE_OBJECT)

GQuark
e_certdb_error_quark (void)
{
    static GQuark q = 0;
    if (q == 0)
        q = g_quark_from_static_string ("e-certdb-error-quark");

    return q;
}

static const gchar *
nss_error_to_string (glong errorcode)
{
#define cs(a,b) case a: return b;

    switch (errorcode) {
    cs (SEC_ERROR_IO, "An I/O error occurred during security authorization.")
    cs (SEC_ERROR_LIBRARY_FAILURE, "security library failure.")
    cs (SEC_ERROR_BAD_DATA, "security library: received bad data.")
    cs (SEC_ERROR_OUTPUT_LEN, "security library: output length error.")
    cs (SEC_ERROR_INPUT_LEN, "security library has experienced an input length error.")
    cs (SEC_ERROR_INVALID_ARGS, "security library: invalid arguments.")
    cs (SEC_ERROR_INVALID_ALGORITHM, "security library: invalid algorithm.")
    cs (SEC_ERROR_INVALID_AVA, "security library: invalid AVA.")
    cs (SEC_ERROR_INVALID_TIME, "Improperly formatted time string.")
    cs (SEC_ERROR_BAD_DER, "security library: improperly formatted DER-encoded message.")
    cs (SEC_ERROR_BAD_SIGNATURE, "Peer's certificate has an invalid signature.")
    cs (SEC_ERROR_EXPIRED_CERTIFICATE, "Peer's Certificate has expired.")
    cs (SEC_ERROR_REVOKED_CERTIFICATE, "Peer's Certificate has been revoked.")
    cs (SEC_ERROR_UNKNOWN_ISSUER, "Peer's Certificate issuer is not recognized.")
    cs (SEC_ERROR_BAD_KEY, "Peer's public key is invalid.")
    cs (SEC_ERROR_BAD_PASSWORD, "The security password entered is incorrect.")
    cs (SEC_ERROR_RETRY_PASSWORD, "New password entered incorrectly.  Please try again.")
    cs (SEC_ERROR_NO_NODELOCK, "security library: no nodelock.")
    cs (SEC_ERROR_BAD_DATABASE, "security library: bad database.")
    cs (SEC_ERROR_NO_MEMORY, "security library: memory allocation failure.")
    cs (SEC_ERROR_UNTRUSTED_ISSUER, "Peer's certificate issuer has been marked as not trusted by the user.")
    cs (SEC_ERROR_UNTRUSTED_CERT, "Peer's certificate has been marked as not trusted by the user.")
    cs (SEC_ERROR_DUPLICATE_CERT, "Certificate already exists in your database.")
    cs (SEC_ERROR_DUPLICATE_CERT_NAME, "Downloaded certificate's name duplicates one already in your database.")
    cs (SEC_ERROR_ADDING_CERT, "Error adding certificate to database.")
    cs (SEC_ERROR_FILING_KEY, "Error refiling the key for this certificate.")
    cs (SEC_ERROR_NO_KEY, "The private key for this certificate cannot be found in key database")
    cs (SEC_ERROR_CERT_VALID, "This certificate is valid.")
    cs (SEC_ERROR_CERT_NOT_VALID, "This certificate is not valid.")
    cs (SEC_ERROR_CERT_NO_RESPONSE, "Cert Library: No Response")
    cs (SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE, "The certificate issuer's certificate has expired.  Check your system date and time.")
    cs (SEC_ERROR_CRL_EXPIRED, "The CRL for the certificate's issuer has expired.  Update it or check your system date and time.")
    cs (SEC_ERROR_CRL_BAD_SIGNATURE, "The CRL for the certificate's issuer has an invalid signature.")
    cs (SEC_ERROR_CRL_INVALID, "New CRL has an invalid format.")
    cs (SEC_ERROR_EXTENSION_VALUE_INVALID, "Certificate extension value is invalid.")
    cs (SEC_ERROR_EXTENSION_NOT_FOUND, "Certificate extension not found.")
    cs (SEC_ERROR_CA_CERT_INVALID, "Issuer certificate is invalid.")
    cs (SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID, "Certificate path length constraint is invalid.")
    cs (SEC_ERROR_CERT_USAGES_INVALID, "Certificate usages field is invalid.")
    cs (SEC_INTERNAL_ONLY, "**Internal ONLY module**")
    cs (SEC_ERROR_INVALID_KEY, "The key does not support the requested operation.")
    cs (SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION, "Certificate contains unknown critical extension.")
    cs (SEC_ERROR_OLD_CRL, "New CRL is not later than the current one.")
    cs (SEC_ERROR_NO_EMAIL_CERT, "Not encrypted or signed: you do not yet have an email certificate.")
    cs (SEC_ERROR_NO_RECIPIENT_CERTS_QUERY, "Not encrypted: you do not have certificates for each of the recipients.")
    cs (SEC_ERROR_NOT_A_RECIPIENT, "Cannot decrypt: you are not a recipient, or matching certificate and private key not found.")
    cs (SEC_ERROR_PKCS7_KEYALG_MISMATCH, "Cannot decrypt: key encryption algorithm does not match your certificate.")
    cs (SEC_ERROR_PKCS7_BAD_SIGNATURE, "Signature verification failed: no signer found, too many signers found, or improper or corrupted data.")
    cs (SEC_ERROR_UNSUPPORTED_KEYALG, "Unsupported or unknown key algorithm.")
    cs (SEC_ERROR_DECRYPTION_DISALLOWED, "Cannot decrypt: encrypted using a disallowed algorithm or key size.")
    cs (XP_SEC_FORTEZZA_BAD_CARD, "Fortezza card has not been properly initialized.  Please remove it and return it to your issuer.")
    cs (XP_SEC_FORTEZZA_NO_CARD, "No Fortezza cards Found")
    cs (XP_SEC_FORTEZZA_NONE_SELECTED, "No Fortezza card selected")
    cs (XP_SEC_FORTEZZA_MORE_INFO, "Please select a personality to get more info on")
    cs (XP_SEC_FORTEZZA_PERSON_NOT_FOUND, "Personality not found")
    cs (XP_SEC_FORTEZZA_NO_MORE_INFO, "No more information on that Personality")
    cs (XP_SEC_FORTEZZA_BAD_PIN, "Invalid Pin")
    cs (XP_SEC_FORTEZZA_PERSON_ERROR, "Couldn't initialize Fortezza personalities.")
    cs (SEC_ERROR_NO_KRL, "No KRL for this site's certificate has been found.")
    cs (SEC_ERROR_KRL_EXPIRED, "The KRL for this site's certificate has expired.")
    cs (SEC_ERROR_KRL_BAD_SIGNATURE, "The KRL for this site's certificate has an invalid signature.")
    cs (SEC_ERROR_REVOKED_KEY, "The key for this site's certificate has been revoked.")
    cs (SEC_ERROR_KRL_INVALID, "New KRL has an invalid format.")
    cs (SEC_ERROR_NEED_RANDOM, "security library: need random data.")
    cs (SEC_ERROR_NO_MODULE, "security library: no security module can perform the requested operation.")
    cs (SEC_ERROR_NO_TOKEN, "The security card or token does not exist, needs to be initialized, or has been removed.")
    cs (SEC_ERROR_READ_ONLY, "security library: read-only database.")
    cs (SEC_ERROR_NO_SLOT_SELECTED, "No slot or token was selected.")
    cs (SEC_ERROR_CERT_NICKNAME_COLLISION, "A certificate with the same nickname already exists.")
    cs (SEC_ERROR_KEY_NICKNAME_COLLISION, "A key with the same nickname already exists.")
    cs (SEC_ERROR_SAFE_NOT_CREATED, "error while creating safe object")
    cs (SEC_ERROR_BAGGAGE_NOT_CREATED, "error while creating baggage object")
    cs (XP_JAVA_REMOVE_PRINCIPAL_ERROR, "Couldn't remove the principal")
    cs (XP_JAVA_DELETE_PRIVILEGE_ERROR, "Couldn't delete the privilege")
    cs (XP_JAVA_CERT_NOT_EXISTS_ERROR, "This principal doesn't have a certificate")
    cs (SEC_ERROR_BAD_EXPORT_ALGORITHM, "Required algorithm is not allowed.")
    cs (SEC_ERROR_EXPORTING_CERTIFICATES, "Error attempting to export certificates.")
    cs (SEC_ERROR_IMPORTING_CERTIFICATES, "Error attempting to import certificates.")
    cs (SEC_ERROR_PKCS12_DECODING_PFX, "Unable to import.  Decoding error.  File not valid.")
    cs (SEC_ERROR_PKCS12_INVALID_MAC, "Unable to import.  Invalid MAC.  Incorrect password or corrupt file.")
    cs (SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM, "Unable to import.  MAC algorithm not supported.")
    cs (SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE, "Unable to import.  Only password integrity and privacy modes supported.")
    cs (SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE, "Unable to import.  File structure is corrupt.")
    cs (SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM, "Unable to import.  Encryption algorithm not supported.")
    cs (SEC_ERROR_PKCS12_UNSUPPORTED_VERSION, "Unable to import.  File version not supported.")
    cs (SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT, "Unable to import.  Incorrect privacy password.")
    cs (SEC_ERROR_PKCS12_CERT_COLLISION, "Unable to import.  Same nickname already exists in database.")
    cs (SEC_ERROR_USER_CANCELLED, "The user pressed cancel.")
    cs (SEC_ERROR_PKCS12_DUPLICATE_DATA, "Not imported, already in database.")
    cs (SEC_ERROR_MESSAGE_SEND_ABORTED, "Message not sent.")
    cs (SEC_ERROR_INADEQUATE_KEY_USAGE, "Certificate key usage inadequate for attempted operation.")
    cs (SEC_ERROR_INADEQUATE_CERT_TYPE, "Certificate type not approved for application.")
    cs (SEC_ERROR_CERT_ADDR_MISMATCH, "Address in signing certificate does not match address in message headers.")
    cs (SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY, "Unable to import.  Error attempting to import private key.")
    cs (SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN, "Unable to import.  Error attempting to import certificate chain.")
    cs (SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME, "Unable to export.  Unable to locate certificate or key by nickname.")
    cs (SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY, "Unable to export.  Private Key could not be located and exported.")
    cs (SEC_ERROR_PKCS12_UNABLE_TO_WRITE, "Unable to export.  Unable to write the export file.")
    cs (SEC_ERROR_PKCS12_UNABLE_TO_READ, "Unable to import.  Unable to read the import file.")
    cs (SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED, "Unable to export.  Key database corrupt or deleted.")
    cs (SEC_ERROR_KEYGEN_FAIL, "Unable to generate public/private key pair.")
    cs (SEC_ERROR_INVALID_PASSWORD, "Password entered is invalid.  Please pick a different one.")
    cs (SEC_ERROR_RETRY_OLD_PASSWORD, "Old password entered incorrectly.  Please try again.")
    cs (SEC_ERROR_BAD_NICKNAME, "Certificate nickname already in use.")
    cs (SEC_ERROR_NOT_FORTEZZA_ISSUER, "Peer FORTEZZA chain has a non-FORTEZZA Certificate.")
    cs (SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY, "A sensitive key cannot be moved to the slot where it is needed.")
    cs (SEC_ERROR_JS_INVALID_MODULE_NAME, "Invalid module name.")
    cs (SEC_ERROR_JS_INVALID_DLL, "Invalid module path/filename")
    cs (SEC_ERROR_JS_ADD_MOD_FAILURE, "Unable to add module")
    cs (SEC_ERROR_JS_DEL_MOD_FAILURE, "Unable to delete module")
    cs (SEC_ERROR_OLD_KRL, "New KRL is not later than the current one.")
    cs (SEC_ERROR_CKL_CONFLICT, "New CKL has different issuer than current CKL.  Delete current CKL.")
    cs (SEC_ERROR_CERT_NOT_IN_NAME_SPACE, "The Certifying Authority for this certificate is not permitted to issue a certificate with this name.")
    cs (SEC_ERROR_KRL_NOT_YET_VALID, "The key revocation list for this certificate is not yet valid.")
    cs (SEC_ERROR_CRL_NOT_YET_VALID, "The certificate revocation list for this certificate is not yet valid.")
    cs (SEC_ERROR_UNKNOWN_CERT, "The requested certificate could not be found.")
    cs (SEC_ERROR_UNKNOWN_SIGNER, "The signer's certificate could not be found.")
    cs (SEC_ERROR_CERT_BAD_ACCESS_LOCATION,  "The location for the certificate status server has invalid format.")
    cs (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE, "The OCSP response cannot be fully decoded; it is of an unknown type.")
    cs (SEC_ERROR_OCSP_BAD_HTTP_RESPONSE, "The OCSP server returned unexpected/invalid HTTP data.")
    cs (SEC_ERROR_OCSP_MALFORMED_REQUEST, "The OCSP server found the request to be corrupted or improperly formed.")
    cs (SEC_ERROR_OCSP_SERVER_ERROR, "The OCSP server experienced an internal error.")
    cs (SEC_ERROR_OCSP_TRY_SERVER_LATER, "The OCSP server suggests trying again later.")
    cs (SEC_ERROR_OCSP_REQUEST_NEEDS_SIG, "The OCSP server requires a signature on this request.")
    cs (SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST, "The OCSP server has refused this request as unauthorized.")
    cs (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, "The OCSP server returned an unrecognizable status.")
    cs (SEC_ERROR_OCSP_UNKNOWN_CERT, "The OCSP server has no status for the certificate.")
    cs (SEC_ERROR_OCSP_NOT_ENABLED, "You must enable OCSP before performing this operation.")
    cs (SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER, "You must set the OCSP default responder before performing this operation.")
    cs (SEC_ERROR_OCSP_MALFORMED_RESPONSE, "The response from the OCSP server was corrupted or improperly formed.")
    cs (SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE, "The signer of the OCSP response is not authorized to give status for this certificate.")
    cs (SEC_ERROR_OCSP_FUTURE_RESPONSE, "The OCSP response is not yet valid (contains a date in the future).")
    cs (SEC_ERROR_OCSP_OLD_RESPONSE, "The OCSP response contains out-of-date information.")
    cs (SEC_ERROR_DIGEST_NOT_FOUND, "The CMS or PKCS #7 Digest was not found in signed message.")
    cs (SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE, "The CMS or PKCS #7 Message type is unsupported.")
    cs (SEC_ERROR_MODULE_STUCK, "PKCS #11 module could not be removed because it is still in use.")
    cs (SEC_ERROR_BAD_TEMPLATE, "Could not decode ASN.1 data. Specified template was invalid.")
    cs (SEC_ERROR_CRL_NOT_FOUND, "No matching CRL was found.")
    cs (SEC_ERROR_REUSED_ISSUER_AND_SERIAL, "You are attempting to import a cert with the same issuer/serial as an existing cert, but that is not the same cert.")
    cs (SEC_ERROR_BUSY, "NSS could not shutdown. Objects are still in use.")
    cs (SEC_ERROR_EXTRA_INPUT, "DER-encoded message contained extra unused data.")
    cs (SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE, "Unsupported elliptic curve.")
    cs (SEC_ERROR_UNSUPPORTED_EC_POINT_FORM, "Unsupported elliptic curve point form.")
    cs (SEC_ERROR_UNRECOGNIZED_OID, "Unrecognized Object Identifier.")
    cs (SEC_ERROR_OCSP_INVALID_SIGNING_CERT, "Invalid OCSP signing certificate in OCSP response.")
    cs (SEC_ERROR_REVOKED_CERTIFICATE_CRL, "Certificate is revoked in issuer's certificate revocation list.")
    cs (SEC_ERROR_REVOKED_CERTIFICATE_OCSP, "Issuer's OCSP responder reports certificate is revoked.")
    cs (SEC_ERROR_CRL_INVALID_VERSION, "Issuer's Certificate Revocation List has an unknown version number.")
    cs (SEC_ERROR_CRL_V1_CRITICAL_EXTENSION, "Issuer's V1 Certificate Revocation List has a critical extension.")
    cs (SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION, "Issuer's V2 Certificate Revocation List has an unknown critical extension.")
    cs (SEC_ERROR_UNKNOWN_OBJECT_TYPE, "Unknown object type specified.")
    cs (SEC_ERROR_INCOMPATIBLE_PKCS11, "PKCS #11 driver violates the spec in an incompatible way.")
    cs (SEC_ERROR_NO_EVENT, "No new slot event is available at this time.")
    cs (SEC_ERROR_CRL_ALREADY_EXISTS, "CRL already exists.")
    cs (SEC_ERROR_NOT_INITIALIZED, "NSS is not initialized.")
    cs (SEC_ERROR_TOKEN_NOT_LOGGED_IN, "The operation failed because the PKCS#11 token is not logged in.")
    cs (SEC_ERROR_OCSP_RESPONDER_CERT_INVALID, "Configured OCSP responder's certificate is invalid.")
    cs (SEC_ERROR_OCSP_BAD_SIGNATURE, "OCSP response has an invalid signature.")

    #if defined (NSS_VMAJOR) && defined (NSS_VMINOR) && defined (NSS_VPATCH) && (NSS_VMAJOR > 3 || (NSS_VMAJOR == 3 && NSS_VMINOR > 12) || (NSS_VMAJOR == 3 && NSS_VMINOR == 12 && NSS_VPATCH >= 2))
    cs (SEC_ERROR_OUT_OF_SEARCH_LIMITS, "Cert validation search is out of search limits")
    cs (SEC_ERROR_INVALID_POLICY_MAPPING, "Policy mapping contains anypolicy")
    cs (SEC_ERROR_POLICY_VALIDATION_FAILED, "Cert chain fails policy validation")
    cs (SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE, "Unknown location type in cert AIA extension")
    cs (SEC_ERROR_BAD_HTTP_RESPONSE, "Server returned bad HTTP response")
    cs (SEC_ERROR_BAD_LDAP_RESPONSE, "Server returned bad LDAP response")
    cs (SEC_ERROR_FAILED_TO_ENCODE_DATA, "Failed to encode data with ASN1 encoder")
    cs (SEC_ERROR_BAD_INFO_ACCESS_LOCATION, "Bad information access location in cert extension")
    cs (SEC_ERROR_LIBPKIX_INTERNAL, "Libpkix internal error occured during cert validation.")
    cs (SEC_ERROR_PKCS11_GENERAL_ERROR, "A PKCS #11 module returned CKR_GENERAL_ERROR, indicating that an unrecoverable error has occurred.")
    cs (SEC_ERROR_PKCS11_FUNCTION_FAILED, "A PKCS #11 module returned CKR_FUNCTION_FAILED, indicating that the requested function could not be performed.  Trying the same operation again might succeed.")
    cs (SEC_ERROR_PKCS11_DEVICE_ERROR, "A PKCS #11 module returned CKR_DEVICE_ERROR, indicating that a problem has occurred with the token or slot.")
    #endif
    }

    #undef cs

    return NULL;
}

static void
set_nss_error (GError **error)
{
    glong err_code;
    const gchar *err_str;

    if (!error)
        return;

    g_return_if_fail (*error == NULL);

    err_code = PORT_GetError ();

    if (!err_code)
        return;

    err_str = nss_error_to_string (err_code);
    if (!err_str)
        return;

    *error = g_error_new_literal (E_CERTDB_ERROR, err_code, err_str);
}

static SECStatus PR_CALLBACK
collect_certs (gpointer arg,
               SECItem **certs,
               gint numcerts)
{
    CERTDERCerts *collectArgs;
    SECItem *cert;
    SECStatus rv;

    collectArgs = (CERTDERCerts *) arg;

    collectArgs->numcerts = numcerts;
    collectArgs->rawCerts = (SECItem *) PORT_ArenaZAlloc (
        collectArgs->arena, sizeof (SECItem) * numcerts);
    if (collectArgs->rawCerts == NULL)
        return (SECFailure);

    cert = collectArgs->rawCerts;

    while (numcerts--) {
        rv = SECITEM_CopyItem (collectArgs->arena, cert, *certs);
        if (rv == SECFailure)
            return (SECFailure);
        cert++;
        certs++;
    }

    return (SECSuccess);
}

static CERTDERCerts *
e_cert_db_get_certs_from_package (PRArenaPool *arena,
                                  gchar *data,
                                  guint32 length)
{
    /*nsNSSShutDownPreventionLock locker;*/
    CERTDERCerts *collectArgs =
        (CERTDERCerts *) PORT_ArenaZAlloc (arena, sizeof (CERTDERCerts));
    SECStatus sec_rv;

    if (!collectArgs)
        return NULL;

    collectArgs->arena = arena;
    sec_rv = CERT_DecodeCertPackage (data,
                    length, collect_certs,
                    (gpointer) collectArgs);

    if (sec_rv != SECSuccess)
        return NULL;

    return collectArgs;
}

#ifdef notyet
PRBool
ucs2_ascii_conversion_fn (PRBool toUnicode,
                          guchar *inBuf,
                          guint inBufLen,
                          guchar *outBuf,
                          guint maxOutBufLen,
                          guint *outBufLen,
                          PRBool swapBytes)
{
    printf ("in ucs2_ascii_conversion_fn\n");
}
#endif

static gchar * PR_CALLBACK
pk11_password (PK11SlotInfo *slot,
               PRBool retry,
               gpointer arg)
{
    gchar *pwd;
    gchar *nsspwd;

    gboolean rv = FALSE;

    g_signal_emit (e_cert_db_peek (),
               e_cert_db_signals[PK11_PASSWD], 0,
               slot,
               retry,
               &pwd,
               &rv);

    if (pwd == NULL)
        return NULL;

    nsspwd = PORT_Strdup (pwd);
    memset (pwd, 0, strlen (pwd));
    g_free (pwd);
    return nsspwd;
}

static void
initialize_nss (void)
{
    /* Use camel_init() to initialise NSS consistently... */
    camel_init (e_get_user_data_dir (), TRUE);

    /* ... except for the bits we only seem to do here. FIXME */
    PK11_SetPasswordFunc (pk11_password);

    /* Enable ciphers for PKCS#12 */
    SEC_PKCS12EnableCipher (PKCS12_RC4_40, 1);
    SEC_PKCS12EnableCipher (PKCS12_RC4_128, 1);
    SEC_PKCS12EnableCipher (PKCS12_RC2_CBC_40, 1);
    SEC_PKCS12EnableCipher (PKCS12_RC2_CBC_128, 1);
    SEC_PKCS12EnableCipher (PKCS12_DES_56, 1);
    SEC_PKCS12EnableCipher (PKCS12_DES_EDE3_168, 1);
    SEC_PKCS12SetPreferredCipher (PKCS12_DES_EDE3_168, 1);
#ifdef notyet
    PORT_SetUCS2_ASCIIConversionFunction (ucs2_ascii_conversion_fn);
#endif
}

static void
install_loadable_roots (void)
{
    SECMODModuleList *list = SECMOD_GetDefaultModuleList ();
    SECMODListLock *lock = SECMOD_GetDefaultModuleListLock ();
    SECMODModule *RootsModule = NULL;
    gint i;

    SECMOD_GetReadLock (lock);
    while (!RootsModule && list) {
        SECMODModule *module = list->module;

        for (i = 0; i < module->slotCount; i++) {
            PK11SlotInfo *slot = module->slots[i];
            if (PK11_IsPresent (slot)) {
                if (PK11_HasRootCerts (slot)) {
                    RootsModule = module;
                    break;
                }
            }
        }

        list = list->next;
    }
    SECMOD_ReleaseReadLock (lock);

    if (RootsModule) {
        /* Check version, and unload module if it is too old */
        CK_INFO info;

        if (PK11_GetModInfo (RootsModule, &info) != SECSuccess) {
            /* Do not use this module */
            RootsModule = NULL;
        } else {
            /* NSS_BUILTINS_LIBRARY_VERSION_MAJOR and NSS_BUILTINS_LIBRARY_VERSION_MINOR
             * define the version we expect to have.
             * Later version are fine.
             * Older versions are not ok, and we will replace with our own version.
             */
            if ((info.libraryVersion.major < NSS_BUILTINS_LIBRARY_VERSION_MAJOR)
                || (info.libraryVersion.major == NSS_BUILTINS_LIBRARY_VERSION_MAJOR
                && info.libraryVersion.minor < NSS_BUILTINS_LIBRARY_VERSION_MINOR)) {
                PRInt32 modType;

                SECMOD_DeleteModule (RootsModule->commonName, &modType);

                RootsModule = NULL;
            }
        }
    }

    if (!RootsModule) {
#ifndef G_OS_WIN32
        /* grovel in various places for mozilla's built-in
         * cert module.
         *
         * XXX yes this is gross.  *sigh *
        */
        const gchar *paths_to_check[] = {
#ifdef MOZILLA_NSS_LIB_DIR
            MOZILLA_NSS_LIB_DIR,
#endif
            "/usr/lib",
            "/usr/lib/mozilla",
            "/opt/mozilla/lib",
            "/opt/mozilla/lib/mozilla"
        };

        for (i = 0; i < G_N_ELEMENTS (paths_to_check); i++) {
            gchar *dll_path = g_module_build_path (paths_to_check[i], "nssckbi");

            if (g_file_test (dll_path, G_FILE_TEST_EXISTS)) {
                PRInt32 modType;

                /* Delete the existing module */
                SECMOD_DeleteModule ("Mozilla Root Certs", &modType);

                SECMOD_AddNewModule ("Mozilla Root Certs",dll_path, 0, 0);
                g_free (dll_path);
                break;
            }

            g_free (dll_path);
        }
#else
        /* FIXME: Might be useful to look up if there is a
         * Mozilla installation on the machine and use the
         * nssckbi.dll from there.
         */
#endif
    }
}

static void
e_cert_db_class_init (ECertDBClass *class)
{
    GObjectClass *object_class;

    object_class = G_OBJECT_CLASS (class);

    initialize_nss ();
    /* check to see if you have a rootcert module installed */
    install_loadable_roots ();

    e_cert_db_signals[PK11_PASSWD] =
        g_signal_new ("pk11_passwd",
                  G_OBJECT_CLASS_TYPE (object_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (ECertDBClass, pk11_passwd),
                  NULL, NULL,
                  e_marshal_BOOLEAN__POINTER_BOOLEAN_POINTER,
                  G_TYPE_BOOLEAN, 3,
                  G_TYPE_POINTER, G_TYPE_BOOLEAN, G_TYPE_POINTER);

    e_cert_db_signals[PK11_CHANGE_PASSWD] =
        g_signal_new ("pk11_change_passwd",
                  G_OBJECT_CLASS_TYPE (object_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (ECertDBClass, pk11_change_passwd),
                  NULL, NULL,
                  e_marshal_BOOLEAN__POINTER_POINTER,
                  G_TYPE_BOOLEAN, 2,
                  G_TYPE_POINTER, G_TYPE_POINTER);

    e_cert_db_signals[CONFIRM_CA_CERT_IMPORT] =
        g_signal_new ("confirm_ca_cert_import",
                  G_OBJECT_CLASS_TYPE (object_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (ECertDBClass, confirm_ca_cert_import),
                  NULL, NULL,
                  e_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER,
                  G_TYPE_BOOLEAN, 4,
                  G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER);
}

static void
e_cert_db_init (ECertDB *ec)
{
}

GStaticMutex init_mutex = G_STATIC_MUTEX_INIT;
static ECertDB *cert_db = NULL;

ECertDB *
e_cert_db_peek (void)
{
    g_static_mutex_lock (&init_mutex);
    if (!cert_db)
        cert_db = g_object_new (E_TYPE_CERT_DB, NULL);
    g_static_mutex_unlock (&init_mutex);

    return cert_db;
}

void
e_cert_db_shutdown (void)
{
    /* XXX */
}

/* searching for certificates */
ECert *
e_cert_db_find_cert_by_nickname (ECertDB *certdb,
                                 const gchar *nickname,
                                 GError **error)
{
    /*  nsNSSShutDownPreventionLock locker;*/
    CERTCertificate *cert = NULL;

    /*PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting \"%s\"\n", asciiname));*/
    cert = PK11_FindCertFromNickname ((gchar *) nickname, NULL);
    if (!cert) {
        cert = CERT_FindCertByNickname (CERT_GetDefaultCertDB (), (gchar *) nickname);
    }

    if (cert) {
        /*    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("got it\n"));*/
        ECert *ecert = e_cert_new (cert);
        return ecert;
    }
    else {
        set_nss_error (error);
        return NULL;
    }
}

#ifdef notyet
ECert *
e_cert_db_find_cert_by_key (ECertDB *certdb,
                            const gchar *db_key,
                            GError **error)
{
    /*  nsNSSShutDownPreventionLock locker;*/
    SECItem keyItem = {siBuffer, NULL, 0};
    SECItem *dummy;
    CERTIssuerAndSN issuerSN;
    gulong moduleID,slotID;
    CERTCertificate *cert;

    if (!db_key) {
        set_nss_error (error);
        return NULL;
    }

    dummy = NSSBase64_DecodeBuffer (NULL, &keyItem, db_key,
                       (PRUint32) PL_strlen (db_key));

    /* someday maybe we can speed up the search using the moduleID and slotID*/
    moduleID = NS_NSS_GET_LONG (keyItem.data);
    slotID = NS_NSS_GET_LONG (&keyItem.data[NS_NSS_LONG]);

    /* build the issuer/SN structure*/
    issuerSN.serialNumber.len = NS_NSS_GET_LONG (&keyItem.data[NS_NSS_LONG *2]);
    issuerSN.derIssuer.len = NS_NSS_GET_LONG (&keyItem.data[NS_NSS_LONG *3]);
    issuerSN.serialNumber.data= &keyItem.data[NS_NSS_LONG *4];
    issuerSN.derIssuer.data= &keyItem.data[NS_NSS_LONG *4+
                           issuerSN.serialNumber.len];

    cert = CERT_FindCertByIssuerAndSN (CERT_GetDefaultCertDB (), &issuerSN);
    PR_FREEIF (keyItem.data);
    if (cert) {
        ECert *ecert = e_cert_new (cert);
        return e_cert;
    }

    set_nss_error (error);
    return NULL;
}

GList *
e_cert_db_get_cert_nicknames (ECertDB *certdb,
                              ECertType cert_type,
                              GError **error)
{
}

ECert *
e_cert_db_find_email_encryption_cert (ECertDB *certdb,
                                      const gchar *nickname,
                                      GError **error)
{
}

ECert *
e_cert_db_find_email_signing_cert (ECertDB *certdb,
                                   const gchar *nickname,
                                   GError **error)
{
}
#endif

ECert *
e_cert_db_find_cert_by_email_address (ECertDB *certdb,
                                      const gchar *email,
                                      GError **error)
{
    /*  nsNSSShutDownPreventionLock locker; */
    ECert *cert;
    CERTCertificate *any_cert;
    CERTCertList *certlist;

    any_cert = CERT_FindCertByNicknameOrEmailAddr (
        CERT_GetDefaultCertDB (), (gchar *) email);

    if (!any_cert) {
        set_nss_error (error);
        return NULL;
    }

    /* any_cert now contains a cert with the right subject,
     * but it might not have the correct usage. */
    certlist = CERT_CreateSubjectCertList (NULL,
                          CERT_GetDefaultCertDB (),
                          &any_cert->derSubject,
                          PR_Now (), PR_TRUE);
    if (!certlist) {
        set_nss_error (error);
        CERT_DestroyCertificate (any_cert);
        return NULL;
    }

    if (SECSuccess != CERT_FilterCertListByUsage (
        certlist, certUsageEmailRecipient, PR_FALSE)) {
        set_nss_error (error);
        CERT_DestroyCertificate (any_cert);
        CERT_DestroyCertList (certlist);
        return NULL;
    }

    if (CERT_LIST_END (CERT_LIST_HEAD (certlist), certlist)) {
        set_nss_error (error);
        CERT_DestroyCertificate (any_cert);
        CERT_DestroyCertList (certlist);
        return NULL;
    }

    cert = e_cert_new (CERT_DupCertificate (CERT_LIST_HEAD (certlist)->cert));

    CERT_DestroyCertList (certlist);
    CERT_DestroyCertificate (any_cert);

    return cert;
}

static gboolean
confirm_download_ca_cert (ECertDB *cert_db,
                          ECert *cert,
                          gboolean *trust_ssl,
                          gboolean *trust_email,
                          gboolean *trust_objsign)
{
    gboolean rv = FALSE;

    *trust_ssl =
        *trust_email =
        *trust_objsign = FALSE;

    g_signal_emit (e_cert_db_peek (),
               e_cert_db_signals[CONFIRM_CA_CERT_IMPORT], 0,
               cert,
               trust_ssl,
               trust_email,
               trust_objsign,
               &rv);

    return rv;
}

static gboolean
handle_ca_cert_download (ECertDB *cert_db,
                         GList *certs,
                         GError **error)
{
    ECert *certToShow;
    SECItem der;
    gchar *raw_der = NULL;
    CERTCertificate *tmpCert;

    /* First thing we have to do is figure out which certificate
     * we're gonna present to the user.  The CA may have sent down
     * a list of certs which may or may not be a chained list of
     * certs.  Until the day we can design some solid UI for the
     * general case, we'll code to the > 90% case.  That case is
     * where a CA sends down a list that is a chain up to its root
     * in either ascending or descending order.  What we're gonna
     * do is compare the first 2 entries, if the first was signed
     * by the second, we assume the leaf cert is the first cert
     * and display it.  If the second cert was signed by the first
     * cert, then we assume the first cert is the root and the
     * last cert in the array is the leaf.  In this case we
     * display the last cert.
    */

    /*  nsNSSShutDownPreventionLock locker;*/

    if (certs == NULL) {
        g_warning ("Didn't get any certs to import.");
        return TRUE;
    }
    else if (certs->next == NULL) {
        /* there's 1 cert */
        certToShow = E_CERT (certs->data);
    }
    else {
        /* there are multiple certs */
        ECert *cert0;
        ECert *cert1;
        const gchar * cert0SubjectName;
        const gchar * cert0IssuerName;
        const gchar * cert1SubjectName;
        const gchar * cert1IssuerName;

        cert0 = E_CERT (certs->data);
        cert1 = E_CERT (certs->next->data);

        cert0IssuerName = e_cert_get_issuer_name (cert0);
        cert0SubjectName = e_cert_get_subject_name (cert0);

        cert1IssuerName = e_cert_get_issuer_name (cert1);
        cert1SubjectName = e_cert_get_subject_name (cert1);

        if (!strcmp (cert1IssuerName, cert0SubjectName)) {
            /* In this case, the first cert in the list signed the second,
             * so the first cert is the root.  Let's display the last cert
             * in the list. */
            certToShow = E_CERT (g_list_last (certs)->data);
        }
        else if (!strcmp (cert0IssuerName, cert1SubjectName)) {
            /* In this case the second cert has signed the first cert.  The
             * first cert is the leaf, so let's display it. */
            certToShow = cert0;
        } else {
            /* It's not a chain, so let's just show the first one in the
             * downloaded list. */
            certToShow = cert0;
        }
    }

    if (!certToShow) {
        set_nss_error (error);
        return FALSE;
    }

    if (!e_cert_get_raw_der (certToShow, &raw_der, &der.len)) {
        set_nss_error (error);
        return FALSE;
    }

    der.data = (guchar *) raw_der;

    {
        /*PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n"));*/
        CERTCertDBHandle *certdb = CERT_GetDefaultCertDB ();
        tmpCert = CERT_FindCertByDERCert (certdb, &der);
        if (!tmpCert) {
            tmpCert = CERT_NewTempCertificate (certdb, &der,
                              NULL, PR_FALSE, PR_TRUE);
        }
        if (!tmpCert) {
            g_warning ("Couldn't create cert from DER blob");
            set_nss_error (error);
            return FALSE;
        }
    }

#if 0
    CERTCertificateCleaner tmpCertCleaner (tmpCert);
#endif

    if (tmpCert->isperm) {
        if (error && !*error)
            *error = g_error_new_literal (E_CERTDB_ERROR, 0, _("Certificate already exists"));
        return FALSE;
    }
    else {
        gboolean trust_ssl, trust_email, trust_objsign;
        gchar *nickname;
        SECStatus srv;
        CERTCertTrust trust;

        if (!confirm_download_ca_cert (
            cert_db, certToShow, &trust_ssl,
            &trust_email, &trust_objsign)) {
            set_nss_error (error);
            return FALSE;
        }

        /*PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("trust is %d\n", trustBits));*/

        nickname = CERT_MakeCANickname (tmpCert);

        /*PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get()));*/

        e_cert_trust_init (&trust);
        e_cert_trust_set_valid_ca (&trust);
        e_cert_trust_add_ca_trust (&trust,
                       trust_ssl,
                       trust_email,
                       trust_objsign);

        srv = CERT_AddTempCertToPerm (tmpCert,
                         nickname,
                         &trust);

        /* If we aren't logged into the token, then what *should*
         * happen is the above call should fail, and we should
         * authenticate and then try again. But see NSS bug #595861.
         * With NSS 3.12.6 at least, the above call will fail, but
         * it *will* have added the cert to the database, with
         * random trust bits. We have to authenticate and then set
         * the trust bits correctly. And calling
         * CERT_AddTempCertToPerm() again doesn't work either -- it'll
         * fail even though it arguably ought to succeed (which is
         * probably another NSS bug).
         * So if we get SEC_ERROR_TOKEN_NOT_LOGGED_IN, we first try
         * CERT_ChangeCertTrust(), and if that doesn't work we hope
         * we're on a fixed version of NSS and we try calling
         * CERT_AddTempCertToPerm() again instead. */
        if (srv != SECSuccess &&
            PORT_GetError () == SEC_ERROR_TOKEN_NOT_LOGGED_IN &&
            e_cert_db_login_to_slot (NULL, PK11_GetInternalKeySlot ())) {
            srv = CERT_ChangeCertTrust (CERT_GetDefaultCertDB (),
                            tmpCert, &trust);
            if (srv != SECSuccess)
                srv = CERT_AddTempCertToPerm (tmpCert,
                                  nickname,
                                  &trust);
        }
        if (srv != SECSuccess) {
            set_nss_error (error);
            return FALSE;
        }

#if 0
        /* Now it's time to add the rest of the certs we just downloaded.
         * Since we didn't prompt the user about any of these certs, we
         * won't set any trust bits for them. */
        e_cert_trust_init (&trust);
        e_cert_trust_set_valid_ca (&trust);
        e_cert_trusts_add_ca_trust (&trust, 0, 0, 0);
        for (PRUint32 i = 0; i < numCerts; i++) {
            if (i == selCertIndex)
                continue;

            certToShow = do_QueryElementAt (x509Certs, i);
            certToShow->GetRawDER (&der.len, (PRUint8 **) &der.data);

            CERTCertificate *tmpCert2 =
                CERT_NewTempCertificate (certdb, &der, nsnull, PR_FALSE, PR_TRUE);

            if (!tmpCert2) {
                NS_ASSERTION (0, "Couldn't create temp cert from DER blob\n");
                continue;  /* Let's try to import the rest of 'em */
            }
            nickname.Adopt (CERT_MakeCANickname (tmpCert2));
            CERT_AddTempCertToPerm (tmpCert2, NS_CONST_CAST (gchar *,nickname.get ()),
                           defaultTrust.GetTrust ());
            CERT_DestroyCertificate (tmpCert2);
        }
#endif
        return TRUE;
    }
}
gboolean e_cert_db_change_cert_trust (CERTCertificate *cert, CERTCertTrust *trust)
{
    SECStatus srv;

    srv = CERT_ChangeCertTrust (CERT_GetDefaultCertDB (),
                    cert, trust);
    if (srv != SECSuccess &&
        PORT_GetError () == SEC_ERROR_TOKEN_NOT_LOGGED_IN &&
        e_cert_db_login_to_slot (NULL, PK11_GetInternalKeySlot ()))
        srv = CERT_ChangeCertTrust (CERT_GetDefaultCertDB (),
                        cert, trust);

    if (srv != SECSuccess) {
        glong err = PORT_GetError ();
        g_warning ("CERT_ChangeCertTrust() failed: %s\n",
               nss_error_to_string (err));
        return FALSE;
    }
    return TRUE;
}

/* deleting certificates */
gboolean
e_cert_db_delete_cert (ECertDB *certdb,
                       ECert *ecert)
{
    /*  nsNSSShutDownPreventionLock locker;
     *  nsNSSCertificate *nssCert = NS_STATIC_CAST (nsNSSCertificate *, aCert); */

    CERTCertificate *cert;

    if (!e_cert_mark_for_deletion (ecert)) {
        return FALSE;
    }

    cert = e_cert_get_internal_cert (ecert);
    if (cert->slot && e_cert_get_cert_type (ecert) != E_CERT_USER) {
        /* To delete a cert of a slot (builtin, most likely), mark it as
         * completely untrusted.  This way we keep a copy cached in the
         * local database, and next time we try to load it off of the
         * external token/slot, we'll know not to trust it.  We don't
         * want to do that with user certs, because a user may  re-store
         * the cert onto the card again at which point we *will* want to
         * trust that cert if it chains up properly. */
        CERTCertTrust trust;

        e_cert_trust_init_with_values (&trust, 0, 0, 0);
        return e_cert_db_change_cert_trust (cert, &trust);
    }

    return TRUE;
}

/* importing certificates */
gboolean
e_cert_db_import_certs (ECertDB *certdb,
                        gchar *data,
                        guint32 length,
                        ECertType cert_type,
                        GSList **imported_certs,
                        GError **error)
{
    /*nsNSSShutDownPreventionLock locker;*/
    PRArenaPool *arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
    GList *certs = NULL;
    CERTDERCerts *certCollection = e_cert_db_get_certs_from_package (arena, data, length);
    gint i;
    gboolean rv;

    if (!certCollection) {
        set_nss_error (error);
        PORT_FreeArena (arena, PR_FALSE);
        return FALSE;
    }

    /* Now let's create some certs to work with */
    for (i = 0; i < certCollection->numcerts; i++) {
        SECItem *currItem = &certCollection->rawCerts[i];
        ECert *cert;

        cert = e_cert_new_from_der ((gchar *) currItem->data, currItem->len);
        if (!cert) {
            set_nss_error (error);
            g_list_foreach (certs, (GFunc) g_object_unref, NULL);
            g_list_free (certs);
            PORT_FreeArena (arena, PR_FALSE);
            return FALSE;
        }
        certs = g_list_append (certs, cert);
    }
    switch (cert_type) {
    case E_CERT_CA:
        rv = handle_ca_cert_download (certdb, certs, error);
        if (rv && imported_certs) {
            GList *l;

            /* copy certificates to the caller */
            *imported_certs = NULL;
            for (l = certs; l; l = l->next) {
                ECert *cert = l->data;

                if (cert)
                    *imported_certs = g_slist_prepend (*imported_certs, g_object_ref (cert));
            }

            *imported_certs = g_slist_reverse (*imported_certs);
        }
        break;
    default:
        /* We only deal with import CA certs in this method currently.*/
        set_nss_error (error);
        PORT_FreeArena (arena, PR_FALSE);
        rv = FALSE;
    }

    g_list_foreach (certs, (GFunc) g_object_unref, NULL);
    g_list_free (certs);
    PORT_FreeArena (arena, PR_FALSE);
    return rv;
}

gboolean
e_cert_db_import_email_cert (ECertDB *certdb,
                             gchar *data,
                             guint32 length,
                             GSList **imported_certs,
                             GError **error)
{
    /*nsNSSShutDownPreventionLock locker;*/
    SECStatus srv = SECFailure;
    gboolean rv = TRUE;
    CERTCertificate * cert;
    SECItem **rawCerts;
    gint numcerts;
    gint i;
    PRArenaPool *arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
    CERTDERCerts *certCollection = e_cert_db_get_certs_from_package (arena, data, length);

    if (!certCollection) {
        set_nss_error (error);
        PORT_FreeArena (arena, PR_FALSE);
        return FALSE;
    }

    cert = CERT_NewTempCertificate (CERT_GetDefaultCertDB (), certCollection->rawCerts,
                       (gchar *) NULL, PR_FALSE, PR_TRUE);
    if (!cert) {
        set_nss_error (error);
        rv = FALSE;
        goto loser;
    }
    numcerts = certCollection->numcerts;
    rawCerts = (SECItem **) PORT_Alloc (sizeof (SECItem *) * numcerts);
    if (!rawCerts) {
        set_nss_error (error);
        rv = FALSE;
        goto loser;
    }

    for (i = 0; i < numcerts; i++) {
        rawCerts[i] = &certCollection->rawCerts[i];
    }

    srv = CERT_ImportCerts (CERT_GetDefaultCertDB (), certUsageEmailSigner,
                   numcerts, rawCerts, NULL, PR_TRUE, PR_FALSE,
                   NULL);
    if (srv != SECSuccess) {
        set_nss_error (error);
        rv = FALSE;
        goto loser;
    }
    CERT_SaveSMimeProfile (cert, NULL, NULL);

    if (imported_certs) {
        *imported_certs = NULL;
        for (i = 0; i < certCollection->numcerts; i++) {
            SECItem *currItem = &certCollection->rawCerts[i];
            ECert *cert;

            cert = e_cert_new_from_der ((gchar *) currItem->data, currItem->len);
            if (cert)
                *imported_certs = g_slist_prepend (*imported_certs, cert);
        }

        *imported_certs = g_slist_reverse (*imported_certs);
    }

    PORT_Free (rawCerts);
 loser:
    if (cert)
        CERT_DestroyCertificate (cert);
    if (arena)
        PORT_FreeArena (arena, PR_TRUE);
    return rv;
}

static gchar *
default_nickname (CERTCertificate *cert)
{
    /*  nsNSSShutDownPreventionLock locker; */
    gchar *username = NULL;
    gchar *caname = NULL;
    gchar *nickname = NULL;
    gchar *tmp = NULL;
    gint count;
    const gchar *nickFmt = NULL;
    CERTCertificate *dummycert;
    PK11SlotInfo *slot = NULL;
    CK_OBJECT_HANDLE keyHandle;

    CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB ();

    username = CERT_GetCommonName (&cert->subject);
    if (username == NULL)
        username = PL_strdup ("");

    if (username == NULL)
        goto loser;

    caname = CERT_GetOrgName (&cert->issuer);
    if (caname == NULL)
        caname = PL_strdup ("");

    if (caname == NULL)
        goto loser;

    count = 1;

    nickFmt = "%1$s's %2$s ID";

    nickname = PR_smprintf (nickFmt, username, caname);
    /*
     * We need to see if the private key exists on a token, if it does
     * then we need to check for nicknames that already exist on the smart
     * card.
     */
    slot = PK11_KeyForCertExists (cert, &keyHandle, NULL);
    if (slot == NULL) {
        goto loser;
    }
    if (!PK11_IsInternal (slot)) {
        tmp = PR_smprintf ("%s:%s", PK11_GetTokenName (slot), nickname);
        PR_Free (nickname);
        nickname = tmp;
        tmp = NULL;
    }
    tmp = nickname;
    while (1) {
        if (count > 1) {
            nickname = PR_smprintf ("%s #%d", tmp, count);
        }

        if (nickname == NULL)
            goto loser;

        if (PK11_IsInternal (slot)) {
            /* look up the nickname to make sure it isn't in use already */
            dummycert = CERT_FindCertByNickname (defaultcertdb, nickname);

        } else {
            /*
             * Check the cert against others that already live on the smart
             * card.
             */
            dummycert = PK11_FindCertFromNickname (nickname, NULL);
            if (dummycert != NULL) {
                /*
                 * Make sure the subject names are different.
                 */
                if (CERT_CompareName (&cert->subject, &dummycert->subject) == SECEqual) {
                    /*
                     * There is another certificate with the same nickname and
                     * the same subject name on the smart card, so let's use this
                     * nickname.
                     */
                    CERT_DestroyCertificate (dummycert);
                    dummycert = NULL;
                }
            }
        }
        if (dummycert == NULL)
            goto done;

        /* found a cert, destroy it and loop */
        CERT_DestroyCertificate (dummycert);
        if (tmp != nickname) PR_Free (nickname);
        count++;
    } /* end of while (1) */

 loser:
    if (nickname) {
        PR_Free (nickname);
    }
    nickname = NULL;
 done:
    if (caname) {
        PR_Free (caname);
    }
    if (username)  {
        PR_Free (username);
    }
    if (slot != NULL) {
        PK11_FreeSlot (slot);
        if (nickname != NULL) {
            tmp = nickname;
            nickname = strchr (tmp, ':');
            if (nickname != NULL) {
                nickname++;
                nickname = PL_strdup (nickname);
                PR_Free (tmp);
                tmp = NULL;
            } else {
                nickname = tmp;
                tmp = NULL;
            }
        }
    }
    PR_FREEIF (tmp);
    return (nickname);
}

gboolean
e_cert_db_import_user_cert (ECertDB *certdb,
                            gchar *data,
                            guint32 length,
                            GError **error)
{
    /*  nsNSSShutDownPreventionLock locker;*/
    PK11SlotInfo *slot;
    gchar * nickname = NULL;
    gboolean rv = FALSE;
    gint numCACerts;
    SECItem *CACerts;
    CERTDERCerts * collectArgs;
    PRArenaPool *arena;
    CERTCertificate * cert = NULL;

    arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
    if (arena == NULL) {
        set_nss_error (error);
        goto loser;
    }

    collectArgs = e_cert_db_get_certs_from_package (arena, data, length);
    if (!collectArgs) {
        set_nss_error (error);
        goto loser;
    }

    cert = CERT_NewTempCertificate (CERT_GetDefaultCertDB (), collectArgs->rawCerts,
                       (gchar *) NULL, PR_FALSE, PR_TRUE);
    if (!cert) {
        set_nss_error (error);
        goto loser;
    }

    slot = PK11_KeyForCertExists (cert, NULL, NULL);
    if (slot == NULL) {
        set_nss_error (error);
        goto loser;
    }
    PK11_FreeSlot (slot);

    /* pick a nickname for the cert */
    if (cert->nickname) {
        /* sigh, we need a call to look up other certs with this subject and
         * identify nicknames from them. We can no longer walk down internal
         * database structures  rjr */
        nickname = cert->nickname;
    }
    else {
        nickname = default_nickname (cert);
    }

    /* user wants to import the cert */
    slot = PK11_ImportCertForKey (cert, nickname, NULL);
    if (!slot) {
        set_nss_error (error);
        goto loser;
    }
    PK11_FreeSlot (slot);
    numCACerts = collectArgs->numcerts - 1;

    if (numCACerts) {
        CACerts = collectArgs->rawCerts + 1;
        if (!CERT_ImportCAChain (CACerts, numCACerts, certUsageUserCertImport)) {
            rv = TRUE;
        }
    }

 loser:
    if (arena) {
        PORT_FreeArena (arena, PR_FALSE);
    }
    if (cert) {
        CERT_DestroyCertificate (cert);
    }
    return rv;
}

gboolean
e_cert_db_import_server_cert (ECertDB *certdb,
                              gchar *data,
                              guint32 length,
                              GSList **imported_certs,
                              GError **error)
{
    /* not c&p'ing this over at the moment, as we don't have a UI
     * for server certs anyway */
    return FALSE;
}

gboolean
e_cert_db_import_certs_from_file (ECertDB *cert_db,
                                  const gchar *file_path,
                                  ECertType cert_type,
                                  GSList **imported_certs,
                                  GError **error)
{
    gboolean rv;
    gint fd;
    struct stat sb;
    gchar *buf;
    gint bytes_read;

    switch (cert_type) {
    case E_CERT_CA:
    case E_CERT_CONTACT:
    case E_CERT_SITE:
        /* good */
        break;

    default:
        /* not supported (yet) */
        set_nss_error (error);
        return FALSE;
    }

    fd = g_open (file_path, O_RDONLY | O_BINARY, 0);
    if (fd == -1) {
        set_nss_error (error);
        return FALSE;
    }

    if (-1 == fstat (fd, &sb)) {
        set_nss_error (error);
        close (fd);
        return FALSE;
    }

    buf = g_malloc (sb.st_size);
    if (!buf) {
        set_nss_error (error);
        close (fd);
        return FALSE;
    }

    bytes_read = read (fd, buf, sb.st_size);

    close (fd);

    if (bytes_read != sb.st_size) {
        set_nss_error (error);
        rv = FALSE;
    }
    else {
        printf ("importing %d bytes from '%s'\n", bytes_read, file_path);

        switch (cert_type) {
        case E_CERT_CA:
            rv = e_cert_db_import_certs (cert_db, buf, bytes_read, cert_type, imported_certs, error);
            break;

        case E_CERT_SITE:
            rv = e_cert_db_import_server_cert (cert_db, buf, bytes_read, imported_certs, error);
            break;

        case E_CERT_CONTACT:
            rv = e_cert_db_import_email_cert (cert_db, buf, bytes_read, imported_certs, error);
            break;

        default:
            rv = FALSE;
            break;
        }
    }

    g_free (buf);
    return rv;
}

gboolean
e_cert_db_import_pkcs12_file (ECertDB *cert_db,
                              const gchar *file_path,
                              GError **error)
{
    EPKCS12 *pkcs12 = e_pkcs12_new ();
    GError *e = NULL;

    if (!e_pkcs12_import_from_file (pkcs12, file_path, &e)) {
        g_propagate_error (error, e);
        return FALSE;
    }

    return TRUE;
}

#ifdef notyet
gboolean
e_cert_db_export_pkcs12_file (ECertDB *cert_db,
                              const gchar *file_path,
                              GList *certs,
                              GError **error)
{
}
#endif

gboolean
e_cert_db_login_to_slot (ECertDB *cert_db,
                         PK11SlotInfo *slot)
{
    if (PK11_NeedLogin (slot)) {
        PK11_Logout (slot);

        if (PK11_NeedUserInit (slot)) {
            gchar *pwd;
            gboolean rv = FALSE;

            printf ("initializing slot password\n");

            g_signal_emit (e_cert_db_peek (),
                       e_cert_db_signals[PK11_CHANGE_PASSWD], 0,
                       NULL,
                       &pwd,
                       &rv);

            if (!rv)
                return FALSE;

            /* the user needs to specify the initial password */
            PK11_InitPin (slot, "", pwd);
        }

        PK11_SetPasswordFunc (pk11_password);
        if (PK11_Authenticate (slot, PR_TRUE, NULL) != SECSuccess) {
            printf ("PK11_Authenticate failed (err = %d/%d)\n",
                PORT_GetError (), PORT_GetError () + 0x2000);
            return FALSE;
        }
    }

    return TRUE;
}