Back to index

lightning-sunbird  0.9+nobinonly
certhtml.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /*
00038  * certhtml.c --- convert a cert to html
00039  *
00040  * $Id: certhtml.c,v 1.6 2005/06/30 20:53:57 wtchang%redhat.com Exp $
00041  */
00042 
00043 #include "seccomon.h"
00044 #include "secitem.h"
00045 #include "sechash.h"
00046 #include "cert.h"
00047 #include "keyhi.h"
00048 #include "secder.h"
00049 #include "prprf.h"
00050 #include "secport.h"
00051 #include "secasn1.h"
00052 #include "pk11func.h"
00053 
00054 static char *hex = "0123456789ABCDEF";
00055 
00056 /*
00057 ** Convert a der-encoded integer to a hex printable string form
00058 */
00059 char *CERT_Hexify (SECItem *i, int do_colon)
00060 {
00061     unsigned char *cp, *end;
00062     char *rv, *o;
00063 
00064     if (!i->len) {
00065        return PORT_Strdup("00");
00066     }
00067 
00068     rv = o = (char*) PORT_Alloc(i->len * 3);
00069     if (!rv) return rv;
00070 
00071     cp = i->data;
00072     end = cp + i->len;
00073     while (cp < end) {
00074        unsigned char ch = *cp++;
00075        *o++ = hex[(ch >> 4) & 0xf];
00076        *o++ = hex[ch & 0xf];
00077        if (cp != end) {
00078            if (do_colon) {
00079               *o++ = ':';
00080            }
00081        } 
00082     }
00083     *o = 0;           /* Null terminate the string */
00084     return rv;
00085 }
00086 
00087 static char *
00088 gatherStrings(char **strings)
00089 {
00090     char **strs;
00091     int len;
00092     char *ret;
00093     char *s;
00094 
00095     /* find total length of all strings */
00096     strs = strings;
00097     len = 0;
00098     while ( *strs ) {
00099        len += PORT_Strlen(*strs);
00100        strs++;
00101     }
00102     
00103     /* alloc enough memory for it */
00104     ret = (char*)PORT_Alloc(len + 1);
00105     if ( !ret ) {
00106        return(ret);
00107     }
00108 
00109     s = ret;
00110     
00111     /* copy the strings */
00112     strs = strings;
00113     while ( *strs ) {
00114        PORT_Strcpy(s, *strs);
00115        s += PORT_Strlen(*strs);
00116        strs++;
00117     }
00118 
00119     return( ret );
00120 }
00121 
00122 #define BREAK "<br>"
00123 #define BREAKLEN 4
00124 #define COMMA ", "
00125 #define COMMALEN 2
00126 
00127 #define MAX_OUS 20
00128 #define MAX_DC MAX_OUS
00129 
00130 
00131 char *CERT_FormatName (CERTName *name)
00132 {
00133     CERTRDN** rdns;
00134     CERTRDN * rdn;
00135     CERTAVA** avas;
00136     CERTAVA*  ava;
00137     char *    buf    = 0;
00138     char *    tmpbuf = 0;
00139     SECItem * cn     = 0;
00140     SECItem * email  = 0;
00141     SECItem * org    = 0;
00142     SECItem * loc    = 0;
00143     SECItem * state  = 0;
00144     SECItem * country       = 0;
00145     SECItem * dq            = 0;
00146 
00147     unsigned  len    = 0;
00148     int       tag;
00149     int       i;
00150     int       ou_count = 0;
00151     int       dc_count = 0;
00152     PRBool    first;
00153     SECItem * orgunit[MAX_OUS];
00154     SECItem * dc[MAX_DC];
00155 
00156     /* Loop over name components and gather the interesting ones */
00157     rdns = name->rdns;
00158     while ((rdn = *rdns++) != 0) {
00159        avas = rdn->avas;
00160        while ((ava = *avas++) != 0) {
00161            tag = CERT_GetAVATag(ava);
00162            switch(tag) {
00163              case SEC_OID_AVA_COMMON_NAME:
00164               cn = CERT_DecodeAVAValue(&ava->value);
00165               len += cn->len;
00166               break;
00167              case SEC_OID_AVA_COUNTRY_NAME:
00168               country = CERT_DecodeAVAValue(&ava->value);
00169               len += country->len;
00170               break;
00171              case SEC_OID_AVA_LOCALITY:
00172               loc = CERT_DecodeAVAValue(&ava->value);
00173               len += loc->len;
00174               break;
00175              case SEC_OID_AVA_STATE_OR_PROVINCE:
00176               state = CERT_DecodeAVAValue(&ava->value);
00177               len += state->len;
00178               break;
00179              case SEC_OID_AVA_ORGANIZATION_NAME:
00180               org = CERT_DecodeAVAValue(&ava->value);
00181               len += org->len;
00182               break;
00183              case SEC_OID_AVA_DN_QUALIFIER:
00184               dq = CERT_DecodeAVAValue(&ava->value);
00185               len += dq->len;
00186               break;
00187              case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME:
00188               if (ou_count < MAX_OUS) {
00189                      orgunit[ou_count] = CERT_DecodeAVAValue(&ava->value);
00190                      len += orgunit[ou_count++]->len;
00191               }
00192               break;
00193              case SEC_OID_AVA_DC:
00194               if (dc_count < MAX_DC) {
00195                      dc[dc_count] = CERT_DecodeAVAValue(&ava->value);
00196                      len += dc[dc_count++]->len;
00197               }
00198               break;
00199              case SEC_OID_PKCS9_EMAIL_ADDRESS:
00200              case SEC_OID_RFC1274_MAIL:
00201               email = CERT_DecodeAVAValue(&ava->value);
00202               len += email->len;
00203               break;
00204              default:
00205               break;
00206            }
00207        }
00208     }
00209 
00210     /* XXX - add some for formatting */
00211     len += 128;
00212 
00213     /* allocate buffer */
00214     buf = (char *)PORT_Alloc(len);
00215     if ( !buf ) {
00216        return(0);
00217     }
00218 
00219     tmpbuf = buf;
00220     
00221     if ( cn ) {
00222        PORT_Memcpy(tmpbuf, cn->data, cn->len);
00223        tmpbuf += cn->len;
00224        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
00225        tmpbuf += BREAKLEN;
00226        SECITEM_FreeItem(cn, PR_TRUE);
00227     }
00228     if ( email ) {
00229        PORT_Memcpy(tmpbuf, email->data, email->len);
00230        tmpbuf += ( email->len );
00231        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
00232        tmpbuf += BREAKLEN;
00233        SECITEM_FreeItem(email, PR_TRUE);
00234     }
00235     for (i=ou_count-1; i >= 0; i--) {
00236        PORT_Memcpy(tmpbuf, orgunit[i]->data, orgunit[i]->len);
00237        tmpbuf += ( orgunit[i]->len );
00238        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
00239        tmpbuf += BREAKLEN;
00240        SECITEM_FreeItem(orgunit[i], PR_TRUE);
00241     }
00242     if ( dq ) {
00243        PORT_Memcpy(tmpbuf, dq->data, dq->len);
00244        tmpbuf += ( dq->len );
00245        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
00246        tmpbuf += BREAKLEN;
00247        SECITEM_FreeItem(dq, PR_TRUE);
00248     }
00249     if ( org ) {
00250        PORT_Memcpy(tmpbuf, org->data, org->len);
00251        tmpbuf += ( org->len );
00252        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
00253        tmpbuf += BREAKLEN;
00254        SECITEM_FreeItem(org, PR_TRUE);
00255     }
00256     for (i=dc_count-1; i >= 0; i--) {
00257        PORT_Memcpy(tmpbuf, dc[i]->data, dc[i]->len);
00258        tmpbuf += ( dc[i]->len );
00259        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
00260        tmpbuf += BREAKLEN;
00261        SECITEM_FreeItem(dc[i], PR_TRUE);
00262     }
00263     first = PR_TRUE;
00264     if ( loc ) {
00265        PORT_Memcpy(tmpbuf, loc->data,  loc->len);
00266        tmpbuf += ( loc->len );
00267        first = PR_FALSE;
00268        SECITEM_FreeItem(loc, PR_TRUE);
00269     }
00270     if ( state ) {
00271        if ( !first ) {
00272            PORT_Memcpy(tmpbuf, COMMA, COMMALEN);
00273            tmpbuf += COMMALEN;
00274        }
00275        PORT_Memcpy(tmpbuf, state->data, state->len);
00276        tmpbuf += ( state->len );
00277        first = PR_FALSE;
00278        SECITEM_FreeItem(state, PR_TRUE);
00279     }
00280     if ( country ) {
00281        if ( !first ) {
00282            PORT_Memcpy(tmpbuf, COMMA, COMMALEN);
00283            tmpbuf += COMMALEN;
00284        }
00285        PORT_Memcpy(tmpbuf, country->data, country->len);
00286        tmpbuf += ( country->len );
00287        first = PR_FALSE;
00288        SECITEM_FreeItem(country, PR_TRUE);
00289     }
00290     if ( !first ) {
00291        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
00292        tmpbuf += BREAKLEN;
00293     }
00294 
00295     *tmpbuf = 0;
00296 
00297     return(buf);
00298 }
00299 
00300 static char *sec_FortezzaClearance(SECItem *clearance) {
00301     unsigned char clr = 0;
00302 
00303     if (clearance->len > 0) { clr = clearance->data[0]; }
00304 
00305     if (clr & 0x4) return "Top Secret";
00306     if (clr & 0x8) return "Secret";
00307     if (clr & 0x10) return "Confidential";
00308     if (clr & 0x20) return "Sensitive";
00309     if (clr & 0x40) return "Unclassified";
00310     return "None";
00311 }
00312 
00313 static char *sec_FortezzaMessagePrivilege(SECItem *priv) {
00314     unsigned char clr = 0;
00315 
00316     if (priv->len > 0) { clr = (priv->data[0]) & 0x78; }
00317 
00318     if (clr == 0x00) {
00319        return "None";
00320     } else {
00321 
00322        return PR_smprintf("%s%s%s%s%s%s%s",
00323 
00324            clr&0x40?"Critical/Flash":"",
00325            (clr&0x40) && (clr&0x38) ? ", " : "" ,
00326 
00327            clr&0x20?"Immediate/Priority":"",
00328            (clr&0x20) && (clr&0x18) ? ", " : "" ,
00329 
00330            clr&0x10?"Routine/Deferred":"",
00331            (clr&0x10) && (clr&0x08) ? ", " : "" ,
00332 
00333            clr&0x08?"Rekey Agent":"");
00334     }
00335 
00336 }
00337                                    
00338 static char *sec_FortezzaCertPrivilege(SECItem *priv) {
00339     unsigned char clr = 0;
00340 
00341     if (priv->len > 0) { clr = priv->data[0]; }
00342 
00343     return PR_smprintf("%s%s%s%s%s%s%s%s%s%s%s%s",
00344        clr&0x40?"Organizational Releaser":"",
00345        (clr&0x40) && (clr&0x3e) ? "," : "" ,
00346        clr&0x20?"Policy Creation Authority":"",
00347        (clr&0x20) && (clr&0x1e) ? "," : "" ,
00348        clr&0x10?"Certificate Authority":"",
00349        (clr&0x10) && (clr&0x0e) ? "," : "" ,
00350        clr&0x08?"Local Managment Authority":"",
00351        (clr&0x08) && (clr&0x06) ? "," : "" ,
00352        clr&0x04?"Configuration Vector Authority":"",
00353        (clr&0x04) && (clr&0x02) ? "," : "" ,
00354        clr&0x02?"No Signature Capability":"",
00355        clr&0x7e?"":"Signing Only"
00356     );
00357 }
00358 
00359 static char *htmlcertstrings[] = {
00360     "<table border=0 cellspacing=0 cellpadding=0><tr><td valign=top>"
00361     "<font size=2><b>This Certificate belongs to:</b><br>"
00362     "<table border=0 cellspacing=0 cellpadding=0><tr><td>",
00363     0, /* image goes here */
00364     0,
00365     0,
00366     "</td><td width=10> </td><td><font size=2>",
00367     0, /* subject name goes here */
00368     "</td></tr></table></font></td><td width=20> </td><td valign=top>"
00369     "<font size=2><b>This Certificate was issued by:</b><br>"
00370     "<table border=0 cellspacing=0 cellpadding=0><tr><td>",
00371     0, /* image goes here */
00372     0,
00373     0,
00374     "</td><td width=10> </td><td><font size=2>",
00375     0, /* issuer name goes here */
00376     "</td></tr></table></font></td></tr></table>"
00377     "<b>Serial Number:</b> ",
00378     0,
00379     "<br><b>This Certificate is valid from ",
00380     0, /* notBefore goes here */
00381     " to ",
00382     0, /* notAfter does here */
00383     "</b><br><b>Clearance:</b>",
00384     0,
00385     "<br><b>DSS Privileges:</b>",
00386     0,
00387     "<br><b>KEA Privileges:</b>",
00388     0,
00389     "<br><b>KMID:</b>",
00390     0,
00391     "<br><b>Certificate Fingerprint:</b>"
00392     "<table border=0 cellspacing=0 cellpadding=0><tr>"
00393     "<td width=10> </td><td><font size=2>",
00394     0, /* fingerprint goes here */
00395     "</td></tr></table>",
00396     0, /* comment header goes here */
00397     0, /* comment goes here */
00398     0, /* comment trailer goes here */
00399     0
00400 };
00401 
00402 char *
00403 CERT_HTMLCertInfo(CERTCertificate *cert, PRBool showImages, PRBool showIssuer)
00404 {
00405     SECStatus rv;
00406     char *issuer, *subject, *serialNumber, *version;
00407     char *notBefore, *notAfter;
00408     char *ret;
00409     char *nickname;
00410     unsigned char fingerprint[16];   /* result of MD5, always 16 bytes */
00411     char *fpstr;
00412     SECItem fpitem;
00413     char *commentstring = NULL;
00414     SECKEYPublicKey *pubk;
00415     char *DSSPriv;
00416     char *KMID = NULL;
00417     char *servername;
00418     
00419     if (!cert) {
00420        return(0);
00421     }
00422 
00423     issuer = CERT_FormatName (&cert->issuer);
00424     subject = CERT_FormatName (&cert->subject);
00425     version = CERT_Hexify (&cert->version,1);
00426     serialNumber = CERT_Hexify (&cert->serialNumber,1);
00427     notBefore = DER_TimeChoiceDayToAscii(&cert->validity.notBefore);
00428     notAfter = DER_TimeChoiceDayToAscii(&cert->validity.notAfter);
00429     servername = CERT_FindNSStringExtension(cert,
00430                                SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME);
00431 
00432     nickname = cert->nickname;
00433     if ( nickname == NULL ) {
00434        showImages = PR_FALSE;
00435     }
00436 
00437     rv = CERT_FindCertExtension(cert, SEC_OID_NS_CERT_EXT_SUBJECT_LOGO,
00438                             NULL);
00439     
00440     if ( rv || !showImages ) {
00441        htmlcertstrings[1] = "";
00442        htmlcertstrings[2] = "";
00443        htmlcertstrings[3] = "";
00444     } else {
00445        htmlcertstrings[1] = "<img src=\"about:security?subject-logo=";
00446        htmlcertstrings[2] = nickname;
00447        htmlcertstrings[3] = "\">";
00448     }
00449 
00450     if ( servername ) {
00451        char *tmpstr;
00452        tmpstr = (char *)PORT_Alloc(PORT_Strlen(subject) +
00453                                 PORT_Strlen(servername) +
00454                                 sizeof("<br>") + 1);
00455        if ( tmpstr ) {
00456            PORT_Strcpy(tmpstr, servername);
00457            PORT_Strcat(tmpstr, "<br>");
00458            PORT_Strcat(tmpstr, subject);
00459            PORT_Free(subject);
00460            subject = tmpstr;
00461        }
00462     }
00463     
00464     htmlcertstrings[5] = subject;
00465 
00466     rv = CERT_FindCertExtension(cert, SEC_OID_NS_CERT_EXT_ISSUER_LOGO,
00467                             NULL);
00468     
00469     if ( rv || !showImages ) {
00470        htmlcertstrings[7] = "";
00471        htmlcertstrings[8] = "";
00472        htmlcertstrings[9] = "";
00473     } else {
00474        htmlcertstrings[7] = "<img src=\"about:security?issuer-logo=";
00475        htmlcertstrings[8] = nickname;
00476        htmlcertstrings[9] = "\">";
00477     }
00478 
00479     
00480     if (showIssuer == PR_TRUE) {
00481         htmlcertstrings[11] = issuer;
00482     } else {
00483        htmlcertstrings[11] = "";
00484     }
00485 
00486     htmlcertstrings[13] = serialNumber;
00487     htmlcertstrings[15] = notBefore;
00488     htmlcertstrings[17] = notAfter;
00489 
00490     pubk = CERT_ExtractPublicKey(cert);
00491     DSSPriv = NULL;
00492     if (pubk && (pubk->keyType == fortezzaKey)) {
00493        SECItem dummyitem;
00494        htmlcertstrings[18] = "</b><br><b>Clearance:</b>";
00495        htmlcertstrings[19] = sec_FortezzaClearance(
00496                                    &pubk->u.fortezza.clearance);
00497        htmlcertstrings[20] = "<br><b>DSS Privileges:</b>";
00498        DSSPriv = sec_FortezzaCertPrivilege(
00499                                    &pubk->u.fortezza.DSSpriviledge);
00500        htmlcertstrings[21] = DSSPriv;
00501        htmlcertstrings[22] = "<br><b>KEA Privileges:</b>";
00502        htmlcertstrings[23] = sec_FortezzaMessagePrivilege(
00503                                    &pubk->u.fortezza.KEApriviledge);
00504        htmlcertstrings[24] = "<br><b>KMID:</b>";
00505        dummyitem.data = &pubk->u.fortezza.KMID[0];
00506        dummyitem.len = sizeof(pubk->u.fortezza.KMID);
00507        KMID = CERT_Hexify (&dummyitem,0);
00508        htmlcertstrings[25] = KMID;
00509     } else {
00510        /* clear out the headers in the non-fortezza cases */
00511        htmlcertstrings[18] = "";
00512        htmlcertstrings[19] = "";
00513        htmlcertstrings[20] = "";
00514        htmlcertstrings[21] = "";
00515        htmlcertstrings[22] = "";
00516        htmlcertstrings[23] = "";
00517        htmlcertstrings[24] = "";
00518        htmlcertstrings[25] = "</b>";
00519     }
00520 
00521     if (pubk) {
00522       SECKEY_DestroyPublicKey(pubk);
00523     }
00524 
00525 #define HTML_OFF 27
00526     rv = PK11_HashBuf(SEC_OID_MD5, fingerprint, 
00527                      cert->derCert.data, cert->derCert.len);
00528     
00529     fpitem.data = fingerprint;
00530     fpitem.len = sizeof(fingerprint);
00531 
00532     fpstr = CERT_Hexify (&fpitem,1);
00533     
00534     htmlcertstrings[HTML_OFF] = fpstr;
00535 
00536     commentstring = CERT_GetCertCommentString(cert);
00537 
00538     if (commentstring == NULL) {
00539        htmlcertstrings[HTML_OFF+2] = "";
00540        htmlcertstrings[HTML_OFF+3] = "";
00541        htmlcertstrings[HTML_OFF+4] = "";
00542     } else {
00543        htmlcertstrings[HTML_OFF+2] =
00544            "<b>Comment:</b>"
00545            "<table border=0 cellspacing=0 cellpadding=0><tr>"
00546            "<td width=10> </td><td><font size=3>"
00547            "<textarea name=foobar rows=4 cols=55 onfocus=\"this.blur()\">";
00548        htmlcertstrings[HTML_OFF+3] = commentstring;
00549        htmlcertstrings[HTML_OFF+4] = "</textarea></font></td></tr></table>";
00550     }
00551     
00552     ret = gatherStrings(htmlcertstrings);
00553     
00554     if ( issuer ) {
00555        PORT_Free(issuer);
00556     }
00557     
00558     if ( subject ) {
00559        PORT_Free(subject);
00560     }
00561     
00562     if ( version ) {
00563        PORT_Free(version);
00564     }
00565     
00566     if ( serialNumber ) {
00567        PORT_Free(serialNumber);
00568     }
00569     
00570     if ( notBefore ) {
00571        PORT_Free(notBefore);
00572     }
00573     
00574     if ( notAfter ) {
00575        PORT_Free(notAfter);
00576     }
00577     
00578     if ( fpstr ) {
00579        PORT_Free(fpstr);
00580     }
00581     if (DSSPriv) {
00582        PORT_Free(DSSPriv);
00583     }
00584 
00585     if (KMID) {
00586        PORT_Free(KMID);
00587     }
00588 
00589     if ( commentstring ) {
00590        PORT_Free(commentstring);
00591     }
00592     
00593     if ( servername ) {
00594        PORT_Free(servername);
00595     }
00596     
00597     return(ret);
00598 }
00599