michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: /* michael@0: ** secutil.c - various functions used by security stuff michael@0: ** michael@0: */ michael@0: michael@0: #include "prtypes.h" michael@0: #include "prtime.h" michael@0: #include "prlong.h" michael@0: #include "prerror.h" michael@0: #include "prprf.h" michael@0: #include "plgetopt.h" michael@0: #include "prenv.h" michael@0: #include "prnetdb.h" michael@0: michael@0: #include "cryptohi.h" michael@0: #include "secutil.h" michael@0: #include "secpkcs7.h" michael@0: #include "secpkcs5.h" michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #ifdef XP_UNIX michael@0: #include michael@0: #endif michael@0: michael@0: /* for SEC_TraverseNames */ michael@0: #include "cert.h" michael@0: #include "certt.h" michael@0: #include "certdb.h" michael@0: michael@0: /* #include "secmod.h" */ michael@0: #include "pk11func.h" michael@0: #include "secoid.h" michael@0: michael@0: static char consoleName[] = { michael@0: #ifdef XP_UNIX michael@0: "/dev/tty" michael@0: #else michael@0: #ifdef XP_OS2 michael@0: "\\DEV\\CON" michael@0: #else michael@0: "CON:" michael@0: #endif michael@0: #endif michael@0: }; michael@0: michael@0: #include "nssutil.h" michael@0: #include "ssl.h" michael@0: #include "sslproto.h" michael@0: michael@0: static PRBool utf8DisplayEnabled = PR_FALSE; michael@0: michael@0: void michael@0: SECU_EnableUtf8Display(PRBool enable) michael@0: { michael@0: utf8DisplayEnabled = enable; michael@0: } michael@0: michael@0: PRBool michael@0: SECU_GetUtf8DisplayEnabled(void) michael@0: { michael@0: return utf8DisplayEnabled; michael@0: } michael@0: michael@0: static void michael@0: secu_ClearPassword(char *p) michael@0: { michael@0: if (p) { michael@0: PORT_Memset(p, 0, PORT_Strlen(p)); michael@0: PORT_Free(p); michael@0: } michael@0: } michael@0: michael@0: char * michael@0: SECU_GetPasswordString(void *arg, char *prompt) michael@0: { michael@0: #ifndef _WINDOWS michael@0: char *p = NULL; michael@0: FILE *input, *output; michael@0: michael@0: /* open terminal */ michael@0: input = fopen(consoleName, "r"); michael@0: if (input == NULL) { michael@0: fprintf(stderr, "Error opening input terminal for read\n"); michael@0: return NULL; michael@0: } michael@0: michael@0: output = fopen(consoleName, "w"); michael@0: if (output == NULL) { michael@0: fprintf(stderr, "Error opening output terminal for write\n"); michael@0: return NULL; michael@0: } michael@0: michael@0: p = SEC_GetPassword (input, output, prompt, SEC_BlindCheckPassword); michael@0: michael@0: michael@0: fclose(input); michael@0: fclose(output); michael@0: michael@0: return p; michael@0: michael@0: #else michael@0: /* Win32 version of above. opening the console may fail michael@0: on windows95, and certainly isn't necessary.. */ michael@0: michael@0: char *p = NULL; michael@0: michael@0: p = SEC_GetPassword (stdin, stdout, prompt, SEC_BlindCheckPassword); michael@0: return p; michael@0: michael@0: #endif michael@0: } michael@0: michael@0: michael@0: /* michael@0: * p a s s w o r d _ h a r d c o d e michael@0: * michael@0: * A function to use the password passed in the -f(pwfile) argument michael@0: * of the command line. michael@0: * After use once, null it out otherwise PKCS11 calls us forever.? michael@0: * michael@0: */ michael@0: char * michael@0: SECU_FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg) michael@0: { michael@0: char* phrases, *phrase; michael@0: PRFileDesc *fd; michael@0: PRInt32 nb; michael@0: char *pwFile = arg; michael@0: int i; michael@0: const long maxPwdFileSize = 4096; michael@0: char* tokenName = NULL; michael@0: int tokenLen = 0; michael@0: michael@0: if (!pwFile) michael@0: return 0; michael@0: michael@0: if (retry) { michael@0: return 0; /* no good retrying - the files contents will be the same */ michael@0: } michael@0: michael@0: phrases = PORT_ZAlloc(maxPwdFileSize); michael@0: michael@0: if (!phrases) { michael@0: return 0; /* out of memory */ michael@0: } michael@0: michael@0: fd = PR_Open(pwFile, PR_RDONLY, 0); michael@0: if (!fd) { michael@0: fprintf(stderr, "No password file \"%s\" exists.\n", pwFile); michael@0: PORT_Free(phrases); michael@0: return NULL; michael@0: } michael@0: michael@0: nb = PR_Read(fd, phrases, maxPwdFileSize); michael@0: michael@0: PR_Close(fd); michael@0: michael@0: if (nb == 0) { michael@0: fprintf(stderr,"password file contains no data\n"); michael@0: PORT_Free(phrases); michael@0: return NULL; michael@0: } michael@0: michael@0: if (slot) { michael@0: tokenName = PK11_GetTokenName(slot); michael@0: if (tokenName) { michael@0: tokenLen = PORT_Strlen(tokenName); michael@0: } michael@0: } michael@0: i = 0; michael@0: do michael@0: { michael@0: int startphrase = i; michael@0: int phraseLen; michael@0: michael@0: /* handle the Windows EOL case */ michael@0: while (phrases[i] != '\r' && phrases[i] != '\n' && i < nb) i++; michael@0: /* terminate passphrase */ michael@0: phrases[i++] = '\0'; michael@0: /* clean up any EOL before the start of the next passphrase */ michael@0: while ( (isource != PW_NONE) { michael@0: PR_fprintf(PR_STDERR, "Incorrect password/PIN entered.\n"); michael@0: return NULL; michael@0: } michael@0: michael@0: switch (pwdata->source) { michael@0: case PW_NONE: michael@0: sprintf(prompt, "Enter Password or Pin for \"%s\":", michael@0: PK11_GetTokenName(slot)); michael@0: return SECU_GetPasswordString(NULL, prompt); michael@0: case PW_FROMFILE: michael@0: /* Instead of opening and closing the file every time, get the pw michael@0: * once, then keep it in memory (duh). michael@0: */ michael@0: pw = SECU_FilePasswd(slot, retry, pwdata->data); michael@0: pwdata->source = PW_PLAINTEXT; michael@0: pwdata->data = PL_strdup(pw); michael@0: /* it's already been dup'ed */ michael@0: return pw; michael@0: case PW_EXTERNAL: michael@0: sprintf(prompt, michael@0: "Press Enter, then enter PIN for \"%s\" on external device.\n", michael@0: PK11_GetTokenName(slot)); michael@0: (void) SECU_GetPasswordString(NULL, prompt); michael@0: /* Fall Through */ michael@0: case PW_PLAINTEXT: michael@0: return PL_strdup(pwdata->data); michael@0: default: michael@0: break; michael@0: } michael@0: michael@0: PR_fprintf(PR_STDERR, "Password check failed: No password found.\n"); michael@0: return NULL; michael@0: } michael@0: michael@0: char * michael@0: secu_InitSlotPassword(PK11SlotInfo *slot, PRBool retry, void *arg) michael@0: { michael@0: char *p0 = NULL; michael@0: char *p1 = NULL; michael@0: FILE *input, *output; michael@0: secuPWData *pwdata = arg; michael@0: michael@0: if (pwdata->source == PW_FROMFILE) { michael@0: return SECU_FilePasswd(slot, retry, pwdata->data); michael@0: } michael@0: if (pwdata->source == PW_PLAINTEXT) { michael@0: return PL_strdup(pwdata->data); michael@0: } michael@0: michael@0: /* PW_NONE - get it from tty */ michael@0: /* open terminal */ michael@0: #ifdef _WINDOWS michael@0: input = stdin; michael@0: #else michael@0: input = fopen(consoleName, "r"); michael@0: #endif michael@0: if (input == NULL) { michael@0: PR_fprintf(PR_STDERR, "Error opening input terminal for read\n"); michael@0: return NULL; michael@0: } michael@0: michael@0: /* we have no password, so initialize database with one */ michael@0: PR_fprintf(PR_STDERR, michael@0: "Enter a password which will be used to encrypt your keys.\n" michael@0: "The password should be at least 8 characters long,\n" michael@0: "and should contain at least one non-alphabetic character.\n\n"); michael@0: michael@0: output = fopen(consoleName, "w"); michael@0: if (output == NULL) { michael@0: PR_fprintf(PR_STDERR, "Error opening output terminal for write\n"); michael@0: return NULL; michael@0: } michael@0: michael@0: michael@0: for (;;) { michael@0: if (p0) michael@0: PORT_Free(p0); michael@0: p0 = SEC_GetPassword(input, output, "Enter new password: ", michael@0: SEC_BlindCheckPassword); michael@0: michael@0: if (p1) michael@0: PORT_Free(p1); michael@0: p1 = SEC_GetPassword(input, output, "Re-enter password: ", michael@0: SEC_BlindCheckPassword); michael@0: if (p0 && p1 && !PORT_Strcmp(p0, p1)) { michael@0: break; michael@0: } michael@0: PR_fprintf(PR_STDERR, "Passwords do not match. Try again.\n"); michael@0: } michael@0: michael@0: /* clear out the duplicate password string */ michael@0: secu_ClearPassword(p1); michael@0: michael@0: fclose(input); michael@0: fclose(output); michael@0: michael@0: return p0; michael@0: } michael@0: michael@0: SECStatus michael@0: SECU_ChangePW(PK11SlotInfo *slot, char *passwd, char *pwFile) michael@0: { michael@0: return SECU_ChangePW2(slot, passwd, 0, pwFile, 0); michael@0: } michael@0: michael@0: SECStatus michael@0: SECU_ChangePW2(PK11SlotInfo *slot, char *oldPass, char *newPass, michael@0: char *oldPwFile, char *newPwFile) michael@0: { michael@0: SECStatus rv; michael@0: secuPWData pwdata, newpwdata; michael@0: char *oldpw = NULL, *newpw = NULL; michael@0: michael@0: if (oldPass) { michael@0: pwdata.source = PW_PLAINTEXT; michael@0: pwdata.data = oldPass; michael@0: } else if (oldPwFile) { michael@0: pwdata.source = PW_FROMFILE; michael@0: pwdata.data = oldPwFile; michael@0: } else { michael@0: pwdata.source = PW_NONE; michael@0: pwdata.data = NULL; michael@0: } michael@0: michael@0: if (newPass) { michael@0: newpwdata.source = PW_PLAINTEXT; michael@0: newpwdata.data = newPass; michael@0: } else if (newPwFile) { michael@0: newpwdata.source = PW_FROMFILE; michael@0: newpwdata.data = newPwFile; michael@0: } else { michael@0: newpwdata.source = PW_NONE; michael@0: newpwdata.data = NULL; michael@0: } michael@0: michael@0: if (PK11_NeedUserInit(slot)) { michael@0: newpw = secu_InitSlotPassword(slot, PR_FALSE, &pwdata); michael@0: rv = PK11_InitPin(slot, (char*)NULL, newpw); michael@0: goto done; michael@0: } michael@0: michael@0: for (;;) { michael@0: oldpw = SECU_GetModulePassword(slot, PR_FALSE, &pwdata); michael@0: michael@0: if (PK11_CheckUserPassword(slot, oldpw) != SECSuccess) { michael@0: if (pwdata.source == PW_NONE) { michael@0: PR_fprintf(PR_STDERR, "Invalid password. Try again.\n"); michael@0: } else { michael@0: PR_fprintf(PR_STDERR, "Invalid password.\n"); michael@0: PORT_Memset(oldpw, 0, PL_strlen(oldpw)); michael@0: PORT_Free(oldpw); michael@0: return SECFailure; michael@0: } michael@0: } else michael@0: break; michael@0: michael@0: PORT_Free(oldpw); michael@0: } michael@0: michael@0: newpw = secu_InitSlotPassword(slot, PR_FALSE, &newpwdata); michael@0: michael@0: if (PK11_ChangePW(slot, oldpw, newpw) != SECSuccess) { michael@0: PR_fprintf(PR_STDERR, "Failed to change password.\n"); michael@0: return SECFailure; michael@0: } michael@0: michael@0: PORT_Memset(oldpw, 0, PL_strlen(oldpw)); michael@0: PORT_Free(oldpw); michael@0: michael@0: PR_fprintf(PR_STDOUT, "Password changed successfully.\n"); michael@0: michael@0: done: michael@0: PORT_Memset(newpw, 0, PL_strlen(newpw)); michael@0: PORT_Free(newpw); michael@0: return SECSuccess; michael@0: } michael@0: michael@0: struct matchobj { michael@0: SECItem index; michael@0: char *nname; michael@0: PRBool found; michael@0: }; michael@0: michael@0: char * michael@0: SECU_DefaultSSLDir(void) michael@0: { michael@0: char *dir; michael@0: static char sslDir[1000]; michael@0: michael@0: dir = PR_GetEnv("SSL_DIR"); michael@0: if (!dir) michael@0: return NULL; michael@0: michael@0: sprintf(sslDir, "%s", dir); michael@0: michael@0: if (sslDir[strlen(sslDir)-1] == '/') michael@0: sslDir[strlen(sslDir)-1] = 0; michael@0: michael@0: return sslDir; michael@0: } michael@0: michael@0: char * michael@0: SECU_AppendFilenameToDir(char *dir, char *filename) michael@0: { michael@0: static char path[1000]; michael@0: michael@0: if (dir[strlen(dir)-1] == '/') michael@0: sprintf(path, "%s%s", dir, filename); michael@0: else michael@0: sprintf(path, "%s/%s", dir, filename); michael@0: return path; michael@0: } michael@0: michael@0: char * michael@0: SECU_ConfigDirectory(const char* base) michael@0: { michael@0: static PRBool initted = PR_FALSE; michael@0: const char *dir = ".netscape"; michael@0: char *home; michael@0: static char buf[1000]; michael@0: michael@0: if (initted) return buf; michael@0: michael@0: michael@0: if (base == NULL || *base == 0) { michael@0: home = PR_GetEnv("HOME"); michael@0: if (!home) home = ""; michael@0: michael@0: if (*home && home[strlen(home) - 1] == '/') michael@0: sprintf (buf, "%.900s%s", home, dir); michael@0: else michael@0: sprintf (buf, "%.900s/%s", home, dir); michael@0: } else { michael@0: sprintf(buf, "%.900s", base); michael@0: if (buf[strlen(buf) - 1] == '/') michael@0: buf[strlen(buf) - 1] = 0; michael@0: } michael@0: michael@0: michael@0: initted = PR_TRUE; michael@0: return buf; michael@0: } michael@0: michael@0: /*Turn off SSL for now */ michael@0: /* This gets called by SSL when server wants our cert & key */ michael@0: int michael@0: SECU_GetClientAuthData(void *arg, PRFileDesc *fd, michael@0: struct CERTDistNamesStr *caNames, michael@0: struct CERTCertificateStr **pRetCert, michael@0: struct SECKEYPrivateKeyStr **pRetKey) michael@0: { michael@0: SECKEYPrivateKey *key; michael@0: CERTCertificate *cert; michael@0: int errsave; michael@0: michael@0: if (arg == NULL) { michael@0: fprintf(stderr, "no key/cert name specified for client auth\n"); michael@0: return -1; michael@0: } michael@0: cert = PK11_FindCertFromNickname(arg, NULL); michael@0: errsave = PORT_GetError(); michael@0: if (!cert) { michael@0: if (errsave == SEC_ERROR_BAD_PASSWORD) michael@0: fprintf(stderr, "Bad password\n"); michael@0: else if (errsave > 0) michael@0: fprintf(stderr, "Unable to read cert (error %d)\n", errsave); michael@0: else if (errsave == SEC_ERROR_BAD_DATABASE) michael@0: fprintf(stderr, "Unable to get cert from database (%d)\n", errsave); michael@0: else michael@0: fprintf(stderr, "SECKEY_FindKeyByName: internal error %d\n", errsave); michael@0: return -1; michael@0: } michael@0: michael@0: key = PK11_FindKeyByAnyCert(arg,NULL); michael@0: if (!key) { michael@0: fprintf(stderr, "Unable to get key (%d)\n", PORT_GetError()); michael@0: return -1; michael@0: } michael@0: michael@0: michael@0: *pRetCert = cert; michael@0: *pRetKey = key; michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: SECStatus michael@0: SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii, michael@0: PRBool warnOnPrivateKeyInAsciiFile) michael@0: { michael@0: SECStatus rv; michael@0: if (ascii) { michael@0: /* First convert ascii to binary */ michael@0: SECItem filedata; michael@0: char *asc, *body; michael@0: michael@0: /* Read in ascii data */ michael@0: rv = SECU_FileToItem(&filedata, inFile); michael@0: if (rv != SECSuccess) michael@0: return rv; michael@0: asc = (char *)filedata.data; michael@0: if (!asc) { michael@0: fprintf(stderr, "unable to read data from input file\n"); michael@0: return SECFailure; michael@0: } michael@0: michael@0: if (warnOnPrivateKeyInAsciiFile && strstr(asc, "PRIVATE KEY")) { michael@0: fprintf(stderr, "Warning: ignoring private key. Consider to use " michael@0: "pk12util.\n"); michael@0: } michael@0: michael@0: /* check for headers and trailers and remove them */ michael@0: if ((body = strstr(asc, "-----BEGIN")) != NULL) { michael@0: char *trailer = NULL; michael@0: asc = body; michael@0: body = PORT_Strchr(body, '\n'); michael@0: if (!body) michael@0: body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */ michael@0: if (body) michael@0: trailer = strstr(++body, "-----END"); michael@0: if (trailer != NULL) { michael@0: *trailer = '\0'; michael@0: } else { michael@0: fprintf(stderr, "input has header but no trailer\n"); michael@0: PORT_Free(filedata.data); michael@0: return SECFailure; michael@0: } michael@0: } else { michael@0: /* need one additional byte for zero terminator */ michael@0: rv = SECITEM_ReallocItemV2(NULL, &filedata, filedata.len+1); michael@0: if (rv != SECSuccess) { michael@0: PORT_Free(filedata.data); michael@0: return rv; michael@0: } michael@0: body = (char*)filedata.data; michael@0: body[filedata.len-1] = '\0'; michael@0: } michael@0: michael@0: /* Convert to binary */ michael@0: rv = ATOB_ConvertAsciiToItem(der, body); michael@0: if (rv != SECSuccess) { michael@0: fprintf(stderr, "error converting ascii to binary (%s)\n", michael@0: SECU_Strerror(PORT_GetError())); michael@0: PORT_Free(filedata.data); michael@0: return SECFailure; michael@0: } michael@0: michael@0: PORT_Free(filedata.data); michael@0: } else { michael@0: /* Read in binary der */ michael@0: rv = SECU_FileToItem(der, inFile); michael@0: if (rv != SECSuccess) { michael@0: fprintf(stderr, "error converting der (%s)\n", michael@0: SECU_Strerror(PORT_GetError())); michael@0: return SECFailure; michael@0: } michael@0: } michael@0: return SECSuccess; michael@0: } michael@0: michael@0: #define INDENT_MULT 4 michael@0: michael@0: SECStatus michael@0: SECU_StripTagAndLength(SECItem *i) michael@0: { michael@0: unsigned int start; michael@0: michael@0: if (!i || !i->data || i->len < 2) { /* must be at least tag and length */ michael@0: return SECFailure; michael@0: } michael@0: start = ((i->data[1] & 0x80) ? (i->data[1] & 0x7f) + 2 : 2); michael@0: if (i->len < start) { michael@0: return SECFailure; michael@0: } michael@0: i->data += start; michael@0: i->len -= start; michael@0: return SECSuccess; michael@0: } michael@0: michael@0: michael@0: michael@0: static void michael@0: secu_PrintRawStringQuotesOptional(FILE *out, SECItem *si, const char *m, michael@0: int level, PRBool quotes) michael@0: { michael@0: int column; michael@0: unsigned int i; michael@0: michael@0: if ( m ) { michael@0: SECU_Indent(out, level); fprintf(out, "%s: ", m); michael@0: column = (level * INDENT_MULT) + strlen(m) + 2; michael@0: level++; michael@0: } else { michael@0: SECU_Indent(out, level); michael@0: column = level*INDENT_MULT; michael@0: } michael@0: if (quotes) { michael@0: fprintf(out, "\""); column++; michael@0: } michael@0: michael@0: for (i = 0; i < si->len; i++) { michael@0: unsigned char val = si->data[i]; michael@0: unsigned char c; michael@0: if (SECU_GetWrapEnabled() && column > 76) { michael@0: SECU_Newline(out); michael@0: SECU_Indent(out, level); column = level*INDENT_MULT; michael@0: } michael@0: michael@0: if (utf8DisplayEnabled) { michael@0: if (val < 32) michael@0: c = '.'; michael@0: else michael@0: c = val; michael@0: } else { michael@0: c = printable[val]; michael@0: } michael@0: fprintf(out,"%c", c); michael@0: column++; michael@0: } michael@0: michael@0: if (quotes) { michael@0: fprintf(out, "\""); column++; michael@0: } michael@0: if (SECU_GetWrapEnabled() && michael@0: (column != level*INDENT_MULT || column > 76)) { michael@0: SECU_Newline(out); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: secu_PrintRawString(FILE *out, SECItem *si, const char *m, int level) michael@0: { michael@0: secu_PrintRawStringQuotesOptional(out, si, m, level, PR_TRUE); michael@0: } michael@0: michael@0: void michael@0: SECU_PrintString(FILE *out, const SECItem *si, const char *m, int level) michael@0: { michael@0: SECItem my = *si; michael@0: michael@0: if (SECSuccess != SECU_StripTagAndLength(&my) || !my.len) michael@0: return; michael@0: secu_PrintRawString(out, &my, m, level); michael@0: } michael@0: michael@0: /* print an unencoded boolean */ michael@0: static void michael@0: secu_PrintBoolean(FILE *out, SECItem *i, const char *m, int level) michael@0: { michael@0: int val = 0; michael@0: michael@0: if ( i->data && i->len ) { michael@0: val = i->data[0]; michael@0: } michael@0: michael@0: if (!m) { michael@0: m = "Boolean"; michael@0: } michael@0: SECU_Indent(out, level); michael@0: fprintf(out, "%s: %s\n", m, (val ? "True" : "False")); michael@0: } michael@0: michael@0: /* michael@0: * Format and print "time". If the tag message "m" is not NULL, michael@0: * do indent formatting based on "level" and add a newline afterward; michael@0: * otherwise just print the formatted time string only. michael@0: */ michael@0: static void michael@0: secu_PrintTime(FILE *out, const PRTime time, const char *m, int level) michael@0: { michael@0: PRExplodedTime printableTime; michael@0: char *timeString; michael@0: michael@0: /* Convert to local time */ michael@0: PR_ExplodeTime(time, PR_GMTParameters, &printableTime); michael@0: michael@0: timeString = PORT_Alloc(256); michael@0: if (timeString == NULL) michael@0: return; michael@0: michael@0: if (m != NULL) { michael@0: SECU_Indent(out, level); michael@0: fprintf(out, "%s: ", m); michael@0: } michael@0: michael@0: if (PR_FormatTime(timeString, 256, "%a %b %d %H:%M:%S %Y", &printableTime)) { michael@0: fputs(timeString, out); michael@0: } michael@0: michael@0: if (m != NULL) michael@0: fprintf(out, "\n"); michael@0: michael@0: PORT_Free(timeString); michael@0: } michael@0: michael@0: /* michael@0: * Format and print the UTC Time "t". If the tag message "m" is not NULL, michael@0: * do indent formatting based on "level" and add a newline afterward; michael@0: * otherwise just print the formatted time string only. michael@0: */ michael@0: void michael@0: SECU_PrintUTCTime(FILE *out, const SECItem *t, const char *m, int level) michael@0: { michael@0: PRTime time; michael@0: SECStatus rv; michael@0: michael@0: rv = DER_UTCTimeToTime(&time, t); michael@0: if (rv != SECSuccess) michael@0: return; michael@0: michael@0: secu_PrintTime(out, time, m, level); michael@0: } michael@0: michael@0: /* michael@0: * Format and print the Generalized Time "t". If the tag message "m" michael@0: * is not NULL, * do indent formatting based on "level" and add a newline michael@0: * afterward; otherwise just print the formatted time string only. michael@0: */ michael@0: void michael@0: SECU_PrintGeneralizedTime(FILE *out, const SECItem *t, const char *m, int level) michael@0: { michael@0: PRTime time; michael@0: SECStatus rv; michael@0: michael@0: michael@0: rv = DER_GeneralizedTimeToTime(&time, t); michael@0: if (rv != SECSuccess) michael@0: return; michael@0: michael@0: secu_PrintTime(out, time, m, level); michael@0: } michael@0: michael@0: /* michael@0: * Format and print the UTC or Generalized Time "t". If the tag message michael@0: * "m" is not NULL, do indent formatting based on "level" and add a newline michael@0: * afterward; otherwise just print the formatted time string only. michael@0: */ michael@0: void michael@0: SECU_PrintTimeChoice(FILE *out, const SECItem *t, const char *m, int level) michael@0: { michael@0: switch (t->type) { michael@0: case siUTCTime: michael@0: SECU_PrintUTCTime(out, t, m, level); michael@0: break; michael@0: michael@0: case siGeneralizedTime: michael@0: SECU_PrintGeneralizedTime(out, t, m, level); michael@0: break; michael@0: michael@0: default: michael@0: PORT_Assert(0); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: michael@0: /* This prints a SET or SEQUENCE */ michael@0: static void michael@0: SECU_PrintSet(FILE *out, const SECItem *t, const char *m, int level) michael@0: { michael@0: int type = t->data[0] & SEC_ASN1_TAGNUM_MASK; michael@0: int constructed = t->data[0] & SEC_ASN1_CONSTRUCTED; michael@0: const char * label; michael@0: SECItem my = *t; michael@0: michael@0: if (!constructed) { michael@0: SECU_PrintAsHex(out, t, m, level); michael@0: return; michael@0: } michael@0: if (SECSuccess != SECU_StripTagAndLength(&my)) michael@0: return; michael@0: michael@0: SECU_Indent(out, level); michael@0: if (m) { michael@0: fprintf(out, "%s: ", m); michael@0: } michael@0: michael@0: if (type == SEC_ASN1_SET) michael@0: label = "Set "; michael@0: else if (type == SEC_ASN1_SEQUENCE) michael@0: label = "Sequence "; michael@0: else michael@0: label = ""; michael@0: fprintf(out,"%s{\n", label); /* } */ michael@0: michael@0: while (my.len >= 2) { michael@0: SECItem tmp = my; michael@0: michael@0: if (tmp.data[1] & 0x80) { michael@0: unsigned int i; michael@0: unsigned int lenlen = tmp.data[1] & 0x7f; michael@0: if (lenlen > sizeof tmp.len) michael@0: break; michael@0: tmp.len = 0; michael@0: for (i=0; i < lenlen; i++) { michael@0: tmp.len = (tmp.len << 8) | tmp.data[2+i]; michael@0: } michael@0: tmp.len += lenlen + 2; michael@0: } else { michael@0: tmp.len = tmp.data[1] + 2; michael@0: } michael@0: if (tmp.len > my.len) { michael@0: tmp.len = my.len; michael@0: } michael@0: my.data += tmp.len; michael@0: my.len -= tmp.len; michael@0: SECU_PrintAny(out, &tmp, NULL, level + 1); michael@0: } michael@0: SECU_Indent(out, level); fprintf(out, /* { */ "}\n"); michael@0: } michael@0: michael@0: static void michael@0: secu_PrintContextSpecific(FILE *out, const SECItem *i, const char *m, int level) michael@0: { michael@0: int type = i->data[0] & SEC_ASN1_TAGNUM_MASK; michael@0: int constructed = i->data[0] & SEC_ASN1_CONSTRUCTED; michael@0: SECItem tmp; michael@0: michael@0: if (constructed) { michael@0: char * m2; michael@0: if (!m) michael@0: m2 = PR_smprintf("[%d]", type); michael@0: else michael@0: m2 = PR_smprintf("%s: [%d]", m, type); michael@0: if (m2) { michael@0: SECU_PrintSet(out, i, m2, level); michael@0: PR_smprintf_free(m2); michael@0: } michael@0: return; michael@0: } michael@0: michael@0: SECU_Indent(out, level); michael@0: if (m) { michael@0: fprintf(out, "%s: ", m); michael@0: } michael@0: fprintf(out,"[%d]\n", type); michael@0: michael@0: tmp = *i; michael@0: if (SECSuccess == SECU_StripTagAndLength(&tmp)) michael@0: SECU_PrintAsHex(out, &tmp, m, level+1); michael@0: } michael@0: michael@0: static void michael@0: secu_PrintOctetString(FILE *out, const SECItem *i, const char *m, int level) michael@0: { michael@0: SECItem tmp = *i; michael@0: if (SECSuccess == SECU_StripTagAndLength(&tmp)) michael@0: SECU_PrintAsHex(out, &tmp, m, level); michael@0: } michael@0: michael@0: static void michael@0: secu_PrintBitString(FILE *out, const SECItem *i, const char *m, int level) michael@0: { michael@0: int unused_bits; michael@0: SECItem tmp = *i; michael@0: michael@0: if (SECSuccess != SECU_StripTagAndLength(&tmp) || tmp.len < 2) michael@0: return; michael@0: michael@0: unused_bits = *tmp.data++; michael@0: tmp.len--; michael@0: michael@0: SECU_PrintAsHex(out, &tmp, m, level); michael@0: if (unused_bits) { michael@0: SECU_Indent(out, level + 1); michael@0: fprintf(out, "(%d least significant bits unused)\n", unused_bits); michael@0: } michael@0: } michael@0: michael@0: /* in a decoded bit string, the len member is a bit length. */ michael@0: static void michael@0: secu_PrintDecodedBitString(FILE *out, const SECItem *i, const char *m, int level) michael@0: { michael@0: int unused_bits; michael@0: SECItem tmp = *i; michael@0: michael@0: michael@0: unused_bits = (tmp.len & 0x7) ? 8 - (tmp.len & 7) : 0; michael@0: DER_ConvertBitString(&tmp); /* convert length to byte length */ michael@0: michael@0: SECU_PrintAsHex(out, &tmp, m, level); michael@0: if (unused_bits) { michael@0: SECU_Indent(out, level + 1); michael@0: fprintf(out, "(%d least significant bits unused)\n", unused_bits); michael@0: } michael@0: } michael@0: michael@0: michael@0: /* Print a DER encoded Boolean */ michael@0: void michael@0: SECU_PrintEncodedBoolean(FILE *out, const SECItem *i, const char *m, int level) michael@0: { michael@0: SECItem my = *i; michael@0: if (SECSuccess == SECU_StripTagAndLength(&my)) michael@0: secu_PrintBoolean(out, &my, m, level); michael@0: } michael@0: michael@0: /* Print a DER encoded integer */ michael@0: void michael@0: SECU_PrintEncodedInteger(FILE *out, const SECItem *i, const char *m, int level) michael@0: { michael@0: SECItem my = *i; michael@0: if (SECSuccess == SECU_StripTagAndLength(&my)) michael@0: SECU_PrintInteger(out, &my, m, level); michael@0: } michael@0: michael@0: /* Print a DER encoded OID */ michael@0: void michael@0: SECU_PrintEncodedObjectID(FILE *out, const SECItem *i, const char *m, int level) michael@0: { michael@0: SECItem my = *i; michael@0: if (SECSuccess == SECU_StripTagAndLength(&my)) michael@0: SECU_PrintObjectID(out, &my, m, level); michael@0: } michael@0: michael@0: static void michael@0: secu_PrintBMPString(FILE *out, const SECItem *i, const char *m, int level) michael@0: { michael@0: unsigned char * s; michael@0: unsigned char * d; michael@0: int len; michael@0: SECItem tmp = {0, 0, 0}; michael@0: SECItem my = *i; michael@0: michael@0: if (SECSuccess != SECU_StripTagAndLength(&my)) michael@0: goto loser; michael@0: if (my.len % 2) michael@0: goto loser; michael@0: len = (int)(my.len / 2); michael@0: tmp.data = (unsigned char *)PORT_Alloc(len); michael@0: if (!tmp.data) michael@0: goto loser; michael@0: tmp.len = len; michael@0: for (s = my.data, d = tmp.data ; len > 0; len--) { michael@0: PRUint32 bmpChar = (s[0] << 8) | s[1]; s += 2; michael@0: if (!isprint(bmpChar)) michael@0: goto loser; michael@0: *d++ = (unsigned char)bmpChar; michael@0: } michael@0: secu_PrintRawString(out, &tmp, m, level); michael@0: PORT_Free(tmp.data); michael@0: return; michael@0: michael@0: loser: michael@0: SECU_PrintAsHex(out, i, m, level); michael@0: if (tmp.data) michael@0: PORT_Free(tmp.data); michael@0: } michael@0: michael@0: static void michael@0: secu_PrintUniversalString(FILE *out, const SECItem *i, const char *m, int level) michael@0: { michael@0: unsigned char * s; michael@0: unsigned char * d; michael@0: int len; michael@0: SECItem tmp = {0, 0, 0}; michael@0: SECItem my = *i; michael@0: michael@0: if (SECSuccess != SECU_StripTagAndLength(&my)) michael@0: goto loser; michael@0: if (my.len % 4) michael@0: goto loser; michael@0: len = (int)(my.len / 4); michael@0: tmp.data = (unsigned char *)PORT_Alloc(len); michael@0: if (!tmp.data) michael@0: goto loser; michael@0: tmp.len = len; michael@0: for (s = my.data, d = tmp.data ; len > 0; len--) { michael@0: PRUint32 bmpChar = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; michael@0: s += 4; michael@0: if (!isprint(bmpChar)) michael@0: goto loser; michael@0: *d++ = (unsigned char)bmpChar; michael@0: } michael@0: secu_PrintRawString(out, &tmp, m, level); michael@0: PORT_Free(tmp.data); michael@0: return; michael@0: michael@0: loser: michael@0: SECU_PrintAsHex(out, i, m, level); michael@0: if (tmp.data) michael@0: PORT_Free(tmp.data); michael@0: } michael@0: michael@0: static void michael@0: secu_PrintUniversal(FILE *out, const SECItem *i, const char *m, int level) michael@0: { michael@0: switch (i->data[0] & SEC_ASN1_TAGNUM_MASK) { michael@0: case SEC_ASN1_ENUMERATED: michael@0: case SEC_ASN1_INTEGER: michael@0: SECU_PrintEncodedInteger(out, i, m, level); michael@0: break; michael@0: case SEC_ASN1_OBJECT_ID: michael@0: SECU_PrintEncodedObjectID(out, i, m, level); michael@0: break; michael@0: case SEC_ASN1_BOOLEAN: michael@0: SECU_PrintEncodedBoolean(out, i, m, level); michael@0: break; michael@0: case SEC_ASN1_UTF8_STRING: michael@0: case SEC_ASN1_PRINTABLE_STRING: michael@0: case SEC_ASN1_VISIBLE_STRING: michael@0: case SEC_ASN1_IA5_STRING: michael@0: case SEC_ASN1_T61_STRING: michael@0: SECU_PrintString(out, i, m, level); michael@0: break; michael@0: case SEC_ASN1_GENERALIZED_TIME: michael@0: SECU_PrintGeneralizedTime(out, i, m, level); michael@0: break; michael@0: case SEC_ASN1_UTC_TIME: michael@0: SECU_PrintUTCTime(out, i, m, level); michael@0: break; michael@0: case SEC_ASN1_NULL: michael@0: SECU_Indent(out, level); michael@0: if (m && m[0]) michael@0: fprintf(out, "%s: NULL\n", m); michael@0: else michael@0: fprintf(out, "NULL\n"); michael@0: break; michael@0: case SEC_ASN1_SET: michael@0: case SEC_ASN1_SEQUENCE: michael@0: SECU_PrintSet(out, i, m, level); michael@0: break; michael@0: case SEC_ASN1_OCTET_STRING: michael@0: secu_PrintOctetString(out, i, m, level); michael@0: break; michael@0: case SEC_ASN1_BIT_STRING: michael@0: secu_PrintBitString(out, i, m, level); michael@0: break; michael@0: case SEC_ASN1_BMP_STRING: michael@0: secu_PrintBMPString(out, i, m, level); michael@0: break; michael@0: case SEC_ASN1_UNIVERSAL_STRING: michael@0: secu_PrintUniversalString(out, i, m, level); michael@0: break; michael@0: default: michael@0: SECU_PrintAsHex(out, i, m, level); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: void michael@0: SECU_PrintAny(FILE *out, const SECItem *i, const char *m, int level) michael@0: { michael@0: if ( i && i->len && i->data ) { michael@0: switch (i->data[0] & SEC_ASN1_CLASS_MASK) { michael@0: case SEC_ASN1_CONTEXT_SPECIFIC: michael@0: secu_PrintContextSpecific(out, i, m, level); michael@0: break; michael@0: case SEC_ASN1_UNIVERSAL: michael@0: secu_PrintUniversal(out, i, m, level); michael@0: break; michael@0: default: michael@0: SECU_PrintAsHex(out, i, m, level); michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: static int michael@0: secu_PrintValidity(FILE *out, CERTValidity *v, char *m, int level) michael@0: { michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: SECU_PrintTimeChoice(out, &v->notBefore, "Not Before", level+1); michael@0: SECU_PrintTimeChoice(out, &v->notAfter, "Not After ", level+1); michael@0: return 0; michael@0: } michael@0: michael@0: /* This function does NOT expect a DER type and length. */ michael@0: SECOidTag michael@0: SECU_PrintObjectID(FILE *out, const SECItem *oid, const char *m, int level) michael@0: { michael@0: SECOidData *oiddata; michael@0: char * oidString = NULL; michael@0: michael@0: oiddata = SECOID_FindOID(oid); michael@0: if (oiddata != NULL) { michael@0: const char *name = oiddata->desc; michael@0: SECU_Indent(out, level); michael@0: if (m != NULL) michael@0: fprintf(out, "%s: ", m); michael@0: fprintf(out, "%s\n", name); michael@0: return oiddata->offset; michael@0: } michael@0: oidString = CERT_GetOidString(oid); michael@0: if (oidString) { michael@0: SECU_Indent(out, level); michael@0: if (m != NULL) michael@0: fprintf(out, "%s: ", m); michael@0: fprintf(out, "%s\n", oidString); michael@0: PR_smprintf_free(oidString); michael@0: return SEC_OID_UNKNOWN; michael@0: } michael@0: SECU_PrintAsHex(out, oid, m, level); michael@0: return SEC_OID_UNKNOWN; michael@0: } michael@0: michael@0: typedef struct secuPBEParamsStr { michael@0: SECItem salt; michael@0: SECItem iterationCount; michael@0: SECItem keyLength; michael@0: SECAlgorithmID cipherAlg; michael@0: SECAlgorithmID kdfAlg; michael@0: } secuPBEParams; michael@0: michael@0: SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) michael@0: michael@0: /* SECOID_PKCS5_PBKDF2 */ michael@0: const SEC_ASN1Template secuKDF2Params[] = michael@0: { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(secuPBEParams) }, michael@0: { SEC_ASN1_OCTET_STRING, offsetof(secuPBEParams, salt) }, michael@0: { SEC_ASN1_INTEGER, offsetof(secuPBEParams, iterationCount) }, michael@0: { SEC_ASN1_INTEGER, offsetof(secuPBEParams, keyLength) }, michael@0: { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(secuPBEParams, kdfAlg), michael@0: SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, michael@0: { 0 } michael@0: }; michael@0: michael@0: /* PKCS5v1 & PKCS12 */ michael@0: const SEC_ASN1Template secuPBEParamsTemp[] = michael@0: { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(secuPBEParams) }, michael@0: { SEC_ASN1_OCTET_STRING, offsetof(secuPBEParams, salt) }, michael@0: { SEC_ASN1_INTEGER, offsetof(secuPBEParams, iterationCount) }, michael@0: { 0 } michael@0: }; michael@0: michael@0: /* SEC_OID_PKCS5_PBES2, SEC_OID_PKCS5_PBMAC1 */ michael@0: const SEC_ASN1Template secuPBEV2Params[] = michael@0: { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(secuPBEParams)}, michael@0: { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(secuPBEParams, kdfAlg), michael@0: SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, michael@0: { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(secuPBEParams, cipherAlg), michael@0: SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, michael@0: { 0 } michael@0: }; michael@0: michael@0: void michael@0: secu_PrintRSAPSSParams(FILE *out, SECItem *value, char *m, int level) michael@0: { michael@0: PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: SECStatus rv; michael@0: SECKEYRSAPSSParams param; michael@0: SECAlgorithmID maskHashAlg; michael@0: michael@0: if (m) { michael@0: SECU_Indent(out, level); michael@0: fprintf (out, "%s:\n", m); michael@0: } michael@0: michael@0: if (!pool) { michael@0: SECU_Indent(out, level); michael@0: fprintf(out, "Out of memory\n"); michael@0: return; michael@0: } michael@0: michael@0: PORT_Memset(¶m, 0, sizeof param); michael@0: michael@0: rv = SEC_QuickDERDecodeItem(pool, ¶m, michael@0: SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate), michael@0: value); michael@0: if (rv == SECSuccess) { michael@0: if (!param.hashAlg) { michael@0: SECU_Indent(out, level+1); michael@0: fprintf(out, "Hash algorithm: default, SHA-1\n"); michael@0: } else { michael@0: SECU_PrintObjectID(out, ¶m.hashAlg->algorithm, michael@0: "Hash algorithm", level+1); michael@0: } michael@0: if (!param.maskAlg) { michael@0: SECU_Indent(out, level+1); michael@0: fprintf(out, "Mask algorithm: default, MGF1\n"); michael@0: SECU_Indent(out, level+1); michael@0: fprintf(out, "Mask hash algorithm: default, SHA-1\n"); michael@0: } else { michael@0: SECU_PrintObjectID(out, ¶m.maskAlg->algorithm, michael@0: "Mask algorithm", level+1); michael@0: rv = SEC_QuickDERDecodeItem(pool, &maskHashAlg, michael@0: SEC_ASN1_GET(SECOID_AlgorithmIDTemplate), michael@0: ¶m.maskAlg->parameters); michael@0: if (rv == SECSuccess) { michael@0: SECU_PrintObjectID(out, &maskHashAlg.algorithm, michael@0: "Mask hash algorithm", level+1); michael@0: } else { michael@0: SECU_Indent(out, level+1); michael@0: fprintf(out, "Invalid mask generation algorithm parameters\n"); michael@0: } michael@0: } michael@0: if (!param.saltLength.data) { michael@0: SECU_Indent(out, level+1); michael@0: fprintf(out, "Salt length: default, %i (0x%2X)\n", 20, 20); michael@0: } else { michael@0: SECU_PrintInteger(out, ¶m.saltLength, "Salt Length", level+1); michael@0: } michael@0: } else { michael@0: SECU_Indent(out, level+1); michael@0: fprintf(out, "Invalid RSA-PSS parameters\n"); michael@0: } michael@0: PORT_FreeArena(pool, PR_FALSE); michael@0: } michael@0: michael@0: void michael@0: secu_PrintKDF2Params(FILE *out, SECItem *value, char *m, int level) michael@0: { michael@0: PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: SECStatus rv; michael@0: secuPBEParams param; michael@0: michael@0: if (m) { michael@0: SECU_Indent(out, level); michael@0: fprintf (out, "%s:\n", m); michael@0: } michael@0: michael@0: if (!pool) { michael@0: SECU_Indent(out, level); michael@0: fprintf(out, "Out of memory\n"); michael@0: return; michael@0: } michael@0: michael@0: PORT_Memset(¶m, 0, sizeof param); michael@0: rv = SEC_QuickDERDecodeItem(pool, ¶m, secuKDF2Params, value); michael@0: if (rv == SECSuccess) { michael@0: SECU_PrintAsHex(out, ¶m.salt, "Salt", level+1); michael@0: SECU_PrintInteger(out, ¶m.iterationCount, "Iteration Count", michael@0: level+1); michael@0: SECU_PrintInteger(out, ¶m.keyLength, "Key Length", level+1); michael@0: SECU_PrintAlgorithmID(out, ¶m.kdfAlg, "KDF algorithm", level+1); michael@0: } michael@0: PORT_FreeArena(pool, PR_FALSE); michael@0: } michael@0: michael@0: void michael@0: secu_PrintPKCS5V2Params(FILE *out, SECItem *value, char *m, int level) michael@0: { michael@0: PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: SECStatus rv; michael@0: secuPBEParams param; michael@0: michael@0: if (m) { michael@0: SECU_Indent(out, level); michael@0: fprintf (out, "%s:\n", m); michael@0: } michael@0: michael@0: if (!pool) { michael@0: SECU_Indent(out, level); michael@0: fprintf(out, "Out of memory\n"); michael@0: return; michael@0: } michael@0: michael@0: PORT_Memset(¶m, 0, sizeof param); michael@0: rv = SEC_QuickDERDecodeItem(pool, ¶m, secuPBEV2Params, value); michael@0: if (rv == SECSuccess) { michael@0: SECU_PrintAlgorithmID(out, ¶m.kdfAlg, "KDF", level+1); michael@0: SECU_PrintAlgorithmID(out, ¶m.cipherAlg, "Cipher", level+1); michael@0: } michael@0: PORT_FreeArena(pool, PR_FALSE); michael@0: } michael@0: michael@0: void michael@0: secu_PrintPBEParams(FILE *out, SECItem *value, char *m, int level) michael@0: { michael@0: PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: SECStatus rv; michael@0: secuPBEParams param; michael@0: michael@0: if (m) { michael@0: SECU_Indent(out, level); michael@0: fprintf (out, "%s:\n", m); michael@0: } michael@0: michael@0: if (!pool) { michael@0: SECU_Indent(out, level); michael@0: fprintf(out, "Out of memory\n"); michael@0: return; michael@0: } michael@0: michael@0: PORT_Memset(¶m, 0, sizeof(secuPBEParams)); michael@0: rv = SEC_QuickDERDecodeItem(pool, ¶m, secuPBEParamsTemp, value); michael@0: if (rv == SECSuccess) { michael@0: SECU_PrintAsHex(out, ¶m.salt, "Salt", level+1); michael@0: SECU_PrintInteger(out, ¶m.iterationCount, "Iteration Count", michael@0: level+1); michael@0: } michael@0: PORT_FreeArena(pool, PR_FALSE); michael@0: } michael@0: michael@0: /* This function does NOT expect a DER type and length. */ michael@0: void michael@0: SECU_PrintAlgorithmID(FILE *out, SECAlgorithmID *a, char *m, int level) michael@0: { michael@0: SECOidTag algtag; michael@0: SECU_PrintObjectID(out, &a->algorithm, m, level); michael@0: michael@0: algtag = SECOID_GetAlgorithmTag(a); michael@0: if (SEC_PKCS5IsAlgorithmPBEAlgTag(algtag)) { michael@0: switch (algtag) { michael@0: case SEC_OID_PKCS5_PBKDF2: michael@0: secu_PrintKDF2Params(out, &a->parameters, "Parameters", level+1); michael@0: break; michael@0: case SEC_OID_PKCS5_PBES2: michael@0: secu_PrintPKCS5V2Params(out, &a->parameters, "Encryption", level+1); michael@0: break; michael@0: case SEC_OID_PKCS5_PBMAC1: michael@0: secu_PrintPKCS5V2Params(out, &a->parameters, "MAC", level+1); michael@0: break; michael@0: default: michael@0: secu_PrintPBEParams(out, &a->parameters, "Parameters", level+1); michael@0: break; michael@0: } michael@0: return; michael@0: } michael@0: michael@0: if (algtag == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) { michael@0: secu_PrintRSAPSSParams(out, &a->parameters, "Parameters", level+1); michael@0: return; michael@0: } michael@0: michael@0: if (a->parameters.len == 0 michael@0: || (a->parameters.len == 2 michael@0: && PORT_Memcmp(a->parameters.data, "\005\000", 2) == 0)) { michael@0: /* No arguments or NULL argument */ michael@0: } else { michael@0: /* Print args to algorithm */ michael@0: SECU_PrintAsHex(out, &a->parameters, "Args", level+1); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: secu_PrintAttribute(FILE *out, SEC_PKCS7Attribute *attr, char *m, int level) michael@0: { michael@0: SECItem *value; michael@0: int i; michael@0: char om[100]; michael@0: michael@0: if (m) { michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: } michael@0: michael@0: /* michael@0: * Should make this smarter; look at the type field and then decode michael@0: * and print the value(s) appropriately! michael@0: */ michael@0: SECU_PrintObjectID(out, &(attr->type), "Type", level+1); michael@0: if (attr->values != NULL) { michael@0: i = 0; michael@0: while ((value = attr->values[i++]) != NULL) { michael@0: sprintf(om, "Value (%d)%s", i, attr->encoded ? " (encoded)" : ""); michael@0: if (attr->encoded || attr->typeTag == NULL) { michael@0: SECU_PrintAny(out, value, om, level+1); michael@0: } else { michael@0: switch (attr->typeTag->offset) { michael@0: default: michael@0: SECU_PrintAsHex(out, value, om, level+1); michael@0: break; michael@0: case SEC_OID_PKCS9_CONTENT_TYPE: michael@0: SECU_PrintObjectID(out, value, om, level+1); michael@0: break; michael@0: case SEC_OID_PKCS9_SIGNING_TIME: michael@0: SECU_PrintTimeChoice(out, value, om, level+1); michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: #ifndef NSS_DISABLE_ECC michael@0: static void michael@0: secu_PrintECPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level) michael@0: { michael@0: SECItem curveOID = { siBuffer, NULL, 0}; michael@0: michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: SECU_PrintInteger(out, &pk->u.ec.publicValue, "PublicValue", level+1); michael@0: /* For named curves, the DEREncodedParams field contains an michael@0: * ASN Object ID (0x06 is SEC_ASN1_OBJECT_ID). michael@0: */ michael@0: if ((pk->u.ec.DEREncodedParams.len > 2) && michael@0: (pk->u.ec.DEREncodedParams.data[0] == 0x06)) { michael@0: curveOID.len = pk->u.ec.DEREncodedParams.data[1]; michael@0: curveOID.data = pk->u.ec.DEREncodedParams.data + 2; michael@0: SECU_PrintObjectID(out, &curveOID, "Curve", level +1); michael@0: } michael@0: } michael@0: #endif /* NSS_DISABLE_ECC */ michael@0: michael@0: void michael@0: SECU_PrintRSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level) michael@0: { michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: SECU_PrintInteger(out, &pk->u.rsa.modulus, "Modulus", level+1); michael@0: SECU_PrintInteger(out, &pk->u.rsa.publicExponent, "Exponent", level+1); michael@0: if (pk->u.rsa.publicExponent.len == 1 && michael@0: pk->u.rsa.publicExponent.data[0] == 1) { michael@0: SECU_Indent(out, level +1); fprintf(out, "Error: INVALID RSA KEY!\n"); michael@0: } michael@0: } michael@0: michael@0: void michael@0: SECU_PrintDSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level) michael@0: { michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: SECU_PrintInteger(out, &pk->u.dsa.params.prime, "Prime", level+1); michael@0: SECU_PrintInteger(out, &pk->u.dsa.params.subPrime, "Subprime", level+1); michael@0: SECU_PrintInteger(out, &pk->u.dsa.params.base, "Base", level+1); michael@0: SECU_PrintInteger(out, &pk->u.dsa.publicValue, "PublicValue", level+1); michael@0: } michael@0: michael@0: static void michael@0: secu_PrintSubjectPublicKeyInfo(FILE *out, PLArenaPool *arena, michael@0: CERTSubjectPublicKeyInfo *i, char *msg, int level) michael@0: { michael@0: SECKEYPublicKey *pk; michael@0: michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", msg); michael@0: SECU_PrintAlgorithmID(out, &i->algorithm, "Public Key Algorithm", level+1); michael@0: michael@0: pk = SECKEY_ExtractPublicKey(i); michael@0: if (pk) { michael@0: switch (pk->keyType) { michael@0: case rsaKey: michael@0: SECU_PrintRSAPublicKey(out, pk, "RSA Public Key", level +1); michael@0: break; michael@0: michael@0: case dsaKey: michael@0: SECU_PrintDSAPublicKey(out, pk, "DSA Public Key", level +1); michael@0: break; michael@0: michael@0: #ifndef NSS_DISABLE_ECC michael@0: case ecKey: michael@0: secu_PrintECPublicKey(out, pk, "EC Public Key", level +1); michael@0: break; michael@0: #endif michael@0: michael@0: case dhKey: michael@0: case fortezzaKey: michael@0: case keaKey: michael@0: SECU_Indent(out, level); michael@0: fprintf(out, "unable to format this SPKI algorithm type\n"); michael@0: goto loser; michael@0: default: michael@0: SECU_Indent(out, level); michael@0: fprintf(out, "unknown SPKI algorithm type\n"); michael@0: goto loser; michael@0: } michael@0: PORT_FreeArena(pk->arena, PR_FALSE); michael@0: } else { michael@0: SECU_PrintErrMsg(out, level, "Error", "Parsing public key"); michael@0: loser: michael@0: if (i->subjectPublicKey.data) { michael@0: SECU_PrintAny(out, &i->subjectPublicKey, "Raw", level); michael@0: } michael@0: } michael@0: } michael@0: michael@0: static void michael@0: printStringWithoutCRLF(FILE *out, const char *str) michael@0: { michael@0: const char *c = str; michael@0: while (*c) { michael@0: if (*c != '\r' && *c != '\n') { michael@0: fputc(*c, out); michael@0: } michael@0: ++c; michael@0: } michael@0: } michael@0: michael@0: int michael@0: SECU_PrintDumpDerIssuerAndSerial(FILE *out, SECItem *der, char *m, michael@0: int level) michael@0: { michael@0: PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: CERTCertificate *c; michael@0: int rv = SEC_ERROR_NO_MEMORY; michael@0: char *derIssuerB64; michael@0: char *derSerialB64; michael@0: michael@0: if (!arena) michael@0: return rv; michael@0: michael@0: /* Decode certificate */ michael@0: c = PORT_ArenaZNew(arena, CERTCertificate); michael@0: if (!c) michael@0: goto loser; michael@0: c->arena = arena; michael@0: rv = SEC_ASN1DecodeItem(arena, c, michael@0: SEC_ASN1_GET(CERT_CertificateTemplate), der); michael@0: if (rv) { michael@0: SECU_PrintErrMsg(out, 0, "Error", "Parsing extension"); michael@0: goto loser; michael@0: } michael@0: michael@0: SECU_PrintName(out, &c->subject, "Subject", 0); michael@0: if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ michael@0: SECU_Newline(out); michael@0: SECU_PrintName(out, &c->issuer, "Issuer", 0); michael@0: if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ michael@0: SECU_Newline(out); michael@0: SECU_PrintInteger(out, &c->serialNumber, "Serial Number", 0); michael@0: michael@0: derIssuerB64 = BTOA_ConvertItemToAscii(&c->derIssuer); michael@0: derSerialB64 = BTOA_ConvertItemToAscii(&c->serialNumber); michael@0: michael@0: fprintf(out, "Issuer DER Base64:\n"); michael@0: if (SECU_GetWrapEnabled()) { michael@0: fprintf(out, "%s\n", derIssuerB64); michael@0: } else { michael@0: printStringWithoutCRLF(out, derIssuerB64); michael@0: fputs("\n", out); michael@0: } michael@0: michael@0: fprintf(out, "Serial DER Base64:\n"); michael@0: if (SECU_GetWrapEnabled()) { michael@0: fprintf(out, "%s\n", derSerialB64); michael@0: } else { michael@0: printStringWithoutCRLF(out, derSerialB64); michael@0: fputs("\n", out); michael@0: } michael@0: michael@0: PORT_Free(derIssuerB64); michael@0: PORT_Free(derSerialB64); michael@0: michael@0: fprintf(out, "Serial DER as C source: \n{ %d, \"", c->serialNumber.len); michael@0: michael@0: { michael@0: int i; michael@0: for (i=0; i < c->serialNumber.len; ++i) { michael@0: unsigned char *chardata = (unsigned char*)(c->serialNumber.data); michael@0: unsigned char c = *(chardata + i); michael@0: michael@0: fprintf(out, "\\x%02x", c); michael@0: } michael@0: fprintf(out, "\" }\n"); michael@0: } michael@0: michael@0: loser: michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: return rv; michael@0: } michael@0: michael@0: static SECStatus michael@0: secu_PrintX509InvalidDate(FILE *out, SECItem *value, char *msg, int level) michael@0: { michael@0: SECItem decodedValue; michael@0: SECStatus rv; michael@0: PRTime invalidTime; michael@0: char *formattedTime = NULL; michael@0: michael@0: decodedValue.data = NULL; michael@0: rv = SEC_ASN1DecodeItem (NULL, &decodedValue, michael@0: SEC_ASN1_GET(SEC_GeneralizedTimeTemplate), michael@0: value); michael@0: if (rv == SECSuccess) { michael@0: rv = DER_GeneralizedTimeToTime(&invalidTime, &decodedValue); michael@0: if (rv == SECSuccess) { michael@0: formattedTime = CERT_GenTime2FormattedAscii michael@0: (invalidTime, "%a %b %d %H:%M:%S %Y"); michael@0: SECU_Indent(out, level +1); michael@0: fprintf (out, "%s: %s\n", msg, formattedTime); michael@0: PORT_Free (formattedTime); michael@0: } michael@0: } michael@0: PORT_Free (decodedValue.data); michael@0: return (rv); michael@0: } michael@0: michael@0: static SECStatus michael@0: PrintExtKeyUsageExtension (FILE *out, SECItem *value, char *msg, int level) michael@0: { michael@0: CERTOidSequence *os; michael@0: SECItem **op; michael@0: michael@0: os = CERT_DecodeOidSequence(value); michael@0: if( (CERTOidSequence *)NULL == os ) { michael@0: return SECFailure; michael@0: } michael@0: michael@0: for( op = os->oids; *op; op++ ) { michael@0: SECU_PrintObjectID(out, *op, msg, level + 1); michael@0: } michael@0: CERT_DestroyOidSequence(os); michael@0: return SECSuccess; michael@0: } michael@0: michael@0: static SECStatus michael@0: secu_PrintBasicConstraints(FILE *out, SECItem *value, char *msg, int level) { michael@0: CERTBasicConstraints constraints; michael@0: SECStatus rv; michael@0: michael@0: SECU_Indent(out, level); michael@0: if (msg) { michael@0: fprintf(out,"%s: ",msg); michael@0: } michael@0: rv = CERT_DecodeBasicConstraintValue(&constraints,value); michael@0: if (rv == SECSuccess && constraints.isCA) { michael@0: if (constraints.pathLenConstraint >= 0) { michael@0: fprintf(out,"Is a CA with a maximum path length of %d.\n", michael@0: constraints.pathLenConstraint); michael@0: } else { michael@0: fprintf(out,"Is a CA with no maximum path length.\n"); michael@0: } michael@0: } else { michael@0: fprintf(out,"Is not a CA.\n"); michael@0: } michael@0: return SECSuccess; michael@0: } michael@0: michael@0: static const char * const nsTypeBits[] = { michael@0: "SSL Client", michael@0: "SSL Server", michael@0: "S/MIME", michael@0: "Object Signing", michael@0: "Reserved", michael@0: "SSL CA", michael@0: "S/MIME CA", michael@0: "ObjectSigning CA" michael@0: }; michael@0: michael@0: /* NSCertType is merely a bit string whose bits are displayed symbolically */ michael@0: static SECStatus michael@0: secu_PrintNSCertType(FILE *out, SECItem *value, char *msg, int level) michael@0: { michael@0: int unused; michael@0: int NS_Type; michael@0: int i; michael@0: int found = 0; michael@0: SECItem my = *value; michael@0: michael@0: if ((my.data[0] != SEC_ASN1_BIT_STRING) || michael@0: SECSuccess != SECU_StripTagAndLength(&my)) { michael@0: SECU_PrintAny(out, value, "Data", level); michael@0: return SECSuccess; michael@0: } michael@0: michael@0: unused = (my.len == 2) ? (my.data[0] & 0x0f) : 0; michael@0: NS_Type = my.data[1] & (0xff << unused); michael@0: michael@0: michael@0: SECU_Indent(out, level); michael@0: if (msg) { michael@0: fprintf(out,"%s: ",msg); michael@0: } else { michael@0: fprintf(out,"Netscape Certificate Type: "); michael@0: } michael@0: for (i=0; i < 8; i++) { michael@0: if ( (0x80 >> i) & NS_Type) { michael@0: fprintf(out, "%c%s", (found ? ',' : '<'), nsTypeBits[i]); michael@0: found = 1; michael@0: } michael@0: } michael@0: fprintf(out, (found ? ">\n" : "none\n")); michael@0: return SECSuccess; michael@0: } michael@0: michael@0: static const char * const usageBits[] = { michael@0: "Digital Signature", /* 0x80 */ michael@0: "Non-Repudiation", /* 0x40 */ michael@0: "Key Encipherment", /* 0x20 */ michael@0: "Data Encipherment", /* 0x10 */ michael@0: "Key Agreement", /* 0x08 */ michael@0: "Certificate Signing", /* 0x04 */ michael@0: "CRL Signing", /* 0x02 */ michael@0: "Encipher Only", /* 0x01 */ michael@0: "Decipher Only", /* 0x0080 */ michael@0: NULL michael@0: }; michael@0: michael@0: /* X509KeyUsage is merely a bit string whose bits are displayed symbolically */ michael@0: static void michael@0: secu_PrintX509KeyUsage(FILE *out, SECItem *value, char *msg, int level) michael@0: { michael@0: int unused; michael@0: int usage; michael@0: int i; michael@0: int found = 0; michael@0: SECItem my = *value; michael@0: michael@0: if ((my.data[0] != SEC_ASN1_BIT_STRING) || michael@0: SECSuccess != SECU_StripTagAndLength(&my)) { michael@0: SECU_PrintAny(out, value, "Data", level); michael@0: return; michael@0: } michael@0: michael@0: unused = (my.len >= 2) ? (my.data[0] & 0x0f) : 0; michael@0: usage = (my.len == 2) ? (my.data[1] & (0xff << unused)) << 8 michael@0: : (my.data[1] << 8) | michael@0: (my.data[2] & (0xff << unused)); michael@0: michael@0: SECU_Indent(out, level); michael@0: fprintf(out, "Usages: "); michael@0: for (i=0; usageBits[i]; i++) { michael@0: if ( (0x8000 >> i) & usage) { michael@0: if (found) michael@0: SECU_Indent(out, level + 2); michael@0: fprintf(out, "%s\n", usageBits[i]); michael@0: found = 1; michael@0: } michael@0: } michael@0: if (!found) { michael@0: fprintf(out, "(none)\n"); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: secu_PrintIPAddress(FILE *out, SECItem *value, char *msg, int level) michael@0: { michael@0: PRStatus st; michael@0: PRNetAddr addr; michael@0: char addrBuf[80]; michael@0: michael@0: memset(&addr, 0, sizeof addr); michael@0: if (value->len == 4) { michael@0: addr.inet.family = PR_AF_INET; michael@0: memcpy(&addr.inet.ip, value->data, value->len); michael@0: } else if (value->len == 16) { michael@0: addr.ipv6.family = PR_AF_INET6; michael@0: memcpy(addr.ipv6.ip.pr_s6_addr, value->data, value->len); michael@0: if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped)) { michael@0: /* convert to IPv4. */ michael@0: addr.inet.family = PR_AF_INET; michael@0: memcpy(&addr.inet.ip, &addr.ipv6.ip.pr_s6_addr[12], 4); michael@0: memset(&addr.inet.pad[0], 0, sizeof addr.inet.pad); michael@0: } michael@0: } else { michael@0: goto loser; michael@0: } michael@0: michael@0: st = PR_NetAddrToString(&addr, addrBuf, sizeof addrBuf); michael@0: if (st == PR_SUCCESS) { michael@0: SECU_Indent(out, level); michael@0: fprintf(out, "%s: %s\n", msg, addrBuf); michael@0: } else { michael@0: loser: michael@0: SECU_PrintAsHex(out, value, msg, level); michael@0: } michael@0: } michael@0: michael@0: michael@0: static void michael@0: secu_PrintGeneralName(FILE *out, CERTGeneralName *gname, char *msg, int level) michael@0: { michael@0: char label[40]; michael@0: if (msg && msg[0]) { michael@0: SECU_Indent(out, level++); fprintf(out, "%s: \n", msg); michael@0: } michael@0: switch (gname->type) { michael@0: case certOtherName : michael@0: SECU_PrintAny( out, &gname->name.OthName.name, "Other Name", level); michael@0: SECU_PrintObjectID(out, &gname->name.OthName.oid, "OID", level+1); michael@0: break; michael@0: case certDirectoryName : michael@0: SECU_PrintName(out, &gname->name.directoryName, "Directory Name", level); michael@0: break; michael@0: case certRFC822Name : michael@0: secu_PrintRawString( out, &gname->name.other, "RFC822 Name", level); michael@0: break; michael@0: case certDNSName : michael@0: secu_PrintRawString( out, &gname->name.other, "DNS name", level); michael@0: break; michael@0: case certURI : michael@0: secu_PrintRawString( out, &gname->name.other, "URI", level); michael@0: break; michael@0: case certIPAddress : michael@0: secu_PrintIPAddress(out, &gname->name.other, "IP Address", level); michael@0: break; michael@0: case certRegisterID : michael@0: SECU_PrintObjectID( out, &gname->name.other, "Registered ID", level); michael@0: break; michael@0: case certX400Address : michael@0: SECU_PrintAny( out, &gname->name.other, "X400 Address", level); michael@0: break; michael@0: case certEDIPartyName : michael@0: SECU_PrintAny( out, &gname->name.other, "EDI Party", level); michael@0: break; michael@0: default: michael@0: PR_snprintf(label, sizeof label, "unknown type [%d]", michael@0: (int)gname->type - 1); michael@0: SECU_PrintAsHex(out, &gname->name.other, label, level); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: static void michael@0: secu_PrintGeneralNames(FILE *out, CERTGeneralName *gname, char *msg, int level) michael@0: { michael@0: CERTGeneralName *name = gname; michael@0: do { michael@0: secu_PrintGeneralName(out, name, msg, level); michael@0: name = CERT_GetNextGeneralName(name); michael@0: } while (name && name != gname); michael@0: } michael@0: michael@0: michael@0: static void michael@0: secu_PrintAuthKeyIDExtension(FILE *out, SECItem *value, char *msg, int level) michael@0: { michael@0: CERTAuthKeyID *kid = NULL; michael@0: PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: michael@0: if (!pool) { michael@0: SECU_PrintError("Error", "Allocating new ArenaPool"); michael@0: return; michael@0: } michael@0: kid = CERT_DecodeAuthKeyID(pool, value); michael@0: if (!kid) { michael@0: SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); michael@0: SECU_PrintAny(out, value, "Data", level); michael@0: } else { michael@0: int keyIDPresent = (kid->keyID.data && kid->keyID.len); michael@0: int issuerPresent = kid->authCertIssuer != NULL; michael@0: int snPresent = (kid->authCertSerialNumber.data && michael@0: kid->authCertSerialNumber.len); michael@0: michael@0: if (keyIDPresent) michael@0: SECU_PrintAsHex(out, &kid->keyID, "Key ID", level); michael@0: if (issuerPresent) michael@0: secu_PrintGeneralName(out, kid->authCertIssuer, "Issuer", level); michael@0: if (snPresent) michael@0: SECU_PrintInteger(out, &kid->authCertSerialNumber, michael@0: "Serial Number", level); michael@0: } michael@0: PORT_FreeArena(pool, PR_FALSE); michael@0: } michael@0: michael@0: michael@0: static void michael@0: secu_PrintAltNameExtension(FILE *out, SECItem *value, char *msg, int level) michael@0: { michael@0: CERTGeneralName * nameList; michael@0: CERTGeneralName * current; michael@0: PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: michael@0: if (!pool) { michael@0: SECU_PrintError("Error", "Allocating new ArenaPool"); michael@0: return; michael@0: } michael@0: nameList = current = CERT_DecodeAltNameExtension(pool, value); michael@0: if (!current) { michael@0: if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) { michael@0: /* Decoder found empty sequence, which is invalid. */ michael@0: PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID); michael@0: } michael@0: SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); michael@0: SECU_PrintAny(out, value, "Data", level); michael@0: } else { michael@0: do { michael@0: secu_PrintGeneralName(out, current, msg, level); michael@0: current = CERT_GetNextGeneralName(current); michael@0: } while (current != nameList); michael@0: } michael@0: PORT_FreeArena(pool, PR_FALSE); michael@0: } michael@0: michael@0: static void michael@0: secu_PrintCRLDistPtsExtension(FILE *out, SECItem *value, char *msg, int level) michael@0: { michael@0: CERTCrlDistributionPoints * dPoints; michael@0: PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: michael@0: if (!pool) { michael@0: SECU_PrintError("Error", "Allocating new ArenaPool"); michael@0: return; michael@0: } michael@0: dPoints = CERT_DecodeCRLDistributionPoints(pool, value); michael@0: if (dPoints && dPoints->distPoints && dPoints->distPoints[0]) { michael@0: CRLDistributionPoint ** pPoints = dPoints->distPoints; michael@0: CRLDistributionPoint * pPoint; michael@0: while (NULL != (pPoint = *pPoints++)) { michael@0: SECU_Indent(out, level); fputs("Distribution point:\n", out); michael@0: if (pPoint->distPointType == generalName && michael@0: pPoint->distPoint.fullName != NULL) { michael@0: secu_PrintGeneralNames(out, pPoint->distPoint.fullName, NULL, michael@0: level + 1); michael@0: } else if (pPoint->distPointType == relativeDistinguishedName && michael@0: pPoint->distPoint.relativeName.avas) { michael@0: SECU_PrintRDN(out, &pPoint->distPoint.relativeName, "RDN", michael@0: level + 1); michael@0: } else if (pPoint->derDistPoint.data) { michael@0: SECU_PrintAny(out, &pPoint->derDistPoint, "Point", level + 1); michael@0: } michael@0: if (pPoint->reasons.data) { michael@0: secu_PrintDecodedBitString(out, &pPoint->reasons, "Reasons", michael@0: level + 1); michael@0: } michael@0: if (pPoint->crlIssuer) { michael@0: secu_PrintGeneralName(out, pPoint->crlIssuer, "CRL issuer", michael@0: level + 1); michael@0: } michael@0: } michael@0: } else { michael@0: SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); michael@0: SECU_PrintAny(out, value, "Data", level); michael@0: } michael@0: PORT_FreeArena(pool, PR_FALSE); michael@0: } michael@0: michael@0: michael@0: static void michael@0: secu_PrintNameConstraintSubtree(FILE *out, CERTNameConstraint *value, michael@0: char *msg, int level) michael@0: { michael@0: CERTNameConstraint *head = value; michael@0: SECU_Indent(out, level); fprintf(out, "%s Subtree:\n", msg); michael@0: level++; michael@0: do { michael@0: secu_PrintGeneralName(out, &value->name, NULL, level); michael@0: if (value->min.data) michael@0: SECU_PrintInteger(out, &value->min, "Minimum", level+1); michael@0: if (value->max.data) michael@0: SECU_PrintInteger(out, &value->max, "Maximum", level+1); michael@0: value = CERT_GetNextNameConstraint(value); michael@0: } while (value != head); michael@0: } michael@0: michael@0: static void michael@0: secu_PrintNameConstraintsExtension(FILE *out, SECItem *value, char *msg, int level) michael@0: { michael@0: CERTNameConstraints * cnstrnts; michael@0: PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: michael@0: if (!pool) { michael@0: SECU_PrintError("Error", "Allocating new ArenaPool"); michael@0: return; michael@0: } michael@0: cnstrnts = CERT_DecodeNameConstraintsExtension(pool, value); michael@0: if (!cnstrnts) { michael@0: SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); michael@0: SECU_PrintAny(out, value, "Raw", level); michael@0: } else { michael@0: if (cnstrnts->permited) michael@0: secu_PrintNameConstraintSubtree(out, cnstrnts->permited, michael@0: "Permitted", level); michael@0: if (cnstrnts->excluded) michael@0: secu_PrintNameConstraintSubtree(out, cnstrnts->excluded, michael@0: "Excluded", level); michael@0: } michael@0: PORT_FreeArena(pool, PR_FALSE); michael@0: } michael@0: michael@0: michael@0: static void michael@0: secu_PrintAuthorityInfoAcess(FILE *out, SECItem *value, char *msg, int level) michael@0: { michael@0: CERTAuthInfoAccess **infos = NULL; michael@0: PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: michael@0: if (!pool) { michael@0: SECU_PrintError("Error", "Allocating new ArenaPool"); michael@0: return; michael@0: } michael@0: infos = CERT_DecodeAuthInfoAccessExtension(pool, value); michael@0: if (!infos) { michael@0: SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); michael@0: SECU_PrintAny(out, value, "Raw", level); michael@0: } else { michael@0: CERTAuthInfoAccess *info; michael@0: while (NULL != (info = *infos++)) { michael@0: if (info->method.data) { michael@0: SECU_PrintObjectID(out, &info->method, "Method", level); michael@0: } else { michael@0: SECU_Indent(out,level); michael@0: fprintf(out, "Error: missing method\n"); michael@0: } michael@0: if (info->location) { michael@0: secu_PrintGeneralName(out, info->location, "Location", level); michael@0: } else { michael@0: SECU_PrintAny(out, &info->derLocation, "Location", level); michael@0: } michael@0: } michael@0: } michael@0: PORT_FreeArena(pool, PR_FALSE); michael@0: } michael@0: michael@0: michael@0: void michael@0: SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions, michael@0: char *msg, int level) michael@0: { michael@0: SECOidTag oidTag; michael@0: michael@0: if ( extensions ) { michael@0: if (msg && *msg) { michael@0: SECU_Indent(out, level++); fprintf(out, "%s:\n", msg); michael@0: } michael@0: michael@0: while ( *extensions ) { michael@0: SECItem *tmpitem; michael@0: michael@0: tmpitem = &(*extensions)->id; michael@0: SECU_PrintObjectID(out, tmpitem, "Name", level); michael@0: michael@0: tmpitem = &(*extensions)->critical; michael@0: if ( tmpitem->len ) { michael@0: secu_PrintBoolean(out, tmpitem, "Critical", level); michael@0: } michael@0: michael@0: oidTag = SECOID_FindOIDTag (&((*extensions)->id)); michael@0: tmpitem = &((*extensions)->value); michael@0: michael@0: switch (oidTag) { michael@0: case SEC_OID_X509_INVALID_DATE: michael@0: case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME: michael@0: secu_PrintX509InvalidDate(out, tmpitem, "Date", level ); michael@0: break; michael@0: case SEC_OID_X509_CERTIFICATE_POLICIES: michael@0: SECU_PrintPolicy(out, tmpitem, "Data", level ); michael@0: break; michael@0: case SEC_OID_NS_CERT_EXT_BASE_URL: michael@0: case SEC_OID_NS_CERT_EXT_REVOCATION_URL: michael@0: case SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL: michael@0: case SEC_OID_NS_CERT_EXT_CA_CRL_URL: michael@0: case SEC_OID_NS_CERT_EXT_CA_CERT_URL: michael@0: case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL: michael@0: case SEC_OID_NS_CERT_EXT_CA_POLICY_URL: michael@0: case SEC_OID_NS_CERT_EXT_HOMEPAGE_URL: michael@0: case SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL: michael@0: case SEC_OID_OCSP_RESPONDER: michael@0: SECU_PrintString(out,tmpitem, "URL", level); michael@0: break; michael@0: case SEC_OID_NS_CERT_EXT_COMMENT: michael@0: SECU_PrintString(out,tmpitem, "Comment", level); michael@0: break; michael@0: case SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME: michael@0: SECU_PrintString(out,tmpitem, "ServerName", level); michael@0: break; michael@0: case SEC_OID_NS_CERT_EXT_CERT_TYPE: michael@0: secu_PrintNSCertType(out,tmpitem,"Data",level); michael@0: break; michael@0: case SEC_OID_X509_BASIC_CONSTRAINTS: michael@0: secu_PrintBasicConstraints(out,tmpitem,"Data",level); michael@0: break; michael@0: case SEC_OID_X509_EXT_KEY_USAGE: michael@0: PrintExtKeyUsageExtension(out, tmpitem, NULL, level); michael@0: break; michael@0: case SEC_OID_X509_KEY_USAGE: michael@0: secu_PrintX509KeyUsage(out, tmpitem, NULL, level ); michael@0: break; michael@0: case SEC_OID_X509_AUTH_KEY_ID: michael@0: secu_PrintAuthKeyIDExtension(out, tmpitem, NULL, level ); michael@0: break; michael@0: case SEC_OID_X509_SUBJECT_ALT_NAME: michael@0: case SEC_OID_X509_ISSUER_ALT_NAME: michael@0: secu_PrintAltNameExtension(out, tmpitem, NULL, level ); michael@0: break; michael@0: case SEC_OID_X509_CRL_DIST_POINTS: michael@0: secu_PrintCRLDistPtsExtension(out, tmpitem, NULL, level ); michael@0: break; michael@0: case SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD: michael@0: SECU_PrintPrivKeyUsagePeriodExtension(out, tmpitem, NULL, michael@0: level ); michael@0: break; michael@0: case SEC_OID_X509_NAME_CONSTRAINTS: michael@0: secu_PrintNameConstraintsExtension(out, tmpitem, NULL, level); michael@0: break; michael@0: case SEC_OID_X509_AUTH_INFO_ACCESS: michael@0: secu_PrintAuthorityInfoAcess(out, tmpitem, NULL, level); michael@0: break; michael@0: michael@0: case SEC_OID_X509_CRL_NUMBER: michael@0: case SEC_OID_X509_REASON_CODE: michael@0: michael@0: /* PKIX OIDs */ michael@0: case SEC_OID_PKIX_OCSP: michael@0: case SEC_OID_PKIX_OCSP_BASIC_RESPONSE: michael@0: case SEC_OID_PKIX_OCSP_NONCE: michael@0: case SEC_OID_PKIX_OCSP_CRL: michael@0: case SEC_OID_PKIX_OCSP_RESPONSE: michael@0: case SEC_OID_PKIX_OCSP_NO_CHECK: michael@0: case SEC_OID_PKIX_OCSP_ARCHIVE_CUTOFF: michael@0: case SEC_OID_PKIX_OCSP_SERVICE_LOCATOR: michael@0: case SEC_OID_PKIX_REGCTRL_REGTOKEN: michael@0: case SEC_OID_PKIX_REGCTRL_AUTHENTICATOR: michael@0: case SEC_OID_PKIX_REGCTRL_PKIPUBINFO: michael@0: case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS: michael@0: case SEC_OID_PKIX_REGCTRL_OLD_CERT_ID: michael@0: case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY: michael@0: case SEC_OID_PKIX_REGINFO_UTF8_PAIRS: michael@0: case SEC_OID_PKIX_REGINFO_CERT_REQUEST: michael@0: michael@0: /* Netscape extension OIDs. */ michael@0: case SEC_OID_NS_CERT_EXT_NETSCAPE_OK: michael@0: case SEC_OID_NS_CERT_EXT_ISSUER_LOGO: michael@0: case SEC_OID_NS_CERT_EXT_SUBJECT_LOGO: michael@0: case SEC_OID_NS_CERT_EXT_ENTITY_LOGO: michael@0: case SEC_OID_NS_CERT_EXT_USER_PICTURE: michael@0: michael@0: /* x.509 v3 Extensions */ michael@0: case SEC_OID_X509_SUBJECT_DIRECTORY_ATTR: michael@0: case SEC_OID_X509_SUBJECT_KEY_ID: michael@0: case SEC_OID_X509_POLICY_MAPPINGS: michael@0: case SEC_OID_X509_POLICY_CONSTRAINTS: michael@0: michael@0: michael@0: default: michael@0: SECU_PrintAny(out, tmpitem, "Data", level); michael@0: break; michael@0: } michael@0: michael@0: SECU_Newline(out); michael@0: extensions++; michael@0: } michael@0: } michael@0: } michael@0: michael@0: /* An RDN is a subset of a DirectoryName, and we already know how to michael@0: * print those, so make a directory name out of the RDN, and print it. michael@0: */ michael@0: void michael@0: SECU_PrintRDN(FILE *out, CERTRDN *rdn, const char *msg, int level) michael@0: { michael@0: CERTName name; michael@0: CERTRDN *rdns[2]; michael@0: michael@0: name.arena = NULL; michael@0: name.rdns = rdns; michael@0: rdns[0] = rdn; michael@0: rdns[1] = NULL; michael@0: SECU_PrintName(out, &name, msg, level); michael@0: } michael@0: michael@0: void michael@0: SECU_PrintNameQuotesOptional(FILE *out, CERTName *name, const char *msg, michael@0: int level, PRBool quotes) michael@0: { michael@0: char *nameStr = NULL; michael@0: char *str; michael@0: SECItem my; michael@0: michael@0: if (!name) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return; michael@0: } michael@0: if (!name->rdns || !name->rdns[0]) { michael@0: str = "(empty)"; michael@0: } else { michael@0: str = nameStr = CERT_NameToAscii(name); michael@0: } michael@0: if (!str) { michael@0: str = "!Invalid AVA!"; michael@0: } michael@0: my.data = (unsigned char *)str; michael@0: my.len = PORT_Strlen(str); michael@0: #if 1 michael@0: secu_PrintRawStringQuotesOptional(out, &my, msg, level, quotes); michael@0: #else michael@0: SECU_Indent(out, level); fprintf(out, "%s: ", msg); michael@0: fprintf(out, str); michael@0: SECU_Newline(out); michael@0: #endif michael@0: PORT_Free(nameStr); michael@0: } michael@0: michael@0: void michael@0: SECU_PrintName(FILE *out, CERTName *name, const char *msg, int level) michael@0: { michael@0: SECU_PrintNameQuotesOptional(out, name, msg, level, PR_TRUE); michael@0: } michael@0: michael@0: void michael@0: printflags(char *trusts, unsigned int flags) michael@0: { michael@0: if (flags & CERTDB_VALID_CA) michael@0: if (!(flags & CERTDB_TRUSTED_CA) && michael@0: !(flags & CERTDB_TRUSTED_CLIENT_CA)) michael@0: PORT_Strcat(trusts, "c"); michael@0: if (flags & CERTDB_TERMINAL_RECORD) michael@0: if (!(flags & CERTDB_TRUSTED)) michael@0: PORT_Strcat(trusts, "p"); michael@0: if (flags & CERTDB_TRUSTED_CA) michael@0: PORT_Strcat(trusts, "C"); michael@0: if (flags & CERTDB_TRUSTED_CLIENT_CA) michael@0: PORT_Strcat(trusts, "T"); michael@0: if (flags & CERTDB_TRUSTED) michael@0: PORT_Strcat(trusts, "P"); michael@0: if (flags & CERTDB_USER) michael@0: PORT_Strcat(trusts, "u"); michael@0: if (flags & CERTDB_SEND_WARN) michael@0: PORT_Strcat(trusts, "w"); michael@0: if (flags & CERTDB_INVISIBLE_CA) michael@0: PORT_Strcat(trusts, "I"); michael@0: if (flags & CERTDB_GOVT_APPROVED_CA) michael@0: PORT_Strcat(trusts, "G"); michael@0: return; michael@0: } michael@0: michael@0: /* callback for listing certs through pkcs11 */ michael@0: SECStatus michael@0: SECU_PrintCertNickname(CERTCertListNode *node, void *data) michael@0: { michael@0: CERTCertTrust trust; michael@0: CERTCertificate* cert; michael@0: FILE *out; michael@0: char trusts[30]; michael@0: char *name; michael@0: michael@0: cert = node->cert; michael@0: michael@0: PORT_Memset (trusts, 0, sizeof (trusts)); michael@0: out = (FILE *)data; michael@0: michael@0: name = node->appData; michael@0: if (!name || !name[0]) { michael@0: name = cert->nickname; michael@0: } michael@0: if (!name || !name[0]) { michael@0: name = cert->emailAddr; michael@0: } michael@0: if (!name || !name[0]) { michael@0: name = "(NULL)"; michael@0: } michael@0: michael@0: if (CERT_GetCertTrust(cert, &trust) == SECSuccess) { michael@0: printflags(trusts, trust.sslFlags); michael@0: PORT_Strcat(trusts, ","); michael@0: printflags(trusts, trust.emailFlags); michael@0: PORT_Strcat(trusts, ","); michael@0: printflags(trusts, trust.objectSigningFlags); michael@0: } else { michael@0: PORT_Memcpy(trusts,",,",3); michael@0: } michael@0: fprintf(out, "%-60s %-5s\n", name, trusts); michael@0: michael@0: return (SECSuccess); michael@0: } michael@0: michael@0: int michael@0: SECU_DecodeAndPrintExtensions(FILE *out, SECItem *any, char *m, int level) michael@0: { michael@0: CERTCertExtension **extensions = NULL; michael@0: PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: int rv = 0; michael@0: michael@0: if (!arena) michael@0: return SEC_ERROR_NO_MEMORY; michael@0: michael@0: rv = SEC_QuickDERDecodeItem(arena, &extensions, michael@0: SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate), any); michael@0: if (!rv) michael@0: SECU_PrintExtensions(out, extensions, m, level); michael@0: else michael@0: SECU_PrintAny(out, any, m, level); michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: return rv; michael@0: } michael@0: michael@0: /* print a decoded SET OF or SEQUENCE OF Extensions */ michael@0: int michael@0: SECU_PrintSetOfExtensions(FILE *out, SECItem **any, char *m, int level) michael@0: { michael@0: int rv = 0; michael@0: if (m && *m) { michael@0: SECU_Indent(out, level++); fprintf(out, "%s:\n", m); michael@0: } michael@0: while (any && any[0]) { michael@0: rv |= SECU_DecodeAndPrintExtensions(out, any[0], "", level); michael@0: any++; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: /* print a decoded SET OF or SEQUENCE OF "ANY" */ michael@0: int michael@0: SECU_PrintSetOfAny(FILE *out, SECItem **any, char *m, int level) michael@0: { michael@0: int rv = 0; michael@0: if (m && *m) { michael@0: SECU_Indent(out, level++); fprintf(out, "%s:\n", m); michael@0: } michael@0: while (any && any[0]) { michael@0: SECU_PrintAny(out, any[0], "", level); michael@0: any++; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: int michael@0: SECU_PrintCertAttribute(FILE *out, CERTAttribute *attr, char *m, int level) michael@0: { michael@0: int rv = 0; michael@0: SECOidTag tag; michael@0: tag = SECU_PrintObjectID(out, &attr->attrType, "Attribute Type", level); michael@0: if (tag == SEC_OID_PKCS9_EXTENSION_REQUEST) { michael@0: rv = SECU_PrintSetOfExtensions(out, attr->attrValue, "Extensions", level); michael@0: } else { michael@0: rv = SECU_PrintSetOfAny(out, attr->attrValue, "Attribute Values", level); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: int michael@0: SECU_PrintCertAttributes(FILE *out, CERTAttribute **attrs, char *m, int level) michael@0: { michael@0: int rv = 0; michael@0: while (attrs[0]) { michael@0: rv |= SECU_PrintCertAttribute(out, attrs[0], m, level+1); michael@0: attrs++; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: int /* sometimes a PRErrorCode, other times a SECStatus. Sigh. */ michael@0: SECU_PrintCertificateRequest(FILE *out, SECItem *der, char *m, int level) michael@0: { michael@0: PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: CERTCertificateRequest *cr; michael@0: int rv = SEC_ERROR_NO_MEMORY; michael@0: michael@0: if (!arena) michael@0: return rv; michael@0: michael@0: /* Decode certificate request */ michael@0: cr = PORT_ArenaZNew(arena, CERTCertificateRequest); michael@0: if (!cr) michael@0: goto loser; michael@0: cr->arena = arena; michael@0: rv = SEC_QuickDERDecodeItem(arena, cr, michael@0: SEC_ASN1_GET(CERT_CertificateRequestTemplate), der); michael@0: if (rv) michael@0: goto loser; michael@0: michael@0: /* Pretty print it out */ michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: SECU_PrintInteger(out, &cr->version, "Version", level+1); michael@0: SECU_PrintName(out, &cr->subject, "Subject", level+1); michael@0: if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ michael@0: SECU_Newline(out); michael@0: secu_PrintSubjectPublicKeyInfo(out, arena, &cr->subjectPublicKeyInfo, michael@0: "Subject Public Key Info", level+1); michael@0: if (cr->attributes) michael@0: SECU_PrintCertAttributes(out, cr->attributes, "Attributes", level+1); michael@0: rv = 0; michael@0: loser: michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: return rv; michael@0: } michael@0: michael@0: int michael@0: SECU_PrintCertificate(FILE *out, const SECItem *der, const char *m, int level) michael@0: { michael@0: PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: CERTCertificate *c; michael@0: int rv = SEC_ERROR_NO_MEMORY; michael@0: int iv; michael@0: michael@0: if (!arena) michael@0: return rv; michael@0: michael@0: /* Decode certificate */ michael@0: c = PORT_ArenaZNew(arena, CERTCertificate); michael@0: if (!c) michael@0: goto loser; michael@0: c->arena = arena; michael@0: rv = SEC_ASN1DecodeItem(arena, c, michael@0: SEC_ASN1_GET(CERT_CertificateTemplate), der); michael@0: if (rv) { michael@0: SECU_Indent(out, level); michael@0: SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); michael@0: SECU_PrintAny(out, der, "Raw", level); michael@0: goto loser; michael@0: } michael@0: /* Pretty print it out */ michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: iv = c->version.len ? DER_GetInteger(&c->version) : 0; /* version is optional */ michael@0: SECU_Indent(out, level+1); fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv); michael@0: michael@0: SECU_PrintInteger(out, &c->serialNumber, "Serial Number", level+1); michael@0: SECU_PrintAlgorithmID(out, &c->signature, "Signature Algorithm", level+1); michael@0: SECU_PrintName(out, &c->issuer, "Issuer", level+1); michael@0: if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ michael@0: SECU_Newline(out); michael@0: secu_PrintValidity(out, &c->validity, "Validity", level+1); michael@0: SECU_PrintName(out, &c->subject, "Subject", level+1); michael@0: if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ michael@0: SECU_Newline(out); michael@0: secu_PrintSubjectPublicKeyInfo(out, arena, &c->subjectPublicKeyInfo, michael@0: "Subject Public Key Info", level+1); michael@0: if (c->issuerID.data) michael@0: secu_PrintDecodedBitString(out, &c->issuerID, "Issuer Unique ID", level+1); michael@0: if (c->subjectID.data) michael@0: secu_PrintDecodedBitString(out, &c->subjectID, "Subject Unique ID", level+1); michael@0: SECU_PrintExtensions(out, c->extensions, "Signed Extensions", level+1); michael@0: loser: michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: return rv; michael@0: } michael@0: michael@0: int michael@0: SECU_PrintSubjectPublicKeyInfo(FILE *out, SECItem *der, char *m, int level) michael@0: { michael@0: PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: int rv = SEC_ERROR_NO_MEMORY; michael@0: CERTSubjectPublicKeyInfo spki; michael@0: michael@0: if (!arena) michael@0: return rv; michael@0: michael@0: PORT_Memset(&spki, 0, sizeof spki); michael@0: rv = SEC_ASN1DecodeItem(arena, &spki, michael@0: SEC_ASN1_GET(CERT_SubjectPublicKeyInfoTemplate), michael@0: der); michael@0: if (!rv) { michael@0: if (m && *m) { michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: } michael@0: secu_PrintSubjectPublicKeyInfo(out, arena, &spki, michael@0: "Subject Public Key Info", level+1); michael@0: } michael@0: michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: return rv; michael@0: } michael@0: michael@0: #ifdef HAVE_EPV_TEMPLATE michael@0: int michael@0: SECU_PrintPrivateKey(FILE *out, SECItem *der, char *m, int level) michael@0: { michael@0: PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: SECKEYEncryptedPrivateKeyInfo key; michael@0: int rv = SEC_ERROR_NO_MEMORY; michael@0: michael@0: if (!arena) michael@0: return rv; michael@0: michael@0: PORT_Memset(&key, 0, sizeof(key)); michael@0: rv = SEC_ASN1DecodeItem(arena, &key, michael@0: SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate), der); michael@0: if (rv) michael@0: goto loser; michael@0: michael@0: /* Pretty print it out */ michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: SECU_PrintAlgorithmID(out, &key.algorithm, "Encryption Algorithm", michael@0: level+1); michael@0: SECU_PrintAsHex(out, &key.encryptedData, "Encrypted Data", level+1); michael@0: loser: michael@0: PORT_FreeArena(arena, PR_TRUE); michael@0: return rv; michael@0: } michael@0: #endif michael@0: michael@0: int michael@0: SECU_PrintFingerprints(FILE *out, SECItem *derCert, char *m, int level) michael@0: { michael@0: unsigned char fingerprint[SHA256_LENGTH]; michael@0: char *fpStr = NULL; michael@0: int err = PORT_GetError(); michael@0: SECStatus rv; michael@0: SECItem fpItem; michael@0: michael@0: /* Print SHA-256 fingerprint */ michael@0: memset(fingerprint, 0, sizeof fingerprint); michael@0: rv = PK11_HashBuf(SEC_OID_SHA256, fingerprint, derCert->data, derCert->len); michael@0: fpItem.data = fingerprint; michael@0: fpItem.len = SHA256_LENGTH; michael@0: fpStr = CERT_Hexify(&fpItem, 1); michael@0: SECU_Indent(out, level); fprintf(out, "%s (SHA-256):", m); michael@0: if (SECU_GetWrapEnabled()) { michael@0: fprintf(out, "\n"); michael@0: SECU_Indent(out, level+1); michael@0: } michael@0: else { michael@0: fprintf(out, " "); michael@0: } michael@0: fprintf(out, "%s\n", fpStr); michael@0: PORT_Free(fpStr); michael@0: fpStr = NULL; michael@0: if (rv != SECSuccess && !err) michael@0: err = PORT_GetError(); michael@0: michael@0: /* print SHA1 fingerprint */ michael@0: memset(fingerprint, 0, sizeof fingerprint); michael@0: rv = PK11_HashBuf(SEC_OID_SHA1,fingerprint, derCert->data, derCert->len); michael@0: fpItem.data = fingerprint; michael@0: fpItem.len = SHA1_LENGTH; michael@0: fpStr = CERT_Hexify(&fpItem, 1); michael@0: SECU_Indent(out, level); fprintf(out, "%s (SHA1):", m); michael@0: if (SECU_GetWrapEnabled()) { michael@0: fprintf(out, "\n"); michael@0: SECU_Indent(out, level+1); michael@0: } michael@0: else { michael@0: fprintf(out, " "); michael@0: } michael@0: fprintf(out, "%s\n", fpStr); michael@0: PORT_Free(fpStr); michael@0: if (SECU_GetWrapEnabled()) michael@0: fprintf(out, "\n"); michael@0: michael@0: if (err) michael@0: PORT_SetError(err); michael@0: if (err || rv != SECSuccess) michael@0: return SECFailure; michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: /* michael@0: ** PKCS7 Support michael@0: */ michael@0: michael@0: /* forward declaration */ michael@0: static int michael@0: secu_PrintPKCS7ContentInfo(FILE *, SEC_PKCS7ContentInfo *, char *, int); michael@0: michael@0: /* michael@0: ** secu_PrintPKCS7EncContent michael@0: ** Prints a SEC_PKCS7EncryptedContentInfo (without decrypting it) michael@0: */ michael@0: static void michael@0: secu_PrintPKCS7EncContent(FILE *out, SEC_PKCS7EncryptedContentInfo *src, michael@0: char *m, int level) michael@0: { michael@0: if (src->contentTypeTag == NULL) michael@0: src->contentTypeTag = SECOID_FindOID(&(src->contentType)); michael@0: michael@0: SECU_Indent(out, level); michael@0: fprintf(out, "%s:\n", m); michael@0: SECU_Indent(out, level + 1); michael@0: fprintf(out, "Content Type: %s\n", michael@0: (src->contentTypeTag != NULL) ? src->contentTypeTag->desc michael@0: : "Unknown"); michael@0: SECU_PrintAlgorithmID(out, &(src->contentEncAlg), michael@0: "Content Encryption Algorithm", level+1); michael@0: SECU_PrintAsHex(out, &(src->encContent), michael@0: "Encrypted Content", level+1); michael@0: } michael@0: michael@0: /* michael@0: ** secu_PrintRecipientInfo michael@0: ** Prints a PKCS7RecipientInfo type michael@0: */ michael@0: static void michael@0: secu_PrintRecipientInfo(FILE *out, SEC_PKCS7RecipientInfo *info, char *m, michael@0: int level) michael@0: { michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: SECU_PrintInteger(out, &(info->version), "Version", level + 1); michael@0: michael@0: SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer", michael@0: level + 1); michael@0: SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber), michael@0: "Serial Number", level + 1); michael@0: michael@0: /* Parse and display encrypted key */ michael@0: SECU_PrintAlgorithmID(out, &(info->keyEncAlg), michael@0: "Key Encryption Algorithm", level + 1); michael@0: SECU_PrintAsHex(out, &(info->encKey), "Encrypted Key", level + 1); michael@0: } michael@0: michael@0: /* michael@0: ** secu_PrintSignerInfo michael@0: ** Prints a PKCS7SingerInfo type michael@0: */ michael@0: static void michael@0: secu_PrintSignerInfo(FILE *out, SEC_PKCS7SignerInfo *info, char *m, int level) michael@0: { michael@0: SEC_PKCS7Attribute *attr; michael@0: int iv; michael@0: char om[100]; michael@0: michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: SECU_PrintInteger(out, &(info->version), "Version", level + 1); michael@0: michael@0: SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer", michael@0: level + 1); michael@0: SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber), michael@0: "Serial Number", level + 1); michael@0: michael@0: SECU_PrintAlgorithmID(out, &(info->digestAlg), "Digest Algorithm", michael@0: level + 1); michael@0: michael@0: if (info->authAttr != NULL) { michael@0: SECU_Indent(out, level + 1); michael@0: fprintf(out, "Authenticated Attributes:\n"); michael@0: iv = 0; michael@0: while ((attr = info->authAttr[iv++]) != NULL) { michael@0: sprintf(om, "Attribute (%d)", iv); michael@0: secu_PrintAttribute(out, attr, om, level + 2); michael@0: } michael@0: } michael@0: michael@0: /* Parse and display signature */ michael@0: SECU_PrintAlgorithmID(out, &(info->digestEncAlg), michael@0: "Digest Encryption Algorithm", level + 1); michael@0: SECU_PrintAsHex(out, &(info->encDigest), "Encrypted Digest", level + 1); michael@0: michael@0: if (info->unAuthAttr != NULL) { michael@0: SECU_Indent(out, level + 1); michael@0: fprintf(out, "Unauthenticated Attributes:\n"); michael@0: iv = 0; michael@0: while ((attr = info->unAuthAttr[iv++]) != NULL) { michael@0: sprintf(om, "Attribute (%x)", iv); michael@0: secu_PrintAttribute(out, attr, om, level + 2); michael@0: } michael@0: } michael@0: } michael@0: michael@0: /* callers of this function must make sure that the CERTSignedCrl michael@0: from which they are extracting the CERTCrl has been fully-decoded. michael@0: Otherwise it will not have the entries even though the CRL may have michael@0: some */ michael@0: michael@0: void michael@0: SECU_PrintCRLInfo(FILE *out, CERTCrl *crl, char *m, int level) michael@0: { michael@0: CERTCrlEntry *entry; michael@0: int iv; michael@0: char om[100]; michael@0: michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: /* version is optional */ michael@0: iv = crl->version.len ? DER_GetInteger(&crl->version) : 0; michael@0: SECU_Indent(out, level+1); michael@0: fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv); michael@0: SECU_PrintAlgorithmID(out, &(crl->signatureAlg), "Signature Algorithm", michael@0: level + 1); michael@0: SECU_PrintName(out, &(crl->name), "Issuer", level + 1); michael@0: SECU_PrintTimeChoice(out, &(crl->lastUpdate), "This Update", level + 1); michael@0: if (crl->nextUpdate.data && crl->nextUpdate.len) /* is optional */ michael@0: SECU_PrintTimeChoice(out, &(crl->nextUpdate), "Next Update", level + 1); michael@0: michael@0: if (crl->entries != NULL) { michael@0: iv = 0; michael@0: while ((entry = crl->entries[iv++]) != NULL) { michael@0: sprintf(om, "Entry %d (0x%x):\n", iv, iv); michael@0: SECU_Indent(out, level + 1); fputs(om, out); michael@0: SECU_PrintInteger(out, &(entry->serialNumber), "Serial Number", michael@0: level + 2); michael@0: SECU_PrintTimeChoice(out, &(entry->revocationDate), michael@0: "Revocation Date", level + 2); michael@0: SECU_PrintExtensions(out, entry->extensions, michael@0: "Entry Extensions", level + 2); michael@0: } michael@0: } michael@0: SECU_PrintExtensions(out, crl->extensions, "CRL Extensions", level + 1); michael@0: } michael@0: michael@0: /* michael@0: ** secu_PrintPKCS7Signed michael@0: ** Pretty print a PKCS7 signed data type (up to version 1). michael@0: */ michael@0: static int michael@0: secu_PrintPKCS7Signed(FILE *out, SEC_PKCS7SignedData *src, michael@0: const char *m, int level) michael@0: { michael@0: SECAlgorithmID *digAlg; /* digest algorithms */ michael@0: SECItem *aCert; /* certificate */ michael@0: CERTSignedCrl *aCrl; /* certificate revocation list */ michael@0: SEC_PKCS7SignerInfo *sigInfo; /* signer information */ michael@0: int rv, iv; michael@0: char om[100]; michael@0: michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: SECU_PrintInteger(out, &(src->version), "Version", level + 1); michael@0: michael@0: /* Parse and list digest algorithms (if any) */ michael@0: if (src->digestAlgorithms != NULL) { michael@0: SECU_Indent(out, level + 1); fprintf(out, "Digest Algorithm List:\n"); michael@0: iv = 0; michael@0: while ((digAlg = src->digestAlgorithms[iv++]) != NULL) { michael@0: sprintf(om, "Digest Algorithm (%x)", iv); michael@0: SECU_PrintAlgorithmID(out, digAlg, om, level + 2); michael@0: } michael@0: } michael@0: michael@0: /* Now for the content */ michael@0: rv = secu_PrintPKCS7ContentInfo(out, &(src->contentInfo), michael@0: "Content Information", level + 1); michael@0: if (rv != 0) michael@0: return rv; michael@0: michael@0: /* Parse and list certificates (if any) */ michael@0: if (src->rawCerts != NULL) { michael@0: SECU_Indent(out, level + 1); fprintf(out, "Certificate List:\n"); michael@0: iv = 0; michael@0: while ((aCert = src->rawCerts[iv++]) != NULL) { michael@0: sprintf(om, "Certificate (%x)", iv); michael@0: rv = SECU_PrintSignedData(out, aCert, om, level + 2, michael@0: SECU_PrintCertificate); michael@0: if (rv) michael@0: return rv; michael@0: } michael@0: } michael@0: michael@0: /* Parse and list CRL's (if any) */ michael@0: if (src->crls != NULL) { michael@0: SECU_Indent(out, level + 1); michael@0: fprintf(out, "Signed Revocation Lists:\n"); michael@0: iv = 0; michael@0: while ((aCrl = src->crls[iv++]) != NULL) { michael@0: sprintf(om, "Signed Revocation List (%x)", iv); michael@0: SECU_Indent(out, level + 2); fprintf(out, "%s:\n", om); michael@0: SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm, michael@0: "Signature Algorithm", level+3); michael@0: DER_ConvertBitString(&aCrl->signatureWrap.signature); michael@0: SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature", michael@0: level+3); michael@0: SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List", michael@0: level + 3); michael@0: } michael@0: } michael@0: michael@0: /* Parse and list signatures (if any) */ michael@0: if (src->signerInfos != NULL) { michael@0: SECU_Indent(out, level + 1); michael@0: fprintf(out, "Signer Information List:\n"); michael@0: iv = 0; michael@0: while ((sigInfo = src->signerInfos[iv++]) != NULL) { michael@0: sprintf(om, "Signer Information (%x)", iv); michael@0: secu_PrintSignerInfo(out, sigInfo, om, level + 2); michael@0: } michael@0: } michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: /* michael@0: ** secu_PrintPKCS7Enveloped michael@0: ** Pretty print a PKCS7 enveloped data type (up to version 1). michael@0: */ michael@0: static void michael@0: secu_PrintPKCS7Enveloped(FILE *out, SEC_PKCS7EnvelopedData *src, michael@0: const char *m, int level) michael@0: { michael@0: SEC_PKCS7RecipientInfo *recInfo; /* pointer for signer information */ michael@0: int iv; michael@0: char om[100]; michael@0: michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: SECU_PrintInteger(out, &(src->version), "Version", level + 1); michael@0: michael@0: /* Parse and list recipients (this is not optional) */ michael@0: if (src->recipientInfos != NULL) { michael@0: SECU_Indent(out, level + 1); michael@0: fprintf(out, "Recipient Information List:\n"); michael@0: iv = 0; michael@0: while ((recInfo = src->recipientInfos[iv++]) != NULL) { michael@0: sprintf(om, "Recipient Information (%x)", iv); michael@0: secu_PrintRecipientInfo(out, recInfo, om, level + 2); michael@0: } michael@0: } michael@0: michael@0: secu_PrintPKCS7EncContent(out, &src->encContentInfo, michael@0: "Encrypted Content Information", level + 1); michael@0: } michael@0: michael@0: /* michael@0: ** secu_PrintPKCS7SignedEnveloped michael@0: ** Pretty print a PKCS7 singed and enveloped data type (up to version 1). michael@0: */ michael@0: static int michael@0: secu_PrintPKCS7SignedAndEnveloped(FILE *out, michael@0: SEC_PKCS7SignedAndEnvelopedData *src, michael@0: const char *m, int level) michael@0: { michael@0: SECAlgorithmID *digAlg; /* pointer for digest algorithms */ michael@0: SECItem *aCert; /* pointer for certificate */ michael@0: CERTSignedCrl *aCrl; /* pointer for certificate revocation list */ michael@0: SEC_PKCS7SignerInfo *sigInfo; /* pointer for signer information */ michael@0: SEC_PKCS7RecipientInfo *recInfo; /* pointer for recipient information */ michael@0: int rv, iv; michael@0: char om[100]; michael@0: michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: SECU_PrintInteger(out, &(src->version), "Version", level + 1); michael@0: michael@0: /* Parse and list recipients (this is not optional) */ michael@0: if (src->recipientInfos != NULL) { michael@0: SECU_Indent(out, level + 1); michael@0: fprintf(out, "Recipient Information List:\n"); michael@0: iv = 0; michael@0: while ((recInfo = src->recipientInfos[iv++]) != NULL) { michael@0: sprintf(om, "Recipient Information (%x)", iv); michael@0: secu_PrintRecipientInfo(out, recInfo, om, level + 2); michael@0: } michael@0: } michael@0: michael@0: /* Parse and list digest algorithms (if any) */ michael@0: if (src->digestAlgorithms != NULL) { michael@0: SECU_Indent(out, level + 1); fprintf(out, "Digest Algorithm List:\n"); michael@0: iv = 0; michael@0: while ((digAlg = src->digestAlgorithms[iv++]) != NULL) { michael@0: sprintf(om, "Digest Algorithm (%x)", iv); michael@0: SECU_PrintAlgorithmID(out, digAlg, om, level + 2); michael@0: } michael@0: } michael@0: michael@0: secu_PrintPKCS7EncContent(out, &src->encContentInfo, michael@0: "Encrypted Content Information", level + 1); michael@0: michael@0: /* Parse and list certificates (if any) */ michael@0: if (src->rawCerts != NULL) { michael@0: SECU_Indent(out, level + 1); fprintf(out, "Certificate List:\n"); michael@0: iv = 0; michael@0: while ((aCert = src->rawCerts[iv++]) != NULL) { michael@0: sprintf(om, "Certificate (%x)", iv); michael@0: rv = SECU_PrintSignedData(out, aCert, om, level + 2, michael@0: SECU_PrintCertificate); michael@0: if (rv) michael@0: return rv; michael@0: } michael@0: } michael@0: michael@0: /* Parse and list CRL's (if any) */ michael@0: if (src->crls != NULL) { michael@0: SECU_Indent(out, level + 1); michael@0: fprintf(out, "Signed Revocation Lists:\n"); michael@0: iv = 0; michael@0: while ((aCrl = src->crls[iv++]) != NULL) { michael@0: sprintf(om, "Signed Revocation List (%x)", iv); michael@0: SECU_Indent(out, level + 2); fprintf(out, "%s:\n", om); michael@0: SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm, michael@0: "Signature Algorithm", level+3); michael@0: DER_ConvertBitString(&aCrl->signatureWrap.signature); michael@0: SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature", michael@0: level+3); michael@0: SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List", michael@0: level + 3); michael@0: } michael@0: } michael@0: michael@0: /* Parse and list signatures (if any) */ michael@0: if (src->signerInfos != NULL) { michael@0: SECU_Indent(out, level + 1); michael@0: fprintf(out, "Signer Information List:\n"); michael@0: iv = 0; michael@0: while ((sigInfo = src->signerInfos[iv++]) != NULL) { michael@0: sprintf(om, "Signer Information (%x)", iv); michael@0: secu_PrintSignerInfo(out, sigInfo, om, level + 2); michael@0: } michael@0: } michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: int michael@0: SECU_PrintCrl (FILE *out, SECItem *der, char *m, int level) michael@0: { michael@0: PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: CERTCrl *c = NULL; michael@0: int rv = SEC_ERROR_NO_MEMORY; michael@0: michael@0: if (!arena) michael@0: return rv; michael@0: do { michael@0: /* Decode CRL */ michael@0: c = PORT_ArenaZNew(arena, CERTCrl); michael@0: if (!c) michael@0: break; michael@0: michael@0: rv = SEC_QuickDERDecodeItem(arena, c, SEC_ASN1_GET(CERT_CrlTemplate), der); michael@0: if (rv != SECSuccess) michael@0: break; michael@0: SECU_PrintCRLInfo (out, c, m, level); michael@0: } while (0); michael@0: PORT_FreeArena (arena, PR_FALSE); michael@0: return rv; michael@0: } michael@0: michael@0: michael@0: /* michael@0: ** secu_PrintPKCS7Encrypted michael@0: ** Pretty print a PKCS7 encrypted data type (up to version 1). michael@0: */ michael@0: static void michael@0: secu_PrintPKCS7Encrypted(FILE *out, SEC_PKCS7EncryptedData *src, michael@0: const char *m, int level) michael@0: { michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: SECU_PrintInteger(out, &(src->version), "Version", level + 1); michael@0: michael@0: secu_PrintPKCS7EncContent(out, &src->encContentInfo, michael@0: "Encrypted Content Information", level + 1); michael@0: } michael@0: michael@0: /* michael@0: ** secu_PrintPKCS7Digested michael@0: ** Pretty print a PKCS7 digested data type (up to version 1). michael@0: */ michael@0: static void michael@0: secu_PrintPKCS7Digested(FILE *out, SEC_PKCS7DigestedData *src, michael@0: const char *m, int level) michael@0: { michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: SECU_PrintInteger(out, &(src->version), "Version", level + 1); michael@0: michael@0: SECU_PrintAlgorithmID(out, &src->digestAlg, "Digest Algorithm", michael@0: level + 1); michael@0: secu_PrintPKCS7ContentInfo(out, &src->contentInfo, "Content Information", michael@0: level + 1); michael@0: SECU_PrintAsHex(out, &src->digest, "Digest", level + 1); michael@0: } michael@0: michael@0: /* michael@0: ** secu_PrintPKCS7ContentInfo michael@0: ** Takes a SEC_PKCS7ContentInfo type and sends the contents to the michael@0: ** appropriate function michael@0: */ michael@0: static int michael@0: secu_PrintPKCS7ContentInfo(FILE *out, SEC_PKCS7ContentInfo *src, michael@0: char *m, int level) michael@0: { michael@0: const char *desc; michael@0: SECOidTag kind; michael@0: int rv; michael@0: michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: level++; michael@0: michael@0: if (src->contentTypeTag == NULL) michael@0: src->contentTypeTag = SECOID_FindOID(&(src->contentType)); michael@0: michael@0: if (src->contentTypeTag == NULL) { michael@0: desc = "Unknown"; michael@0: kind = SEC_OID_PKCS7_DATA; michael@0: } else { michael@0: desc = src->contentTypeTag->desc; michael@0: kind = src->contentTypeTag->offset; michael@0: } michael@0: michael@0: if (src->content.data == NULL) { michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", desc); michael@0: level++; michael@0: SECU_Indent(out, level); fprintf(out, "\n"); michael@0: return 0; michael@0: } michael@0: michael@0: rv = 0; michael@0: switch (kind) { michael@0: case SEC_OID_PKCS7_SIGNED_DATA: /* Signed Data */ michael@0: rv = secu_PrintPKCS7Signed(out, src->content.signedData, desc, level); michael@0: break; michael@0: michael@0: case SEC_OID_PKCS7_ENVELOPED_DATA: /* Enveloped Data */ michael@0: secu_PrintPKCS7Enveloped(out, src->content.envelopedData, desc, level); michael@0: break; michael@0: michael@0: case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: /* Signed and Enveloped */ michael@0: rv = secu_PrintPKCS7SignedAndEnveloped(out, michael@0: src->content.signedAndEnvelopedData, michael@0: desc, level); michael@0: break; michael@0: michael@0: case SEC_OID_PKCS7_DIGESTED_DATA: /* Digested Data */ michael@0: secu_PrintPKCS7Digested(out, src->content.digestedData, desc, level); michael@0: break; michael@0: michael@0: case SEC_OID_PKCS7_ENCRYPTED_DATA: /* Encrypted Data */ michael@0: secu_PrintPKCS7Encrypted(out, src->content.encryptedData, desc, level); michael@0: break; michael@0: michael@0: default: michael@0: SECU_PrintAsHex(out, src->content.data, desc, level); michael@0: break; michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: /* michael@0: ** SECU_PrintPKCS7ContentInfo michael@0: ** Decode and print any major PKCS7 data type (up to version 1). michael@0: */ michael@0: int michael@0: SECU_PrintPKCS7ContentInfo(FILE *out, SECItem *der, char *m, int level) michael@0: { michael@0: SEC_PKCS7ContentInfo *cinfo; michael@0: int rv; michael@0: michael@0: cinfo = SEC_PKCS7DecodeItem(der, NULL, NULL, NULL, NULL, NULL, NULL, NULL); michael@0: if (cinfo != NULL) { michael@0: /* Send it to recursive parsing and printing module */ michael@0: rv = secu_PrintPKCS7ContentInfo(out, cinfo, m, level); michael@0: SEC_PKCS7DestroyContentInfo(cinfo); michael@0: } else { michael@0: rv = -1; michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: /* michael@0: ** End of PKCS7 functions michael@0: */ michael@0: michael@0: void michael@0: printFlags(FILE *out, unsigned int flags, int level) michael@0: { michael@0: if ( flags & CERTDB_TERMINAL_RECORD ) { michael@0: SECU_Indent(out, level); fprintf(out, "Terminal Record\n"); michael@0: } michael@0: if ( flags & CERTDB_TRUSTED ) { michael@0: SECU_Indent(out, level); fprintf(out, "Trusted\n"); michael@0: } michael@0: if ( flags & CERTDB_SEND_WARN ) { michael@0: SECU_Indent(out, level); fprintf(out, "Warn When Sending\n"); michael@0: } michael@0: if ( flags & CERTDB_VALID_CA ) { michael@0: SECU_Indent(out, level); fprintf(out, "Valid CA\n"); michael@0: } michael@0: if ( flags & CERTDB_TRUSTED_CA ) { michael@0: SECU_Indent(out, level); fprintf(out, "Trusted CA\n"); michael@0: } michael@0: if ( flags & CERTDB_NS_TRUSTED_CA ) { michael@0: SECU_Indent(out, level); fprintf(out, "Netscape Trusted CA\n"); michael@0: } michael@0: if ( flags & CERTDB_USER ) { michael@0: SECU_Indent(out, level); fprintf(out, "User\n"); michael@0: } michael@0: if ( flags & CERTDB_TRUSTED_CLIENT_CA ) { michael@0: SECU_Indent(out, level); fprintf(out, "Trusted Client CA\n"); michael@0: } michael@0: if ( flags & CERTDB_GOVT_APPROVED_CA ) { michael@0: SECU_Indent(out, level); fprintf(out, "Step-up\n"); michael@0: } michael@0: } michael@0: michael@0: void michael@0: SECU_PrintTrustFlags(FILE *out, CERTCertTrust *trust, char *m, int level) michael@0: { michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: SECU_Indent(out, level+1); fprintf(out, "SSL Flags:\n"); michael@0: printFlags(out, trust->sslFlags, level+2); michael@0: SECU_Indent(out, level+1); fprintf(out, "Email Flags:\n"); michael@0: printFlags(out, trust->emailFlags, level+2); michael@0: SECU_Indent(out, level+1); fprintf(out, "Object Signing Flags:\n"); michael@0: printFlags(out, trust->objectSigningFlags, level+2); michael@0: } michael@0: michael@0: int SECU_PrintDERName(FILE *out, SECItem *der, const char *m, int level) michael@0: { michael@0: PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: CERTName *name; michael@0: int rv = SEC_ERROR_NO_MEMORY; michael@0: michael@0: if (!arena) michael@0: return rv; michael@0: michael@0: name = PORT_ArenaZNew(arena, CERTName); michael@0: if (!name) michael@0: goto loser; michael@0: michael@0: rv = SEC_ASN1DecodeItem(arena, name, SEC_ASN1_GET(CERT_NameTemplate), der); michael@0: if (rv) michael@0: goto loser; michael@0: michael@0: SECU_PrintName(out, name, m, level); michael@0: if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/ michael@0: SECU_Newline(out); michael@0: loser: michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: return rv; michael@0: } michael@0: michael@0: typedef enum { michael@0: noSignature = 0, michael@0: withSignature = 1 michael@0: } SignatureOptionType; michael@0: michael@0: static int michael@0: secu_PrintSignedDataSigOpt(FILE *out, SECItem *der, const char *m, michael@0: int level, SECU_PPFunc inner, michael@0: SignatureOptionType withSignature) michael@0: { michael@0: PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: CERTSignedData *sd; michael@0: int rv = SEC_ERROR_NO_MEMORY; michael@0: michael@0: if (!arena) michael@0: return rv; michael@0: michael@0: /* Strip off the signature */ michael@0: sd = PORT_ArenaZNew(arena, CERTSignedData); michael@0: if (!sd) michael@0: goto loser; michael@0: michael@0: rv = SEC_ASN1DecodeItem(arena, sd, SEC_ASN1_GET(CERT_SignedDataTemplate), michael@0: der); michael@0: if (rv) michael@0: goto loser; michael@0: michael@0: if (m) { michael@0: SECU_Indent(out, level); fprintf(out, "%s:\n", m); michael@0: } else { michael@0: level -= 1; michael@0: } michael@0: rv = (*inner)(out, &sd->data, "Data", level+1); michael@0: michael@0: if (withSignature) { michael@0: SECU_PrintAlgorithmID(out, &sd->signatureAlgorithm, "Signature Algorithm", michael@0: level+1); michael@0: DER_ConvertBitString(&sd->signature); michael@0: SECU_PrintAsHex(out, &sd->signature, "Signature", level+1); michael@0: } michael@0: SECU_PrintFingerprints(out, der, "Fingerprint", level+1); michael@0: loser: michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: return rv; michael@0: } michael@0: michael@0: int SECU_PrintSignedData(FILE *out, SECItem *der, const char *m, michael@0: int level, SECU_PPFunc inner) michael@0: { michael@0: return secu_PrintSignedDataSigOpt(out, der, m, level, inner, michael@0: withSignature); michael@0: } michael@0: michael@0: int SECU_PrintSignedContent(FILE *out, SECItem *der, char *m, michael@0: int level, SECU_PPFunc inner) michael@0: { michael@0: return secu_PrintSignedDataSigOpt(out, der, m, level, inner, michael@0: noSignature); michael@0: } michael@0: michael@0: SECStatus michael@0: SEC_PrintCertificateAndTrust(CERTCertificate *cert, michael@0: const char *label, michael@0: CERTCertTrust *trust) michael@0: { michael@0: SECStatus rv; michael@0: SECItem data; michael@0: CERTCertTrust certTrust; michael@0: michael@0: data.data = cert->derCert.data; michael@0: data.len = cert->derCert.len; michael@0: michael@0: rv = SECU_PrintSignedData(stdout, &data, label, 0, michael@0: SECU_PrintCertificate); michael@0: if (rv) { michael@0: return(SECFailure); michael@0: } michael@0: if (trust) { michael@0: SECU_PrintTrustFlags(stdout, trust, michael@0: "Certificate Trust Flags", 1); michael@0: } else if (CERT_GetCertTrust(cert, &certTrust) == SECSuccess) { michael@0: SECU_PrintTrustFlags(stdout, &certTrust, michael@0: "Certificate Trust Flags", 1); michael@0: } michael@0: michael@0: printf("\n"); michael@0: michael@0: return(SECSuccess); michael@0: } michael@0: michael@0: michael@0: static char * michael@0: bestCertName(CERTCertificate *cert) { michael@0: if (cert->nickname) { michael@0: return cert->nickname; michael@0: } michael@0: if (cert->emailAddr && cert->emailAddr[0]) { michael@0: return cert->emailAddr; michael@0: } michael@0: return cert->subjectName; michael@0: } michael@0: michael@0: void michael@0: SECU_printCertProblemsOnDate(FILE *outfile, CERTCertDBHandle *handle, michael@0: CERTCertificate *cert, PRBool checksig, michael@0: SECCertificateUsage certUsage, void *pinArg, PRBool verbose, michael@0: PRTime datetime) michael@0: { michael@0: CERTVerifyLog log; michael@0: CERTVerifyLogNode *node; michael@0: michael@0: PRErrorCode err = PORT_GetError(); michael@0: michael@0: log.arena = PORT_NewArena(512); michael@0: log.head = log.tail = NULL; michael@0: log.count = 0; michael@0: CERT_VerifyCertificate(handle, cert, checksig, certUsage, datetime, pinArg, &log, NULL); michael@0: michael@0: SECU_displayVerifyLog(outfile, &log, verbose); michael@0: michael@0: for (node = log.head; node; node = node->next) { michael@0: if (node->cert) michael@0: CERT_DestroyCertificate(node->cert); michael@0: } michael@0: PORT_FreeArena(log.arena, PR_FALSE); michael@0: michael@0: PORT_SetError(err); /* restore original error code */ michael@0: } michael@0: michael@0: void michael@0: SECU_displayVerifyLog(FILE *outfile, CERTVerifyLog *log, michael@0: PRBool verbose) michael@0: { michael@0: CERTVerifyLogNode *node = NULL; michael@0: unsigned int depth = (unsigned int)-1; michael@0: unsigned int flags = 0; michael@0: char * errstr = NULL; michael@0: michael@0: if (log->count > 0) { michael@0: fprintf(outfile,"PROBLEM WITH THE CERT CHAIN:\n"); michael@0: for (node = log->head; node; node = node->next) { michael@0: if (depth != node->depth) { michael@0: depth = node->depth; michael@0: fprintf(outfile,"CERT %d. %s %s:\n", depth, michael@0: bestCertName(node->cert), michael@0: depth ? "[Certificate Authority]": ""); michael@0: if (verbose) { michael@0: const char * emailAddr; michael@0: emailAddr = CERT_GetFirstEmailAddress(node->cert); michael@0: if (emailAddr) { michael@0: fprintf(outfile,"Email Address(es): "); michael@0: do { michael@0: fprintf(outfile, "%s\n", emailAddr); michael@0: emailAddr = CERT_GetNextEmailAddress(node->cert, michael@0: emailAddr); michael@0: } while (emailAddr); michael@0: } michael@0: } michael@0: } michael@0: fprintf(outfile, " ERROR %ld: %s\n", node->error, michael@0: SECU_Strerror(node->error)); michael@0: errstr = NULL; michael@0: switch (node->error) { michael@0: case SEC_ERROR_INADEQUATE_KEY_USAGE: michael@0: flags = (unsigned int)node->arg; michael@0: switch (flags) { michael@0: case KU_DIGITAL_SIGNATURE: michael@0: errstr = "Cert cannot sign."; michael@0: break; michael@0: case KU_KEY_ENCIPHERMENT: michael@0: errstr = "Cert cannot encrypt."; michael@0: break; michael@0: case KU_KEY_CERT_SIGN: michael@0: errstr = "Cert cannot sign other certs."; michael@0: break; michael@0: default: michael@0: errstr = "[unknown usage]."; michael@0: break; michael@0: } michael@0: case SEC_ERROR_INADEQUATE_CERT_TYPE: michael@0: flags = (unsigned int)node->arg; michael@0: switch (flags) { michael@0: case NS_CERT_TYPE_SSL_CLIENT: michael@0: case NS_CERT_TYPE_SSL_SERVER: michael@0: errstr = "Cert cannot be used for SSL."; michael@0: break; michael@0: case NS_CERT_TYPE_SSL_CA: michael@0: errstr = "Cert cannot be used as an SSL CA."; michael@0: break; michael@0: case NS_CERT_TYPE_EMAIL: michael@0: errstr = "Cert cannot be used for SMIME."; michael@0: break; michael@0: case NS_CERT_TYPE_EMAIL_CA: michael@0: errstr = "Cert cannot be used as an SMIME CA."; michael@0: break; michael@0: case NS_CERT_TYPE_OBJECT_SIGNING: michael@0: errstr = "Cert cannot be used for object signing."; michael@0: break; michael@0: case NS_CERT_TYPE_OBJECT_SIGNING_CA: michael@0: errstr = "Cert cannot be used as an object signing CA."; michael@0: break; michael@0: default: michael@0: errstr = "[unknown usage]."; michael@0: break; michael@0: } michael@0: case SEC_ERROR_UNKNOWN_ISSUER: michael@0: case SEC_ERROR_UNTRUSTED_ISSUER: michael@0: case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: michael@0: errstr = node->cert->issuerName; michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: if (errstr) { michael@0: fprintf(stderr," %s\n",errstr); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: SECU_printCertProblems(FILE *outfile, CERTCertDBHandle *handle, michael@0: CERTCertificate *cert, PRBool checksig, michael@0: SECCertificateUsage certUsage, void *pinArg, PRBool verbose) michael@0: { michael@0: SECU_printCertProblemsOnDate(outfile, handle, cert, checksig, michael@0: certUsage, pinArg, verbose, PR_Now()); michael@0: } michael@0: michael@0: SECStatus michael@0: SECU_StoreCRL(PK11SlotInfo *slot, SECItem *derCrl, PRFileDesc *outFile, michael@0: PRBool ascii, char *url) michael@0: { michael@0: PORT_Assert(derCrl != NULL); michael@0: if (!derCrl) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return SECFailure; michael@0: } michael@0: michael@0: if (outFile != NULL) { michael@0: if (ascii) { michael@0: PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CRL_HEADER, michael@0: BTOA_DataToAscii(derCrl->data, derCrl->len), michael@0: NS_CRL_TRAILER); michael@0: } else { michael@0: if (PR_Write(outFile, derCrl->data, derCrl->len) != derCrl->len) { michael@0: return SECFailure; michael@0: } michael@0: } michael@0: } michael@0: if (slot) { michael@0: CERTSignedCrl *newCrl = PK11_ImportCRL(slot, derCrl, url, michael@0: SEC_CRL_TYPE, NULL, 0, NULL, 0); michael@0: if (newCrl != NULL) { michael@0: SEC_DestroyCrl(newCrl); michael@0: return SECSuccess; michael@0: } michael@0: return SECFailure; michael@0: } michael@0: if (!outFile && !slot) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return SECFailure; michael@0: } michael@0: return SECSuccess; michael@0: } michael@0: michael@0: SECStatus michael@0: SECU_SignAndEncodeCRL(CERTCertificate *issuer, CERTSignedCrl *signCrl, michael@0: SECOidTag hashAlgTag, SignAndEncodeFuncExitStat *resCode) michael@0: { michael@0: SECItem der; michael@0: SECKEYPrivateKey *caPrivateKey = NULL; michael@0: SECStatus rv; michael@0: PLArenaPool *arena; michael@0: SECOidTag algID; michael@0: void *dummy; michael@0: michael@0: PORT_Assert(issuer != NULL && signCrl != NULL); michael@0: if (!issuer || !signCrl) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return SECFailure; michael@0: } michael@0: michael@0: arena = signCrl->arena; michael@0: michael@0: caPrivateKey = PK11_FindKeyByAnyCert(issuer, NULL); michael@0: if (caPrivateKey == NULL) { michael@0: *resCode = noKeyFound; michael@0: return SECFailure; michael@0: } michael@0: michael@0: algID = SEC_GetSignatureAlgorithmOidTag(caPrivateKey->keyType, hashAlgTag); michael@0: if (algID == SEC_OID_UNKNOWN) { michael@0: *resCode = noSignatureMatch; michael@0: rv = SECFailure; michael@0: goto done; michael@0: } michael@0: michael@0: if (!signCrl->crl.signatureAlg.parameters.data) { michael@0: rv = SECOID_SetAlgorithmID(arena, &signCrl->crl.signatureAlg, algID, 0); michael@0: if (rv != SECSuccess) { michael@0: *resCode = failToEncode; michael@0: goto done; michael@0: } michael@0: } michael@0: michael@0: der.len = 0; michael@0: der.data = NULL; michael@0: dummy = SEC_ASN1EncodeItem(arena, &der, &signCrl->crl, michael@0: SEC_ASN1_GET(CERT_CrlTemplate)); michael@0: if (!dummy) { michael@0: *resCode = failToEncode; michael@0: rv = SECFailure; michael@0: goto done; michael@0: } michael@0: michael@0: rv = SECU_DerSignDataCRL(arena, &signCrl->signatureWrap, michael@0: der.data, der.len, caPrivateKey, algID); michael@0: if (rv != SECSuccess) { michael@0: *resCode = failToSign; michael@0: goto done; michael@0: } michael@0: michael@0: signCrl->derCrl = PORT_ArenaZNew(arena, SECItem); michael@0: if (signCrl->derCrl == NULL) { michael@0: *resCode = noMem; michael@0: PORT_SetError(SEC_ERROR_NO_MEMORY); michael@0: rv = SECFailure; michael@0: goto done; michael@0: } michael@0: michael@0: signCrl->derCrl->len = 0; michael@0: signCrl->derCrl->data = NULL; michael@0: dummy = SEC_ASN1EncodeItem (arena, signCrl->derCrl, signCrl, michael@0: SEC_ASN1_GET(CERT_SignedCrlTemplate)); michael@0: if (!dummy) { michael@0: *resCode = failToEncode; michael@0: rv = SECFailure; michael@0: goto done; michael@0: } michael@0: michael@0: done: michael@0: if (caPrivateKey) { michael@0: SECKEY_DestroyPrivateKey(caPrivateKey); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: michael@0: michael@0: SECStatus michael@0: SECU_CopyCRL(PLArenaPool *destArena, CERTCrl *destCrl, CERTCrl *srcCrl) michael@0: { michael@0: void *dummy; michael@0: SECStatus rv = SECSuccess; michael@0: SECItem der; michael@0: michael@0: PORT_Assert(destArena && srcCrl && destCrl); michael@0: if (!destArena || !srcCrl || !destCrl) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return SECFailure; michael@0: } michael@0: michael@0: der.len = 0; michael@0: der.data = NULL; michael@0: dummy = SEC_ASN1EncodeItem (destArena, &der, srcCrl, michael@0: SEC_ASN1_GET(CERT_CrlTemplate)); michael@0: if (!dummy) { michael@0: return SECFailure; michael@0: } michael@0: michael@0: rv = SEC_QuickDERDecodeItem(destArena, destCrl, michael@0: SEC_ASN1_GET(CERT_CrlTemplate), &der); michael@0: if (rv != SECSuccess) { michael@0: return SECFailure; michael@0: } michael@0: michael@0: destCrl->arena = destArena; michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: SECStatus michael@0: SECU_DerSignDataCRL(PLArenaPool *arena, CERTSignedData *sd, michael@0: unsigned char *buf, int len, SECKEYPrivateKey *pk, michael@0: SECOidTag algID) michael@0: { michael@0: SECItem it; michael@0: SECStatus rv; michael@0: michael@0: it.data = 0; michael@0: michael@0: /* XXX We should probably have some asserts here to make sure the key type michael@0: * and algID match michael@0: */ michael@0: michael@0: /* Sign input buffer */ michael@0: rv = SEC_SignData(&it, buf, len, pk, algID); michael@0: if (rv) goto loser; michael@0: michael@0: /* Fill out SignedData object */ michael@0: PORT_Memset(sd, 0, sizeof(*sd)); michael@0: sd->data.data = buf; michael@0: sd->data.len = len; michael@0: sd->signature.data = it.data; michael@0: sd->signature.len = it.len << 3; /* convert to bit string */ michael@0: rv = SECOID_SetAlgorithmID(arena, &sd->signatureAlgorithm, algID, 0); michael@0: if (rv) goto loser; michael@0: michael@0: return rv; michael@0: michael@0: loser: michael@0: PORT_Free(it.data); michael@0: return rv; michael@0: } michael@0: michael@0: #if 0 michael@0: michael@0: /* we need access to the private function cert_FindExtension for this code to work */ michael@0: michael@0: CERTAuthKeyID * michael@0: SECU_FindCRLAuthKeyIDExten (PLArenaPool *arena, CERTSignedCrl *scrl) michael@0: { michael@0: SECItem encodedExtenValue; michael@0: SECStatus rv; michael@0: CERTAuthKeyID *ret; michael@0: CERTCrl* crl; michael@0: michael@0: if (!scrl) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return NULL; michael@0: } michael@0: michael@0: crl = &scrl->crl; michael@0: michael@0: encodedExtenValue.data = NULL; michael@0: encodedExtenValue.len = 0; michael@0: michael@0: rv = cert_FindExtension(crl->extensions, SEC_OID_X509_AUTH_KEY_ID, michael@0: &encodedExtenValue); michael@0: if ( rv != SECSuccess ) { michael@0: return (NULL); michael@0: } michael@0: michael@0: ret = CERT_DecodeAuthKeyID (arena, &encodedExtenValue); michael@0: michael@0: PORT_Free(encodedExtenValue.data); michael@0: encodedExtenValue.data = NULL; michael@0: michael@0: return(ret); michael@0: } michael@0: michael@0: #endif michael@0: michael@0: /* michael@0: * Find the issuer of a Crl. Use the authorityKeyID if it exists. michael@0: */ michael@0: CERTCertificate * michael@0: SECU_FindCrlIssuer(CERTCertDBHandle *dbhandle, SECItem* subject, michael@0: CERTAuthKeyID* authorityKeyID, PRTime validTime) michael@0: { michael@0: CERTCertificate *issuerCert = NULL; michael@0: CERTCertList *certList = NULL; michael@0: CERTCertTrust trust; michael@0: michael@0: if (!subject) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return NULL; michael@0: } michael@0: michael@0: certList = michael@0: CERT_CreateSubjectCertList(NULL, dbhandle, subject, michael@0: validTime, PR_TRUE); michael@0: if (certList) { michael@0: CERTCertListNode *node = CERT_LIST_HEAD(certList); michael@0: michael@0: /* XXX and authoritykeyid in the future */ michael@0: while ( ! CERT_LIST_END(node, certList) ) { michael@0: CERTCertificate *cert = node->cert; michael@0: /* check cert CERTCertTrust data is allocated, check cert michael@0: usage extension, check that cert has pkey in db. Select michael@0: the first (newest) user cert */ michael@0: if (CERT_GetCertTrust(cert, &trust) == SECSuccess && michael@0: CERT_CheckCertUsage(cert, KU_CRL_SIGN) == SECSuccess && michael@0: CERT_IsUserCert(cert)) { michael@0: michael@0: issuerCert = CERT_DupCertificate(cert); michael@0: break; michael@0: } michael@0: node = CERT_LIST_NEXT(node); michael@0: } michael@0: CERT_DestroyCertList(certList); michael@0: } michael@0: return(issuerCert); michael@0: } michael@0: michael@0: michael@0: /* Encodes and adds extensions to the CRL or CRL entries. */ michael@0: SECStatus michael@0: SECU_EncodeAndAddExtensionValue(PLArenaPool *arena, void *extHandle, michael@0: void *value, PRBool criticality, int extenType, michael@0: EXTEN_EXT_VALUE_ENCODER EncodeValueFn) michael@0: { michael@0: SECItem encodedValue; michael@0: SECStatus rv; michael@0: michael@0: encodedValue.data = NULL; michael@0: encodedValue.len = 0; michael@0: do { michael@0: rv = (*EncodeValueFn)(arena, value, &encodedValue); michael@0: if (rv != SECSuccess) michael@0: break; michael@0: michael@0: rv = CERT_AddExtension(extHandle, extenType, &encodedValue, michael@0: criticality, PR_TRUE); michael@0: if (rv != SECSuccess) michael@0: break; michael@0: } while (0); michael@0: michael@0: return (rv); michael@0: } michael@0: michael@0: CERTCertificate* michael@0: SECU_FindCertByNicknameOrFilename(CERTCertDBHandle *handle, michael@0: char *name, PRBool ascii, michael@0: void *pwarg) michael@0: { michael@0: CERTCertificate *the_cert; michael@0: the_cert = CERT_FindCertByNicknameOrEmailAddr(handle, name); michael@0: if (the_cert) { michael@0: return the_cert; michael@0: } michael@0: the_cert = PK11_FindCertFromNickname(name, pwarg); michael@0: if (!the_cert) { michael@0: /* Don't have a cert with name "name" in the DB. Try to michael@0: * open a file with such name and get the cert from there.*/ michael@0: SECStatus rv; michael@0: SECItem item = {0, NULL, 0}; michael@0: PRFileDesc* fd = PR_Open(name, PR_RDONLY, 0777); michael@0: if (!fd) { michael@0: return NULL; michael@0: } michael@0: rv = SECU_ReadDERFromFile(&item, fd, ascii, PR_FALSE); michael@0: PR_Close(fd); michael@0: if (rv != SECSuccess || !item.len) { michael@0: PORT_Free(item.data); michael@0: return NULL; michael@0: } michael@0: the_cert = CERT_NewTempCertificate(handle, &item, michael@0: NULL /* nickname */, michael@0: PR_FALSE /* isPerm */, michael@0: PR_TRUE /* copyDER */); michael@0: PORT_Free(item.data); michael@0: } michael@0: return the_cert; michael@0: } michael@0: michael@0: /* Convert a SSL/TLS protocol version string into the respective numeric value michael@0: * defined by the SSL_LIBRARY_VERSION_* constants, michael@0: * while accepting a flexible set of case-insensitive identifiers. michael@0: * michael@0: * Caller must specify bufLen, allowing the function to operate on substrings. michael@0: */ michael@0: static SECStatus michael@0: SECU_GetSSLVersionFromName(const char *buf, size_t bufLen, PRUint16 *version) michael@0: { michael@0: if (!buf || !version) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return SECFailure; michael@0: } michael@0: michael@0: if (!PL_strncasecmp(buf, "ssl2", bufLen)) { michael@0: *version = SSL_LIBRARY_VERSION_2; michael@0: return SECSuccess; michael@0: } michael@0: if (!PL_strncasecmp(buf, "ssl3", bufLen)) { michael@0: *version = SSL_LIBRARY_VERSION_3_0; michael@0: return SECSuccess; michael@0: } michael@0: if (!PL_strncasecmp(buf, "tls1.0", bufLen)) { michael@0: *version = SSL_LIBRARY_VERSION_TLS_1_0; michael@0: return SECSuccess; michael@0: } michael@0: if (!PL_strncasecmp(buf, "tls1.1", bufLen)) { michael@0: *version = SSL_LIBRARY_VERSION_TLS_1_1; michael@0: return SECSuccess; michael@0: } michael@0: if (!PL_strncasecmp(buf, "tls1.2", bufLen)) { michael@0: *version = SSL_LIBRARY_VERSION_TLS_1_2; michael@0: return SECSuccess; michael@0: } michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return SECFailure; michael@0: } michael@0: michael@0: SECStatus michael@0: SECU_ParseSSLVersionRangeString(const char *input, michael@0: const SSLVersionRange defaultVersionRange, michael@0: const PRBool defaultEnableSSL2, michael@0: SSLVersionRange *vrange, PRBool *enableSSL2) michael@0: { michael@0: const char *colonPos; michael@0: size_t colonIndex; michael@0: const char *maxStr; michael@0: michael@0: if (!input || !vrange || !enableSSL2) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return SECFailure; michael@0: } michael@0: michael@0: if (!strcmp(input, ":")) { michael@0: /* special value, use default */ michael@0: *enableSSL2 = defaultEnableSSL2; michael@0: *vrange = defaultVersionRange; michael@0: return SECSuccess; michael@0: } michael@0: michael@0: colonPos = strchr(input, ':'); michael@0: if (!colonPos) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return SECFailure; michael@0: } michael@0: michael@0: colonIndex = colonPos - input; michael@0: maxStr = colonPos + 1; michael@0: michael@0: if (!colonIndex) { michael@0: /* colon was first character, min version is empty */ michael@0: *enableSSL2 = defaultEnableSSL2; michael@0: vrange->min = defaultVersionRange.min; michael@0: } else { michael@0: PRUint16 version; michael@0: /* colonIndex is equivalent to the length of the min version substring */ michael@0: if (SECU_GetSSLVersionFromName(input, colonIndex, &version) != SECSuccess) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return SECFailure; michael@0: } michael@0: michael@0: if (version == SSL_LIBRARY_VERSION_2) { michael@0: *enableSSL2 = PR_TRUE; michael@0: vrange->min = defaultVersionRange.min; michael@0: } else { michael@0: *enableSSL2 = PR_FALSE; michael@0: vrange->min = version; michael@0: } michael@0: } michael@0: michael@0: if (!*maxStr) { michael@0: vrange->max = defaultVersionRange.max; michael@0: } else { michael@0: PRUint16 version; michael@0: /* if max version is empty, then maxStr points to the string terminator */ michael@0: if (SECU_GetSSLVersionFromName(maxStr, strlen(maxStr), &version) michael@0: != SECSuccess) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return SECFailure; michael@0: } michael@0: michael@0: if (version == SSL_LIBRARY_VERSION_2) { michael@0: /* consistency checking, require that min allows enableSSL2, too */ michael@0: if (!*enableSSL2) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return SECFailure; michael@0: } michael@0: /* we use 0 because SSL_LIBRARY_VERSION_NONE is private: */ michael@0: vrange->min = 0; michael@0: vrange->max = 0; michael@0: } else { michael@0: vrange->max = version; michael@0: } michael@0: } michael@0: michael@0: return SECSuccess; michael@0: }