Back to index

lightning-sunbird  0.9+nobinonly
secutil.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  *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 /*
00038 ** secutil.c - various functions used by security stuff
00039 **
00040 */
00041 
00042 #include "prtypes.h"
00043 #include "prtime.h"
00044 #include "prlong.h"
00045 #include "prerror.h"
00046 #include "prprf.h"
00047 #include "plgetopt.h"
00048 #include "prenv.h"
00049 #include "prnetdb.h"
00050 
00051 #include "cryptohi.h"
00052 #include "secutil.h"
00053 #include "secpkcs7.h"
00054 #include <stdarg.h>
00055 #if !defined(_WIN32_WCE)
00056 #include <sys/stat.h>
00057 #include <errno.h>
00058 #endif
00059 
00060 #ifdef XP_UNIX
00061 #include <unistd.h>
00062 #endif
00063 
00064 /* for SEC_TraverseNames */
00065 #include "cert.h"
00066 #include "certt.h"
00067 #include "certdb.h"
00068 
00069 /* #include "secmod.h" */
00070 #include "pk11func.h"
00071 #include "secoid.h"
00072 
00073 static char consoleName[] =  {
00074 #ifdef XP_UNIX
00075 #ifdef VMS
00076     "TT"
00077 #else
00078     "/dev/tty"
00079 #endif
00080 #else
00081 #ifdef XP_OS2
00082     "\\DEV\\CON"
00083 #else
00084     "CON:"
00085 #endif
00086 #endif
00087 };
00088 
00089 
00090 char *
00091 SECU_GetString(int16 error_number)
00092 {
00093 
00094     static char errString[80];
00095     sprintf(errString, "Unknown error string (%d)", error_number);
00096     return errString;
00097 }
00098 
00099 void 
00100 SECU_PrintErrMsg(FILE *out, int level, char *progName, char *msg, ...)
00101 {
00102     va_list args;
00103     PRErrorCode err = PORT_GetError();
00104     const char * errString = SECU_Strerror(err);
00105 
00106     va_start(args, msg);
00107 
00108     SECU_Indent(out, level);
00109     fprintf(out, "%s: ", progName);
00110     vfprintf(out, msg, args);
00111     if (errString != NULL && PORT_Strlen(errString) > 0)
00112        fprintf(out, ": %s\n", errString);
00113     else
00114        fprintf(out, ": error %d\n", (int)err);
00115 
00116     va_end(args);
00117 }
00118 
00119 void 
00120 SECU_PrintError(char *progName, char *msg, ...)
00121 {
00122     va_list args;
00123     PRErrorCode err = PORT_GetError();
00124     const char * errString = SECU_Strerror(err);
00125 
00126     va_start(args, msg);
00127 
00128     fprintf(stderr, "%s: ", progName);
00129     vfprintf(stderr, msg, args);
00130     if (errString != NULL && PORT_Strlen(errString) > 0)
00131        fprintf(stderr, ": %s\n", errString);
00132     else
00133        fprintf(stderr, ": error %d\n", (int)err);
00134 
00135     va_end(args);
00136 }
00137 
00138 void
00139 SECU_PrintSystemError(char *progName, char *msg, ...)
00140 {
00141     va_list args;
00142 
00143     va_start(args, msg);
00144     fprintf(stderr, "%s: ", progName);
00145     vfprintf(stderr, msg, args);
00146 #if defined(_WIN32_WCE)
00147     fprintf(stderr, ": %d\n", PR_GetOSError());
00148 #else
00149     fprintf(stderr, ": %s\n", strerror(errno));
00150 #endif
00151     va_end(args);
00152 }
00153 
00154 static void
00155 secu_ClearPassword(char *p)
00156 {
00157     if (p) {
00158        PORT_Memset(p, 0, PORT_Strlen(p));
00159        PORT_Free(p);
00160     }
00161 }
00162 
00163 char *
00164 SECU_GetPasswordString(void *arg, char *prompt)
00165 {
00166 #ifndef _WINDOWS
00167     char *p = NULL;
00168     FILE *input, *output;
00169 
00170     /* open terminal */
00171     input = fopen(consoleName, "r");
00172     if (input == NULL) {
00173        fprintf(stderr, "Error opening input terminal for read\n");
00174        return NULL;
00175     }
00176 
00177     output = fopen(consoleName, "w");
00178     if (output == NULL) {
00179        fprintf(stderr, "Error opening output terminal for write\n");
00180        return NULL;
00181     }
00182 
00183     p = SEC_GetPassword (input, output, prompt, SEC_BlindCheckPassword);
00184         
00185 
00186     fclose(input);
00187     fclose(output);
00188 
00189     return p;
00190 
00191 #else
00192     /* Win32 version of above. opening the console may fail
00193        on windows95, and certainly isn't necessary.. */
00194 
00195     char *p = NULL;
00196 
00197     p = SEC_GetPassword (stdin, stdout, prompt, SEC_BlindCheckPassword);
00198     return p;
00199 
00200 #endif
00201 }
00202 
00203 
00204 /*
00205  *  p a s s w o r d _ h a r d c o d e 
00206  *
00207  *  A function to use the password passed in the -f(pwfile) argument
00208  *  of the command line.  
00209  *  After use once, null it out otherwise PKCS11 calls us forever.?
00210  *
00211  */
00212 char *
00213 SECU_FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg)
00214 {
00215     unsigned char phrase[200];
00216     PRFileDesc *fd;
00217     PRInt32 nb;
00218     char *pwFile = arg;
00219     int i;
00220 
00221     if (!pwFile)
00222        return 0;
00223 
00224     if (retry) {
00225        return 0;  /* no good retrying - the files contents will be the same */
00226     } 
00227  
00228     fd = PR_Open(pwFile, PR_RDONLY, 0);
00229     if (!fd) {
00230        fprintf(stderr, "No password file \"%s\" exists.\n", pwFile);
00231        return NULL;
00232     }
00233 
00234     nb = PR_Read(fd, phrase, sizeof(phrase));
00235   
00236     PR_Close(fd);
00237     /* handle the Windows EOL case */
00238     i = 0;
00239     while (phrase[i] != '\r' && phrase[i] != '\n' && i < nb) i++;
00240     phrase[i] = '\0';
00241     if (nb == 0) {
00242        fprintf(stderr,"password file contains no data\n");
00243        return NULL;
00244     }
00245     return (char*) PORT_Strdup((char*)phrase);
00246 }
00247 
00248 char *
00249 SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg) 
00250 {
00251     char prompt[255];
00252     secuPWData *pwdata = (secuPWData *)arg;
00253     secuPWData pwnull = { PW_NONE, 0 };
00254     secuPWData pwxtrn = { PW_EXTERNAL, "external" };
00255     char *pw;
00256 
00257     if (pwdata == NULL)
00258        pwdata = &pwnull;
00259 
00260     if (PK11_ProtectedAuthenticationPath(slot)) {
00261        pwdata = &pwxtrn;
00262     }
00263     if (retry && pwdata->source != PW_NONE) {
00264        PR_fprintf(PR_STDERR, "Incorrect password/PIN entered.\n");
00265        return NULL;
00266     }
00267 
00268     switch (pwdata->source) {
00269     case PW_NONE:
00270        sprintf(prompt, "Enter Password or Pin for \"%s\":",
00271                         PK11_GetTokenName(slot));
00272        return SECU_GetPasswordString(NULL, prompt);
00273     case PW_FROMFILE:
00274        /* Instead of opening and closing the file every time, get the pw
00275         * once, then keep it in memory (duh).
00276         */
00277        pw = SECU_FilePasswd(slot, retry, pwdata->data);
00278        pwdata->source = PW_PLAINTEXT;
00279        pwdata->data = PL_strdup(pw);
00280        /* it's already been dup'ed */
00281        return pw;
00282     case PW_EXTERNAL:
00283        sprintf(prompt, 
00284                "Press Enter, then enter PIN for \"%s\" on external device.\n",
00285               PK11_GetTokenName(slot));
00286        (void) SECU_GetPasswordString(NULL, prompt);
00287        /* Fall Through */
00288     case PW_PLAINTEXT:
00289        return PL_strdup(pwdata->data);
00290     default:
00291        break;
00292     }
00293 
00294     PR_fprintf(PR_STDERR, "Password check failed:  No password found.\n");
00295     return NULL;
00296 }
00297 
00298 char *
00299 secu_InitSlotPassword(PK11SlotInfo *slot, PRBool retry, void *arg)
00300 {
00301     char *p0 = NULL;
00302     char *p1 = NULL;
00303     FILE *input, *output;
00304     secuPWData *pwdata = arg;
00305 
00306     if (pwdata->source == PW_FROMFILE) {
00307        return SECU_FilePasswd(slot, retry, pwdata->data);
00308     } 
00309     if (pwdata->source == PW_PLAINTEXT) {
00310        return PL_strdup(pwdata->data);
00311     }
00312     
00313     /* PW_NONE - get it from tty */
00314     /* open terminal */
00315 #ifdef _WINDOWS
00316     input = stdin;
00317 #else
00318     input = fopen(consoleName, "r");
00319 #endif
00320     if (input == NULL) {
00321        PR_fprintf(PR_STDERR, "Error opening input terminal for read\n");
00322        return NULL;
00323     }
00324 
00325     /* we have no password, so initialize database with one */
00326     PR_fprintf(PR_STDERR, 
00327         "Enter a password which will be used to encrypt your keys.\n"
00328        "The password should be at least 8 characters long,\n"
00329        "and should contain at least one non-alphabetic character.\n\n");
00330 
00331     output = fopen(consoleName, "w");
00332     if (output == NULL) {
00333        PR_fprintf(PR_STDERR, "Error opening output terminal for write\n");
00334        return NULL;
00335     }
00336 
00337 
00338     for (;;) {
00339        if (p0) 
00340            PORT_Free(p0);
00341        p0 = SEC_GetPassword(input, output, "Enter new password: ",
00342                           SEC_BlindCheckPassword);
00343 
00344        if (p1)
00345            PORT_Free(p1);
00346        p1 = SEC_GetPassword(input, output, "Re-enter password: ",
00347                           SEC_BlindCheckPassword);
00348        if (p0 && p1 && !PORT_Strcmp(p0, p1)) {
00349            break;
00350        }
00351        PR_fprintf(PR_STDERR, "Passwords do not match. Try again.\n");
00352     }
00353         
00354     /* clear out the duplicate password string */
00355     secu_ClearPassword(p1);
00356     
00357     fclose(input);
00358     fclose(output);
00359 
00360     return p0;
00361 }
00362 
00363 SECStatus
00364 SECU_ChangePW(PK11SlotInfo *slot, char *passwd, char *pwFile)
00365 {
00366     SECStatus rv;
00367     secuPWData pwdata, newpwdata;
00368     char *oldpw = NULL, *newpw = NULL;
00369 
00370     if (passwd) {
00371        pwdata.source = PW_PLAINTEXT;
00372        pwdata.data = passwd;
00373     } else if (pwFile) {
00374        pwdata.source = PW_FROMFILE;
00375        pwdata.data = pwFile;
00376     } else {
00377        pwdata.source = PW_NONE;
00378        pwdata.data = NULL;
00379     }
00380 
00381     if (PK11_NeedUserInit(slot)) {
00382        newpw = secu_InitSlotPassword(slot, PR_FALSE, &pwdata);
00383        rv = PK11_InitPin(slot, (char*)NULL, newpw);
00384        goto done;
00385     }
00386 
00387     for (;;) {
00388        oldpw = SECU_GetModulePassword(slot, PR_FALSE, &pwdata);
00389 
00390        if (PK11_CheckUserPassword(slot, oldpw) != SECSuccess) {
00391            if (pwdata.source == PW_NONE) {
00392               PR_fprintf(PR_STDERR, "Invalid password.  Try again.\n");
00393            } else {
00394               PR_fprintf(PR_STDERR, "Invalid password.\n");
00395               PORT_Memset(oldpw, 0, PL_strlen(oldpw));
00396               PORT_Free(oldpw);
00397               return SECFailure;
00398            }
00399        } else
00400            break;
00401 
00402        PORT_Free(oldpw);
00403     }
00404 
00405     newpwdata.source = PW_NONE;
00406     newpwdata.data = NULL;
00407 
00408     newpw = secu_InitSlotPassword(slot, PR_FALSE, &newpwdata);
00409 
00410     if (PK11_ChangePW(slot, oldpw, newpw) != SECSuccess) {
00411        PR_fprintf(PR_STDERR, "Failed to change password.\n");
00412        return SECFailure;
00413     }
00414 
00415     PORT_Memset(oldpw, 0, PL_strlen(oldpw));
00416     PORT_Free(oldpw);
00417 
00418     PR_fprintf(PR_STDOUT, "Password changed successfully.\n");
00419 
00420 done:
00421     PORT_Memset(newpw, 0, PL_strlen(newpw));
00422     PORT_Free(newpw);
00423     return SECSuccess;
00424 }
00425 
00426 struct matchobj {
00427     SECItem index;
00428     char *nname;
00429     PRBool found;
00430 };
00431 
00432 char *
00433 SECU_DefaultSSLDir(void)
00434 {
00435     char *dir;
00436     static char sslDir[1000];
00437 
00438     dir = PR_GetEnv("SSL_DIR");
00439     if (!dir)
00440        return NULL;
00441 
00442     sprintf(sslDir, "%s", dir);
00443 
00444     if (sslDir[strlen(sslDir)-1] == '/')
00445        sslDir[strlen(sslDir)-1] = 0;
00446 
00447     return sslDir;
00448 }
00449 
00450 char *
00451 SECU_AppendFilenameToDir(char *dir, char *filename)
00452 {
00453     static char path[1000];
00454 
00455     if (dir[strlen(dir)-1] == '/')
00456        sprintf(path, "%s%s", dir, filename);
00457     else
00458        sprintf(path, "%s/%s", dir, filename);
00459     return path;
00460 }
00461 
00462 char *
00463 SECU_ConfigDirectory(const char* base)
00464 {
00465     static PRBool initted = PR_FALSE;
00466     const char *dir = ".netscape";
00467     char *home;
00468     static char buf[1000];
00469 
00470     if (initted) return buf;
00471     
00472 
00473     if (base == NULL || *base == 0) {
00474        home = PR_GetEnv("HOME");
00475        if (!home) home = "";
00476 
00477        if (*home && home[strlen(home) - 1] == '/')
00478            sprintf (buf, "%.900s%s", home, dir);
00479        else
00480            sprintf (buf, "%.900s/%s", home, dir);
00481     } else {
00482        sprintf(buf, "%.900s", base);
00483        if (buf[strlen(buf) - 1] == '/')
00484            buf[strlen(buf) - 1] = 0;
00485     }
00486 
00487 
00488     initted = PR_TRUE;
00489     return buf;
00490 }
00491 
00492 /*Turn off SSL for now */
00493 /* This gets called by SSL when server wants our cert & key */
00494 int
00495 SECU_GetClientAuthData(void *arg, PRFileDesc *fd,
00496                      struct CERTDistNamesStr *caNames,
00497                       struct CERTCertificateStr **pRetCert,
00498                       struct SECKEYPrivateKeyStr **pRetKey)
00499 {
00500     SECKEYPrivateKey *key;
00501     CERTCertificate *cert;
00502     int errsave;
00503 
00504     if (arg == NULL) {
00505         fprintf(stderr, "no key/cert name specified for client auth\n");
00506         return -1;
00507     }
00508     cert = PK11_FindCertFromNickname(arg, NULL);
00509     errsave = PORT_GetError();
00510     if (!cert) {
00511         if (errsave == SEC_ERROR_BAD_PASSWORD)
00512             fprintf(stderr, "Bad password\n");
00513         else if (errsave > 0)
00514             fprintf(stderr, "Unable to read cert (error %d)\n", errsave);
00515         else if (errsave == SEC_ERROR_BAD_DATABASE)
00516             fprintf(stderr, "Unable to get cert from database (%d)\n", errsave);
00517         else
00518             fprintf(stderr, "SECKEY_FindKeyByName: internal error %d\n", errsave);
00519         return -1;
00520     }
00521 
00522     key = PK11_FindKeyByAnyCert(arg,NULL);
00523     if (!key) {
00524         fprintf(stderr, "Unable to get key (%d)\n", PORT_GetError());
00525         return -1;
00526     }
00527 
00528 
00529     *pRetCert = cert;
00530     *pRetKey = key;
00531 
00532     return 0;
00533 }
00534 
00535 SECStatus
00536 secu_StdinToItem(SECItem *dst)
00537 {
00538     unsigned char buf[1000];
00539     PRInt32 numBytes;
00540     PRBool notDone = PR_TRUE;
00541 
00542     dst->len = 0;
00543     dst->data = NULL;
00544 
00545     while (notDone) {
00546        numBytes = PR_Read(PR_STDIN, buf, sizeof(buf));
00547 
00548        if (numBytes < 0) {
00549            return SECFailure;
00550        }
00551 
00552        if (numBytes == 0)
00553            break;
00554 
00555        if (dst->data) {
00556            unsigned char * p = dst->data;
00557            dst->data = (unsigned char*)PORT_Realloc(p, dst->len + numBytes);
00558            if (!dst->data) {
00559               PORT_Free(p);
00560            }
00561        } else {
00562            dst->data = (unsigned char*)PORT_Alloc(numBytes);
00563        }
00564        if (!dst->data) {
00565            return SECFailure;
00566        }
00567        PORT_Memcpy(dst->data + dst->len, buf, numBytes);
00568        dst->len += numBytes;
00569     }
00570 
00571     return SECSuccess;
00572 }
00573 
00574 SECStatus
00575 SECU_FileToItem(SECItem *dst, PRFileDesc *src)
00576 {
00577     PRFileInfo info;
00578     PRInt32 numBytes;
00579     PRStatus prStatus;
00580 
00581     if (src == PR_STDIN)
00582        return secu_StdinToItem(dst);
00583 
00584     prStatus = PR_GetOpenFileInfo(src, &info);
00585 
00586     if (prStatus != PR_SUCCESS) {
00587        PORT_SetError(SEC_ERROR_IO);
00588        return SECFailure;
00589     }
00590 
00591     /* XXX workaround for 3.1, not all utils zero dst before sending */
00592     dst->data = 0;
00593     if (!SECITEM_AllocItem(NULL, dst, info.size))
00594        goto loser;
00595 
00596     numBytes = PR_Read(src, dst->data, info.size);
00597     if (numBytes != info.size) {
00598        PORT_SetError(SEC_ERROR_IO);
00599        goto loser;
00600     }
00601 
00602     return SECSuccess;
00603 loser:
00604     SECITEM_FreeItem(dst, PR_FALSE);
00605     return SECFailure;
00606 }
00607 
00608 SECStatus
00609 SECU_TextFileToItem(SECItem *dst, PRFileDesc *src)
00610 {
00611     PRFileInfo info;
00612     PRInt32 numBytes;
00613     PRStatus prStatus;
00614     unsigned char *buf;
00615 
00616     if (src == PR_STDIN)
00617        return secu_StdinToItem(dst);
00618 
00619     prStatus = PR_GetOpenFileInfo(src, &info);
00620 
00621     if (prStatus != PR_SUCCESS) {
00622        PORT_SetError(SEC_ERROR_IO);
00623        return SECFailure;
00624     }
00625 
00626     buf = (unsigned char*)PORT_Alloc(info.size);
00627     if (!buf)
00628        return SECFailure;
00629 
00630     numBytes = PR_Read(src, buf, info.size);
00631     if (numBytes != info.size) {
00632        PORT_SetError(SEC_ERROR_IO);
00633        goto loser;
00634     }
00635 
00636     if (buf[numBytes-1] == '\n') numBytes--;
00637 #ifdef _WINDOWS
00638     if (buf[numBytes-1] == '\r') numBytes--;
00639 #endif
00640 
00641     /* XXX workaround for 3.1, not all utils zero dst before sending */
00642     dst->data = 0;
00643     if (!SECITEM_AllocItem(NULL, dst, numBytes))
00644        goto loser;
00645 
00646     memcpy(dst->data, buf, numBytes);
00647 
00648     PORT_Free(buf);
00649     return SECSuccess;
00650 loser:
00651     PORT_Free(buf);
00652     return SECFailure;
00653 }
00654 
00655 SECStatus
00656 SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii)
00657 {
00658     SECStatus rv;
00659     if (ascii) {
00660        /* First convert ascii to binary */
00661        SECItem filedata;
00662        char *asc, *body;
00663 
00664        /* Read in ascii data */
00665        rv = SECU_FileToItem(&filedata, inFile);
00666        asc = (char *)filedata.data;
00667        if (!asc) {
00668            fprintf(stderr, "unable to read data from input file\n");
00669            return SECFailure;
00670        }
00671 
00672        /* check for headers and trailers and remove them */
00673        if ((body = strstr(asc, "-----BEGIN")) != NULL) {
00674            char *trailer = NULL;
00675            asc = body;
00676            body = PORT_Strchr(body, '\n');
00677            if (!body)
00678               body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */
00679            if (body)
00680               trailer = strstr(++body, "-----END");
00681            if (trailer != NULL) {
00682               *trailer = '\0';
00683            } else {
00684               fprintf(stderr, "input has header but no trailer\n");
00685               PORT_Free(filedata.data);
00686               return SECFailure;
00687            }
00688        } else {
00689            body = asc;
00690        }
00691      
00692        /* Convert to binary */
00693        rv = ATOB_ConvertAsciiToItem(der, body);
00694        if (rv) {
00695            fprintf(stderr, "error converting ascii to binary (%s)\n",
00696                   SECU_Strerror(PORT_GetError()));
00697            PORT_Free(filedata.data);
00698            return SECFailure;
00699        }
00700 
00701        PORT_Free(filedata.data);
00702     } else {
00703        /* Read in binary der */
00704        rv = SECU_FileToItem(der, inFile);
00705        if (rv) {
00706            fprintf(stderr, "error converting der (%s)\n", 
00707                   SECU_Strerror(PORT_GetError()));
00708            return SECFailure;
00709        }
00710     }
00711     return SECSuccess;
00712 }
00713 
00714 #define INDENT_MULT  4
00715 void
00716 SECU_Indent(FILE *out, int level)
00717 {
00718     int i;
00719 
00720     for (i = 0; i < level; i++) {
00721        fprintf(out, "    ");
00722     }
00723 }
00724 
00725 static void secu_Newline(FILE *out)
00726 {
00727     fprintf(out, "\n");
00728 }
00729 
00730 void
00731 SECU_PrintAsHex(FILE *out, SECItem *data, const char *m, int level)
00732 {
00733     unsigned i;
00734     int column;
00735     PRBool isString     = PR_TRUE;
00736     PRBool isWhiteSpace = PR_TRUE;
00737     PRBool printedHex   = PR_FALSE;
00738     unsigned int limit = 15;
00739 
00740     if ( m ) {
00741        SECU_Indent(out, level); fprintf(out, "%s:\n", m);
00742        level++;
00743     }
00744     
00745     SECU_Indent(out, level); column = level*INDENT_MULT;
00746     if (!data->len) {
00747        fprintf(out, "(empty)\n");
00748        return;
00749     }
00750     /* take a pass to see if it's all printable. */
00751     for (i = 0; i < data->len; i++) {
00752        unsigned char val = data->data[i];
00753         if (!val || !isprint(val)) {
00754            isString = PR_FALSE;
00755            break;
00756        }
00757        if (isWhiteSpace && !isspace(val)) {
00758            isWhiteSpace = PR_FALSE;
00759        }
00760     }
00761 
00762     /* Short values, such as bit strings (which are printed with this
00763     ** function) often look like strings, but we want to see the bits.
00764     ** so this test assures that short values will be printed in hex,
00765     ** perhaps in addition to being printed as strings.
00766     ** The threshold size (4 bytes) is arbitrary.
00767     */
00768     if (!isString || data->len <= 4) {
00769       for (i = 0; i < data->len; i++) {
00770        if (i != data->len - 1) {
00771            fprintf(out, "%02x:", data->data[i]);
00772            column += 3;
00773        } else {
00774            fprintf(out, "%02x", data->data[i]);
00775            column += 2;
00776            break;
00777        }
00778        if (column > 76 || (i % 16 == limit)) {
00779            secu_Newline(out);
00780            SECU_Indent(out, level); 
00781            column = level*INDENT_MULT;
00782            limit = i % 16;
00783        }
00784       }
00785       printedHex = PR_TRUE;
00786     }
00787     if (isString && !isWhiteSpace) {
00788        if (printedHex != PR_FALSE) {
00789            secu_Newline(out);
00790            SECU_Indent(out, level); column = level*INDENT_MULT;
00791        }
00792        for (i = 0; i < data->len; i++) {
00793            unsigned char val = data->data[i];
00794 
00795            if (val) {
00796               fprintf(out,"%c",val);
00797               column++;
00798            } else {
00799               column = 77;
00800            }
00801            if (column > 76) {
00802               secu_Newline(out);
00803               SECU_Indent(out, level); column = level*INDENT_MULT;
00804            }
00805        }
00806     }
00807            
00808     if (column != level*INDENT_MULT) {
00809        secu_Newline(out);
00810     }
00811 }
00812 
00813 static const char *hex = "0123456789abcdef";
00814 
00815 static const char printable[257] = {
00816        "................"   /* 0x */
00817        "................"   /* 1x */
00818        " !\"#$%&'()*+,-./"  /* 2x */
00819        "0123456789:;<=>?"   /* 3x */
00820        "@ABCDEFGHIJKLMNO"   /* 4x */
00821        "PQRSTUVWXYZ[\\]^_"  /* 5x */
00822        "`abcdefghijklmno"   /* 6x */
00823        "pqrstuvwxyz{|}~."   /* 7x */
00824        "................"   /* 8x */
00825        "................"   /* 9x */
00826        "................"   /* ax */
00827        "................"   /* bx */
00828        "................"   /* cx */
00829        "................"   /* dx */
00830        "................"   /* ex */
00831        "................"   /* fx */
00832 };
00833 
00834 void 
00835 SECU_PrintBuf(FILE *out, const char *msg, const void *vp, int len)
00836 {
00837     const unsigned char *cp = (const unsigned char *)vp;
00838     char buf[80];
00839     char *bp;
00840     char *ap;
00841 
00842     fprintf(out, "%s [Len: %d]\n", msg, len);
00843     memset(buf, ' ', sizeof buf);
00844     bp = buf;
00845     ap = buf + 50;
00846     while (--len >= 0) {
00847        unsigned char ch = *cp++;
00848        *bp++ = hex[(ch >> 4) & 0xf];
00849        *bp++ = hex[ch & 0xf];
00850        *bp++ = ' ';
00851        *ap++ = printable[ch];
00852        if (ap - buf >= 66) {
00853            *ap = 0;
00854            fprintf(out, "   %s\n", buf);
00855            memset(buf, ' ', sizeof buf);
00856            bp = buf;
00857            ap = buf + 50;
00858        }
00859     }
00860     if (bp > buf) {
00861        *ap = 0;
00862        fprintf(out, "   %s\n", buf);
00863     }
00864 }
00865 
00866 SECStatus
00867 SECU_StripTagAndLength(SECItem *i)
00868 {
00869     unsigned int start;
00870 
00871     if (!i || !i->data || i->len < 2) { /* must be at least tag and length */
00872         return SECFailure;
00873     }
00874     start = ((i->data[1] & 0x80) ? (i->data[1] & 0x7f) + 2 : 2);
00875     if (i->len < start) {
00876         return SECFailure;
00877     }
00878     i->data += start;
00879     i->len  -= start;
00880     return SECSuccess;
00881 }
00882 
00883 
00884 /* This expents i->data[0] to be the MSB of the integer.
00885 ** if you want to print a DER-encoded integer (with the tag and length)
00886 ** call SECU_PrintEncodedInteger();
00887 */
00888 void
00889 SECU_PrintInteger(FILE *out, SECItem *i, char *m, int level)
00890 {
00891     int iv;
00892 
00893     if (!i || !i->len || !i->data) {
00894        SECU_Indent(out, level); 
00895        if (m) {
00896            fprintf(out, "%s: (null)\n", m);
00897        } else {
00898            fprintf(out, "(null)\n");
00899        }
00900     } else if (i->len > 4) {
00901        SECU_PrintAsHex(out, i, m, level);
00902     } else {
00903        iv = DER_GetInteger(i);
00904        SECU_Indent(out, level); 
00905        if (m) {
00906            fprintf(out, "%s: %d (0x%x)\n", m, iv, iv);
00907        } else {
00908            fprintf(out, "%d (0x%x)\n", iv, iv);
00909        }
00910     }
00911 }
00912 
00913 static void
00914 secu_PrintRawString(FILE *out, SECItem *si, char *m, int level)
00915 {
00916     int column;
00917     unsigned int i;
00918 
00919     if ( m ) {
00920        SECU_Indent(out, level); fprintf(out, "%s: ", m);
00921        column = (level * INDENT_MULT) + strlen(m) + 2;
00922        level++;
00923     } else {
00924        SECU_Indent(out, level); 
00925        column = level*INDENT_MULT;
00926     }
00927     fprintf(out, "\""); column++;
00928 
00929     for (i = 0; i < si->len; i++) {
00930        unsigned char val = si->data[i];
00931        if (column > 76) {
00932            secu_Newline(out);
00933            SECU_Indent(out, level); column = level*INDENT_MULT;
00934        }
00935 
00936        fprintf(out,"%c", printable[val]); column++;
00937     }
00938 
00939     fprintf(out, "\""); column++;
00940     if (column != level*INDENT_MULT || column > 76) {
00941        secu_Newline(out);
00942     }
00943 }
00944 
00945 void
00946 SECU_PrintString(FILE *out, SECItem *si, char *m, int level)
00947 {
00948     SECItem my = *si;
00949 
00950     if (SECSuccess != SECU_StripTagAndLength(&my) || !my.len)
00951        return;
00952     secu_PrintRawString(out, &my, m, level);
00953 }
00954 
00955 /* print an unencoded boolean */
00956 static void
00957 secu_PrintBoolean(FILE *out, SECItem *i, const char *m, int level)
00958 {
00959     int val = 0;
00960     
00961     if ( i->data && i->len ) {
00962        val = i->data[0];
00963     }
00964 
00965     if (!m) {
00966        m = "Boolean";
00967     }
00968     SECU_Indent(out, level); 
00969     fprintf(out, "%s: %s\n", m, (val ? "True" : "False"));
00970 }
00971 
00972 /*
00973  * Format and print "time".  If the tag message "m" is not NULL,
00974  * do indent formatting based on "level" and add a newline afterward;
00975  * otherwise just print the formatted time string only.
00976  */
00977 static void
00978 secu_PrintTime(FILE *out, int64 time, char *m, int level)
00979 {
00980     PRExplodedTime printableTime; 
00981     char *timeString;
00982 
00983     /* Convert to local time */
00984     PR_ExplodeTime(time, PR_GMTParameters, &printableTime);
00985 
00986     timeString = PORT_Alloc(100);
00987     if (timeString == NULL)
00988        return;
00989 
00990     if (m != NULL) {
00991        SECU_Indent(out, level);
00992        fprintf(out, "%s: ", m);
00993     }
00994 
00995     PR_FormatTime(timeString, 100, "%a %b %d %H:%M:%S %Y", &printableTime);
00996     fprintf(out, timeString);
00997 
00998     if (m != NULL)
00999        fprintf(out, "\n");
01000 
01001     PORT_Free(timeString);
01002 }
01003 
01004 /*
01005  * Format and print the UTC Time "t".  If the tag message "m" is not NULL,
01006  * do indent formatting based on "level" and add a newline afterward;
01007  * otherwise just print the formatted time string only.
01008  */
01009 void
01010 SECU_PrintUTCTime(FILE *out, SECItem *t, char *m, int level)
01011 {
01012     int64 time;
01013     SECStatus rv;
01014 
01015     rv = DER_UTCTimeToTime(&time, t);
01016     if (rv != SECSuccess)
01017        return;
01018 
01019     secu_PrintTime(out, time, m, level);
01020 }
01021 
01022 /*
01023  * Format and print the Generalized Time "t".  If the tag message "m"
01024  * is not NULL, * do indent formatting based on "level" and add a newline
01025  * afterward; otherwise just print the formatted time string only.
01026  */
01027 void
01028 SECU_PrintGeneralizedTime(FILE *out, SECItem *t, char *m, int level)
01029 {
01030     int64 time;
01031     SECStatus rv;
01032 
01033 
01034     rv = DER_GeneralizedTimeToTime(&time, t);
01035     if (rv != SECSuccess)
01036        return;
01037 
01038     secu_PrintTime(out, time, m, level);
01039 }
01040 
01041 /*
01042  * Format and print the UTC or Generalized Time "t".  If the tag message
01043  * "m" is not NULL, do indent formatting based on "level" and add a newline
01044  * afterward; otherwise just print the formatted time string only.
01045  */
01046 void
01047 SECU_PrintTimeChoice(FILE *out, SECItem *t, char *m, int level)
01048 {
01049     switch (t->type) {
01050         case siUTCTime:
01051             SECU_PrintUTCTime(out, t, m, level);
01052             break;
01053 
01054         case siGeneralizedTime:
01055             SECU_PrintGeneralizedTime(out, t, m, level);
01056             break;
01057 
01058         default:
01059             PORT_Assert(0);
01060             break;
01061     }
01062 }
01063 
01064 
01065 /* This prints a SET or SEQUENCE */
01066 void
01067 SECU_PrintSet(FILE *out, SECItem *t, char *m, int level)
01068 {
01069     int            type        = t->data[0] & SEC_ASN1_TAGNUM_MASK;
01070     int            constructed = t->data[0] & SEC_ASN1_CONSTRUCTED;
01071     const char *   label;
01072     SECItem        my          = *t;
01073 
01074     if (!constructed) {
01075        SECU_PrintAsHex(out, t, m, level);
01076         return;
01077     }
01078     if (SECSuccess != SECU_StripTagAndLength(&my))
01079        return;
01080 
01081     SECU_Indent(out, level);
01082     if (m) {
01083        fprintf(out, "%s: ", m);
01084     }
01085 
01086     if (type == SEC_ASN1_SET)
01087        label = "Set ";
01088     else if (type == SEC_ASN1_SEQUENCE)
01089        label = "Sequence ";
01090     else
01091        label = "";
01092     fprintf(out,"%s{\n", label); /* } */
01093 
01094     while (my.len >= 2) {
01095        SECItem  tmp = my;
01096 
01097         if (tmp.data[1] & 0x80) {
01098            unsigned int i;
01099            unsigned int lenlen = tmp.data[1] & 0x7f;
01100            if (lenlen > sizeof tmp.len)
01101                break;
01102            tmp.len = 0;
01103            for (i=0; i < lenlen; i++) {
01104               tmp.len = (tmp.len << 8) | tmp.data[2+i];
01105            }
01106            tmp.len += lenlen + 2;
01107        } else {
01108            tmp.len = tmp.data[1] + 2;
01109        }
01110        if (tmp.len > my.len) {
01111            tmp.len = my.len;
01112        }
01113        my.data += tmp.len;
01114        my.len  -= tmp.len;
01115        SECU_PrintAny(out, &tmp, NULL, level + 1);
01116     }
01117     SECU_Indent(out, level); fprintf(out, /* { */ "}\n");
01118 }
01119 
01120 static void
01121 secu_PrintContextSpecific(FILE *out, SECItem *i, char *m, int level)
01122 {
01123     int type        = i->data[0] & SEC_ASN1_TAGNUM_MASK;
01124     int constructed = i->data[0] & SEC_ASN1_CONSTRUCTED;
01125     SECItem tmp;
01126 
01127     if (constructed) {
01128        char * m2;
01129        if (!m) 
01130            m2 = PR_smprintf("[%d]", type);
01131        else
01132            m2 = PR_smprintf("%s: [%d]", m, type);
01133        if (m2) {
01134            SECU_PrintSet(out, i, m2, level);
01135            PR_smprintf_free(m2);
01136        }
01137        return;
01138     }
01139 
01140     SECU_Indent(out, level);
01141     if (m) {
01142        fprintf(out, "%s: ", m);
01143     }
01144     fprintf(out,"[%d]\n", type);
01145 
01146     tmp = *i;
01147     if (SECSuccess == SECU_StripTagAndLength(&tmp))
01148        SECU_PrintAsHex(out, &tmp, m, level+1);
01149 }
01150 
01151 static void
01152 secu_PrintOctetString(FILE *out, SECItem *i, char *m, int level)
01153 {
01154     SECItem tmp = *i;
01155     if (SECSuccess == SECU_StripTagAndLength(&tmp))
01156        SECU_PrintAsHex(out, &tmp, m, level);
01157 }
01158 
01159 static void
01160 secu_PrintBitString(FILE *out, SECItem *i, char *m, int level)
01161 {
01162     int unused_bits;
01163     SECItem tmp = *i;
01164 
01165     if (SECSuccess != SECU_StripTagAndLength(&tmp) || tmp.len < 2)
01166        return;
01167 
01168     unused_bits = *tmp.data++;
01169     tmp.len--;
01170 
01171     SECU_PrintAsHex(out, &tmp, m, level);
01172     if (unused_bits) {
01173        SECU_Indent(out, level + 1);
01174        fprintf(out, "(%d least significant bits unused)\n", unused_bits);
01175     }
01176 }
01177 
01178 /* in a decoded bit string, the len member is a bit length. */
01179 static void
01180 secu_PrintDecodedBitString(FILE *out, SECItem *i, char *m, int level)
01181 {
01182     int unused_bits;
01183     SECItem tmp = *i;
01184 
01185 
01186     unused_bits = (tmp.len & 0x7) ? 8 - (tmp.len & 7) : 0;
01187     DER_ConvertBitString(&tmp); /* convert length to byte length */
01188 
01189     SECU_PrintAsHex(out, &tmp, m, level);
01190     if (unused_bits) {
01191        SECU_Indent(out, level + 1);
01192        fprintf(out, "(%d least significant bits unused)\n", unused_bits);
01193     }
01194 }
01195 
01196 
01197 /* Print a DER encoded Boolean */
01198 void
01199 SECU_PrintEncodedBoolean(FILE *out, SECItem *i, char *m, int level)
01200 {
01201     SECItem my    = *i;
01202     if (SECSuccess == SECU_StripTagAndLength(&my))
01203        secu_PrintBoolean(out, &my, m, level);
01204 }
01205 
01206 /* Print a DER encoded integer */
01207 void
01208 SECU_PrintEncodedInteger(FILE *out, SECItem *i, char *m, int level)
01209 {
01210     SECItem my    = *i;
01211     if (SECSuccess == SECU_StripTagAndLength(&my))
01212        SECU_PrintInteger(out, &my, m, level);
01213 }
01214 
01215 /* Print a DER encoded OID */
01216 void
01217 SECU_PrintEncodedObjectID(FILE *out, SECItem *i, char *m, int level)
01218 {
01219     SECItem my    = *i;
01220     if (SECSuccess == SECU_StripTagAndLength(&my))
01221        SECU_PrintObjectID(out, &my, m, level);
01222 }
01223 
01224 static void
01225 secu_PrintBMPString(FILE *out, SECItem *i, char *m, int level)
01226 {
01227     unsigned char * s;
01228     unsigned char * d;
01229     int      len;
01230     SECItem  tmp = {0, 0, 0};
01231     SECItem  my  = *i;
01232 
01233     if (SECSuccess != SECU_StripTagAndLength(&my))
01234        goto loser;
01235     if (my.len % 2) 
01236        goto loser;
01237     len = (int)(my.len / 2);
01238     tmp.data = (unsigned char *)PORT_Alloc(len);
01239     if (!tmp.data)
01240        goto loser;
01241     tmp.len = len;
01242     for (s = my.data, d = tmp.data ; len > 0; len--) {
01243        PRUint32 bmpChar = (s[0] << 8) | s[1]; s += 2;
01244        if (!isprint(bmpChar))
01245            goto loser;
01246        *d++ = (unsigned char)bmpChar;
01247     }
01248     secu_PrintRawString(out, &tmp, m, level);
01249     PORT_Free(tmp.data);
01250     return;
01251 
01252 loser:
01253     SECU_PrintAsHex(out, i, m, level);
01254     if (tmp.data)
01255        PORT_Free(tmp.data);
01256 }
01257 
01258 static void
01259 secu_PrintUniversalString(FILE *out, SECItem *i, char *m, int level)
01260 {
01261     unsigned char * s;
01262     unsigned char * d;
01263     int      len;
01264     SECItem  tmp = {0, 0, 0};
01265     SECItem  my  = *i;
01266 
01267     if (SECSuccess != SECU_StripTagAndLength(&my))
01268        goto loser;
01269     if (my.len % 4) 
01270        goto loser;
01271     len = (int)(my.len / 4);
01272     tmp.data = (unsigned char *)PORT_Alloc(len);
01273     if (!tmp.data)
01274        goto loser;
01275     tmp.len = len;
01276     for (s = my.data, d = tmp.data ; len > 0; len--) {
01277        PRUint32 bmpChar = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
01278        s += 4;
01279        if (!isprint(bmpChar))
01280            goto loser;
01281        *d++ = (unsigned char)bmpChar;
01282     }
01283     secu_PrintRawString(out, &tmp, m, level);
01284     PORT_Free(tmp.data);
01285     return;
01286 
01287 loser:
01288     SECU_PrintAsHex(out, i, m, level);
01289     if (tmp.data)
01290        PORT_Free(tmp.data);
01291 }
01292 
01293 static void
01294 secu_PrintUniversal(FILE *out, SECItem *i, char *m, int level)
01295 {
01296        switch (i->data[0] & SEC_ASN1_TAGNUM_MASK) {
01297          case SEC_ASN1_ENUMERATED:
01298          case SEC_ASN1_INTEGER:
01299            SECU_PrintEncodedInteger(out, i, m, level);
01300            break;
01301          case SEC_ASN1_OBJECT_ID:
01302            SECU_PrintEncodedObjectID(out, i, m, level);
01303            break;
01304          case SEC_ASN1_BOOLEAN:
01305            SECU_PrintEncodedBoolean(out, i, m, level);
01306            break;
01307          case SEC_ASN1_UTF8_STRING:
01308          case SEC_ASN1_PRINTABLE_STRING:
01309          case SEC_ASN1_VISIBLE_STRING:
01310          case SEC_ASN1_IA5_STRING:
01311          case SEC_ASN1_T61_STRING:
01312            SECU_PrintString(out, i, m, level);
01313            break;
01314          case SEC_ASN1_GENERALIZED_TIME:
01315            SECU_PrintGeneralizedTime(out, i, m, level);
01316            break;
01317          case SEC_ASN1_UTC_TIME:
01318            SECU_PrintUTCTime(out, i, m, level);
01319            break;
01320          case SEC_ASN1_NULL:
01321            SECU_Indent(out, level); 
01322            if (m && m[0]) 
01323              fprintf(out, "%s: NULL\n", m);
01324            else
01325              fprintf(out, "NULL\n");
01326            break;
01327           case SEC_ASN1_SET:
01328           case SEC_ASN1_SEQUENCE:
01329            SECU_PrintSet(out, i, m, level);
01330            break;
01331          case SEC_ASN1_OCTET_STRING:
01332            secu_PrintOctetString(out, i, m, level);
01333            break;
01334          case SEC_ASN1_BIT_STRING:
01335            secu_PrintBitString(out, i, m, level);
01336            break;
01337          case SEC_ASN1_BMP_STRING:
01338            secu_PrintBMPString(out, i, m, level);
01339            break;
01340          case SEC_ASN1_UNIVERSAL_STRING:
01341            secu_PrintUniversalString(out, i, m, level);
01342            break;
01343          default:
01344            SECU_PrintAsHex(out, i, m, level);
01345            break;
01346        }
01347 }
01348 
01349 void
01350 SECU_PrintAny(FILE *out, SECItem *i, char *m, int level)
01351 {
01352     if ( i && i->len && i->data ) {
01353        switch (i->data[0] & SEC_ASN1_CLASS_MASK) {
01354        case SEC_ASN1_CONTEXT_SPECIFIC:
01355            secu_PrintContextSpecific(out, i, m, level);
01356            break;
01357        case SEC_ASN1_UNIVERSAL:
01358            secu_PrintUniversal(out, i, m, level);
01359            break;
01360        default:
01361            SECU_PrintAsHex(out, i, m, level);
01362            break;
01363        }
01364     }
01365 }
01366 
01367 static int
01368 secu_PrintValidity(FILE *out, CERTValidity *v, char *m, int level)
01369 {
01370     SECU_Indent(out, level);  fprintf(out, "%s:\n", m);
01371     SECU_PrintTimeChoice(out, &v->notBefore, "Not Before", level+1);
01372     SECU_PrintTimeChoice(out, &v->notAfter,  "Not After ", level+1);
01373     return 0;
01374 }
01375 
01376 /* This function does NOT expect a DER type and length. */
01377 SECOidTag
01378 SECU_PrintObjectID(FILE *out, SECItem *oid, char *m, int level)
01379 {
01380     SECOidData *oiddata;
01381     char *      oidString = NULL;
01382     
01383     oiddata = SECOID_FindOID(oid);
01384     if (oiddata != NULL) {
01385        const char *name = oiddata->desc;
01386        SECU_Indent(out, level);
01387        if (m != NULL)
01388            fprintf(out, "%s: ", m);
01389        fprintf(out, "%s\n", name);
01390        return oiddata->offset;
01391     } 
01392     oidString = CERT_GetOidString(oid);
01393     if (oidString) {
01394        SECU_Indent(out, level);
01395        if (m != NULL)
01396            fprintf(out, "%s: ", m);
01397        fprintf(out, "%s\n", oidString);
01398        PR_smprintf_free(oidString);
01399        return SEC_OID_UNKNOWN;
01400     }
01401     SECU_PrintAsHex(out, oid, m, level);
01402     return SEC_OID_UNKNOWN;
01403 }
01404 
01405 
01406 /* This function does NOT expect a DER type and length. */
01407 void
01408 SECU_PrintAlgorithmID(FILE *out, SECAlgorithmID *a, char *m, int level)
01409 {
01410     SECU_PrintObjectID(out, &a->algorithm, m, level);
01411 
01412     if (a->parameters.len == 0
01413        || (a->parameters.len == 2
01414            && PORT_Memcmp(a->parameters.data, "\005\000", 2) == 0)) {
01415        /* No arguments or NULL argument */
01416     } else {
01417        /* Print args to algorithm */
01418        SECU_PrintAsHex(out, &a->parameters, "Args", level+1);
01419     }
01420 }
01421 
01422 static void
01423 secu_PrintAttribute(FILE *out, SEC_PKCS7Attribute *attr, char *m, int level)
01424 {
01425     SECItem *value;
01426     int i;
01427     char om[100];
01428 
01429     if (m) {
01430        SECU_Indent(out, level); fprintf(out, "%s:\n", m);
01431     }
01432 
01433     /*
01434      * Should make this smarter; look at the type field and then decode
01435      * and print the value(s) appropriately!
01436      */
01437     SECU_PrintObjectID(out, &(attr->type), "Type", level+1);
01438     if (attr->values != NULL) {
01439        i = 0;
01440        while ((value = attr->values[i++]) != NULL) {
01441            sprintf(om, "Value (%d)%s", i, attr->encoded ? " (encoded)" : ""); 
01442            if (attr->encoded || attr->typeTag == NULL) {
01443               SECU_PrintAny(out, value, om, level+1);
01444            } else {
01445               switch (attr->typeTag->offset) {
01446                 default:
01447                   SECU_PrintAsHex(out, value, om, level+1);
01448                   break;
01449                 case SEC_OID_PKCS9_CONTENT_TYPE:
01450                   SECU_PrintObjectID(out, value, om, level+1);
01451                   break;
01452                 case SEC_OID_PKCS9_SIGNING_TIME:
01453                   SECU_PrintTimeChoice(out, value, om, level+1);
01454                   break;
01455               }
01456            }
01457        }
01458     }
01459 }
01460 
01461 static void
01462 secu_PrintRSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level)
01463 {
01464 
01465     SECU_Indent(out, level); fprintf(out, "%s:\n", m);
01466     SECU_PrintInteger(out, &pk->u.rsa.modulus, "Modulus", level+1);
01467     SECU_PrintInteger(out, &pk->u.rsa.publicExponent, "Exponent", level+1);
01468     if (pk->u.rsa.publicExponent.len == 1 &&
01469         pk->u.rsa.publicExponent.data[0] == 1) {
01470        SECU_Indent(out, level +1); fprintf(out, "Error: INVALID RSA KEY!\n");
01471     }
01472 }
01473 
01474 static void
01475 secu_PrintDSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level)
01476 {
01477     SECU_Indent(out, level); fprintf(out, "%s:\n", m);
01478     SECU_PrintInteger(out, &pk->u.dsa.params.prime, "Prime", level+1);
01479     SECU_PrintInteger(out, &pk->u.dsa.params.subPrime, "Subprime", level+1);
01480     SECU_PrintInteger(out, &pk->u.dsa.params.base, "Base", level+1);
01481     SECU_PrintInteger(out, &pk->u.dsa.publicValue, "PublicValue", level+1);
01482 }
01483 
01484 #ifdef NSS_ENABLE_ECC
01485 static void
01486 secu_PrintECPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level)
01487 {
01488     SECItem curveOID = { siBuffer, NULL, 0};
01489 
01490     SECU_Indent(out, level); fprintf(out, "%s:\n", m);
01491     SECU_PrintInteger(out, &pk->u.ec.publicValue, "PublicValue", level+1);
01492     /* For named curves, the DEREncodedParams field contains an
01493      * ASN Object ID (0x06 is SEC_ASN1_OBJECT_ID).
01494      */
01495     if ((pk->u.ec.DEREncodedParams.len > 2) &&
01496        (pk->u.ec.DEREncodedParams.data[0] == 0x06)) {
01497         curveOID.len = pk->u.ec.DEREncodedParams.data[1];
01498        curveOID.data = pk->u.ec.DEREncodedParams.data + 2;
01499        SECU_PrintObjectID(out, &curveOID, "Curve", level +1);
01500     }
01501 }
01502 #endif /* NSS_ENABLE_ECC */
01503 
01504 static void
01505 secu_PrintSubjectPublicKeyInfo(FILE *out, PRArenaPool *arena,
01506                      CERTSubjectPublicKeyInfo *i,  char *msg, int level)
01507 {
01508     SECKEYPublicKey *pk;
01509 
01510     SECU_Indent(out, level); fprintf(out, "%s:\n", msg);
01511     SECU_PrintAlgorithmID(out, &i->algorithm, "Public Key Algorithm", level+1);
01512 
01513     pk = SECKEY_ExtractPublicKey(i);
01514     if (pk) {
01515        switch (pk->keyType) {
01516        case rsaKey:
01517            secu_PrintRSAPublicKey(out, pk, "RSA Public Key", level +1);
01518            break;
01519 
01520        case dsaKey:
01521            secu_PrintDSAPublicKey(out, pk, "DSA Public Key", level +1);
01522            break;
01523 
01524 #ifdef NSS_ENABLE_ECC
01525        case ecKey:
01526            secu_PrintECPublicKey(out, pk, "EC Public Key", level +1);
01527            break;
01528 #endif
01529 
01530        case dhKey:
01531        case fortezzaKey:
01532        case keaKey:
01533            SECU_Indent(out, level);
01534            fprintf(out, "unable to format this SPKI algorithm type\n");
01535            goto loser;
01536        default:
01537            SECU_Indent(out, level);
01538            fprintf(out, "unknown SPKI algorithm type\n");
01539            goto loser;
01540        }
01541        PORT_FreeArena(pk->arena, PR_FALSE);
01542     } else {
01543        SECU_PrintErrMsg(out, level, "Error", "Parsing public key");
01544 loser:
01545        if (i->subjectPublicKey.data) {
01546            SECU_PrintAny(out, &i->subjectPublicKey, "Raw", level);
01547        }
01548     }
01549 }
01550 
01551 static SECStatus
01552 secu_PrintX509InvalidDate(FILE *out, SECItem *value, char *msg, int level)
01553 {
01554     SECItem decodedValue;
01555     SECStatus rv;
01556     int64 invalidTime;
01557     char *formattedTime = NULL;
01558 
01559     decodedValue.data = NULL;
01560     rv = SEC_ASN1DecodeItem (NULL, &decodedValue, 
01561                          SEC_ASN1_GET(SEC_GeneralizedTimeTemplate),
01562                          value);
01563     if (rv == SECSuccess) {
01564        rv = DER_GeneralizedTimeToTime(&invalidTime, &decodedValue);
01565        if (rv == SECSuccess) {
01566            formattedTime = CERT_GenTime2FormattedAscii
01567                          (invalidTime, "%a %b %d %H:%M:%S %Y");
01568            SECU_Indent(out, level +1);
01569            fprintf (out, "%s: %s\n", msg, formattedTime);
01570            PORT_Free (formattedTime);
01571        }
01572     }
01573     PORT_Free (decodedValue.data);
01574     return (rv);
01575 }
01576 
01577 static SECStatus
01578 PrintExtKeyUsageExtension  (FILE *out, SECItem *value, char *msg, int level)
01579 {
01580     CERTOidSequence *os;
01581     SECItem **op;
01582 
01583     os = CERT_DecodeOidSequence(value);
01584     if( (CERTOidSequence *)NULL == os ) {
01585        return SECFailure;
01586     }
01587 
01588     for( op = os->oids; *op; op++ ) {
01589        SECU_PrintObjectID(out, *op, msg, level + 1);
01590     }
01591     CERT_DestroyOidSequence(os);
01592     return SECSuccess;
01593 }
01594 
01595 static SECStatus
01596 secu_PrintBasicConstraints(FILE *out, SECItem *value, char *msg, int level) {
01597     CERTBasicConstraints constraints;
01598     SECStatus rv;
01599 
01600     SECU_Indent(out, level);
01601     if (msg) {
01602            fprintf(out,"%s: ",msg);
01603     } 
01604     rv = CERT_DecodeBasicConstraintValue(&constraints,value);
01605     if (rv == SECSuccess && constraints.isCA) {
01606        if (constraints.pathLenConstraint >= 0) {
01607            fprintf(out,"Is a CA with a maximum path length of %d.\n",
01608                      constraints.pathLenConstraint);
01609        } else {
01610            fprintf(out,"Is a CA with no maximum path length.\n");
01611        }
01612     } else  {
01613        fprintf(out,"Is not a CA.\n");
01614     }
01615     return SECSuccess;
01616 }
01617 
01618 static const char * const nsTypeBits[] = {
01619     "SSL Client",
01620     "SSL Server",
01621     "S/MIME",
01622     "Object Signing",
01623     "Reserved",
01624     "SSL CA",
01625     "S/MIME CA",
01626     "ObjectSigning CA" 
01627 };
01628 
01629 /* NSCertType is merely a bit string whose bits are displayed symbolically */
01630 static SECStatus
01631 secu_PrintNSCertType(FILE *out, SECItem *value, char *msg, int level) 
01632 {
01633     int     unused;
01634     int     NS_Type;
01635     int     i;
01636     int     found   = 0;
01637     SECItem my      = *value;
01638 
01639     if ((my.data[0] != SEC_ASN1_BIT_STRING) || 
01640         SECSuccess != SECU_StripTagAndLength(&my)) {
01641        SECU_PrintAny(out, value, "Data", level);
01642        return SECSuccess;
01643     }
01644 
01645     unused = (my.len == 2) ? (my.data[0] & 0x0f) : 0;  
01646     NS_Type = my.data[1] & (0xff << unused);
01647        
01648 
01649     SECU_Indent(out, level);
01650     if (msg) {
01651        fprintf(out,"%s: ",msg);
01652     } else {
01653        fprintf(out,"Netscape Certificate Type: ");
01654     }
01655     for (i=0; i < 8; i++) {
01656        if ( (0x80 >> i) & NS_Type) {
01657            fprintf(out, "%c%s", (found ? ',' : '<'), nsTypeBits[i]);
01658            found = 1;
01659        }
01660     }
01661     fprintf(out, (found ? ">\n" : "none\n"));
01662     return SECSuccess;
01663 }
01664 
01665 static const char * const usageBits[] = {
01666     "Digital Signature",   /* 0x80 */
01667     "Non-Repudiation",     /* 0x40 */
01668     "Key Encipherment",    /* 0x20 */
01669     "Data Encipherment",   /* 0x10 */
01670     "Key Agreement",       /* 0x08 */
01671     "Certificate Signing", /* 0x04 */
01672     "CRL Signing",         /* 0x02 */
01673     "Encipher Only",       /* 0x01 */
01674     "Decipher Only",       /* 0x0080 */ 
01675     NULL
01676 };
01677 
01678 /* X509KeyUsage is merely a bit string whose bits are displayed symbolically */
01679 static void
01680 secu_PrintX509KeyUsage(FILE *out, SECItem *value, char *msg, int level) 
01681 {
01682     int     unused;
01683     int     usage;
01684     int     i;
01685     int     found   = 0;
01686     SECItem my      = *value;
01687 
01688     if ((my.data[0] != SEC_ASN1_BIT_STRING) || 
01689         SECSuccess != SECU_StripTagAndLength(&my)) {
01690        SECU_PrintAny(out, value, "Data", level);
01691        return;
01692     }
01693 
01694     unused = (my.len >= 2) ? (my.data[0] & 0x0f) : 0;  
01695     usage  = (my.len == 2) ? (my.data[1] & (0xff << unused)) << 8
01696                            : (my.data[1] << 8) | 
01697                           (my.data[2] & (0xff << unused));
01698 
01699     SECU_Indent(out, level);
01700     fprintf(out, "Usages: ");
01701     for (i=0; usageBits[i]; i++) {
01702        if ( (0x8000 >> i) & usage) {
01703            if (found)
01704               SECU_Indent(out, level + 2);
01705            fprintf(out, "%s\n", usageBits[i]);
01706            found = 1;
01707        }
01708     }
01709     if (!found) {
01710        fprintf(out, "(none)\n");
01711     }
01712 }
01713 
01714 static void
01715 secu_PrintIPAddress(FILE *out, SECItem *value, char *msg, int level)
01716 {
01717     PRStatus   st;
01718     PRNetAddr  addr;
01719     char       addrBuf[80];
01720 
01721     memset(&addr, 0, sizeof addr);
01722     if (value->len == 4) {
01723        addr.inet.family = PR_AF_INET;
01724        memcpy(&addr.inet.ip, value->data, value->len);
01725     } else if (value->len == 16) {
01726        addr.ipv6.family = PR_AF_INET6;
01727        memcpy(addr.ipv6.ip.pr_s6_addr, value->data, value->len);
01728        if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped)) {
01729            /* convert to IPv4.  */
01730            addr.inet.family = PR_AF_INET;
01731            memcpy(&addr.inet.ip, &addr.ipv6.ip.pr_s6_addr[12], 4);
01732            memset(&addr.inet.pad[0], 0, sizeof addr.inet.pad);
01733        }
01734     } else {
01735        goto loser;
01736     }
01737 
01738     st = PR_NetAddrToString(&addr, addrBuf, sizeof addrBuf);
01739     if (st == PR_SUCCESS) {
01740        SECU_Indent(out, level);
01741        fprintf(out, "%s: %s\n", msg, addrBuf);
01742     } else {
01743 loser:
01744        SECU_PrintAsHex(out, value, msg, level);
01745     }
01746 }
01747 
01748 
01749 static void
01750 secu_PrintGeneralName(FILE *out, CERTGeneralName *gname, char *msg, int level) 
01751 {
01752     char label[40];
01753     if (msg && msg[0]) {
01754        SECU_Indent(out, level++); fprintf(out, "%s: \n", msg);
01755     }
01756     switch (gname->type) {
01757     case certOtherName :
01758        SECU_PrintAny(     out, &gname->name.OthName.name, "Other Name", level);
01759        SECU_PrintObjectID(out, &gname->name.OthName.oid,  "OID",      level+1);
01760        break;
01761     case certDirectoryName :
01762        SECU_PrintName(out, &gname->name.directoryName, "Directory Name", level);
01763        break;
01764     case certRFC822Name :
01765        secu_PrintRawString(   out, &gname->name.other, "RFC822 Name", level);
01766        break;
01767     case certDNSName :
01768        secu_PrintRawString(   out, &gname->name.other, "DNS name", level);
01769        break;
01770     case certURI :
01771        secu_PrintRawString(   out, &gname->name.other, "URI", level);
01772        break;
01773     case certIPAddress :
01774        secu_PrintIPAddress(out, &gname->name.other, "IP Address", level);
01775        break;
01776     case certRegisterID :
01777        SECU_PrintObjectID( out, &gname->name.other, "Registered ID", level);
01778        break;
01779     case certX400Address :
01780        SECU_PrintAny(      out, &gname->name.other, "X400 Address", level);
01781        break;
01782     case certEDIPartyName :
01783        SECU_PrintAny(      out, &gname->name.other, "EDI Party", level);
01784        break;
01785     default:
01786        PR_snprintf(label, sizeof label, "unknown type [%d]", 
01787                                        (int)gname->type - 1);
01788        SECU_PrintAsHex(out, &gname->name.other, label, level);
01789        break;
01790     }
01791 }
01792 
01793 static void
01794 secu_PrintAuthKeyIDExtension(FILE *out, SECItem *value, char *msg, int level) 
01795 {
01796     CERTAuthKeyID *kid  = NULL;
01797     PLArenaPool   *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01798 
01799     if (!pool) {
01800        SECU_PrintError("Error", "Allocating new ArenaPool");
01801        return;
01802     }
01803     kid = CERT_DecodeAuthKeyID(pool, value);
01804     if (!kid) {
01805        SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
01806        SECU_PrintAny(out, value, "Data", level);
01807     } else {
01808        int keyIDPresent  = (kid->keyID.data && kid->keyID.len);
01809        int issuerPresent = kid->authCertIssuer != NULL;
01810        int snPresent = (kid->authCertSerialNumber.data &&
01811                         kid->authCertSerialNumber.len);
01812 
01813         if ((keyIDPresent && !issuerPresent && !snPresent) ||
01814            (!keyIDPresent && issuerPresent && snPresent)) {
01815            /* all is well */
01816        } else {
01817            SECU_Indent(out, level);
01818            fprintf(out, 
01819            "Error: KeyID OR (Issuer AND Serial) must be present, not both.\n");
01820        }
01821        if (keyIDPresent)
01822            SECU_PrintAsHex(out, &kid->keyID, "Key ID", level);
01823        if (issuerPresent)
01824            secu_PrintGeneralName(out, kid->authCertIssuer, "Issuer", level);
01825        if (snPresent)
01826            SECU_PrintInteger(out, &kid->authCertSerialNumber, 
01827                            "Serial Number", level);
01828     }
01829     PORT_FreeArena(pool, PR_FALSE);
01830 }
01831 
01832 
01833 static void
01834 secu_PrintAltNameExtension(FILE *out, SECItem *value, char *msg, int level)
01835 {
01836     CERTGeneralName * nameList;
01837     CERTGeneralName * current;
01838     PLArenaPool     * pool      = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01839 
01840     if (!pool) {
01841        SECU_PrintError("Error", "Allocating new ArenaPool");
01842        return;
01843     }
01844     nameList = current = CERT_DecodeAltNameExtension(pool, value);
01845     if (!current) {
01846        if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) {
01847            /* Decoder found empty sequence, which is invalid. */
01848            PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID);
01849        }
01850        SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
01851        SECU_PrintAny(out, value, "Data", level);
01852     } else {
01853        do {
01854            secu_PrintGeneralName(out, current, msg, level);
01855            current = CERT_GetNextGeneralName(current);
01856        } while (current != nameList);
01857     }
01858     PORT_FreeArena(pool, PR_FALSE);
01859 }
01860 
01861 static void
01862 secu_PrintCRLDistPtsExtension(FILE *out, SECItem *value, char *msg, int level)
01863 {
01864     CERTCrlDistributionPoints * dPoints;
01865     PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01866 
01867     if (!pool) {
01868        SECU_PrintError("Error", "Allocating new ArenaPool");
01869        return;
01870     }
01871     dPoints = CERT_DecodeCRLDistributionPoints(pool, value);
01872     if (dPoints && dPoints->distPoints && dPoints->distPoints[0]) {
01873        CRLDistributionPoint ** pPoints = dPoints->distPoints;
01874        CRLDistributionPoint *  pPoint;
01875        while (NULL != (pPoint = *pPoints++)) {
01876            if (pPoint->distPointType == generalName && 
01877                pPoint->distPoint.fullName != NULL) {
01878               secu_PrintGeneralName(out, pPoint->distPoint.fullName, NULL,
01879                                     level);
01880 #if defined(LATER)
01881            } else if (pPoint->distPointType == relativeDistinguishedName) {
01882               /* print the relative name */
01883 #endif
01884            } else if (pPoint->derDistPoint.data) {
01885               SECU_PrintAny(out, &pPoint->derDistPoint, "Point", level);
01886            }
01887            if (pPoint->reasons.data) {
01888               secu_PrintDecodedBitString(out, &pPoint->reasons, "Reasons", 
01889                                          level);
01890            }
01891            if (pPoint->crlIssuer) {
01892               secu_PrintGeneralName(out, pPoint->crlIssuer, "Issuer", level);
01893            }
01894        }
01895     } else {
01896        SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
01897        SECU_PrintAny(out, value, "Data", level);
01898     }
01899     PORT_FreeArena(pool, PR_FALSE);
01900 }
01901 
01902 
01903 static void
01904 secu_PrintNameConstraintSubtree(FILE *out, CERTNameConstraint *value, 
01905                                 char *msg, int level)
01906 {
01907     CERTNameConstraint *head = value;
01908     SECU_Indent(out, level); fprintf(out, "%s Subtree:\n", msg);
01909     level++;
01910     do {
01911        secu_PrintGeneralName(out, &value->name, NULL, level);
01912        if (value->min.data)
01913            SECU_PrintInteger(out, &value->min, "Minimum", level+1);
01914        if (value->max.data)
01915            SECU_PrintInteger(out, &value->max, "Maximum", level+1);
01916        value = CERT_GetNextNameConstraint(value);
01917     } while (value != head);
01918 }
01919 
01920 static void
01921 secu_PrintNameConstraintsExtension(FILE *out, SECItem *value, char *msg, int level)
01922 {
01923     CERTNameConstraints * cnstrnts;
01924     PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01925 
01926     if (!pool) {
01927        SECU_PrintError("Error", "Allocating new ArenaPool");
01928        return;
01929     }
01930     cnstrnts = CERT_DecodeNameConstraintsExtension(pool, value);
01931     if (!cnstrnts) {
01932        SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
01933        SECU_PrintAny(out, value, "Raw", level);
01934     } else {
01935        if (cnstrnts->permited)
01936            secu_PrintNameConstraintSubtree(out, cnstrnts->permited, 
01937                                            "Permitted", level);
01938        if (cnstrnts->excluded)
01939            secu_PrintNameConstraintSubtree(out, cnstrnts->excluded, 
01940                                            "Excluded", level);
01941     }
01942     PORT_FreeArena(pool, PR_FALSE);
01943 }
01944 
01945 
01946 static void
01947 secu_PrintAuthorityInfoAcess(FILE *out, SECItem *value, char *msg, int level)
01948 {
01949     CERTAuthInfoAccess **infos = NULL;
01950     PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01951 
01952     if (!pool) {
01953        SECU_PrintError("Error", "Allocating new ArenaPool");
01954        return;
01955     }
01956     infos = CERT_DecodeAuthInfoAccessExtension(pool, value);
01957     if (!infos) {
01958        SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
01959        SECU_PrintAny(out, value, "Raw", level);
01960     } else {
01961        CERTAuthInfoAccess *info;
01962        while (NULL != (info = *infos++)) {
01963            if (info->method.data) {
01964               SECU_PrintObjectID(out, &info->method, "Method", level);
01965            } else {
01966               SECU_Indent(out,level);
01967               fprintf(out, "Error: missing method\n");
01968            }
01969            if (info->location) {
01970               secu_PrintGeneralName(out, info->location, "Location", level);
01971            } else {
01972               SECU_PrintAny(out, &info->derLocation, "Location", level);
01973            }
01974        }
01975     }
01976     PORT_FreeArena(pool, PR_FALSE);
01977 }
01978 
01979 
01980 void
01981 SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions,
01982                    char *msg, int level)
01983 {
01984     SECOidTag oidTag;
01985     
01986     if ( extensions ) {
01987        if (msg && *msg) {
01988            SECU_Indent(out, level++); fprintf(out, "%s:\n", msg);
01989        }
01990        
01991        while ( *extensions ) {
01992            SECItem *tmpitem;
01993 
01994            tmpitem = &(*extensions)->id;
01995            SECU_PrintObjectID(out, tmpitem, "Name", level);
01996 
01997            tmpitem = &(*extensions)->critical;
01998            if ( tmpitem->len ) {
01999               secu_PrintBoolean(out, tmpitem, "Critical", level);
02000            }
02001 
02002            oidTag = SECOID_FindOIDTag (&((*extensions)->id));
02003            tmpitem = &((*extensions)->value);
02004 
02005            switch (oidTag) {
02006               case SEC_OID_X509_INVALID_DATE:
02007               case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME:
02008                  secu_PrintX509InvalidDate(out, tmpitem, "Date", level );
02009                  break;
02010               case SEC_OID_X509_CERTIFICATE_POLICIES:
02011                  SECU_PrintPolicy(out, tmpitem, "Data", level );
02012                  break;
02013               case SEC_OID_NS_CERT_EXT_BASE_URL:
02014               case SEC_OID_NS_CERT_EXT_REVOCATION_URL:
02015               case SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL:
02016               case SEC_OID_NS_CERT_EXT_CA_CRL_URL:
02017               case SEC_OID_NS_CERT_EXT_CA_CERT_URL:
02018               case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL:
02019               case SEC_OID_NS_CERT_EXT_CA_POLICY_URL:
02020               case SEC_OID_NS_CERT_EXT_HOMEPAGE_URL:
02021               case SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL:
02022               case SEC_OID_OCSP_RESPONDER:
02023                   SECU_PrintString(out,tmpitem, "URL", level);
02024                   break;
02025               case SEC_OID_NS_CERT_EXT_COMMENT:
02026                   SECU_PrintString(out,tmpitem, "Comment", level);
02027                   break;
02028               case SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME:
02029                   SECU_PrintString(out,tmpitem, "ServerName", level);
02030                   break;
02031               case SEC_OID_NS_CERT_EXT_CERT_TYPE:
02032                   secu_PrintNSCertType(out,tmpitem,"Data",level);
02033                   break;
02034               case SEC_OID_X509_BASIC_CONSTRAINTS:
02035                   secu_PrintBasicConstraints(out,tmpitem,"Data",level);
02036                   break;
02037               case SEC_OID_X509_EXT_KEY_USAGE:
02038                   PrintExtKeyUsageExtension(out, tmpitem, NULL, level);
02039                   break;
02040               case SEC_OID_X509_KEY_USAGE:
02041                   secu_PrintX509KeyUsage(out, tmpitem, NULL, level );
02042                   break;
02043               case SEC_OID_X509_AUTH_KEY_ID:
02044                   secu_PrintAuthKeyIDExtension(out, tmpitem, NULL, level );
02045                   break;
02046               case SEC_OID_X509_SUBJECT_ALT_NAME:
02047               case SEC_OID_X509_ISSUER_ALT_NAME:
02048                   secu_PrintAltNameExtension(out, tmpitem, NULL, level );
02049                   break;
02050               case SEC_OID_X509_CRL_DIST_POINTS:
02051                   secu_PrintCRLDistPtsExtension(out, tmpitem, NULL, level );
02052                   break;
02053               case SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD:
02054                   SECU_PrintPrivKeyUsagePeriodExtension(out, tmpitem, NULL, 
02055                                                  level );
02056                   break;
02057               case SEC_OID_X509_NAME_CONSTRAINTS:
02058                   secu_PrintNameConstraintsExtension(out, tmpitem, NULL, level);
02059                   break;
02060               case SEC_OID_X509_AUTH_INFO_ACCESS:
02061                   secu_PrintAuthorityInfoAcess(out, tmpitem, NULL, level);
02062                   break;
02063 
02064               case SEC_OID_X509_CRL_NUMBER:
02065               case SEC_OID_X509_REASON_CODE:
02066 
02067               /* PKIX OIDs */
02068               case SEC_OID_PKIX_OCSP:
02069               case SEC_OID_PKIX_OCSP_BASIC_RESPONSE:
02070               case SEC_OID_PKIX_OCSP_NONCE:
02071               case SEC_OID_PKIX_OCSP_CRL:
02072               case SEC_OID_PKIX_OCSP_RESPONSE:
02073               case SEC_OID_PKIX_OCSP_NO_CHECK:
02074               case SEC_OID_PKIX_OCSP_ARCHIVE_CUTOFF:
02075               case SEC_OID_PKIX_OCSP_SERVICE_LOCATOR:
02076               case SEC_OID_PKIX_REGCTRL_REGTOKEN:
02077               case SEC_OID_PKIX_REGCTRL_AUTHENTICATOR:
02078               case SEC_OID_PKIX_REGCTRL_PKIPUBINFO:
02079               case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS:
02080               case SEC_OID_PKIX_REGCTRL_OLD_CERT_ID:
02081               case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY:
02082               case SEC_OID_PKIX_REGINFO_UTF8_PAIRS:
02083               case SEC_OID_PKIX_REGINFO_CERT_REQUEST:
02084 
02085                /* Netscape extension OIDs. */
02086               case SEC_OID_NS_CERT_EXT_NETSCAPE_OK:
02087               case SEC_OID_NS_CERT_EXT_ISSUER_LOGO:
02088               case SEC_OID_NS_CERT_EXT_SUBJECT_LOGO:
02089               case SEC_OID_NS_CERT_EXT_ENTITY_LOGO:
02090               case SEC_OID_NS_CERT_EXT_USER_PICTURE:
02091 
02092               /* x.509 v3 Extensions */
02093               case SEC_OID_X509_SUBJECT_DIRECTORY_ATTR:
02094               case SEC_OID_X509_SUBJECT_KEY_ID:
02095               case SEC_OID_X509_POLICY_MAPPINGS:
02096               case SEC_OID_X509_POLICY_CONSTRAINTS:
02097 
02098 
02099                default:
02100                   SECU_PrintAny(out, tmpitem, "Data", level);
02101               break;
02102            }
02103 
02104            secu_Newline(out);
02105            extensions++;
02106        }
02107     }
02108 }
02109 
02110 
02111 void
02112 SECU_PrintName(FILE *out, CERTName *name, char *msg, int level)
02113 {
02114     char *nameStr;
02115     char *str;
02116     SECItem my;
02117 
02118     str = nameStr = CERT_NameToAscii(name);
02119     if (!str) {
02120        str = "!Invalid AVA!";
02121     }
02122     my.data = (unsigned char *)str;
02123     my.len  = PORT_Strlen(str);
02124 #if 1
02125     secu_PrintRawString(out, &my, msg, level);
02126 #else
02127     SECU_Indent(out, level); fprintf(out, "%s: ", msg);
02128     fprintf(out, str);
02129     secu_Newline(out);
02130 #endif
02131     PORT_Free(nameStr);
02132 }
02133 
02134 void
02135 printflags(char *trusts, unsigned int flags)
02136 {
02137     if (flags & CERTDB_VALID_CA)
02138        if (!(flags & CERTDB_TRUSTED_CA) &&
02139            !(flags & CERTDB_TRUSTED_CLIENT_CA))
02140            PORT_Strcat(trusts, "c");
02141     if (flags & CERTDB_VALID_PEER)
02142        if (!(flags & CERTDB_TRUSTED))
02143            PORT_Strcat(trusts, "p");
02144     if (flags & CERTDB_TRUSTED_CA)
02145        PORT_Strcat(trusts, "C");
02146     if (flags & CERTDB_TRUSTED_CLIENT_CA)
02147        PORT_Strcat(trusts, "T");
02148     if (flags & CERTDB_TRUSTED)
02149        PORT_Strcat(trusts, "P");
02150     if (flags & CERTDB_USER)
02151        PORT_Strcat(trusts, "u");
02152     if (flags & CERTDB_SEND_WARN)
02153        PORT_Strcat(trusts, "w");
02154     if (flags & CERTDB_INVISIBLE_CA)
02155        PORT_Strcat(trusts, "I");
02156     if (flags & CERTDB_GOVT_APPROVED_CA)
02157        PORT_Strcat(trusts, "G");
02158     return;
02159 }
02160 
02161 /* callback for listing certs through pkcs11 */
02162 SECStatus
02163 SECU_PrintCertNickname(CERTCertListNode *node, void *data)
02164 {
02165     CERTCertTrust *trust;
02166     CERTCertificate* cert;
02167     FILE *out;
02168     char trusts[30];
02169     char *name;
02170 
02171     cert = node->cert;
02172 
02173     PORT_Memset (trusts, 0, sizeof (trusts));
02174     out = (FILE *)data;
02175     
02176     name = node->appData;
02177     if (!name || !name[0]) {
02178         name = cert->nickname;
02179     }
02180     if (!name || !name[0]) {
02181         name = cert->emailAddr;
02182     }
02183     if (!name || !name[0]) {
02184         name = "(NULL)";
02185     }
02186 
02187     trust = cert->trust;
02188     if (trust) {
02189         printflags(trusts, trust->sslFlags);
02190         PORT_Strcat(trusts, ",");
02191         printflags(trusts, trust->emailFlags);
02192         PORT_Strcat(trusts, ",");
02193         printflags(trusts, trust->objectSigningFlags);
02194     } else {
02195         PORT_Memcpy(trusts,",,",3);
02196     }
02197     fprintf(out, "%-60s %-5s\n", name, trusts);
02198 
02199     return (SECSuccess);
02200 }
02201 
02202 int
02203 SECU_DecodeAndPrintExtensions(FILE *out, SECItem *any, char *m, int level)
02204 {
02205     CERTCertExtension **extensions = NULL;
02206     PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02207     int rv = 0;
02208 
02209     if (!arena) 
02210        return SEC_ERROR_NO_MEMORY;
02211 
02212     rv = SEC_QuickDERDecodeItem(arena, &extensions, 
02213                  SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate), any);
02214     if (!rv)
02215        SECU_PrintExtensions(out, extensions, m, level);
02216     else 
02217        SECU_PrintAny(out, any, m, level);
02218     PORT_FreeArena(arena, PR_FALSE);
02219     return rv;
02220 }
02221 
02222 /* print a decoded SET OF or SEQUENCE OF Extensions */
02223 int
02224 SECU_PrintSetOfExtensions(FILE *out, SECItem **any, char *m, int level)
02225 {
02226     int rv = 0;
02227     if (m && *m) {
02228        SECU_Indent(out, level++); fprintf(out, "%s:\n", m);
02229     }
02230     while (any && any[0]) {
02231        rv |= SECU_DecodeAndPrintExtensions(out, any[0], "", level);
02232        any++;
02233     }
02234     return rv;
02235 }
02236 
02237 /* print a decoded SET OF or SEQUENCE OF "ANY" */
02238 int
02239 SECU_PrintSetOfAny(FILE *out, SECItem **any, char *m, int level)
02240 {
02241     int rv = 0;
02242     if (m && *m) {
02243        SECU_Indent(out, level++); fprintf(out, "%s:\n", m);
02244     }
02245     while (any && any[0]) {
02246        SECU_PrintAny(out, any[0], "", level);
02247        any++;
02248     }
02249     return rv;
02250 }
02251 
02252 int
02253 SECU_PrintCertAttribute(FILE *out, CERTAttribute *attr, char *m, int level)
02254 {
02255     int rv = 0;
02256     SECOidTag tag;
02257     tag = SECU_PrintObjectID(out, &attr->attrType, "Attribute Type", level);
02258     if (tag == SEC_OID_PKCS9_EXTENSION_REQUEST) {
02259        rv = SECU_PrintSetOfExtensions(out, attr->attrValue, "Extensions", level);
02260     } else {
02261        rv = SECU_PrintSetOfAny(out, attr->attrValue, "Attribute Values", level);
02262     }
02263     return rv;
02264 }
02265 
02266 int
02267 SECU_PrintCertAttributes(FILE *out, CERTAttribute **attrs, char *m, int level)
02268 {
02269     int rv = 0;
02270     while (attrs[0]) {
02271        rv |= SECU_PrintCertAttribute(out, attrs[0], m, level+1);
02272        attrs++;
02273     }
02274     return rv;
02275 }
02276 
02277 int  /* sometimes a PRErrorCode, other times a SECStatus.  Sigh. */
02278 SECU_PrintCertificateRequest(FILE *out, SECItem *der, char *m, int level)
02279 {
02280     PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02281     CERTCertificateRequest *cr;
02282     int rv = SEC_ERROR_NO_MEMORY;
02283 
02284     if (!arena) 
02285        return rv;
02286 
02287     /* Decode certificate request */
02288     cr = PORT_ArenaZNew(arena, CERTCertificateRequest);
02289     if (!cr)
02290        goto loser;
02291     cr->arena = arena;
02292     rv = SEC_QuickDERDecodeItem(arena, cr, 
02293                            SEC_ASN1_GET(CERT_CertificateRequestTemplate), der);
02294     if (rv) 
02295        goto loser;
02296 
02297     /* Pretty print it out */
02298     SECU_Indent(out, level); fprintf(out, "%s:\n", m);
02299     SECU_PrintInteger(out, &cr->version, "Version", level+1);
02300     SECU_PrintName(out, &cr->subject, "Subject", level+1);
02301     secu_PrintSubjectPublicKeyInfo(out, arena, &cr->subjectPublicKeyInfo,
02302                            "Subject Public Key Info", level+1);
02303     if (cr->attributes)
02304        SECU_PrintCertAttributes(out, cr->attributes, "Attributes", level+1);
02305     rv = 0;
02306 loser:
02307     PORT_FreeArena(arena, PR_FALSE);
02308     return rv;
02309 }
02310 
02311 int
02312 SECU_PrintCertificate(FILE *out, SECItem *der, char *m, int level)
02313 {
02314     PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02315     CERTCertificate *c;
02316     int rv = SEC_ERROR_NO_MEMORY;
02317     int iv;
02318     
02319     if (!arena)
02320        return rv;
02321 
02322     /* Decode certificate */
02323     c = PORT_ArenaZNew(arena, CERTCertificate);
02324     if (!c)
02325        goto loser;
02326     c->arena = arena;
02327     rv = SEC_ASN1DecodeItem(arena, c, 
02328                             SEC_ASN1_GET(CERT_CertificateTemplate), der);
02329     if (rv) {
02330         SECU_Indent(out, level); 
02331        SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
02332        SECU_PrintAny(out, der, "Raw", level);
02333        goto loser;
02334     }
02335     /* Pretty print it out */
02336     SECU_Indent(out, level); fprintf(out, "%s:\n", m);
02337     iv = c->version.len ? DER_GetInteger(&c->version) : 0;  /* version is optional */
02338     SECU_Indent(out, level+1); fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv);
02339 
02340     SECU_PrintInteger(out, &c->serialNumber, "Serial Number", level+1);
02341     SECU_PrintAlgorithmID(out, &c->signature, "Signature Algorithm", level+1);
02342     SECU_PrintName(out, &c->issuer, "Issuer", level+1);
02343     secu_PrintValidity(out, &c->validity, "Validity", level+1);
02344     SECU_PrintName(out, &c->subject, "Subject", level+1);
02345     secu_PrintSubjectPublicKeyInfo(out, arena, &c->subjectPublicKeyInfo,
02346                            "Subject Public Key Info", level+1);
02347     if (c->issuerID.data) 
02348        secu_PrintDecodedBitString(out, &c->issuerID, "Issuer Unique ID", level+1);
02349     if (c->subjectID.data) 
02350        secu_PrintDecodedBitString(out, &c->subjectID, "Subject Unique ID", level+1);
02351     SECU_PrintExtensions(out, c->extensions, "Signed Extensions", level+1);
02352 loser:
02353     PORT_FreeArena(arena, PR_FALSE);
02354     return rv;
02355 }
02356 
02357 int
02358 SECU_PrintPublicKey(FILE *out, SECItem *der, char *m, int level)
02359 {
02360     PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02361     SECKEYPublicKey key;
02362     int rv = SEC_ERROR_NO_MEMORY;
02363 
02364     if (!arena)
02365        return rv;
02366 
02367     PORT_Memset(&key, 0, sizeof(key));
02368     rv = SEC_ASN1DecodeItem(arena, &key, 
02369                             SEC_ASN1_GET(SECKEY_RSAPublicKeyTemplate), der);
02370     if (!rv) {
02371        /* Pretty print it out */
02372        secu_PrintRSAPublicKey(out, &key, m, level);
02373     }
02374 
02375     PORT_FreeArena(arena, PR_FALSE);
02376     return rv;
02377 }
02378 
02379 #ifdef HAVE_EPV_TEMPLATE
02380 int
02381 SECU_PrintPrivateKey(FILE *out, SECItem *der, char *m, int level)
02382 {
02383     PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02384     SECKEYEncryptedPrivateKeyInfo key;
02385     int rv = SEC_ERROR_NO_MEMORY;
02386 
02387     if (!arena)
02388        return rv;
02389 
02390     PORT_Memset(&key, 0, sizeof(key));
02391     rv = SEC_ASN1DecodeItem(arena, &key, 
02392               SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate), der);
02393     if (rv)
02394        goto loser;
02395 
02396     /* Pretty print it out */
02397     SECU_Indent(out, level); fprintf(out, "%s:\n", m);
02398     SECU_PrintAlgorithmID(out, &key.algorithm, "Encryption Algorithm", 
02399                        level+1);
02400     SECU_PrintAsHex(out, &key.encryptedData, "Encrypted Data", level+1);
02401 loser:
02402     PORT_FreeArena(arena, PR_TRUE);
02403     return rv;
02404 }
02405 #endif
02406 
02407 int
02408 SECU_PrintFingerprints(FILE *out, SECItem *derCert, char *m, int level)
02409 {
02410     unsigned char fingerprint[20];
02411     char *fpStr = NULL;
02412     int err     = PORT_GetError();
02413     SECStatus rv;
02414     SECItem fpItem;
02415 
02416     /* print MD5 fingerprint */
02417     memset(fingerprint, 0, sizeof fingerprint);
02418     rv = PK11_HashBuf(SEC_OID_MD5,fingerprint, derCert->data, derCert->len);
02419     fpItem.data = fingerprint;
02420     fpItem.len = MD5_LENGTH;
02421     fpStr = CERT_Hexify(&fpItem, 1);
02422     SECU_Indent(out, level);  fprintf(out, "%s (MD5):\n", m);
02423     SECU_Indent(out, level+1); fprintf(out, "%s\n", fpStr);
02424     PORT_Free(fpStr);
02425     fpStr = NULL;
02426     if (rv != SECSuccess && !err)
02427        err = PORT_GetError();
02428 
02429     /* print SHA1 fingerprint */
02430     memset(fingerprint, 0, sizeof fingerprint);
02431     rv = PK11_HashBuf(SEC_OID_SHA1,fingerprint, derCert->data, derCert->len);
02432     fpItem.data = fingerprint;
02433     fpItem.len = SHA1_LENGTH;
02434     fpStr = CERT_Hexify(&fpItem, 1);
02435     SECU_Indent(out, level);  fprintf(out, "%s (SHA1):\n", m);
02436     SECU_Indent(out, level+1); fprintf(out, "%s\n", fpStr);
02437     PORT_Free(fpStr);
02438     fprintf(out, "\n");
02439 
02440     if (err) 
02441        PORT_SetError(err);
02442     if (err || rv != SECSuccess)
02443        return SECFailure;
02444 
02445     return 0;
02446 }
02447 
02448 /*
02449 ** PKCS7 Support
02450 */
02451 
02452 /* forward declaration */
02453 static int
02454 secu_PrintPKCS7ContentInfo(FILE *, SEC_PKCS7ContentInfo *, char *, int);
02455 
02456 /*
02457 ** secu_PrintPKCS7EncContent
02458 **   Prints a SEC_PKCS7EncryptedContentInfo (without decrypting it)
02459 */
02460 static void
02461 secu_PrintPKCS7EncContent(FILE *out, SEC_PKCS7EncryptedContentInfo *src, 
02462                        char *m, int level)
02463 {
02464     if (src->contentTypeTag == NULL)
02465        src->contentTypeTag = SECOID_FindOID(&(src->contentType));
02466 
02467     SECU_Indent(out, level);
02468     fprintf(out, "%s:\n", m);
02469     SECU_Indent(out, level + 1); 
02470     fprintf(out, "Content Type: %s\n",
02471            (src->contentTypeTag != NULL) ? src->contentTypeTag->desc
02472                                      : "Unknown");
02473     SECU_PrintAlgorithmID(out, &(src->contentEncAlg),
02474                        "Content Encryption Algorithm", level+1);
02475     SECU_PrintAsHex(out, &(src->encContent), 
02476                   "Encrypted Content", level+1);
02477 }
02478 
02479 /*
02480 ** secu_PrintRecipientInfo
02481 **   Prints a PKCS7RecipientInfo type
02482 */
02483 static void
02484 secu_PrintRecipientInfo(FILE *out, SEC_PKCS7RecipientInfo *info, char *m, 
02485                      int level)
02486 {
02487     SECU_Indent(out, level); fprintf(out, "%s:\n", m);
02488     SECU_PrintInteger(out, &(info->version), "Version", level + 1);   
02489 
02490     SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer", 
02491                level + 1);
02492     SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber), 
02493                     "Serial Number", level + 1);
02494 
02495     /* Parse and display encrypted key */
02496     SECU_PrintAlgorithmID(out, &(info->keyEncAlg), 
02497                      "Key Encryption Algorithm", level + 1);
02498     SECU_PrintAsHex(out, &(info->encKey), "Encrypted Key", level + 1);
02499 }
02500 
02501 /* 
02502 ** secu_PrintSignerInfo
02503 **   Prints a PKCS7SingerInfo type
02504 */
02505 static void
02506 secu_PrintSignerInfo(FILE *out, SEC_PKCS7SignerInfo *info, char *m, int level)
02507 {
02508     SEC_PKCS7Attribute *attr;
02509     int iv;
02510     char om[100];
02511     
02512     SECU_Indent(out, level); fprintf(out, "%s:\n", m);
02513     SECU_PrintInteger(out, &(info->version), "Version", level + 1);   
02514 
02515     SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer", 
02516                level + 1);
02517     SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber), 
02518                     "Serial Number", level + 1);
02519   
02520     SECU_PrintAlgorithmID(out, &(info->digestAlg), "Digest Algorithm",
02521                        level + 1);
02522     
02523     if (info->authAttr != NULL) {
02524        SECU_Indent(out, level + 1); 
02525        fprintf(out, "Authenticated Attributes:\n");
02526        iv = 0;
02527        while ((attr = info->authAttr[iv++]) != NULL) {
02528            sprintf(om, "Attribute (%d)", iv); 
02529            secu_PrintAttribute(out, attr, om, level + 2);
02530        }
02531     }
02532     
02533     /* Parse and display signature */
02534     SECU_PrintAlgorithmID(out, &(info->digestEncAlg), 
02535                      "Digest Encryption Algorithm", level + 1);
02536     SECU_PrintAsHex(out, &(info->encDigest), "Encrypted Digest", level + 1);
02537     
02538     if (info->unAuthAttr != NULL) {
02539        SECU_Indent(out, level + 1); 
02540        fprintf(out, "Unauthenticated Attributes:\n");
02541        iv = 0;
02542        while ((attr = info->unAuthAttr[iv++]) != NULL) {
02543            sprintf(om, "Attribute (%x)", iv); 
02544            secu_PrintAttribute(out, attr, om, level + 2);
02545        }
02546     }
02547 }
02548 
02549 /* callers of this function must make sure that the CERTSignedCrl
02550    from which they are extracting the CERTCrl has been fully-decoded.
02551    Otherwise it will not have the entries even though the CRL may have
02552    some */
02553 
02554 void
02555 SECU_PrintCRLInfo(FILE *out, CERTCrl *crl, char *m, int level)
02556 {
02557     CERTCrlEntry *entry;
02558     int iv;
02559     char om[100];
02560     
02561     SECU_Indent(out, level); fprintf(out, "%s:\n", m);
02562     /* version is optional */
02563     iv = crl->version.len ? DER_GetInteger(&crl->version) : 0;  
02564     SECU_Indent(out, level+1); 
02565        fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv);
02566     SECU_PrintAlgorithmID(out, &(crl->signatureAlg), "Signature Algorithm",
02567                        level + 1);
02568     SECU_PrintName(out, &(crl->name), "Issuer", level + 1);
02569     SECU_PrintTimeChoice(out, &(crl->lastUpdate), "This Update", level + 1);
02570     if (crl->nextUpdate.data && crl->nextUpdate.len) /* is optional */
02571        SECU_PrintTimeChoice(out, &(crl->nextUpdate), "Next Update", level + 1);
02572     
02573     if (crl->entries != NULL) {
02574        iv = 0;
02575        while ((entry = crl->entries[iv++]) != NULL) {
02576            sprintf(om, "Entry (%x):\n", iv); 
02577            SECU_Indent(out, level + 1); fprintf(out, om);
02578            SECU_PrintInteger(out, &(entry->serialNumber), "Serial Number",
02579                            level + 2);
02580            SECU_PrintTimeChoice(out, &(entry->revocationDate), 
02581                                 "Revocation Date", level + 2);
02582            SECU_PrintExtensions(out, entry->extensions, 
02583                                 "Entry Extensions", level + 2);
02584        }
02585     }
02586     SECU_PrintExtensions(out, crl->extensions, "CRL Extensions", level + 1);
02587 }
02588 
02589 /*
02590 ** secu_PrintPKCS7Signed
02591 **   Pretty print a PKCS7 signed data type (up to version 1).
02592 */
02593 static int
02594 secu_PrintPKCS7Signed(FILE *out, SEC_PKCS7SignedData *src,
02595                     const char *m, int level)
02596 {
02597     SECAlgorithmID *digAlg;        /* digest algorithms */
02598     SECItem *aCert;                /* certificate */
02599     CERTSignedCrl *aCrl;           /* certificate revocation list */
02600     SEC_PKCS7SignerInfo *sigInfo;  /* signer information */
02601     int rv, iv;
02602     char om[100];
02603 
02604     SECU_Indent(out, level); fprintf(out, "%s:\n", m);
02605     SECU_PrintInteger(out, &(src->version), "Version", level + 1);
02606 
02607     /* Parse and list digest algorithms (if any) */
02608     if (src->digestAlgorithms != NULL) {
02609        SECU_Indent(out, level + 1);  fprintf(out, "Digest Algorithm List:\n");
02610        iv = 0;
02611        while ((digAlg = src->digestAlgorithms[iv++]) != NULL) {
02612            sprintf(om, "Digest Algorithm (%x)", iv);
02613            SECU_PrintAlgorithmID(out, digAlg, om, level + 2);
02614        }
02615     }
02616 
02617     /* Now for the content */
02618     rv = secu_PrintPKCS7ContentInfo(out, &(src->contentInfo), 
02619                                 "Content Information", level + 1);
02620     if (rv != 0)
02621        return rv;
02622 
02623     /* Parse and list certificates (if any) */
02624     if (src->rawCerts != NULL) {
02625        SECU_Indent(out, level + 1);  fprintf(out, "Certificate List:\n");
02626        iv = 0;
02627        while ((aCert = src->rawCerts[iv++]) != NULL) {
02628            sprintf(om, "Certificate (%x)", iv);
02629            rv = SECU_PrintSignedData(out, aCert, om, level + 2, 
02630                                   SECU_PrintCertificate);
02631            if (rv)
02632               return rv;
02633        }
02634     }
02635 
02636     /* Parse and list CRL's (if any) */
02637     if (src->crls != NULL) {
02638        SECU_Indent(out, level + 1);  
02639        fprintf(out, "Signed Revocation Lists:\n");
02640        iv = 0;
02641        while ((aCrl = src->crls[iv++]) != NULL) {
02642            sprintf(om, "Signed Revocation List (%x)", iv);
02643            SECU_Indent(out, level + 2);  fprintf(out, "%s:\n", om);
02644            SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm, 
02645                               "Signature Algorithm", level+3);
02646            DER_ConvertBitString(&aCrl->signatureWrap.signature);
02647            SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature",
02648                          level+3);
02649            SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List", 
02650                        level + 3); 
02651        }
02652     }
02653 
02654     /* Parse and list signatures (if any) */
02655     if (src->signerInfos != NULL) {
02656        SECU_Indent(out, level + 1);
02657        fprintf(out, "Signer Information List:\n");
02658        iv = 0;
02659        while ((sigInfo = src->signerInfos[iv++]) != NULL) {
02660            sprintf(om, "Signer Information (%x)", iv);
02661            secu_PrintSignerInfo(out, sigInfo, om, level + 2);
02662        }
02663     }  
02664 
02665     return 0;
02666 }
02667 
02668 /*
02669 ** secu_PrintPKCS7Enveloped
02670 **  Pretty print a PKCS7 enveloped data type (up to version 1).
02671 */
02672 static void
02673 secu_PrintPKCS7Enveloped(FILE *out, SEC_PKCS7EnvelopedData *src,
02674                       const char *m, int level)
02675 {
02676     SEC_PKCS7RecipientInfo *recInfo;   /* pointer for signer information */
02677     int iv;
02678     char om[100];
02679 
02680     SECU_Indent(out, level); fprintf(out, "%s:\n", m);
02681     SECU_PrintInteger(out, &(src->version), "Version", level + 1);
02682 
02683     /* Parse and list recipients (this is not optional) */
02684     if (src->recipientInfos != NULL) {
02685        SECU_Indent(out, level + 1);
02686        fprintf(out, "Recipient Information List:\n");
02687        iv = 0;
02688        while ((recInfo = src->recipientInfos[iv++]) != NULL) {
02689            sprintf(om, "Recipient Information (%x)", iv);
02690            secu_PrintRecipientInfo(out, recInfo, om, level + 2);
02691        }
02692     }  
02693 
02694     secu_PrintPKCS7EncContent(out, &src->encContentInfo, 
02695                            "Encrypted Content Information", level + 1);
02696 }
02697 
02698 /*
02699 ** secu_PrintPKCS7SignedEnveloped
02700 **   Pretty print a PKCS7 singed and enveloped data type (up to version 1).
02701 */
02702 static int
02703 secu_PrintPKCS7SignedAndEnveloped(FILE *out,
02704                               SEC_PKCS7SignedAndEnvelopedData *src,
02705                               const char *m, int level)
02706 {
02707     SECAlgorithmID *digAlg;  /* pointer for digest algorithms */
02708     SECItem *aCert;           /* pointer for certificate */
02709     CERTSignedCrl *aCrl;        /* pointer for certificate revocation list */
02710     SEC_PKCS7SignerInfo *sigInfo;   /* pointer for signer information */
02711     SEC_PKCS7RecipientInfo *recInfo; /* pointer for recipient information */
02712     int rv, iv;
02713     char om[100];
02714 
02715     SECU_Indent(out, level); fprintf(out, "%s:\n", m);
02716     SECU_PrintInteger(out, &(src->version), "Version", level + 1);
02717 
02718     /* Parse and list recipients (this is not optional) */
02719     if (src->recipientInfos != NULL) {
02720        SECU_Indent(out, level + 1);
02721        fprintf(out, "Recipient Information List:\n");
02722        iv = 0;
02723        while ((recInfo = src->recipientInfos[iv++]) != NULL) {
02724            sprintf(om, "Recipient Information (%x)", iv);
02725            secu_PrintRecipientInfo(out, recInfo, om, level + 2);
02726        }
02727     }  
02728 
02729     /* Parse and list digest algorithms (if any) */
02730     if (src->digestAlgorithms != NULL) {
02731        SECU_Indent(out, level + 1);  fprintf(out, "Digest Algorithm List:\n");
02732        iv = 0;
02733        while ((digAlg = src->digestAlgorithms[iv++]) != NULL) {
02734            sprintf(om, "Digest Algorithm (%x)", iv);
02735            SECU_PrintAlgorithmID(out, digAlg, om, level + 2);
02736        }
02737     }
02738 
02739     secu_PrintPKCS7EncContent(out, &src->encContentInfo, 
02740                            "Encrypted Content Information", level + 1);
02741 
02742     /* Parse and list certificates (if any) */
02743     if (src->rawCerts != NULL) {
02744        SECU_Indent(out, level + 1);  fprintf(out, "Certificate List:\n");
02745        iv = 0;
02746        while ((aCert = src->rawCerts[iv++]) != NULL) {
02747            sprintf(om, "Certificate (%x)", iv);
02748            rv = SECU_PrintSignedData(out, aCert, om, level + 2, 
02749                                   SECU_PrintCertificate);
02750            if (rv)
02751               return rv;
02752        }
02753     }
02754 
02755     /* Parse and list CRL's (if any) */
02756     if (src->crls != NULL) {
02757        SECU_Indent(out, level + 1);  
02758        fprintf(out, "Signed Revocation Lists:\n");
02759        iv = 0;
02760        while ((aCrl = src->crls[iv++]) != NULL) {
02761            sprintf(om, "Signed Revocation List (%x)", iv);
02762            SECU_Indent(out, level + 2);  fprintf(out, "%s:\n", om);
02763            SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm, 
02764                               "Signature Algorithm", level+3);
02765            DER_ConvertBitString(&aCrl->signatureWrap.signature);
02766            SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature",
02767                          level+3);
02768            SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List", 
02769                        level + 3); 
02770        }
02771     }
02772 
02773     /* Parse and list signatures (if any) */
02774     if (src->signerInfos != NULL) {
02775        SECU_Indent(out, level + 1);
02776        fprintf(out, "Signer Information List:\n");
02777        iv = 0;
02778        while ((sigInfo = src->signerInfos[iv++]) != NULL) {
02779            sprintf(om, "Signer Information (%x)", iv);
02780            secu_PrintSignerInfo(out, sigInfo, om, level + 2);
02781        }
02782     }  
02783 
02784     return 0;
02785 }
02786 
02787 int
02788 SECU_PrintCrl (FILE *out, SECItem *der, char *m, int level)
02789 {
02790     PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02791     CERTCrl *c = NULL;
02792     int rv = SEC_ERROR_NO_MEMORY;
02793 
02794     if (!arena)
02795        return rv;
02796     do {
02797        /* Decode CRL */
02798        c = PORT_ArenaZNew(arena, CERTCrl);
02799        if (!c)
02800            break;
02801 
02802        rv = SEC_QuickDERDecodeItem(arena, c, SEC_ASN1_GET(CERT_CrlTemplate), der);
02803        if (rv != SECSuccess)
02804            break;
02805        SECU_PrintCRLInfo (out, c, m, level);
02806     } while (0);
02807     PORT_FreeArena (arena, PR_FALSE);
02808     return rv;
02809 }
02810 
02811 
02812 /*
02813 ** secu_PrintPKCS7Encrypted
02814 **   Pretty print a PKCS7 encrypted data type (up to version 1).
02815 */
02816 static void
02817 secu_PrintPKCS7Encrypted(FILE *out, SEC_PKCS7EncryptedData *src,
02818                       const char *m, int level)
02819 {
02820     SECU_Indent(out, level); fprintf(out, "%s:\n", m);
02821     SECU_PrintInteger(out, &(src->version), "Version", level + 1);
02822 
02823     secu_PrintPKCS7EncContent(out, &src->encContentInfo, 
02824                            "Encrypted Content Information", level + 1);
02825 }
02826 
02827 /*
02828 ** secu_PrintPKCS7Digested
02829 **   Pretty print a PKCS7 digested data type (up to version 1).
02830 */
02831 static void
02832 secu_PrintPKCS7Digested(FILE *out, SEC_PKCS7DigestedData *src,
02833                      const char *m, int level)
02834 {
02835     SECU_Indent(out, level); fprintf(out, "%s:\n", m);
02836     SECU_PrintInteger(out, &(src->version), "Version", level + 1);
02837     
02838     SECU_PrintAlgorithmID(out, &src->digestAlg, "Digest Algorithm",
02839                        level + 1);
02840     secu_PrintPKCS7ContentInfo(out, &src->contentInfo, "Content Information",
02841                             level + 1);
02842     SECU_PrintAsHex(out, &src->digest, "Digest", level + 1);  
02843 }
02844 
02845 /*
02846 ** secu_PrintPKCS7ContentInfo
02847 **   Takes a SEC_PKCS7ContentInfo type and sends the contents to the 
02848 ** appropriate function
02849 */
02850 static int
02851 secu_PrintPKCS7ContentInfo(FILE *out, SEC_PKCS7ContentInfo *src,
02852                         char *m, int level)
02853 {
02854     const char *desc;
02855     SECOidTag kind;
02856     int rv;
02857 
02858     SECU_Indent(out, level);  fprintf(out, "%s:\n", m);
02859     level++;
02860 
02861     if (src->contentTypeTag == NULL)
02862        src->contentTypeTag = SECOID_FindOID(&(src->contentType));
02863 
02864     if (src->contentTypeTag == NULL) {
02865        desc = "Unknown";
02866        kind = SEC_OID_PKCS7_DATA;
02867     } else {
02868        desc = src->contentTypeTag->desc;
02869        kind = src->contentTypeTag->offset;
02870     }
02871 
02872     if (src->content.data == NULL) {
02873        SECU_Indent(out, level); fprintf(out, "%s:\n", desc);
02874        level++;
02875        SECU_Indent(out, level); fprintf(out, "<no content>\n");
02876        return 0;
02877     }
02878 
02879     rv = 0;
02880     switch (kind) {
02881       case SEC_OID_PKCS7_SIGNED_DATA:  /* Signed Data */
02882        rv = secu_PrintPKCS7Signed(out, src->content.signedData, desc, level);
02883        break;
02884 
02885       case SEC_OID_PKCS7_ENVELOPED_DATA:  /* Enveloped Data */
02886         secu_PrintPKCS7Enveloped(out, src->content.envelopedData, desc, level);
02887        break;
02888 
02889       case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:  /* Signed and Enveloped */
02890        rv = secu_PrintPKCS7SignedAndEnveloped(out,
02891                                    src->content.signedAndEnvelopedData,
02892                                    desc, level);
02893        break;
02894 
02895       case SEC_OID_PKCS7_DIGESTED_DATA:  /* Digested Data */
02896        secu_PrintPKCS7Digested(out, src->content.digestedData, desc, level);
02897        break;
02898 
02899       case SEC_OID_PKCS7_ENCRYPTED_DATA:  /* Encrypted Data */
02900        secu_PrintPKCS7Encrypted(out, src->content.encryptedData, desc, level);
02901        break;
02902 
02903       default:
02904        SECU_PrintAsHex(out, src->content.data, desc, level);
02905        break;
02906     }
02907 
02908     return rv;
02909 }
02910 
02911 /*
02912 ** SECU_PrintPKCS7ContentInfo
02913 **   Decode and print any major PKCS7 data type (up to version 1).
02914 */
02915 int
02916 SECU_PrintPKCS7ContentInfo(FILE *out, SECItem *der, char *m, int level)
02917 {
02918     SEC_PKCS7ContentInfo *cinfo;
02919     int rv;
02920 
02921     cinfo = SEC_PKCS7DecodeItem(der, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
02922     if (cinfo != NULL) {
02923        /* Send it to recursive parsing and printing module */
02924        rv = secu_PrintPKCS7ContentInfo(out, cinfo, m, level);
02925        SEC_PKCS7DestroyContentInfo(cinfo);
02926     } else {
02927        rv = -1;
02928     }
02929 
02930     return rv;
02931 }
02932 
02933 /*
02934 ** End of PKCS7 functions
02935 */
02936 
02937 void
02938 printFlags(FILE *out, unsigned int flags, int level)
02939 {
02940     if ( flags & CERTDB_VALID_PEER ) {
02941        SECU_Indent(out, level); fprintf(out, "Valid Peer\n");
02942     }
02943     if ( flags & CERTDB_TRUSTED ) {
02944        SECU_Indent(out, level); fprintf(out, "Trusted\n");
02945     }
02946     if ( flags & CERTDB_SEND_WARN ) {
02947        SECU_Indent(out, level); fprintf(out, "Warn When Sending\n");
02948     }
02949     if ( flags & CERTDB_VALID_CA ) {
02950        SECU_Indent(out, level); fprintf(out, "Valid CA\n");
02951     }
02952     if ( flags & CERTDB_TRUSTED_CA ) {
02953        SECU_Indent(out, level); fprintf(out, "Trusted CA\n");
02954     }
02955     if ( flags & CERTDB_NS_TRUSTED_CA ) {
02956        SECU_Indent(out, level); fprintf(out, "Netscape Trusted CA\n");
02957     }
02958     if ( flags & CERTDB_USER ) {
02959        SECU_Indent(out, level); fprintf(out, "User\n");
02960     }
02961     if ( flags & CERTDB_TRUSTED_CLIENT_CA ) {
02962        SECU_Indent(out, level); fprintf(out, "Trusted Client CA\n");
02963     }
02964     if ( flags & CERTDB_GOVT_APPROVED_CA ) {
02965        SECU_Indent(out, level); fprintf(out, "Step-up\n");
02966     }
02967 }
02968 
02969 void
02970 SECU_PrintTrustFlags(FILE *out, CERTCertTrust *trust, char *m, int level)
02971 {
02972     SECU_Indent(out, level); fprintf(out, "%s:\n", m);
02973     SECU_Indent(out, level+1); fprintf(out, "SSL Flags:\n");
02974     printFlags(out, trust->sslFlags, level+2);
02975     SECU_Indent(out, level+1); fprintf(out, "Email Flags:\n");
02976     printFlags(out, trust->emailFlags, level+2);
02977     SECU_Indent(out, level+1); fprintf(out, "Object Signing Flags:\n");
02978     printFlags(out, trust->objectSigningFlags, level+2);
02979 }
02980 
02981 int SECU_PrintSignedData(FILE *out, SECItem *der, char *m,
02982                         int level, SECU_PPFunc inner)
02983 {
02984     PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02985     CERTSignedData *sd;
02986     int rv = SEC_ERROR_NO_MEMORY;
02987 
02988     if (!arena)
02989        return rv;
02990 
02991     /* Strip off the signature */
02992     sd = PORT_ArenaZNew(arena, CERTSignedData);
02993     if (!sd)
02994        goto loser;
02995 
02996     rv = SEC_ASN1DecodeItem(arena, sd, SEC_ASN1_GET(CERT_SignedDataTemplate), 
02997                             der);
02998     if (rv)
02999        goto loser;
03000 
03001     SECU_Indent(out, level); fprintf(out, "%s:\n", m);
03002     rv = (*inner)(out, &sd->data, "Data", level+1);
03003 
03004     SECU_PrintAlgorithmID(out, &sd->signatureAlgorithm, "Signature Algorithm",
03005                        level+1);
03006     DER_ConvertBitString(&sd->signature);
03007     SECU_PrintAsHex(out, &sd->signature, "Signature", level+1);
03008     SECU_PrintFingerprints(out, der, "Fingerprint", level+1);
03009 loser:
03010     PORT_FreeArena(arena, PR_FALSE);
03011     return rv;
03012 
03013 }
03014 
03015 SECStatus
03016 SECU_ParseCommandLine(int argc, char **argv, char *progName, secuCommand *cmd)
03017 {
03018     PRBool found;
03019     PLOptState *optstate;
03020     PLOptStatus status;
03021     char *optstring;
03022     int i, j;
03023 
03024     optstring = (char *)malloc(cmd->numCommands + 2*cmd->numOptions);
03025     j = 0;
03026 
03027     for (i=0; i<cmd->numCommands; i++) {
03028        optstring[j++] = cmd->commands[i].flag;
03029     }
03030     for (i=0; i<cmd->numOptions; i++) {
03031        optstring[j++] = cmd->options[i].flag;
03032        if (cmd->options[i].needsArg)
03033            optstring[j++] = ':';
03034     }
03035     optstring[j] = '\0';
03036     optstate = PL_CreateOptState(argc, argv, optstring);
03037 
03038     /* Parse command line arguments */
03039     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
03040 
03041        /*  Wasn't really an option, just standalone arg.  */
03042        if (optstate->option == '\0')
03043            continue;
03044 
03045        found = PR_FALSE;
03046 
03047        for (i=0; i<cmd->numCommands; i++) {
03048            if (cmd->commands[i].flag == optstate->option) {
03049               cmd->commands[i].activated = PR_TRUE;
03050               if (optstate->value) {
03051                   cmd->commands[i].arg = (char *)optstate->value;
03052               }
03053               found = PR_TRUE;
03054               break;
03055            }
03056        }
03057 
03058        if (found)
03059            continue;
03060 
03061        for (i=0; i<cmd->numOptions; i++) {
03062            if (cmd->options[i].flag == optstate->option) {
03063               cmd->options[i].activated = PR_TRUE;
03064               if (optstate->value) {
03065                   cmd->options[i].arg = (char *)optstate->value;
03066               } else if (cmd->options[i].needsArg) {
03067                     return SECFailure;
03068                 }
03069               found = PR_TRUE;
03070               break;
03071            }
03072        }
03073 
03074        if (!found)
03075            return SECFailure;
03076     }
03077     if (status == PL_OPT_BAD)
03078        return SECFailure;
03079     return SECSuccess;
03080 }
03081 
03082 char *
03083 SECU_GetOptionArg(secuCommand *cmd, int optionNum)
03084 {
03085        if (optionNum < 0 || optionNum >= cmd->numOptions)
03086               return NULL;
03087        if (cmd->options[optionNum].activated)
03088               return PL_strdup(cmd->options[optionNum].arg);
03089        else
03090               return NULL;
03091 }
03092 
03093 static char SECUErrorBuf[64];
03094 
03095 char *
03096 SECU_ErrorStringRaw(int16 err)
03097 {
03098     if (err == 0)
03099        SECUErrorBuf[0] = '\0';
03100     else if (err == SEC_ERROR_BAD_DATA)
03101        sprintf(SECUErrorBuf, "Bad data");
03102     else if (err == SEC_ERROR_BAD_DATABASE)
03103        sprintf(SECUErrorBuf, "Problem with database");
03104     else if (err == SEC_ERROR_BAD_DER)
03105        sprintf(SECUErrorBuf, "Problem with DER");
03106     else if (err == SEC_ERROR_BAD_KEY)
03107        sprintf(SECUErrorBuf, "Problem with key");
03108     else if (err == SEC_ERROR_BAD_PASSWORD)
03109        sprintf(SECUErrorBuf, "Incorrect password");
03110     else if (err == SEC_ERROR_BAD_SIGNATURE)
03111        sprintf(SECUErrorBuf, "Bad signature");
03112     else if (err == SEC_ERROR_EXPIRED_CERTIFICATE)
03113        sprintf(SECUErrorBuf, "Expired certificate");
03114     else if (err == SEC_ERROR_EXTENSION_VALUE_INVALID)
03115        sprintf(SECUErrorBuf, "Invalid extension value");
03116     else if (err == SEC_ERROR_INPUT_LEN)
03117        sprintf(SECUErrorBuf, "Problem with input length");
03118     else if (err == SEC_ERROR_INVALID_ALGORITHM)
03119        sprintf(SECUErrorBuf, "Invalid algorithm");
03120     else if (err == SEC_ERROR_INVALID_ARGS)
03121        sprintf(SECUErrorBuf, "Invalid arguments");
03122     else if (err == SEC_ERROR_INVALID_AVA)
03123        sprintf(SECUErrorBuf, "Invalid AVA");
03124     else if (err == SEC_ERROR_INVALID_TIME)
03125        sprintf(SECUErrorBuf, "Invalid time");
03126     else if (err == SEC_ERROR_IO)
03127        sprintf(SECUErrorBuf, "Security I/O error");
03128     else if (err == SEC_ERROR_LIBRARY_FAILURE)
03129        sprintf(SECUErrorBuf, "Library failure");
03130     else if (err == SEC_ERROR_NO_MEMORY)
03131        sprintf(SECUErrorBuf, "Out of memory");
03132     else if (err == SEC_ERROR_OLD_CRL)
03133        sprintf(SECUErrorBuf, "CRL is older than the current one");
03134     else if (err == SEC_ERROR_OUTPUT_LEN)
03135        sprintf(SECUErrorBuf, "Problem with output length");
03136     else if (err == SEC_ERROR_UNKNOWN_ISSUER)
03137        sprintf(SECUErrorBuf, "Unknown issuer");
03138     else if (err == SEC_ERROR_UNTRUSTED_CERT)
03139        sprintf(SECUErrorBuf, "Untrusted certificate");
03140     else if (err == SEC_ERROR_UNTRUSTED_ISSUER)
03141        sprintf(SECUErrorBuf, "Untrusted issuer");
03142     else if (err == SSL_ERROR_BAD_CERTIFICATE)
03143        sprintf(SECUErrorBuf, "Bad certificate");
03144     else if (err == SSL_ERROR_BAD_CLIENT)
03145        sprintf(SECUErrorBuf, "Bad client");
03146     else if (err == SSL_ERROR_BAD_SERVER)
03147        sprintf(SECUErrorBuf, "Bad server");
03148     else if (err == SSL_ERROR_EXPORT_ONLY_SERVER)
03149        sprintf(SECUErrorBuf, "Export only server");
03150     else if (err == SSL_ERROR_NO_CERTIFICATE)
03151        sprintf(SECUErrorBuf, "No certificate");
03152     else if (err == SSL_ERROR_NO_CYPHER_OVERLAP)
03153        sprintf(SECUErrorBuf, "No cypher overlap");
03154     else if (err == SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE)
03155        sprintf(SECUErrorBuf, "Unsupported certificate type");
03156     else if (err == SSL_ERROR_UNSUPPORTED_VERSION)
03157        sprintf(SECUErrorBuf, "Unsupported version");
03158     else if (err == SSL_ERROR_US_ONLY_SERVER)
03159        sprintf(SECUErrorBuf, "U.S. only server");
03160     else if (err == PR_IO_ERROR)
03161        sprintf(SECUErrorBuf, "I/O error");
03162 
03163     else if (err == SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE)
03164         sprintf (SECUErrorBuf, "Expired Issuer Certificate");
03165     else if (err == SEC_ERROR_REVOKED_CERTIFICATE)
03166         sprintf (SECUErrorBuf, "Revoked certificate");
03167     else if (err == SEC_ERROR_NO_KEY)
03168         sprintf (SECUErrorBuf, "No private key in database for this cert");
03169     else if (err == SEC_ERROR_CERT_NOT_VALID)
03170         sprintf (SECUErrorBuf, "Certificate is not valid");
03171     else if (err == SEC_ERROR_EXTENSION_NOT_FOUND)
03172         sprintf (SECUErrorBuf, "Certificate extension was not found");
03173     else if (err == SEC_ERROR_EXTENSION_VALUE_INVALID)
03174         sprintf (SECUErrorBuf, "Certificate extension value invalid");
03175     else if (err == SEC_ERROR_CA_CERT_INVALID)
03176         sprintf (SECUErrorBuf, "Issuer certificate is invalid");
03177     else if (err == SEC_ERROR_CERT_USAGES_INVALID)
03178         sprintf (SECUErrorBuf, "Certificate usages is invalid");
03179     else if (err == SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION)
03180         sprintf (SECUErrorBuf, "Certificate has unknown critical extension");
03181     else if (err == SEC_ERROR_PKCS7_BAD_SIGNATURE)
03182         sprintf (SECUErrorBuf, "Bad PKCS7 signature");
03183     else if (err == SEC_ERROR_INADEQUATE_KEY_USAGE)
03184         sprintf (SECUErrorBuf, "Certificate not approved for this operation");
03185     else if (err == SEC_ERROR_INADEQUATE_CERT_TYPE)
03186         sprintf (SECUErrorBuf, "Certificate not approved for this operation");
03187 
03188     return SECUErrorBuf;
03189 }
03190 
03191 char *
03192 SECU_ErrorString(int16 err)
03193 {
03194     char *error_string;
03195 
03196     *SECUErrorBuf = 0;
03197     SECU_ErrorStringRaw (err);
03198 
03199     if (*SECUErrorBuf == 0) { 
03200        error_string = SECU_GetString(err);
03201        if (error_string == NULL || *error_string == '\0') 
03202            sprintf(SECUErrorBuf, "No error string found for %d.",  err);
03203        else
03204            return error_string;
03205     }
03206 
03207     return SECUErrorBuf;
03208 }
03209 
03210 
03211 void 
03212 SECU_PrintPRandOSError(char *progName) 
03213 {
03214     char buffer[513];
03215     PRInt32     errLen = PR_GetErrorTextLength();
03216     if (errLen > 0 && errLen < sizeof buffer) {
03217         PR_GetErrorText(buffer);
03218     }
03219     SECU_PrintError(progName, "function failed");
03220     if (errLen > 0 && errLen < sizeof buffer) {
03221         PR_fprintf(PR_STDERR, "\t%s\n", buffer);
03222     }
03223 }
03224 
03225 
03226 static char *
03227 bestCertName(CERTCertificate *cert) {
03228     if (cert->nickname) {
03229        return cert->nickname;
03230     }
03231     if (cert->emailAddr && cert->emailAddr[0]) {
03232        return cert->emailAddr;
03233     }
03234     return cert->subjectName;
03235 }
03236 
03237 void
03238 SECU_printCertProblems(FILE *outfile, CERTCertDBHandle *handle, 
03239        CERTCertificate *cert, PRBool checksig, 
03240        SECCertificateUsage certUsage, void *pinArg, PRBool verbose)
03241 {
03242     CERTVerifyLog      log;
03243     CERTVerifyLogNode *node   = NULL;
03244     unsigned int       depth  = (unsigned int)-1;
03245     unsigned int       flags  = 0;
03246     char *             errstr = NULL;
03247     PRErrorCode             err    = PORT_GetError();
03248 
03249     log.arena = PORT_NewArena(512);
03250     log.head = log.tail = NULL;
03251     log.count = 0;
03252     CERT_VerifyCertificate(handle, cert, checksig, certUsage, PR_Now(), pinArg, &log, NULL);
03253 
03254     if (log.count > 0) {
03255        fprintf(outfile,"PROBLEM WITH THE CERT CHAIN:\n");
03256        for (node = log.head; node; node = node->next) {
03257            if (depth != node->depth) {
03258               depth = node->depth;
03259               fprintf(outfile,"CERT %d. %s %s:\n", depth,
03260                              bestCertName(node->cert), 
03261                              depth ? "[Certificate Authority]": "");
03262               if (verbose) {
03263                   const char * emailAddr;
03264                   emailAddr = CERT_GetFirstEmailAddress(node->cert);
03265                   if (emailAddr) {
03266                      fprintf(outfile,"Email Address(es): ");
03267                      do {
03268                          fprintf(outfile, "%s\n", emailAddr);
03269                          emailAddr = CERT_GetNextEmailAddress(node->cert,
03270                                                               emailAddr);
03271                      } while (emailAddr);
03272                   }
03273               }
03274            }
03275            fprintf(outfile,"  ERROR %ld: %s\n", node->error,
03276                                           SECU_Strerror(node->error));
03277            errstr = NULL;
03278            switch (node->error) {
03279            case SEC_ERROR_INADEQUATE_KEY_USAGE:
03280               flags = (unsigned int)node->arg;
03281               switch (flags) {
03282               case KU_DIGITAL_SIGNATURE:
03283                   errstr = "Cert cannot sign.";
03284                   break;
03285               case KU_KEY_ENCIPHERMENT:
03286                   errstr = "Cert cannot encrypt.";
03287                   break;
03288               case KU_KEY_CERT_SIGN:
03289                   errstr = "Cert cannot sign other certs.";
03290                   break;
03291               default:
03292                   errstr = "[unknown usage].";
03293                   break;
03294               }
03295            case SEC_ERROR_INADEQUATE_CERT_TYPE:
03296               flags = (unsigned int)node->arg;
03297               switch (flags) {
03298               case NS_CERT_TYPE_SSL_CLIENT:
03299               case NS_CERT_TYPE_SSL_SERVER:
03300                   errstr = "Cert cannot be used for SSL.";
03301                   break;
03302               case NS_CERT_TYPE_SSL_CA:
03303                   errstr = "Cert cannot be used as an SSL CA.";
03304                   break;
03305               case NS_CERT_TYPE_EMAIL:
03306                   errstr = "Cert cannot be used for SMIME.";
03307                   break;
03308               case NS_CERT_TYPE_EMAIL_CA:
03309                   errstr = "Cert cannot be used as an SMIME CA.";
03310                   break;
03311               case NS_CERT_TYPE_OBJECT_SIGNING:
03312                   errstr = "Cert cannot be used for object signing.";
03313                   break;
03314               case NS_CERT_TYPE_OBJECT_SIGNING_CA:
03315                   errstr = "Cert cannot be used as an object signing CA.";
03316                   break;
03317               default:
03318                   errstr = "[unknown usage].";
03319                   break;
03320               }
03321            case SEC_ERROR_UNKNOWN_ISSUER:
03322            case SEC_ERROR_UNTRUSTED_ISSUER:
03323            case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
03324               errstr = node->cert->issuerName;
03325               break;
03326            default:
03327               break;
03328            }
03329            if (errstr) {
03330               fprintf(stderr,"    %s\n",errstr);
03331            }
03332            CERT_DestroyCertificate(node->cert);
03333        }    
03334     }
03335     PORT_SetError(err); /* restore original error code */
03336 }
03337 
03338 SECOidTag 
03339 SECU_StringToSignatureAlgTag(const char *alg)
03340 {
03341     SECOidTag hashAlgTag = SEC_OID_UNKNOWN;
03342 
03343     if (alg) {
03344        if (!PL_strcmp(alg, "MD2")) {
03345            hashAlgTag = SEC_OID_MD2;
03346        } else if (!PL_strcmp(alg, "MD4")) {
03347            hashAlgTag = SEC_OID_MD4;
03348        } else if (!PL_strcmp(alg, "MD5")) {
03349            hashAlgTag = SEC_OID_MD5;
03350        } else if (!PL_strcmp(alg, "SHA1")) {
03351            hashAlgTag = SEC_OID_SHA1;
03352        } else if (!PL_strcmp(alg, "SHA256")) {
03353            hashAlgTag = SEC_OID_SHA256;
03354        } else if (!PL_strcmp(alg, "SHA384")) {
03355            hashAlgTag = SEC_OID_SHA384;
03356        } else if (!PL_strcmp(alg, "SHA512")) {
03357            hashAlgTag = SEC_OID_SHA512;
03358        }
03359     }
03360     return hashAlgTag;
03361 }
03362 
03363 
03364 SECStatus
03365 SECU_StoreCRL(PK11SlotInfo *slot, SECItem *derCrl, PRFileDesc *outFile,
03366               const PRBool ascii, char *url)
03367 {
03368     PORT_Assert(derCrl != NULL);
03369     if (!derCrl) {
03370         PORT_SetError(SEC_ERROR_INVALID_ARGS);
03371         return SECFailure;
03372     }
03373 
03374     if (outFile != NULL) {
03375         if (ascii) {
03376             PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CRL_HEADER, 
03377                        BTOA_DataToAscii(derCrl->data, derCrl->len), 
03378                        NS_CRL_TRAILER);
03379         } else {
03380             if (PR_Write(outFile, derCrl->data, derCrl->len) != derCrl->len) {
03381                 return SECFailure;
03382             }
03383         }
03384     }
03385     if (slot) {
03386         CERTSignedCrl *newCrl = PK11_ImportCRL(slot, derCrl, url,
03387                                                SEC_CRL_TYPE, NULL, 0, NULL, 0);
03388         if (newCrl != NULL) {
03389             SEC_DestroyCrl(newCrl);
03390             return SECSuccess;
03391         }
03392         return SECFailure;
03393     }
03394     if (!outFile && !slot) {
03395         PORT_SetError(SEC_ERROR_INVALID_ARGS);
03396         return SECFailure;
03397     }
03398     return SECSuccess;
03399 }
03400 
03401 SECStatus
03402 SECU_SignAndEncodeCRL(CERTCertificate *issuer, CERTSignedCrl *signCrl,
03403                       SECOidTag hashAlgTag, SignAndEncodeFuncExitStat *resCode)
03404 {
03405     SECItem der;
03406     SECKEYPrivateKey *caPrivateKey = NULL;    
03407     SECStatus rv;
03408     PRArenaPool *arena;
03409     SECOidTag algID;
03410     void *dummy;
03411 
03412     PORT_Assert(issuer != NULL && signCrl != NULL);
03413     if (!issuer || !signCrl) {
03414         PORT_SetError(SEC_ERROR_INVALID_ARGS);
03415         return SECFailure;
03416     }
03417 
03418     arena = signCrl->arena;
03419 
03420     caPrivateKey = PK11_FindKeyByAnyCert(issuer, NULL);
03421     if (caPrivateKey == NULL) {
03422         *resCode = noKeyFound;
03423         return SECFailure;
03424     }
03425 
03426     algID = SEC_GetSignatureAlgorithmOidTag(caPrivateKey->keyType, hashAlgTag);
03427     if (algID == SEC_OID_UNKNOWN) {
03428         *resCode = noSignatureMatch;
03429         rv = SECFailure;
03430         goto done;
03431     }
03432 
03433     if (!signCrl->crl.signatureAlg.parameters.data) {
03434         rv = SECOID_SetAlgorithmID(arena, &signCrl->crl.signatureAlg, algID, 0);
03435         if (rv != SECSuccess) {
03436             *resCode = failToEncode;
03437             goto done;
03438         }
03439     }
03440 
03441     der.len = 0;
03442     der.data = NULL;
03443     dummy = SEC_ASN1EncodeItem(arena, &der, &signCrl->crl,
03444                                SEC_ASN1_GET(CERT_CrlTemplate));
03445     if (!dummy) {
03446         *resCode = failToEncode;
03447         rv = SECFailure;
03448         goto done;
03449     }
03450 
03451     rv = SECU_DerSignDataCRL(arena, &signCrl->signatureWrap,
03452                              der.data, der.len, caPrivateKey, algID);
03453     if (rv != SECSuccess) {
03454         *resCode = failToSign;
03455         goto done;
03456     }
03457 
03458     signCrl->derCrl = PORT_ArenaZNew(arena, SECItem);
03459     if (signCrl->derCrl == NULL) {
03460         *resCode = noMem;
03461         PORT_SetError(SEC_ERROR_NO_MEMORY);
03462         rv = SECFailure;
03463         goto done;
03464     }
03465 
03466     signCrl->derCrl->len = 0;
03467     signCrl->derCrl->data = NULL;
03468     dummy = SEC_ASN1EncodeItem (arena, signCrl->derCrl, signCrl,
03469                                 SEC_ASN1_GET(CERT_SignedCrlTemplate));
03470     if (!dummy) {
03471         *resCode = failToEncode;
03472         rv = SECFailure;
03473         goto done;
03474     }
03475 
03476 done:
03477     if (caPrivateKey) {
03478         SECKEY_DestroyPrivateKey(caPrivateKey);
03479     }
03480     return rv;
03481 }
03482 
03483 
03484 
03485 SECStatus
03486 SECU_CopyCRL(PRArenaPool *destArena, CERTCrl *destCrl, CERTCrl *srcCrl)
03487 {
03488     void *dummy;
03489     SECStatus rv = SECSuccess;
03490     SECItem der;
03491 
03492     PORT_Assert(destArena && srcCrl && destCrl);
03493     if (!destArena || !srcCrl || !destCrl) {
03494         PORT_SetError(SEC_ERROR_INVALID_ARGS);
03495         return SECFailure;
03496     }
03497 
03498     der.len = 0;
03499     der.data = NULL;
03500     dummy = SEC_ASN1EncodeItem (destArena, &der, srcCrl,
03501                                 SEC_ASN1_GET(CERT_CrlTemplate));
03502     if (!dummy) {
03503         return SECFailure;
03504     }
03505 
03506     rv = SEC_QuickDERDecodeItem(destArena, destCrl,
03507                                 SEC_ASN1_GET(CERT_CrlTemplate), &der);
03508     if (rv != SECSuccess) {
03509         return SECFailure;
03510     }
03511     
03512     destCrl->arena = destArena;
03513 
03514     return rv;
03515 }
03516 
03517 SECStatus
03518 SECU_DerSignDataCRL(PRArenaPool *arena, CERTSignedData *sd,
03519                     unsigned char *buf, int len, SECKEYPrivateKey *pk,
03520                     SECOidTag algID)
03521 {
03522     SECItem it;
03523     SECStatus rv;
03524 
03525     it.data = 0;
03526 
03527     /* XXX We should probably have some asserts here to make sure the key type
03528      * and algID match
03529      */
03530 
03531     /* Sign input buffer */
03532     rv = SEC_SignData(&it, buf, len, pk, algID);
03533     if (rv) goto loser;
03534 
03535     /* Fill out SignedData object */
03536     PORT_Memset(sd, 0, sizeof(sd));
03537     sd->data.data = buf;
03538     sd->data.len = len;
03539     sd->signature.data = it.data;
03540     sd->signature.len = it.len << 3;             /* convert to bit string */
03541     if (!sd->signatureAlgorithm.parameters.data) {
03542         rv = SECOID_SetAlgorithmID(arena, &sd->signatureAlgorithm, algID, 0);
03543         if (rv) goto loser;
03544     }
03545 
03546     return rv;
03547 
03548   loser:
03549     PORT_Free(it.data);
03550     return rv;
03551 }
03552 
03553 #if 0
03554 
03555 /* we need access to the private function cert_FindExtension for this code to work */
03556 
03557 CERTAuthKeyID *
03558 SECU_FindCRLAuthKeyIDExten (PRArenaPool *arena, CERTSignedCrl *scrl)
03559 {
03560     SECItem encodedExtenValue;
03561     SECStatus rv;
03562     CERTAuthKeyID *ret;
03563     CERTCrl* crl;
03564 
03565     if (!scrl) {
03566         PORT_SetError(SEC_ERROR_INVALID_ARGS);
03567         return NULL;
03568     }
03569 
03570     crl = &scrl->crl;
03571     
03572     encodedExtenValue.data = NULL;
03573     encodedExtenValue.len = 0;
03574 
03575     rv = cert_FindExtension(crl->extensions, SEC_OID_X509_AUTH_KEY_ID,
03576                          &encodedExtenValue);
03577     if ( rv != SECSuccess ) {
03578        return (NULL);
03579     }
03580 
03581     ret = CERT_DecodeAuthKeyID (arena, &encodedExtenValue);
03582 
03583     PORT_Free(encodedExtenValue.data);
03584     encodedExtenValue.data = NULL;
03585     
03586     return(ret);
03587 }
03588 
03589 #endif
03590 
03591 /*
03592  * Find the issuer of a Crl.  Use the authorityKeyID if it exists.
03593  */
03594 CERTCertificate *
03595 SECU_FindCrlIssuer(CERTCertDBHandle *dbhandle, SECItem* subject,
03596                    CERTAuthKeyID* authorityKeyID, PRTime validTime)
03597 {
03598     CERTCertificate *issuerCert = NULL;
03599     CERTCertList *certList = NULL;
03600 
03601     if (!subject) {
03602         PORT_SetError(SEC_ERROR_INVALID_ARGS);
03603         return NULL;
03604     }
03605 
03606     certList =
03607         CERT_CreateSubjectCertList(NULL, dbhandle, subject,
03608                                    validTime, PR_TRUE);
03609     if (certList) {
03610         CERTCertListNode *node = CERT_LIST_HEAD(certList);
03611     
03612         /* XXX and authoritykeyid in the future */
03613         while ( ! CERT_LIST_END(node, certList) ) {
03614             CERTCertificate *cert = node->cert;
03615             /* check cert CERTCertTrust data is allocated, check cert
03616                usage extension, check that cert has pkey in db. Select
03617                the first (newest) user cert */
03618             if (cert->trust &&
03619                 CERT_CheckCertUsage(cert, KU_CRL_SIGN) == SECSuccess &&
03620                 CERT_IsUserCert(cert)) {
03621                 
03622                 issuerCert = CERT_DupCertificate(cert);
03623                 break;
03624             }
03625             node = CERT_LIST_NEXT(node);   
03626         }
03627         CERT_DestroyCertList(certList);
03628     }
03629     return(issuerCert);
03630 }
03631 
03632 
03633 /* Encodes and adds extensions to the CRL or CRL entries. */
03634 SECStatus 
03635 SECU_EncodeAndAddExtensionValue(PRArenaPool *arena, void *extHandle, 
03636                                 void *value, PRBool criticality, int extenType, 
03637                                 EXTEN_EXT_VALUE_ENCODER EncodeValueFn)
03638 {
03639     SECItem encodedValue;
03640     SECStatus rv;
03641 
03642     encodedValue.data = NULL;
03643     encodedValue.len = 0;
03644     do {
03645         rv = (*EncodeValueFn)(arena, value, &encodedValue);
03646         if (rv != SECSuccess)
03647             break;
03648 
03649         rv = CERT_AddExtension(extHandle, extenType, &encodedValue,
03650                                criticality, PR_TRUE);
03651         if (rv != SECSuccess)
03652             break;
03653     } while (0);
03654 
03655     return (rv);
03656 }