certlist.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:33k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /*
  3.  * The contents of this file are subject to the Mozilla Public
  4.  * License Version 1.1 (the "License"); you may not use this file
  5.  * except in compliance with the License. You may obtain a copy of
  6.  * the License at http://www.mozilla.org/MPL/
  7.  * 
  8.  * Software distributed under the License is distributed on an "AS
  9.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10.  * implied. See the License for the specific language governing
  11.  * rights and limitations under the License.
  12.  * 
  13.  * The Original Code is the Netscape security libraries.
  14.  * 
  15.  * The Initial Developer of the Original Code is Netscape
  16.  * Communications Corporation.  Portions created by Netscape are 
  17.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  18.  * Rights Reserved.
  19.  * 
  20.  * Contributor(s):
  21.  * 
  22.  * Alternatively, the contents of this file may be used under the
  23.  * terms of the GNU General Public License Version 2 or later (the
  24.  * "GPL"), in which case the provisions of the GPL are applicable 
  25.  * instead of those above.  If you wish to allow use of your 
  26.  * version of this file only under the terms of the GPL and not to
  27.  * allow others to use your version of this file under the MPL,
  28.  * indicate your decision by deleting the provisions above and
  29.  * replace them with the notice and other provisions required by
  30.  * the GPL.  If you do not delete the provisions above, a recipient
  31.  * may use your version of this file under either the MPL or the
  32.  * GPL.
  33.  */
  34. #include "certlist.h"
  35. #include "nlsutil.h"
  36. #include "base64.h"
  37. #include "cert.h"
  38. #include "certdb.h"
  39. #include "textgen.h"
  40. #include "minihttp.h"
  41. #include "advisor.h"
  42. #include "slist.h"
  43. #include "nspr.h"
  44. #include "nlslayer.h"
  45. enum
  46. {
  47.     CERTLIST_PARAM_KEY = (PRIntn) 0,
  48.     CERTLIST_PARAM_USAGE,
  49.     CERTLIST_PARAM_PREFIX,
  50.     /* CERTLIST_PARAM_WRAPPER,  -jp not used, as we format all certs together */
  51.     CERTLIST_PARAM_SUFFIX,
  52.     CERTLIST_PARAM_COUNT
  53. };
  54. SSMSortedListFn list_functions;
  55. #define WRAPPER "cert_list_item"
  56. #define EMAIL_WRAPPER "cert_list_email_item"
  57. typedef enum
  58. {
  59.     clNick,
  60.     clCertID, /* issuer and serial number */
  61.     clRID,
  62.     clEmail
  63. } ssmCLCertKey;
  64. typedef struct 
  65. {
  66.     SSMTextGenContext *cx;
  67.     char *output;
  68.     char *temp;
  69.     char *fmt;
  70.     char *efmt;
  71.     void *datefmt;
  72.     CERTCertDBHandle * db;
  73.     SSMSortedList **hash; /* Hash to contain list of certs to display */
  74.     ssmCLCertKey key;
  75.     ssmCLCertUsage usage;
  76. } ssmCLState;
  77. static SSMStatus format_raw_cert(CERTCertificate *cert, char *wrapper,
  78.                                  void*dfmt, char **result);
  79. /* Hash table functions */
  80. PRIntn ssm_certhash_rid_compare(const void *v1, const void *v2);
  81. PLHashNumber ssm_certhash_issuersn_hash(const void *v);
  82. PRIntn ssm_certhash_issuersn_compare(const void *v1, const void *v2);
  83. PRIntn ssm_pointer_compare(const void *v1, const void *v2);
  84. PRIntn ssm_certhash_cert_compare(const void *v1, const void *v2);
  85. void * ssm_certhash_alloc_table(void *state, PRSize size);
  86. void ssm_certhash_free_table(void *state, void *item);
  87. PLHashEntry * ssm_certhash_alloc_entry(void *state, const void *key);
  88. void ssm_certhash_free_entry(void *s, PLHashEntry *he, PRUintn flag);
  89. void certlist_free_item(SECItem *item);
  90. void certlist_dereturnify(char *s);
  91. SSMStatus ssm_certlist_get_b64_cert_key(CERTCertificate *cert, char **result);
  92. void * certlist_get_cert_key(ssmCLState *state, CERTCertificate *cert, ssmCLCertUsage usage);
  93. PRBool certlist_include_cert(CERTCertificate * cert, ssmCLState *state, 
  94.                       ssmCLCertUsage * usage);
  95. SECStatus certlist_get_cert(CERTCertificate *cert, SECItem *dbkey, void *arg);
  96. SSMStatus certlist_display_cert(PRIntn index, void * arg, 
  97.                                 void * key, void * itemdata);
  98. PRIntn certlist_wrap_cert(PLHashEntry *he, PRIntn index, void *arg);
  99. SSMStatus certlist_get_usage(ssmCLState *state);
  100. SSMStatus certlist_get_key_type(ssmCLState *state);
  101. SSMStatus ssm_populate_key_hash(ssmCLState * state);
  102. PRIntn
  103. certlist_rid_compare(const void *v1, const void *v2)
  104. {
  105.   SSMResourceID rid1 = (SSMResourceID) v1;
  106.     SSMResourceID rid2 = (SSMResourceID) v2;
  107.     PRIntn rv;
  108.     if (rid1 < rid2)
  109. rv = -1;
  110.     else if (rid1 > rid2)
  111. rv = 1;
  112.     else
  113. rv = 0;
  114.     return rv;
  115. }
  116. PRIntn 
  117. certlist_compare_strings(const void * v1, const void *v2)
  118. {
  119.     return PL_strcasecmp((char *)v1, (char *)v2);
  120. }
  121. PRIntn 
  122. certlist_issuersn_compare(const void *v1, const void *v2)
  123.     PRIntn rv;
  124.     SECComparison cmp = SECLessThan; /* this is arbitrary */
  125.     const CERTIssuerAndSN *i1 = (const CERTIssuerAndSN *) v1;
  126.     const CERTIssuerAndSN *i2 = (const CERTIssuerAndSN *) v2;
  127.     PR_ASSERT(i1);
  128.     PR_ASSERT(i2);
  129.     if (!i1 || !i2)
  130. goto loser;
  131.     cmp = SECITEM_CompareItem(&(i1->derIssuer), &(i2->derIssuer));
  132.     if (cmp == SECEqual)
  133. cmp = SECITEM_CompareItem(&(i2->serialNumber), &(i2->serialNumber));
  134.  loser:
  135.     /* Don't need to free i1 and i2, since they are allocated out of
  136.        the certs' arenas. They will be freed when the certs are freed. */
  137.     rv = (PRIntn) cmp;
  138.     return rv;
  139. }
  140. /* Free ops for cert list */
  141. void
  142. certlist_free_data(void * data)
  143. {
  144.     /* Free the cert, then (if asked) free the entry. */
  145.     PR_Free(((ssmCertData *)data)->certEntry);
  146.     PR_Free((ssmCertData *)data);
  147. }
  148. void certlist_none(void * data)
  149. {
  150.     return;
  151. }
  152. void certlist_free_string(void * key)
  153. {
  154.     PR_Free((char *)key);
  155. }
  156. /* Utility routines for cert list keyword handler below */
  157. void
  158. certlist_free_item(SECItem *item)
  159. {
  160.     if (item)
  161.     {
  162. if (item->data)
  163.     PR_Free(item->data);
  164. PR_Free(item);
  165.     }
  166. }
  167. void
  168. certlist_dereturnify(char *s)
  169. {
  170.     char *c = s;
  171.     while(*c)
  172.     {
  173.         if ((*c == '15') || (*c == '12'))
  174.         {
  175.             char *c2 = c;
  176.             while ((*c2 == '15') || (*c2 == '12'))
  177.                 c2++;
  178.             /* move the rest of the string on top of c */
  179.             memmove(c, c2, strlen(c2));
  180.         }
  181. c++;
  182.     }
  183. }
  184. SSMStatus
  185. ssm_certlist_get_b64_cert_key(CERTCertificate *cert, char **result)
  186. {
  187.     SECItem *certKeyItem;
  188.     CERTIssuerAndSN *isn = NULL;
  189.     SSMStatus rv = SSM_SUCCESS;
  190.     PR_ASSERT(cert && result);
  191.     *result = NULL; /* in case we fail */
  192.     isn = CERT_GetCertIssuerAndSN(NULL, cert);
  193.     if (!isn)
  194. goto loser;
  195.     certKeyItem = (SECItem *) PR_CALLOC(sizeof(SECItem));
  196.     if (!certKeyItem)
  197. goto loser;
  198.     certKeyItem->len = isn->serialNumber.len + isn->derIssuer.len;
  199.     certKeyItem->data = (unsigned char*)PR_CALLOC(certKeyItem->len);
  200.     if (certKeyItem->data == NULL)
  201. goto loser;
  202.     /* copy the serialNumber */
  203.     memcpy(certKeyItem->data, isn->serialNumber.data,
  204.    isn->serialNumber.len);
  205.     /* copy the issuer */
  206.     memcpy( &(certKeyItem->data[isn->serialNumber.len]),
  207.     isn->derIssuer.data, isn->derIssuer.len);
  208.     /* b64 the item */
  209.     *result = BTOA_ConvertItemToAscii(certKeyItem);
  210.     certlist_dereturnify(*result);
  211.     goto done;
  212.  loser:
  213.     rv = SSM_FAILURE;
  214.  done:
  215.     certlist_free_item(certKeyItem);
  216.     return rv;
  217. }
  218. /* get the appropriate key depending on what key type we have chosen. */
  219. void *
  220. certlist_get_cert_key(ssmCLState *state, CERTCertificate *cert, ssmCLCertUsage usage)
  221. {
  222.     char *result_ch = NULL;
  223.     void *result = NULL;
  224.     SSMStatus rv = SSM_SUCCESS;
  225.     PR_ASSERT(cert);
  226.     if (!cert) 
  227.         return result;
  228.     switch(state->key)
  229.     {
  230.     case clCertID:
  231. rv = ssm_certlist_get_b64_cert_key(cert, &result_ch);
  232. PR_ASSERT(rv == SSM_SUCCESS);
  233. result = result_ch;
  234. break;
  235.     case clRID:
  236. PR_ASSERT(!"Not yet implemented.");
  237. break;
  238.     case clNick:
  239.         /* duplicate the nickname */
  240.         if (usage == clEmailRecipient) {
  241.             PR_ASSERT(cert && cert->emailAddr);
  242.             result = PR_CALLOC(strlen(cert->emailAddr)+1);
  243.             if (result)
  244.                 PL_strcpy((char*)result, cert->emailAddr);
  245.         } else {
  246.             PR_ASSERT(cert && cert->nickname);
  247.             result = PR_CALLOC(strlen(cert->nickname)+1);
  248.             if (result)
  249.                 PL_strcpy((char *) result, cert->nickname);
  250.         }
  251.         break;   
  252.     case clEmail:
  253.         PR_ASSERT(cert && cert->emailAddr);
  254.         result = PR_CALLOC(strlen(cert->emailAddr)+1);
  255.         if (result)
  256.             PL_strcpy((char*)result, cert->emailAddr);
  257.         break;
  258.     default:
  259.         PR_ASSERT(0); /* scream if we defaulted here */
  260.     }
  261.     return result;
  262. }
  263. PRBool
  264. certlist_include_cert(CERTCertificate * cert, ssmCLState *state, 
  265.                       ssmCLCertUsage * usage)
  266. {
  267.     PRBool usercert = PR_FALSE;
  268.     char *nickname;
  269.     char *emailAddr;
  270.     CERTCertTrust *trust;
  271.     ssmCLCertUsage thisUsage = clNoUsage;
  272.     /* jsw said: look at the base cert info stuff, not the dbEntry since
  273.      * we may have been called from a PKCS#11 module */
  274.     nickname = cert->nickname;
  275.     trust = cert->trust;
  276.     emailAddr = cert->emailAddr;
  277.     /* Don't display certs that are invisible */
  278.     if ( ( ( trust->sslFlags & CERTDB_INVISIBLE_CA ) ||
  279.            (trust->emailFlags & CERTDB_INVISIBLE_CA ) ||
  280.            (trust->objectSigningFlags & CERTDB_INVISIBLE_CA ) ) ) 
  281.         goto dontInclude;
  282.     
  283.     if (nickname) {
  284.         /* 
  285.            it's a cert I have named. Could be a personal cert of mine,
  286.            an SSL server cert, or a CA cert. Find out what kind.
  287.         */
  288.         if (state->usage == clSSLClient) {
  289.             if (trust->sslFlags & CERTDB_USER) {
  290.                 /* It's an SSL cert I own. */
  291.                 thisUsage = clSSLClient;
  292.                 goto include;
  293.             }
  294.             else {
  295.                 goto dontInclude;
  296.             }
  297.         }
  298.         if (state->usage == clEmailSigner) {
  299.             if (trust->emailFlags & CERTDB_USER) {
  300.                 /* It's an email cert I own. */
  301.                 thisUsage = clEmailSigner;
  302.                 goto include;
  303.             }
  304.             else {
  305.                 goto dontInclude;
  306.             }
  307.         }
  308.         if (state->usage == clAllMine) {
  309.             if ((trust->sslFlags & CERTDB_USER) ||
  310.                 (trust->emailFlags & CERTDB_USER) ||
  311.                 (trust->objectSigningFlags & CERTDB_USER)) {
  312.                 /* It's a cert I own. */
  313.                 usercert = PR_TRUE;
  314.                 thisUsage = clAllMine;
  315.                 goto include;
  316.             }
  317.             else {
  318.                 goto dontInclude;
  319.             }
  320.         }
  321.             
  322.         /* it is an SSL site */
  323.         if (trust->sslFlags & CERTDB_VALID_PEER) {
  324.             thisUsage = clSSLServer;
  325.             goto include;
  326.         }
  327.             
  328.         /* CA certs */
  329.         if ((trust->sslFlags & CERTDB_VALID_CA) ||
  330.             (trust->emailFlags & CERTDB_VALID_CA) ||
  331.             (trust->objectSigningFlags & CERTDB_VALID_CA)) { 
  332.             thisUsage = clAllCA;
  333.             goto include;
  334.         }
  335.     } /* end of if nickname */
  336.     /* Check if this is an email cert that belongs to someone else. */
  337.     if (emailAddr && !usercert && (trust->emailFlags & CERTDB_VALID_PEER)) {
  338.         /* Someone else's email cert */
  339.         thisUsage = clEmailRecipient;
  340.         goto include;
  341.     }
  342.     
  343. dontInclude:
  344.     *usage = thisUsage;
  345.     return PR_FALSE;
  346. include:
  347.     *usage = thisUsage;
  348.     if (state->usage == thisUsage ||
  349.         (state->usage == clAllMine &&
  350.          (thisUsage == clSSLClient || thisUsage == clEmailSigner))) {        
  351.         return PR_TRUE;
  352.     }
  353.     return PR_FALSE;
  354. }
  355.    
  356. /* build/append a cert list string depending on key and usage */
  357. SECStatus 
  358. certlist_get_cert(CERTCertificate *cert, SECItem *dbkey, void *arg)
  359. {
  360.     ssmCLState *state = (ssmCLState *) arg;
  361.     SECStatus rv = SECSuccess;
  362.     void *certHashKey; /* the key we use to insert into the hash */ 
  363.     ssmCLCertUsage thisUsage; 
  364.     ssmCertData * data;
  365.     char * certInfo = NULL, *nick = NULL;
  366.     char * wrapper;
  367.     
  368.     /* check if we want to include cert in our hash table */
  369.     if (!certlist_include_cert(cert, state, &thisUsage))
  370.         goto done;
  371.     /* check if cert is already in the db */
  372.     nick = (cert->nickname)?cert->nickname:cert->emailAddr;
  373.     if (SSMSortedList_Lookup(*state->hash, nick))
  374.         goto done;
  375.         
  376.     /* different wrapper for email certs */
  377.     if (thisUsage == clEmailRecipient)
  378.         wrapper = state->efmt;
  379.     else wrapper = state->fmt;
  380.     /* If we get here, then we should include this cert in the hash table. */
  381.     rv = (SECStatus) 
  382.      (format_raw_cert(cert, wrapper, state->datefmt, &certInfo) == SSM_SUCCESS) ?
  383. SECSuccess : SECFailure;
  384.     if (rv != SECSuccess)
  385.         goto done;   
  386.     certHashKey = certlist_get_cert_key(state, cert, thisUsage);
  387.     
  388.     data = (ssmCertData *) PORT_ZAlloc(sizeof(ssmCertData));
  389.     data->usage = thisUsage;
  390.     data->certEntry = certInfo;
  391.     /* XXX the following code is necessary because we want to pick out
  392.      *     email signing certs among "my certs"
  393.      */
  394.     if (cert->trust->emailFlags & CERTDB_USER) {
  395.         data->isEmailSigner = PR_TRUE;
  396.     }
  397.     else {
  398.         data->isEmailSigner = PR_FALSE;
  399.     }
  400.     SSMSortedList_Insert(*state->hash, certHashKey, data);
  401. done:
  402.     return rv;
  403. }
  404. static char * 
  405. escape_quotes(const char * str)
  406. {
  407.     char * outstr = NULL, * ptr = NULL;
  408.     int i=0, length = 0;
  409.     int quotechar = 0;
  410.     if (!str) 
  411.         goto done;
  412.     ptr = str;
  413.     while (*ptr) {
  414.        length++;
  415.        if (*ptr == 39 || *ptr == 34)
  416.            quotechar++;
  417.        ptr++;
  418.     }
  419.     outstr = (char *) PORT_ZAlloc(length+quotechar+1);
  420.     if (!quotechar) {
  421.         memcpy(outstr, str, length);
  422.         goto done;
  423.     }
  424.     ptr = str;
  425.     i = 0;
  426.     while (i < length+quotechar) {
  427.         if (*ptr == 39 || *ptr == 34) 
  428.             outstr[i++] = 92;
  429.         outstr[i++] = *ptr;
  430.         ptr++;
  431.     }
  432.         
  433.  done:
  434.     return outstr;
  435. }
  436. /* Format a raw cert into (wrapper). */
  437. static SSMStatus
  438. format_raw_cert(CERTCertificate *cert, char *wrapper,
  439.                 void *dfmt, char **result)
  440. {
  441.     char *nickStr = NULL;
  442.     char *emailStr = NULL;
  443.     char *subjectName = NULL;
  444.     char *validStartStr = NULL;
  445.     char *validEndStr = NULL;
  446.     char * issuerName = NULL;
  447.     void *dateFormat = dfmt;
  448.     char *isn_ch = NULL;
  449.     SSMStatus rv = SSM_SUCCESS;
  450.     PR_ASSERT(wrapper);
  451.     /* If a date format wasn't supplied, make one. */
  452.     if (dateFormat)
  453.     {
  454. dateFormat = nlsNewDateFormat();
  455. if (!dateFormat) {
  456. goto loser;
  457. }
  458.     }
  459.     /* Get the key from the cert in b64 format */
  460.     rv = ssm_certlist_get_b64_cert_key(cert, &isn_ch);
  461.     if (rv != SSM_SUCCESS)
  462. goto loser;
  463.     PR_ASSERT(isn_ch);
  464.     nickStr  = (cert->nickname)  ?escape_quotes(cert->nickname):PL_strdup("-");
  465.     emailStr = (cert->emailAddr) ?escape_quotes(cert->emailAddr):PL_strdup("-");
  466.     subjectName =  (cert->subjectName) ? escape_quotes(cert->subjectName) : 
  467.         PL_strdup("-");
  468.     issuerName = CERT_GetOrgName(&cert->issuer);
  469.     issuerName = issuerName ? escape_quotes(issuerName) : PL_strdup("-");
  470.         
  471.     validStartStr = DER_UTCDayToAscii(&cert->validity.notBefore);
  472.     if (!validStartStr) 
  473.         validStartStr = PL_strdup("");
  474.     validEndStr = DER_UTCDayToAscii(&cert->validity.notAfter);
  475.     if (!validEndStr) 
  476.         validEndStr = PL_strdup("");
  477.     SSMTextGen_UTF8StringClear(result);
  478.     *result = PR_smprintf(wrapper, isn_ch, nickStr, emailStr, subjectName, 
  479.                           validStartStr, validEndStr,
  480.                           issuerName, 0);
  481.     SSM_DebugUTF8String("wrapped cert", *result);
  482.     goto done;
  483.  loser:
  484.     SSM_DEBUG("Couldn't format cert!");
  485.     if (rv == SSM_SUCCESS)
  486.         rv = SSM_FAILURE;
  487.  done:
  488.     PR_FREEIF(nickStr);
  489.     PR_FREEIF(emailStr);
  490.     PR_FREEIF(subjectName);
  491.     PR_FREEIF(issuerName);
  492.     PR_FREEIF(isn_ch);
  493.     PR_FREEIF(validStartStr);
  494.     PR_FREEIF(validEndStr);
  495.     if (dateFormat && !dfmt) /* if we made the date format, delete it */
  496.         nlsFreeDateFormat(dateFormat);
  497.     return rv;
  498. }
  499. /* Enumerator for cert hash entries. Embed cert information in
  500.    the wrapper (state->wrapper). */
  501. SSMStatus 
  502. certlist_display_cert(PRIntn index, void * arg, void * key, void * itemdata)
  503. {
  504.     ssmCLState *state = (ssmCLState *) arg;
  505.     SSMStatus rv = SSM_SUCCESS;
  506.     ssmCertData * data = (ssmCertData *) itemdata; 
  507.     
  508.     if (state->usage == data->usage ||
  509.         (state->usage == clAllMine && 
  510.          (data->usage == clSSLClient || data->usage == clEmailSigner)) ||
  511.         (state->usage == clEmailSigner && data->usage == clAllMine &&
  512.          data->isEmailSigner)) { 
  513.         rv = SSM_ConcatenateUTF8String(&state->output, data->certEntry);
  514.         if (rv != SSM_SUCCESS)
  515.             goto loser;
  516.     }
  517.     goto done;
  518. loser:
  519.     SSM_DEBUG("certlist_display_cert: couldn't add cert info to display list!");
  520. done:
  521.     /* keep going */
  522.     return SSM_SUCCESS;
  523. }    
  524. /* get the certType parameter */
  525. SSMStatus
  526. certlist_get_usage(ssmCLState *state)
  527. {
  528.     char *usageStr = (char *) SSM_At(state->cx->m_params, CERTLIST_PARAM_USAGE);
  529.     SSMStatus rv = SSM_SUCCESS;
  530.     PR_ASSERT(usageStr);
  531.     if (!usageStr)
  532.     {
  533.         SSM_HTTPReportSpecificError(state->cx->m_request, 
  534.                                     "certlist_get_usage: "
  535.                                     "usage parameter is NULL");
  536.         goto loser;
  537.     }
  538.     /* Figure out which one it is. */
  539.     if (!MIN_STRCMP(usageStr, "AllMine"))
  540.         state->usage = clAllMine;
  541.     else if (!MIN_STRCMP(usageStr, "SSLC"))
  542.         state->usage = clSSLClient;
  543.     else if (!MIN_STRCMP(usageStr, "EmailS"))
  544.         state->usage = clEmailSigner;
  545.     else if (!MIN_STRCMP(usageStr, "SSLS"))
  546.         state->usage = clSSLServer;
  547.     else if (!MIN_STRCMP(usageStr, "EmailR"))
  548.         state->usage = clEmailRecipient;
  549.     else if (!MIN_STRCMP(usageStr, "CA"))
  550.         state->usage = clAllCA;
  551.     else /* bad value */
  552.     {
  553.         SSM_HTTPReportSpecificError(state->cx->m_request,
  554.                                     "_certList: Bad usage -- must be "
  555.                                     "AllMine|SSLClient|EmailSigner|"
  556.                                     "SSLServer|EmailRecipient|CA");
  557.         goto loser;
  558.     }
  559.     goto done;
  560. loser:
  561.     if (rv == SSM_SUCCESS) rv = SSM_FAILURE;
  562. done:
  563.     return rv;
  564. }
  565. /* get the certType parameter */
  566. SSMStatus
  567. certlist_get_key_type(ssmCLState *state)
  568. {
  569.     char *keyStr = (char *) SSM_At(state->cx->m_params, CERTLIST_PARAM_KEY);
  570.     SSMStatus rv = SSM_SUCCESS;
  571.     PR_ASSERT(keyStr);
  572.     if (!keyStr)
  573.     {
  574.         SSM_HTTPReportSpecificError(state->cx->m_request, 
  575.                                     "certlist_get_key_type: "
  576.                                     "key parameter is NULL");
  577.         goto loser;
  578.     }
  579.     /* Figure out which one it is. */
  580.     if (!MIN_STRCMP(keyStr, "nick"))
  581.         state->key = clNick;
  582.     else if (!MIN_STRCMP(keyStr, "certID"))
  583.         state->key = clCertID;
  584.     else if ((!MIN_STRCMP(keyStr, "rid"))
  585.              ||(!MIN_STRCMP(keyStr, "RID")))
  586.         state->key = clRID;
  587.     else if (!MIN_STRCMP(keyStr, "email"))
  588.         state->key = clEmail;
  589.     else/* bad value */
  590.     {
  591.         SSM_HTTPReportSpecificError(state->cx->m_request, 
  592.                                     "_certList: Bad cert key -- must be "
  593.                                     "nick|certID|RID");
  594.         goto loser;
  595.     }
  596.     goto done;
  597. loser:
  598.     if (rv == SSM_SUCCESS) rv = SSM_FAILURE;
  599. done:
  600.     return rv;
  601. }
  602. SSMStatus
  603. ssm_populate_key_hash(ssmCLState * state)
  604. {
  605.     SSMCompare_fn  keyComparer = NULL;
  606.     SSMListFree_fn keyFree = NULL;
  607.     SSMListFree_fn dataFree = certlist_free_data;
  608.     SECStatus srv;
  609.     SSMStatus rv = SSM_SUCCESS;
  610.     char *tempUStr = NULL;
  611.     PermCertCallback callback = certlist_get_cert;
  612.     /* Based on the usage, choose hasher/key comparer functions for
  613.        the hash table we create below. */
  614.     switch(state->key)
  615.         {
  616.         case clRID:
  617.             keyComparer = certlist_rid_compare;
  618.             keyFree = certlist_none;
  619.             break;
  620.         case clEmail:
  621.         case clCertID:
  622.         case clNick:
  623.             keyComparer = certlist_compare_strings;
  624.             keyFree = certlist_free_string;
  625.             break;
  626.         default:
  627.             PR_ASSERT(0); 
  628.         }
  629.     list_functions.keyCompare = keyComparer;
  630.     list_functions.freeListItemData = dataFree;
  631.     list_functions.freeListItemKey = keyFree;
  632.     /* Create the hash table if needed */
  633.     if (!*state->hash)
  634.         *state->hash = SSMSortedList_New(&list_functions);
  635.     if (!*state->hash) 
  636.         goto loser;
  637.     PR_ASSERT(state->db);
  638.     
  639.     /* Get the wrapper text. */
  640.     rv = SSM_GetAndExpandTextKeyedByString(state->cx, WRAPPER, &tempUStr);
  641.     if (rv != SSM_SUCCESS)
  642.         goto loser; /* error string set by the called function */
  643.     SSM_DebugUTF8String("Certlist wrapper", tempUStr);
  644.     state->fmt = tempUStr;
  645.     tempUStr = NULL;
  646.     /* wrapper for email certs */
  647.     rv = SSM_GetAndExpandTextKeyedByString(state->cx, EMAIL_WRAPPER, &tempUStr);
  648.     if (rv != SSM_SUCCESS)
  649.         goto loser; /* error string set by the called function */
  650.     SSM_DebugUTF8String("Certlist email wrapper", tempUStr);
  651.     state->efmt = tempUStr;
  652.     tempUStr = NULL;
  653.     /* 
  654.        Create a DateFormat object which we will use to convert
  655.        cert date/times into displayable text.
  656.      */
  657. state->datefmt = nlsNewDateFormat();
  658. if (!state->datefmt) {
  659. goto loser;
  660. }
  661.     /* Format each cert into the list. */
  662.     srv = SEC_TraversePermCerts(state->db, callback, state);
  663.     if (srv == SECSuccess) 
  664.         srv = PK11_TraverseSlotCerts(callback, state, 
  665.                                      state->cx->m_request->ctrlconn);   
  666.     goto done;
  667.     
  668. loser:
  669.     if (rv == SSM_SUCCESS)
  670.         rv = SSM_FAILURE;
  671. done: 
  672.     return rv;
  673. }
  674. /* 
  675.    Cert list keyword handler.
  676.    Syntax: {_certList <certKey>,<certUsage>,prefix,wrapper,suffix}
  677.    where <certKey>  ::= "nick" | "certID" | "RID" | "email"
  678.          <certUsage>::= "AllMine"|"SSLClient"|"EmailSigner"|
  679.                         "SSLServer"|"EmailRecipient"|"CA"
  680.                         (for now)
  681.    Generates a list of certificates. The following steps are performed:
  682.    - Send {prefix} to the client.
  683.    - For each cert indicated by <certType> and <certUsage>, format the 
  684.      cert data into {wrapper} and send to the client. For the moment, 
  685.      raw certs are used and passed to NLS_MessageFormat in the 
  686.      following form:
  687.          NLS_FORMAT_TYPE_STRING, (cert issuer+sn base64),
  688.          NLS_FORMAT_TYPE_STRING, (cert nick),
  689.          NLS_FORMAT_TYPE_STRING, (cert email address),
  690.          NLS_FORMAT_TYPE_STRING, (cert subject name),
  691.          NLS_FORMAT_TYPE_LONG,   (cert resource ID, 0 for now)
  692.    - After the certs are processed and sent, send {suffix}.
  693. */
  694. SSMStatus
  695. SSM_CertListKeywordHandler(SSMTextGenContext *cx)
  696. {
  697.     SSMStatus rv = SSM_SUCCESS;
  698.     char *prefix = NULL, *suffix = NULL;
  699.     char *tempUStr = NULL;
  700.     SSMResource * target = NULL;
  701.     ssmCLState state;
  702.     SSMResourceType targetType = SSM_RESTYPE_NULL;
  703.     PRIntn certType[clAllCA+1];
  704.     SSMSortedList *nullHash = NULL;
  705.     certType[clAllMine] =        0x00000001;
  706.     certType[clEmailRecipient] = 0x00000010;
  707.     certType[clSSLServer] =      0x00000100;
  708.     certType[clAllCA] =          0x00001000;
  709.     certType[clEmailSigner] =    0x00010000;
  710.     /* Check for parameter validity */
  711.     PR_ASSERT(cx);
  712.     PR_ASSERT(cx->m_request);
  713.     PR_ASSERT(cx->m_params);
  714.     PR_ASSERT(cx->m_result);
  715.     if (!cx || !cx->m_request || !cx->m_params || !cx->m_result)
  716.     {
  717.         rv = (SSMStatus) PR_INVALID_ARGUMENT_ERROR;
  718.         goto real_loser; /* really bail here */
  719.     }
  720.     state.cx = cx;
  721.     state.fmt = NULL;
  722.     state.efmt = NULL;
  723.     state.datefmt = NULL;
  724.     state.output = NULL;
  725.     state.temp = NULL;
  726.     state.db = cx->m_request->ctrlconn->m_certdb;
  727.     if (!state.db)
  728.     {
  729.         SSM_HTTPReportSpecificError(state.cx->m_request, 
  730.                                     "_certlist: no cert db available");
  731.         goto user_loser;
  732.     }
  733.     if (SSM_Count(cx->m_params) != CERTLIST_PARAM_COUNT)
  734.     {
  735.         SSM_HTTPReportSpecificError(cx->m_request, "_certList: "
  736.                                     "Incorrect number of parameters "
  737.                                     "(%d supplied, %d needed).n",
  738.                                     SSM_Count(cx->m_params), 
  739.                                     CERTLIST_PARAM_COUNT);
  740.         goto user_loser;
  741.     }
  742.     /* Convert parameters to something we can use in finding certs. */
  743.     rv = certlist_get_key_type(&state);
  744.     if (rv != SSM_SUCCESS)
  745.         goto user_loser;
  746.     rv = certlist_get_usage(&state);
  747.     if (rv != SSM_SUCCESS)
  748.         goto user_loser;
  749.     prefix = (char *) SSM_At(cx->m_params, CERTLIST_PARAM_PREFIX);
  750.     suffix = (char *) SSM_At(cx->m_params, CERTLIST_PARAM_SUFFIX);
  751.     PR_ASSERT(prefix); /* already did user check, so bomb here if null */
  752.     PR_ASSERT(suffix);
  753.     /* check where we're called from */
  754.     target = SSMTextGen_GetTargetObject(cx);
  755.     if (!target) 
  756.         goto real_loser;
  757.     /* SecurityAdvisor context keeps hash around, otherwise create new one */
  758.     if (SSM_IsAKindOf(target, SSM_RESTYPE_SECADVISOR_CONTEXT)) {
  759.         targetType = SSM_RESTYPE_SECADVISOR_CONTEXT;
  760.         state.hash = &((SSMSecurityAdvisorContext *)target)->m_certhash;
  761.     }
  762.     else 
  763.         state.hash = &nullHash;
  764.     state.output = state.temp = NULL;
  765.     /* Start with the prefix. */
  766.     rv = SSM_GetAndExpandTextKeyedByString(cx, prefix, &tempUStr);
  767.     if (rv != SSM_SUCCESS)
  768.         goto real_loser; /* error string set by the called function */
  769.     SSM_DebugUTF8String("Certlist prefix", tempUStr);
  770.     rv = SSM_ConcatenateUTF8String(&cx->m_result, tempUStr);
  771.     PR_Free(tempUStr);
  772.     tempUStr = NULL;
  773.     if (rv != SSM_SUCCESS) {
  774.         goto real_loser;
  775.     }
  776.     /* initialize a hash if haven't already */
  777.     if ((*state.hash == NULL) || 
  778.         (SSM_IsAKindOf(target, SSM_RESTYPE_SECADVISOR_CONTEXT)) &&
  779.          ((((SSMSecurityAdvisorContext *)target)->m_certsIncluded & 
  780.           certType[state.usage]) 
  781.         == 0)) {
  782.         ((SSMSecurityAdvisorContext *)target)->m_certsIncluded |= certType[state.usage];
  783.         rv = ssm_populate_key_hash(&state);
  784.         if (rv != SSM_SUCCESS)
  785.             goto user_loser;
  786.     }
  787.         
  788.     /* Already have all certs info, output in a list in state.result */
  789.     SSMSortedList_Enumerate(*state.hash, certlist_display_cert, &state);
  790.     
  791.     if (state.output) {
  792.         rv = SSM_ConcatenateUTF8String(&cx->m_result, state.output);
  793.         /* Finally, add the suffix. */
  794.         rv = SSM_GetAndExpandTextKeyedByString(cx, suffix, &tempUStr);
  795.         if (rv != SSM_SUCCESS)
  796.             goto real_loser; /* error string set by the called function */
  797.         SSM_DebugUTF8String("certlist suffix", tempUStr); 
  798.         
  799.         rv = SSM_ConcatenateUTF8String(&cx->m_result, tempUStr);
  800.         if (rv != SSM_SUCCESS) {
  801.             goto real_loser;
  802.         }
  803.     }
  804.     else /* no certs found */
  805.         {  char * tmpStr = NULL;
  806.         /* release prefix */
  807.         PR_FREEIF(state.output);
  808.         state.output = NULL;
  809.         rv = SSM_GetAndExpandTextKeyedByString(cx, "list_empty", &tmpStr);
  810.         if (rv != SSM_SUCCESS) 
  811.             SSM_DEBUG("SSM_CertListKeywordHandler: could not get filler for empty cert list!n");
  812.         PR_FREEIF(cx->m_result);
  813.         cx->m_result = NULL;
  814.         rv = SSM_ConcatenateUTF8String(&cx->m_result, tmpStr);
  815.         PR_FREEIF(tmpStr);
  816.         tmpStr = NULL;
  817.         }
  818.     goto done;
  819. user_loser:
  820.     /* If we reach this point, something in the input is wrong, but we
  821.        can still send something back to the client to indicate that a
  822.        problem has occurred. */
  823.     /* If we can't do what we're about to do, really bail. */
  824.     if (!cx->m_request || !cx->m_request->errormsg)
  825.         goto real_loser;
  826.     /* Clear the string we were accumulating. */
  827.     SSMTextGen_UTF8StringClear(&cx->m_result);
  828.     rv = SSM_ConcatenateUTF8String(&cx->m_result, cx->m_request->errormsg);
  829.     /* Clear the result string, since we're sending this inline */
  830.     SSMTextGen_UTF8StringClear(&cx->m_request->errormsg);
  831.     goto done;
  832. real_loser:
  833.     /* If we reach this point, then we are so screwed that we cannot
  834.        send anything vaguely normal back to the client. Bail. */
  835.     if (rv == SSM_SUCCESS) rv = SSM_FAILURE;
  836. done:
  837.     if (targetType && targetType != SSM_RESTYPE_SECADVISOR_CONTEXT)
  838.         if (*state.hash) 
  839.             SSMSortedList_Destroy(*state.hash);    
  840.     PR_FREEIF(state.fmt);
  841.     PR_FREEIF(state.efmt);
  842.     PR_FREEIF(state.output);
  843.     PR_FREEIF(state.temp);
  844.     if (state.datefmt)
  845.         nlsFreeDateFormat(state.datefmt);
  846.     PR_FREEIF(tempUStr);
  847.     return rv;
  848. }
  849. static int ssm_CertsOnSmartcards(SSMControlConnection* ctrl, char* name)
  850. {
  851.     CERTCertList* list = NULL;
  852.     int numCerts = 0;
  853.     
  854.     list = PK11_FindCertsFromNickname(name, (void*)ctrl);
  855.     if (list == NULL) {
  856.         return 0;
  857.     }
  858.     numCerts = SSM_CertListCount(list);
  859.     CERT_DestroyCertList(list);
  860.     return numCerts;
  861. }
  862. static PRBool ssm_OtherCertsByNicknameOrEmailAddr(SSMControlConnection* ctrl,
  863.                                                   char* name)
  864. {
  865.     int numCerts = 0;
  866.     /* first get the number of certs under the nickname */
  867.     numCerts = CERT_NumPermCertsForNickname(ctrl->m_certdb, name);
  868.     if (numCerts == 0) {
  869.         /* we may not see the cert because it's on external token: check it */
  870.         numCerts = ssm_CertsOnSmartcards(ctrl, name);
  871.     }
  872.     if (numCerts > 1) {
  873.         /* note that the cert in question is still in the DB: it is just
  874.          * marked for deletion, but not deleted yet
  875.          */
  876.         return PR_TRUE;
  877.     }
  878.     else if (numCerts == 1) {
  879.         /* it is the only cert */
  880.         return PR_FALSE;
  881.     }
  882.     else {
  883.         /* nickname may be email address: try the email address */
  884.         CERTCertList* list = NULL;
  885.         int count = 0;
  886.         
  887.         list = CERT_CreateEmailAddrCertList(list, ctrl->m_certdb, name, 
  888.                                             PR_Now(), PR_FALSE);
  889.         if (list == NULL) {
  890.             /* this usually shouldn't happen */
  891.             return PR_FALSE;
  892.         }
  893.         count = SSM_CertListCount(list);
  894.         if (list != NULL) {
  895.             CERT_DestroyCertList(list);
  896.         }
  897.         if (count > 1) {
  898.             return PR_TRUE;
  899.         }
  900.         else {
  901.             return PR_FALSE;
  902.         }
  903.     }
  904. }
  905. SSMStatus SSM_ChangeCertSecAdvisorList(HTTPRequest * req, char * nickname, 
  906.        ssmCertHashAction action)
  907. {
  908.     SSMStatus rv = SSM_SUCCESS;
  909.     SSMControlConnection * ctrl = req->ctrlconn;
  910.     CERTCertificate * dbCert = NULL; 
  911.     PRIntn i;
  912.     SSMSecurityAdvisorContext * advisor = NULL;
  913.     SSMResourceID resID;
  914.     char * tmp;
  915.     SSMSortedList * hash;
  916.     PR_ASSERT(ctrl && SSM_IsAKindOf((SSMResource *)ctrl, 
  917.                                     SSM_RESTYPE_CONTROL_CONNECTION));
  918.     if (!ctrl->m_secAdvisorList || !ctrl->m_secAdvisorList->len) 
  919.         goto done;
  920.     if (action == certHashRemove) /* check if need to delete */ {   
  921.         PR_ASSERT(nickname);
  922.         /* find out if there are other certs under the same nickname than
  923.          * the one marked for deletion
  924.          */
  925.         if (ssm_OtherCertsByNicknameOrEmailAddr(ctrl, nickname)) {
  926.             goto done;
  927.         }
  928.     }
  929.     /* there might be multiple Security Advisor up */
  930.     for (i=0; i<ctrl->m_secAdvisorList->len; i++){
  931.         resID = ctrl->m_secAdvisorList->data[i];
  932.         
  933.         rv = (SSMStatus) SSMControlConnection_GetResource(ctrl, resID, (SSMResource **)&advisor);
  934.         if (rv != SSM_SUCCESS)
  935.             continue;
  936.         PR_ASSERT(advisor && SSM_IsAKindOf((SSMResource *)advisor,
  937.                                            SSM_RESTYPE_SECADVISOR_CONTEXT));
  938.         if (!advisor->m_certhash)
  939.             continue;
  940.         hash = advisor->m_certhash;
  941.         if (action == certHashRemove) 
  942.             SSMSortedList_Remove(hash, nickname, (void **)&tmp);
  943.         else if (action == certHashAdd) {
  944.             ssmCLState state;
  945.             char * form;
  946.             SSMTextGenContext *cx; 
  947.             state.key = clNick;
  948.             state.hash = &advisor->m_certhash;
  949.             state.db = ctrl->m_certdb;
  950.             
  951.             /* this assumes we're called from Restore certificate or 
  952.              * or some other place that includes form name in HTTP request 
  953.              */
  954.             rv = SSM_HTTPParamValue(req, "formName", &form);
  955.             if (strstr(form, "mine")) 
  956.                 state.usage = clAllMine;
  957.             else if (strstr(form, "others"))
  958.                 state.usage = clEmailRecipient;
  959.             else if (strstr(form, "websites"))
  960.                 state.usage = clSSLServer;
  961.             else if (strstr(form, "authorities"))
  962.                 state.usage = clAllCA;
  963.             
  964.             rv = SSMTextGen_NewTopLevelContext(req, &cx);
  965.             if (rv != SSM_SUCCESS) {
  966.                 SSM_DEBUG("ChangeCertSecAdvisorList: can't get TextGenContextn");
  967.                 goto done;
  968.             }
  969.             state.cx = cx;
  970.             
  971.             rv = ssm_populate_key_hash(&state);
  972.             if (rv != SSM_SUCCESS) 
  973.                 SSM_DEBUG("ChangeCertSecAdvisorList: error reading certsn");
  974.             SSMTextGen_DestroyContext(cx);
  975.         } else
  976.             SSM_DEBUG("ChangeCertSecAdvisorList: bad change request %dn", action);
  977.         SSM_FreeResource((SSMResource *)advisor);
  978.         advisor = NULL;
  979.     }
  980. done:
  981.     
  982.     if (dbCert) 
  983.         CERT_DestroyCertificate(dbCert);
  984.     return rv;
  985. }