security/nss/cmd/lib/secutil.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4 /*
michael@0 5 ** secutil.c - various functions used by security stuff
michael@0 6 **
michael@0 7 */
michael@0 8
michael@0 9 #include "prtypes.h"
michael@0 10 #include "prtime.h"
michael@0 11 #include "prlong.h"
michael@0 12 #include "prerror.h"
michael@0 13 #include "prprf.h"
michael@0 14 #include "plgetopt.h"
michael@0 15 #include "prenv.h"
michael@0 16 #include "prnetdb.h"
michael@0 17
michael@0 18 #include "cryptohi.h"
michael@0 19 #include "secutil.h"
michael@0 20 #include "secpkcs7.h"
michael@0 21 #include "secpkcs5.h"
michael@0 22 #include <stdarg.h>
michael@0 23 #include <sys/stat.h>
michael@0 24 #include <errno.h>
michael@0 25
michael@0 26 #ifdef XP_UNIX
michael@0 27 #include <unistd.h>
michael@0 28 #endif
michael@0 29
michael@0 30 /* for SEC_TraverseNames */
michael@0 31 #include "cert.h"
michael@0 32 #include "certt.h"
michael@0 33 #include "certdb.h"
michael@0 34
michael@0 35 /* #include "secmod.h" */
michael@0 36 #include "pk11func.h"
michael@0 37 #include "secoid.h"
michael@0 38
michael@0 39 static char consoleName[] = {
michael@0 40 #ifdef XP_UNIX
michael@0 41 "/dev/tty"
michael@0 42 #else
michael@0 43 #ifdef XP_OS2
michael@0 44 "\\DEV\\CON"
michael@0 45 #else
michael@0 46 "CON:"
michael@0 47 #endif
michael@0 48 #endif
michael@0 49 };
michael@0 50
michael@0 51 #include "nssutil.h"
michael@0 52 #include "ssl.h"
michael@0 53 #include "sslproto.h"
michael@0 54
michael@0 55 static PRBool utf8DisplayEnabled = PR_FALSE;
michael@0 56
michael@0 57 void
michael@0 58 SECU_EnableUtf8Display(PRBool enable)
michael@0 59 {
michael@0 60 utf8DisplayEnabled = enable;
michael@0 61 }
michael@0 62
michael@0 63 PRBool
michael@0 64 SECU_GetUtf8DisplayEnabled(void)
michael@0 65 {
michael@0 66 return utf8DisplayEnabled;
michael@0 67 }
michael@0 68
michael@0 69 static void
michael@0 70 secu_ClearPassword(char *p)
michael@0 71 {
michael@0 72 if (p) {
michael@0 73 PORT_Memset(p, 0, PORT_Strlen(p));
michael@0 74 PORT_Free(p);
michael@0 75 }
michael@0 76 }
michael@0 77
michael@0 78 char *
michael@0 79 SECU_GetPasswordString(void *arg, char *prompt)
michael@0 80 {
michael@0 81 #ifndef _WINDOWS
michael@0 82 char *p = NULL;
michael@0 83 FILE *input, *output;
michael@0 84
michael@0 85 /* open terminal */
michael@0 86 input = fopen(consoleName, "r");
michael@0 87 if (input == NULL) {
michael@0 88 fprintf(stderr, "Error opening input terminal for read\n");
michael@0 89 return NULL;
michael@0 90 }
michael@0 91
michael@0 92 output = fopen(consoleName, "w");
michael@0 93 if (output == NULL) {
michael@0 94 fprintf(stderr, "Error opening output terminal for write\n");
michael@0 95 return NULL;
michael@0 96 }
michael@0 97
michael@0 98 p = SEC_GetPassword (input, output, prompt, SEC_BlindCheckPassword);
michael@0 99
michael@0 100
michael@0 101 fclose(input);
michael@0 102 fclose(output);
michael@0 103
michael@0 104 return p;
michael@0 105
michael@0 106 #else
michael@0 107 /* Win32 version of above. opening the console may fail
michael@0 108 on windows95, and certainly isn't necessary.. */
michael@0 109
michael@0 110 char *p = NULL;
michael@0 111
michael@0 112 p = SEC_GetPassword (stdin, stdout, prompt, SEC_BlindCheckPassword);
michael@0 113 return p;
michael@0 114
michael@0 115 #endif
michael@0 116 }
michael@0 117
michael@0 118
michael@0 119 /*
michael@0 120 * p a s s w o r d _ h a r d c o d e
michael@0 121 *
michael@0 122 * A function to use the password passed in the -f(pwfile) argument
michael@0 123 * of the command line.
michael@0 124 * After use once, null it out otherwise PKCS11 calls us forever.?
michael@0 125 *
michael@0 126 */
michael@0 127 char *
michael@0 128 SECU_FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg)
michael@0 129 {
michael@0 130 char* phrases, *phrase;
michael@0 131 PRFileDesc *fd;
michael@0 132 PRInt32 nb;
michael@0 133 char *pwFile = arg;
michael@0 134 int i;
michael@0 135 const long maxPwdFileSize = 4096;
michael@0 136 char* tokenName = NULL;
michael@0 137 int tokenLen = 0;
michael@0 138
michael@0 139 if (!pwFile)
michael@0 140 return 0;
michael@0 141
michael@0 142 if (retry) {
michael@0 143 return 0; /* no good retrying - the files contents will be the same */
michael@0 144 }
michael@0 145
michael@0 146 phrases = PORT_ZAlloc(maxPwdFileSize);
michael@0 147
michael@0 148 if (!phrases) {
michael@0 149 return 0; /* out of memory */
michael@0 150 }
michael@0 151
michael@0 152 fd = PR_Open(pwFile, PR_RDONLY, 0);
michael@0 153 if (!fd) {
michael@0 154 fprintf(stderr, "No password file \"%s\" exists.\n", pwFile);
michael@0 155 PORT_Free(phrases);
michael@0 156 return NULL;
michael@0 157 }
michael@0 158
michael@0 159 nb = PR_Read(fd, phrases, maxPwdFileSize);
michael@0 160
michael@0 161 PR_Close(fd);
michael@0 162
michael@0 163 if (nb == 0) {
michael@0 164 fprintf(stderr,"password file contains no data\n");
michael@0 165 PORT_Free(phrases);
michael@0 166 return NULL;
michael@0 167 }
michael@0 168
michael@0 169 if (slot) {
michael@0 170 tokenName = PK11_GetTokenName(slot);
michael@0 171 if (tokenName) {
michael@0 172 tokenLen = PORT_Strlen(tokenName);
michael@0 173 }
michael@0 174 }
michael@0 175 i = 0;
michael@0 176 do
michael@0 177 {
michael@0 178 int startphrase = i;
michael@0 179 int phraseLen;
michael@0 180
michael@0 181 /* handle the Windows EOL case */
michael@0 182 while (phrases[i] != '\r' && phrases[i] != '\n' && i < nb) i++;
michael@0 183 /* terminate passphrase */
michael@0 184 phrases[i++] = '\0';
michael@0 185 /* clean up any EOL before the start of the next passphrase */
michael@0 186 while ( (i<nb) && (phrases[i] == '\r' || phrases[i] == '\n')) {
michael@0 187 phrases[i++] = '\0';
michael@0 188 }
michael@0 189 /* now analyze the current passphrase */
michael@0 190 phrase = &phrases[startphrase];
michael@0 191 if (!tokenName)
michael@0 192 break;
michael@0 193 if (PORT_Strncmp(phrase, tokenName, tokenLen)) continue;
michael@0 194 phraseLen = PORT_Strlen(phrase);
michael@0 195 if (phraseLen < (tokenLen+1)) continue;
michael@0 196 if (phrase[tokenLen] != ':') continue;
michael@0 197 phrase = &phrase[tokenLen+1];
michael@0 198 break;
michael@0 199
michael@0 200 } while (i<nb);
michael@0 201
michael@0 202 phrase = PORT_Strdup((char*)phrase);
michael@0 203 PORT_Free(phrases);
michael@0 204 return phrase;
michael@0 205 }
michael@0 206
michael@0 207 char *
michael@0 208 SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg)
michael@0 209 {
michael@0 210 char prompt[255];
michael@0 211 secuPWData *pwdata = (secuPWData *)arg;
michael@0 212 secuPWData pwnull = { PW_NONE, 0 };
michael@0 213 secuPWData pwxtrn = { PW_EXTERNAL, "external" };
michael@0 214 char *pw;
michael@0 215
michael@0 216 if (pwdata == NULL)
michael@0 217 pwdata = &pwnull;
michael@0 218
michael@0 219 if (PK11_ProtectedAuthenticationPath(slot)) {
michael@0 220 pwdata = &pwxtrn;
michael@0 221 }
michael@0 222 if (retry && pwdata->source != PW_NONE) {
michael@0 223 PR_fprintf(PR_STDERR, "Incorrect password/PIN entered.\n");
michael@0 224 return NULL;
michael@0 225 }
michael@0 226
michael@0 227 switch (pwdata->source) {
michael@0 228 case PW_NONE:
michael@0 229 sprintf(prompt, "Enter Password or Pin for \"%s\":",
michael@0 230 PK11_GetTokenName(slot));
michael@0 231 return SECU_GetPasswordString(NULL, prompt);
michael@0 232 case PW_FROMFILE:
michael@0 233 /* Instead of opening and closing the file every time, get the pw
michael@0 234 * once, then keep it in memory (duh).
michael@0 235 */
michael@0 236 pw = SECU_FilePasswd(slot, retry, pwdata->data);
michael@0 237 pwdata->source = PW_PLAINTEXT;
michael@0 238 pwdata->data = PL_strdup(pw);
michael@0 239 /* it's already been dup'ed */
michael@0 240 return pw;
michael@0 241 case PW_EXTERNAL:
michael@0 242 sprintf(prompt,
michael@0 243 "Press Enter, then enter PIN for \"%s\" on external device.\n",
michael@0 244 PK11_GetTokenName(slot));
michael@0 245 (void) SECU_GetPasswordString(NULL, prompt);
michael@0 246 /* Fall Through */
michael@0 247 case PW_PLAINTEXT:
michael@0 248 return PL_strdup(pwdata->data);
michael@0 249 default:
michael@0 250 break;
michael@0 251 }
michael@0 252
michael@0 253 PR_fprintf(PR_STDERR, "Password check failed: No password found.\n");
michael@0 254 return NULL;
michael@0 255 }
michael@0 256
michael@0 257 char *
michael@0 258 secu_InitSlotPassword(PK11SlotInfo *slot, PRBool retry, void *arg)
michael@0 259 {
michael@0 260 char *p0 = NULL;
michael@0 261 char *p1 = NULL;
michael@0 262 FILE *input, *output;
michael@0 263 secuPWData *pwdata = arg;
michael@0 264
michael@0 265 if (pwdata->source == PW_FROMFILE) {
michael@0 266 return SECU_FilePasswd(slot, retry, pwdata->data);
michael@0 267 }
michael@0 268 if (pwdata->source == PW_PLAINTEXT) {
michael@0 269 return PL_strdup(pwdata->data);
michael@0 270 }
michael@0 271
michael@0 272 /* PW_NONE - get it from tty */
michael@0 273 /* open terminal */
michael@0 274 #ifdef _WINDOWS
michael@0 275 input = stdin;
michael@0 276 #else
michael@0 277 input = fopen(consoleName, "r");
michael@0 278 #endif
michael@0 279 if (input == NULL) {
michael@0 280 PR_fprintf(PR_STDERR, "Error opening input terminal for read\n");
michael@0 281 return NULL;
michael@0 282 }
michael@0 283
michael@0 284 /* we have no password, so initialize database with one */
michael@0 285 PR_fprintf(PR_STDERR,
michael@0 286 "Enter a password which will be used to encrypt your keys.\n"
michael@0 287 "The password should be at least 8 characters long,\n"
michael@0 288 "and should contain at least one non-alphabetic character.\n\n");
michael@0 289
michael@0 290 output = fopen(consoleName, "w");
michael@0 291 if (output == NULL) {
michael@0 292 PR_fprintf(PR_STDERR, "Error opening output terminal for write\n");
michael@0 293 return NULL;
michael@0 294 }
michael@0 295
michael@0 296
michael@0 297 for (;;) {
michael@0 298 if (p0)
michael@0 299 PORT_Free(p0);
michael@0 300 p0 = SEC_GetPassword(input, output, "Enter new password: ",
michael@0 301 SEC_BlindCheckPassword);
michael@0 302
michael@0 303 if (p1)
michael@0 304 PORT_Free(p1);
michael@0 305 p1 = SEC_GetPassword(input, output, "Re-enter password: ",
michael@0 306 SEC_BlindCheckPassword);
michael@0 307 if (p0 && p1 && !PORT_Strcmp(p0, p1)) {
michael@0 308 break;
michael@0 309 }
michael@0 310 PR_fprintf(PR_STDERR, "Passwords do not match. Try again.\n");
michael@0 311 }
michael@0 312
michael@0 313 /* clear out the duplicate password string */
michael@0 314 secu_ClearPassword(p1);
michael@0 315
michael@0 316 fclose(input);
michael@0 317 fclose(output);
michael@0 318
michael@0 319 return p0;
michael@0 320 }
michael@0 321
michael@0 322 SECStatus
michael@0 323 SECU_ChangePW(PK11SlotInfo *slot, char *passwd, char *pwFile)
michael@0 324 {
michael@0 325 return SECU_ChangePW2(slot, passwd, 0, pwFile, 0);
michael@0 326 }
michael@0 327
michael@0 328 SECStatus
michael@0 329 SECU_ChangePW2(PK11SlotInfo *slot, char *oldPass, char *newPass,
michael@0 330 char *oldPwFile, char *newPwFile)
michael@0 331 {
michael@0 332 SECStatus rv;
michael@0 333 secuPWData pwdata, newpwdata;
michael@0 334 char *oldpw = NULL, *newpw = NULL;
michael@0 335
michael@0 336 if (oldPass) {
michael@0 337 pwdata.source = PW_PLAINTEXT;
michael@0 338 pwdata.data = oldPass;
michael@0 339 } else if (oldPwFile) {
michael@0 340 pwdata.source = PW_FROMFILE;
michael@0 341 pwdata.data = oldPwFile;
michael@0 342 } else {
michael@0 343 pwdata.source = PW_NONE;
michael@0 344 pwdata.data = NULL;
michael@0 345 }
michael@0 346
michael@0 347 if (newPass) {
michael@0 348 newpwdata.source = PW_PLAINTEXT;
michael@0 349 newpwdata.data = newPass;
michael@0 350 } else if (newPwFile) {
michael@0 351 newpwdata.source = PW_FROMFILE;
michael@0 352 newpwdata.data = newPwFile;
michael@0 353 } else {
michael@0 354 newpwdata.source = PW_NONE;
michael@0 355 newpwdata.data = NULL;
michael@0 356 }
michael@0 357
michael@0 358 if (PK11_NeedUserInit(slot)) {
michael@0 359 newpw = secu_InitSlotPassword(slot, PR_FALSE, &pwdata);
michael@0 360 rv = PK11_InitPin(slot, (char*)NULL, newpw);
michael@0 361 goto done;
michael@0 362 }
michael@0 363
michael@0 364 for (;;) {
michael@0 365 oldpw = SECU_GetModulePassword(slot, PR_FALSE, &pwdata);
michael@0 366
michael@0 367 if (PK11_CheckUserPassword(slot, oldpw) != SECSuccess) {
michael@0 368 if (pwdata.source == PW_NONE) {
michael@0 369 PR_fprintf(PR_STDERR, "Invalid password. Try again.\n");
michael@0 370 } else {
michael@0 371 PR_fprintf(PR_STDERR, "Invalid password.\n");
michael@0 372 PORT_Memset(oldpw, 0, PL_strlen(oldpw));
michael@0 373 PORT_Free(oldpw);
michael@0 374 return SECFailure;
michael@0 375 }
michael@0 376 } else
michael@0 377 break;
michael@0 378
michael@0 379 PORT_Free(oldpw);
michael@0 380 }
michael@0 381
michael@0 382 newpw = secu_InitSlotPassword(slot, PR_FALSE, &newpwdata);
michael@0 383
michael@0 384 if (PK11_ChangePW(slot, oldpw, newpw) != SECSuccess) {
michael@0 385 PR_fprintf(PR_STDERR, "Failed to change password.\n");
michael@0 386 return SECFailure;
michael@0 387 }
michael@0 388
michael@0 389 PORT_Memset(oldpw, 0, PL_strlen(oldpw));
michael@0 390 PORT_Free(oldpw);
michael@0 391
michael@0 392 PR_fprintf(PR_STDOUT, "Password changed successfully.\n");
michael@0 393
michael@0 394 done:
michael@0 395 PORT_Memset(newpw, 0, PL_strlen(newpw));
michael@0 396 PORT_Free(newpw);
michael@0 397 return SECSuccess;
michael@0 398 }
michael@0 399
michael@0 400 struct matchobj {
michael@0 401 SECItem index;
michael@0 402 char *nname;
michael@0 403 PRBool found;
michael@0 404 };
michael@0 405
michael@0 406 char *
michael@0 407 SECU_DefaultSSLDir(void)
michael@0 408 {
michael@0 409 char *dir;
michael@0 410 static char sslDir[1000];
michael@0 411
michael@0 412 dir = PR_GetEnv("SSL_DIR");
michael@0 413 if (!dir)
michael@0 414 return NULL;
michael@0 415
michael@0 416 sprintf(sslDir, "%s", dir);
michael@0 417
michael@0 418 if (sslDir[strlen(sslDir)-1] == '/')
michael@0 419 sslDir[strlen(sslDir)-1] = 0;
michael@0 420
michael@0 421 return sslDir;
michael@0 422 }
michael@0 423
michael@0 424 char *
michael@0 425 SECU_AppendFilenameToDir(char *dir, char *filename)
michael@0 426 {
michael@0 427 static char path[1000];
michael@0 428
michael@0 429 if (dir[strlen(dir)-1] == '/')
michael@0 430 sprintf(path, "%s%s", dir, filename);
michael@0 431 else
michael@0 432 sprintf(path, "%s/%s", dir, filename);
michael@0 433 return path;
michael@0 434 }
michael@0 435
michael@0 436 char *
michael@0 437 SECU_ConfigDirectory(const char* base)
michael@0 438 {
michael@0 439 static PRBool initted = PR_FALSE;
michael@0 440 const char *dir = ".netscape";
michael@0 441 char *home;
michael@0 442 static char buf[1000];
michael@0 443
michael@0 444 if (initted) return buf;
michael@0 445
michael@0 446
michael@0 447 if (base == NULL || *base == 0) {
michael@0 448 home = PR_GetEnv("HOME");
michael@0 449 if (!home) home = "";
michael@0 450
michael@0 451 if (*home && home[strlen(home) - 1] == '/')
michael@0 452 sprintf (buf, "%.900s%s", home, dir);
michael@0 453 else
michael@0 454 sprintf (buf, "%.900s/%s", home, dir);
michael@0 455 } else {
michael@0 456 sprintf(buf, "%.900s", base);
michael@0 457 if (buf[strlen(buf) - 1] == '/')
michael@0 458 buf[strlen(buf) - 1] = 0;
michael@0 459 }
michael@0 460
michael@0 461
michael@0 462 initted = PR_TRUE;
michael@0 463 return buf;
michael@0 464 }
michael@0 465
michael@0 466 /*Turn off SSL for now */
michael@0 467 /* This gets called by SSL when server wants our cert & key */
michael@0 468 int
michael@0 469 SECU_GetClientAuthData(void *arg, PRFileDesc *fd,
michael@0 470 struct CERTDistNamesStr *caNames,
michael@0 471 struct CERTCertificateStr **pRetCert,
michael@0 472 struct SECKEYPrivateKeyStr **pRetKey)
michael@0 473 {
michael@0 474 SECKEYPrivateKey *key;
michael@0 475 CERTCertificate *cert;
michael@0 476 int errsave;
michael@0 477
michael@0 478 if (arg == NULL) {
michael@0 479 fprintf(stderr, "no key/cert name specified for client auth\n");
michael@0 480 return -1;
michael@0 481 }
michael@0 482 cert = PK11_FindCertFromNickname(arg, NULL);
michael@0 483 errsave = PORT_GetError();
michael@0 484 if (!cert) {
michael@0 485 if (errsave == SEC_ERROR_BAD_PASSWORD)
michael@0 486 fprintf(stderr, "Bad password\n");
michael@0 487 else if (errsave > 0)
michael@0 488 fprintf(stderr, "Unable to read cert (error %d)\n", errsave);
michael@0 489 else if (errsave == SEC_ERROR_BAD_DATABASE)
michael@0 490 fprintf(stderr, "Unable to get cert from database (%d)\n", errsave);
michael@0 491 else
michael@0 492 fprintf(stderr, "SECKEY_FindKeyByName: internal error %d\n", errsave);
michael@0 493 return -1;
michael@0 494 }
michael@0 495
michael@0 496 key = PK11_FindKeyByAnyCert(arg,NULL);
michael@0 497 if (!key) {
michael@0 498 fprintf(stderr, "Unable to get key (%d)\n", PORT_GetError());
michael@0 499 return -1;
michael@0 500 }
michael@0 501
michael@0 502
michael@0 503 *pRetCert = cert;
michael@0 504 *pRetKey = key;
michael@0 505
michael@0 506 return 0;
michael@0 507 }
michael@0 508
michael@0 509 SECStatus
michael@0 510 SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii,
michael@0 511 PRBool warnOnPrivateKeyInAsciiFile)
michael@0 512 {
michael@0 513 SECStatus rv;
michael@0 514 if (ascii) {
michael@0 515 /* First convert ascii to binary */
michael@0 516 SECItem filedata;
michael@0 517 char *asc, *body;
michael@0 518
michael@0 519 /* Read in ascii data */
michael@0 520 rv = SECU_FileToItem(&filedata, inFile);
michael@0 521 if (rv != SECSuccess)
michael@0 522 return rv;
michael@0 523 asc = (char *)filedata.data;
michael@0 524 if (!asc) {
michael@0 525 fprintf(stderr, "unable to read data from input file\n");
michael@0 526 return SECFailure;
michael@0 527 }
michael@0 528
michael@0 529 if (warnOnPrivateKeyInAsciiFile && strstr(asc, "PRIVATE KEY")) {
michael@0 530 fprintf(stderr, "Warning: ignoring private key. Consider to use "
michael@0 531 "pk12util.\n");
michael@0 532 }
michael@0 533
michael@0 534 /* check for headers and trailers and remove them */
michael@0 535 if ((body = strstr(asc, "-----BEGIN")) != NULL) {
michael@0 536 char *trailer = NULL;
michael@0 537 asc = body;
michael@0 538 body = PORT_Strchr(body, '\n');
michael@0 539 if (!body)
michael@0 540 body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */
michael@0 541 if (body)
michael@0 542 trailer = strstr(++body, "-----END");
michael@0 543 if (trailer != NULL) {
michael@0 544 *trailer = '\0';
michael@0 545 } else {
michael@0 546 fprintf(stderr, "input has header but no trailer\n");
michael@0 547 PORT_Free(filedata.data);
michael@0 548 return SECFailure;
michael@0 549 }
michael@0 550 } else {
michael@0 551 /* need one additional byte for zero terminator */
michael@0 552 rv = SECITEM_ReallocItemV2(NULL, &filedata, filedata.len+1);
michael@0 553 if (rv != SECSuccess) {
michael@0 554 PORT_Free(filedata.data);
michael@0 555 return rv;
michael@0 556 }
michael@0 557 body = (char*)filedata.data;
michael@0 558 body[filedata.len-1] = '\0';
michael@0 559 }
michael@0 560
michael@0 561 /* Convert to binary */
michael@0 562 rv = ATOB_ConvertAsciiToItem(der, body);
michael@0 563 if (rv != SECSuccess) {
michael@0 564 fprintf(stderr, "error converting ascii to binary (%s)\n",
michael@0 565 SECU_Strerror(PORT_GetError()));
michael@0 566 PORT_Free(filedata.data);
michael@0 567 return SECFailure;
michael@0 568 }
michael@0 569
michael@0 570 PORT_Free(filedata.data);
michael@0 571 } else {
michael@0 572 /* Read in binary der */
michael@0 573 rv = SECU_FileToItem(der, inFile);
michael@0 574 if (rv != SECSuccess) {
michael@0 575 fprintf(stderr, "error converting der (%s)\n",
michael@0 576 SECU_Strerror(PORT_GetError()));
michael@0 577 return SECFailure;
michael@0 578 }
michael@0 579 }
michael@0 580 return SECSuccess;
michael@0 581 }
michael@0 582
michael@0 583 #define INDENT_MULT 4
michael@0 584
michael@0 585 SECStatus
michael@0 586 SECU_StripTagAndLength(SECItem *i)
michael@0 587 {
michael@0 588 unsigned int start;
michael@0 589
michael@0 590 if (!i || !i->data || i->len < 2) { /* must be at least tag and length */
michael@0 591 return SECFailure;
michael@0 592 }
michael@0 593 start = ((i->data[1] & 0x80) ? (i->data[1] & 0x7f) + 2 : 2);
michael@0 594 if (i->len < start) {
michael@0 595 return SECFailure;
michael@0 596 }
michael@0 597 i->data += start;
michael@0 598 i->len -= start;
michael@0 599 return SECSuccess;
michael@0 600 }
michael@0 601
michael@0 602
michael@0 603
michael@0 604 static void
michael@0 605 secu_PrintRawStringQuotesOptional(FILE *out, SECItem *si, const char *m,
michael@0 606 int level, PRBool quotes)
michael@0 607 {
michael@0 608 int column;
michael@0 609 unsigned int i;
michael@0 610
michael@0 611 if ( m ) {
michael@0 612 SECU_Indent(out, level); fprintf(out, "%s: ", m);
michael@0 613 column = (level * INDENT_MULT) + strlen(m) + 2;
michael@0 614 level++;
michael@0 615 } else {
michael@0 616 SECU_Indent(out, level);
michael@0 617 column = level*INDENT_MULT;
michael@0 618 }
michael@0 619 if (quotes) {
michael@0 620 fprintf(out, "\""); column++;
michael@0 621 }
michael@0 622
michael@0 623 for (i = 0; i < si->len; i++) {
michael@0 624 unsigned char val = si->data[i];
michael@0 625 unsigned char c;
michael@0 626 if (SECU_GetWrapEnabled() && column > 76) {
michael@0 627 SECU_Newline(out);
michael@0 628 SECU_Indent(out, level); column = level*INDENT_MULT;
michael@0 629 }
michael@0 630
michael@0 631 if (utf8DisplayEnabled) {
michael@0 632 if (val < 32)
michael@0 633 c = '.';
michael@0 634 else
michael@0 635 c = val;
michael@0 636 } else {
michael@0 637 c = printable[val];
michael@0 638 }
michael@0 639 fprintf(out,"%c", c);
michael@0 640 column++;
michael@0 641 }
michael@0 642
michael@0 643 if (quotes) {
michael@0 644 fprintf(out, "\""); column++;
michael@0 645 }
michael@0 646 if (SECU_GetWrapEnabled() &&
michael@0 647 (column != level*INDENT_MULT || column > 76)) {
michael@0 648 SECU_Newline(out);
michael@0 649 }
michael@0 650 }
michael@0 651
michael@0 652 static void
michael@0 653 secu_PrintRawString(FILE *out, SECItem *si, const char *m, int level)
michael@0 654 {
michael@0 655 secu_PrintRawStringQuotesOptional(out, si, m, level, PR_TRUE);
michael@0 656 }
michael@0 657
michael@0 658 void
michael@0 659 SECU_PrintString(FILE *out, const SECItem *si, const char *m, int level)
michael@0 660 {
michael@0 661 SECItem my = *si;
michael@0 662
michael@0 663 if (SECSuccess != SECU_StripTagAndLength(&my) || !my.len)
michael@0 664 return;
michael@0 665 secu_PrintRawString(out, &my, m, level);
michael@0 666 }
michael@0 667
michael@0 668 /* print an unencoded boolean */
michael@0 669 static void
michael@0 670 secu_PrintBoolean(FILE *out, SECItem *i, const char *m, int level)
michael@0 671 {
michael@0 672 int val = 0;
michael@0 673
michael@0 674 if ( i->data && i->len ) {
michael@0 675 val = i->data[0];
michael@0 676 }
michael@0 677
michael@0 678 if (!m) {
michael@0 679 m = "Boolean";
michael@0 680 }
michael@0 681 SECU_Indent(out, level);
michael@0 682 fprintf(out, "%s: %s\n", m, (val ? "True" : "False"));
michael@0 683 }
michael@0 684
michael@0 685 /*
michael@0 686 * Format and print "time". If the tag message "m" is not NULL,
michael@0 687 * do indent formatting based on "level" and add a newline afterward;
michael@0 688 * otherwise just print the formatted time string only.
michael@0 689 */
michael@0 690 static void
michael@0 691 secu_PrintTime(FILE *out, const PRTime time, const char *m, int level)
michael@0 692 {
michael@0 693 PRExplodedTime printableTime;
michael@0 694 char *timeString;
michael@0 695
michael@0 696 /* Convert to local time */
michael@0 697 PR_ExplodeTime(time, PR_GMTParameters, &printableTime);
michael@0 698
michael@0 699 timeString = PORT_Alloc(256);
michael@0 700 if (timeString == NULL)
michael@0 701 return;
michael@0 702
michael@0 703 if (m != NULL) {
michael@0 704 SECU_Indent(out, level);
michael@0 705 fprintf(out, "%s: ", m);
michael@0 706 }
michael@0 707
michael@0 708 if (PR_FormatTime(timeString, 256, "%a %b %d %H:%M:%S %Y", &printableTime)) {
michael@0 709 fputs(timeString, out);
michael@0 710 }
michael@0 711
michael@0 712 if (m != NULL)
michael@0 713 fprintf(out, "\n");
michael@0 714
michael@0 715 PORT_Free(timeString);
michael@0 716 }
michael@0 717
michael@0 718 /*
michael@0 719 * Format and print the UTC Time "t". If the tag message "m" is not NULL,
michael@0 720 * do indent formatting based on "level" and add a newline afterward;
michael@0 721 * otherwise just print the formatted time string only.
michael@0 722 */
michael@0 723 void
michael@0 724 SECU_PrintUTCTime(FILE *out, const SECItem *t, const char *m, int level)
michael@0 725 {
michael@0 726 PRTime time;
michael@0 727 SECStatus rv;
michael@0 728
michael@0 729 rv = DER_UTCTimeToTime(&time, t);
michael@0 730 if (rv != SECSuccess)
michael@0 731 return;
michael@0 732
michael@0 733 secu_PrintTime(out, time, m, level);
michael@0 734 }
michael@0 735
michael@0 736 /*
michael@0 737 * Format and print the Generalized Time "t". If the tag message "m"
michael@0 738 * is not NULL, * do indent formatting based on "level" and add a newline
michael@0 739 * afterward; otherwise just print the formatted time string only.
michael@0 740 */
michael@0 741 void
michael@0 742 SECU_PrintGeneralizedTime(FILE *out, const SECItem *t, const char *m, int level)
michael@0 743 {
michael@0 744 PRTime time;
michael@0 745 SECStatus rv;
michael@0 746
michael@0 747
michael@0 748 rv = DER_GeneralizedTimeToTime(&time, t);
michael@0 749 if (rv != SECSuccess)
michael@0 750 return;
michael@0 751
michael@0 752 secu_PrintTime(out, time, m, level);
michael@0 753 }
michael@0 754
michael@0 755 /*
michael@0 756 * Format and print the UTC or Generalized Time "t". If the tag message
michael@0 757 * "m" is not NULL, do indent formatting based on "level" and add a newline
michael@0 758 * afterward; otherwise just print the formatted time string only.
michael@0 759 */
michael@0 760 void
michael@0 761 SECU_PrintTimeChoice(FILE *out, const SECItem *t, const char *m, int level)
michael@0 762 {
michael@0 763 switch (t->type) {
michael@0 764 case siUTCTime:
michael@0 765 SECU_PrintUTCTime(out, t, m, level);
michael@0 766 break;
michael@0 767
michael@0 768 case siGeneralizedTime:
michael@0 769 SECU_PrintGeneralizedTime(out, t, m, level);
michael@0 770 break;
michael@0 771
michael@0 772 default:
michael@0 773 PORT_Assert(0);
michael@0 774 break;
michael@0 775 }
michael@0 776 }
michael@0 777
michael@0 778
michael@0 779 /* This prints a SET or SEQUENCE */
michael@0 780 static void
michael@0 781 SECU_PrintSet(FILE *out, const SECItem *t, const char *m, int level)
michael@0 782 {
michael@0 783 int type = t->data[0] & SEC_ASN1_TAGNUM_MASK;
michael@0 784 int constructed = t->data[0] & SEC_ASN1_CONSTRUCTED;
michael@0 785 const char * label;
michael@0 786 SECItem my = *t;
michael@0 787
michael@0 788 if (!constructed) {
michael@0 789 SECU_PrintAsHex(out, t, m, level);
michael@0 790 return;
michael@0 791 }
michael@0 792 if (SECSuccess != SECU_StripTagAndLength(&my))
michael@0 793 return;
michael@0 794
michael@0 795 SECU_Indent(out, level);
michael@0 796 if (m) {
michael@0 797 fprintf(out, "%s: ", m);
michael@0 798 }
michael@0 799
michael@0 800 if (type == SEC_ASN1_SET)
michael@0 801 label = "Set ";
michael@0 802 else if (type == SEC_ASN1_SEQUENCE)
michael@0 803 label = "Sequence ";
michael@0 804 else
michael@0 805 label = "";
michael@0 806 fprintf(out,"%s{\n", label); /* } */
michael@0 807
michael@0 808 while (my.len >= 2) {
michael@0 809 SECItem tmp = my;
michael@0 810
michael@0 811 if (tmp.data[1] & 0x80) {
michael@0 812 unsigned int i;
michael@0 813 unsigned int lenlen = tmp.data[1] & 0x7f;
michael@0 814 if (lenlen > sizeof tmp.len)
michael@0 815 break;
michael@0 816 tmp.len = 0;
michael@0 817 for (i=0; i < lenlen; i++) {
michael@0 818 tmp.len = (tmp.len << 8) | tmp.data[2+i];
michael@0 819 }
michael@0 820 tmp.len += lenlen + 2;
michael@0 821 } else {
michael@0 822 tmp.len = tmp.data[1] + 2;
michael@0 823 }
michael@0 824 if (tmp.len > my.len) {
michael@0 825 tmp.len = my.len;
michael@0 826 }
michael@0 827 my.data += tmp.len;
michael@0 828 my.len -= tmp.len;
michael@0 829 SECU_PrintAny(out, &tmp, NULL, level + 1);
michael@0 830 }
michael@0 831 SECU_Indent(out, level); fprintf(out, /* { */ "}\n");
michael@0 832 }
michael@0 833
michael@0 834 static void
michael@0 835 secu_PrintContextSpecific(FILE *out, const SECItem *i, const char *m, int level)
michael@0 836 {
michael@0 837 int type = i->data[0] & SEC_ASN1_TAGNUM_MASK;
michael@0 838 int constructed = i->data[0] & SEC_ASN1_CONSTRUCTED;
michael@0 839 SECItem tmp;
michael@0 840
michael@0 841 if (constructed) {
michael@0 842 char * m2;
michael@0 843 if (!m)
michael@0 844 m2 = PR_smprintf("[%d]", type);
michael@0 845 else
michael@0 846 m2 = PR_smprintf("%s: [%d]", m, type);
michael@0 847 if (m2) {
michael@0 848 SECU_PrintSet(out, i, m2, level);
michael@0 849 PR_smprintf_free(m2);
michael@0 850 }
michael@0 851 return;
michael@0 852 }
michael@0 853
michael@0 854 SECU_Indent(out, level);
michael@0 855 if (m) {
michael@0 856 fprintf(out, "%s: ", m);
michael@0 857 }
michael@0 858 fprintf(out,"[%d]\n", type);
michael@0 859
michael@0 860 tmp = *i;
michael@0 861 if (SECSuccess == SECU_StripTagAndLength(&tmp))
michael@0 862 SECU_PrintAsHex(out, &tmp, m, level+1);
michael@0 863 }
michael@0 864
michael@0 865 static void
michael@0 866 secu_PrintOctetString(FILE *out, const SECItem *i, const char *m, int level)
michael@0 867 {
michael@0 868 SECItem tmp = *i;
michael@0 869 if (SECSuccess == SECU_StripTagAndLength(&tmp))
michael@0 870 SECU_PrintAsHex(out, &tmp, m, level);
michael@0 871 }
michael@0 872
michael@0 873 static void
michael@0 874 secu_PrintBitString(FILE *out, const SECItem *i, const char *m, int level)
michael@0 875 {
michael@0 876 int unused_bits;
michael@0 877 SECItem tmp = *i;
michael@0 878
michael@0 879 if (SECSuccess != SECU_StripTagAndLength(&tmp) || tmp.len < 2)
michael@0 880 return;
michael@0 881
michael@0 882 unused_bits = *tmp.data++;
michael@0 883 tmp.len--;
michael@0 884
michael@0 885 SECU_PrintAsHex(out, &tmp, m, level);
michael@0 886 if (unused_bits) {
michael@0 887 SECU_Indent(out, level + 1);
michael@0 888 fprintf(out, "(%d least significant bits unused)\n", unused_bits);
michael@0 889 }
michael@0 890 }
michael@0 891
michael@0 892 /* in a decoded bit string, the len member is a bit length. */
michael@0 893 static void
michael@0 894 secu_PrintDecodedBitString(FILE *out, const SECItem *i, const char *m, int level)
michael@0 895 {
michael@0 896 int unused_bits;
michael@0 897 SECItem tmp = *i;
michael@0 898
michael@0 899
michael@0 900 unused_bits = (tmp.len & 0x7) ? 8 - (tmp.len & 7) : 0;
michael@0 901 DER_ConvertBitString(&tmp); /* convert length to byte length */
michael@0 902
michael@0 903 SECU_PrintAsHex(out, &tmp, m, level);
michael@0 904 if (unused_bits) {
michael@0 905 SECU_Indent(out, level + 1);
michael@0 906 fprintf(out, "(%d least significant bits unused)\n", unused_bits);
michael@0 907 }
michael@0 908 }
michael@0 909
michael@0 910
michael@0 911 /* Print a DER encoded Boolean */
michael@0 912 void
michael@0 913 SECU_PrintEncodedBoolean(FILE *out, const SECItem *i, const char *m, int level)
michael@0 914 {
michael@0 915 SECItem my = *i;
michael@0 916 if (SECSuccess == SECU_StripTagAndLength(&my))
michael@0 917 secu_PrintBoolean(out, &my, m, level);
michael@0 918 }
michael@0 919
michael@0 920 /* Print a DER encoded integer */
michael@0 921 void
michael@0 922 SECU_PrintEncodedInteger(FILE *out, const SECItem *i, const char *m, int level)
michael@0 923 {
michael@0 924 SECItem my = *i;
michael@0 925 if (SECSuccess == SECU_StripTagAndLength(&my))
michael@0 926 SECU_PrintInteger(out, &my, m, level);
michael@0 927 }
michael@0 928
michael@0 929 /* Print a DER encoded OID */
michael@0 930 void
michael@0 931 SECU_PrintEncodedObjectID(FILE *out, const SECItem *i, const char *m, int level)
michael@0 932 {
michael@0 933 SECItem my = *i;
michael@0 934 if (SECSuccess == SECU_StripTagAndLength(&my))
michael@0 935 SECU_PrintObjectID(out, &my, m, level);
michael@0 936 }
michael@0 937
michael@0 938 static void
michael@0 939 secu_PrintBMPString(FILE *out, const SECItem *i, const char *m, int level)
michael@0 940 {
michael@0 941 unsigned char * s;
michael@0 942 unsigned char * d;
michael@0 943 int len;
michael@0 944 SECItem tmp = {0, 0, 0};
michael@0 945 SECItem my = *i;
michael@0 946
michael@0 947 if (SECSuccess != SECU_StripTagAndLength(&my))
michael@0 948 goto loser;
michael@0 949 if (my.len % 2)
michael@0 950 goto loser;
michael@0 951 len = (int)(my.len / 2);
michael@0 952 tmp.data = (unsigned char *)PORT_Alloc(len);
michael@0 953 if (!tmp.data)
michael@0 954 goto loser;
michael@0 955 tmp.len = len;
michael@0 956 for (s = my.data, d = tmp.data ; len > 0; len--) {
michael@0 957 PRUint32 bmpChar = (s[0] << 8) | s[1]; s += 2;
michael@0 958 if (!isprint(bmpChar))
michael@0 959 goto loser;
michael@0 960 *d++ = (unsigned char)bmpChar;
michael@0 961 }
michael@0 962 secu_PrintRawString(out, &tmp, m, level);
michael@0 963 PORT_Free(tmp.data);
michael@0 964 return;
michael@0 965
michael@0 966 loser:
michael@0 967 SECU_PrintAsHex(out, i, m, level);
michael@0 968 if (tmp.data)
michael@0 969 PORT_Free(tmp.data);
michael@0 970 }
michael@0 971
michael@0 972 static void
michael@0 973 secu_PrintUniversalString(FILE *out, const SECItem *i, const char *m, int level)
michael@0 974 {
michael@0 975 unsigned char * s;
michael@0 976 unsigned char * d;
michael@0 977 int len;
michael@0 978 SECItem tmp = {0, 0, 0};
michael@0 979 SECItem my = *i;
michael@0 980
michael@0 981 if (SECSuccess != SECU_StripTagAndLength(&my))
michael@0 982 goto loser;
michael@0 983 if (my.len % 4)
michael@0 984 goto loser;
michael@0 985 len = (int)(my.len / 4);
michael@0 986 tmp.data = (unsigned char *)PORT_Alloc(len);
michael@0 987 if (!tmp.data)
michael@0 988 goto loser;
michael@0 989 tmp.len = len;
michael@0 990 for (s = my.data, d = tmp.data ; len > 0; len--) {
michael@0 991 PRUint32 bmpChar = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
michael@0 992 s += 4;
michael@0 993 if (!isprint(bmpChar))
michael@0 994 goto loser;
michael@0 995 *d++ = (unsigned char)bmpChar;
michael@0 996 }
michael@0 997 secu_PrintRawString(out, &tmp, m, level);
michael@0 998 PORT_Free(tmp.data);
michael@0 999 return;
michael@0 1000
michael@0 1001 loser:
michael@0 1002 SECU_PrintAsHex(out, i, m, level);
michael@0 1003 if (tmp.data)
michael@0 1004 PORT_Free(tmp.data);
michael@0 1005 }
michael@0 1006
michael@0 1007 static void
michael@0 1008 secu_PrintUniversal(FILE *out, const SECItem *i, const char *m, int level)
michael@0 1009 {
michael@0 1010 switch (i->data[0] & SEC_ASN1_TAGNUM_MASK) {
michael@0 1011 case SEC_ASN1_ENUMERATED:
michael@0 1012 case SEC_ASN1_INTEGER:
michael@0 1013 SECU_PrintEncodedInteger(out, i, m, level);
michael@0 1014 break;
michael@0 1015 case SEC_ASN1_OBJECT_ID:
michael@0 1016 SECU_PrintEncodedObjectID(out, i, m, level);
michael@0 1017 break;
michael@0 1018 case SEC_ASN1_BOOLEAN:
michael@0 1019 SECU_PrintEncodedBoolean(out, i, m, level);
michael@0 1020 break;
michael@0 1021 case SEC_ASN1_UTF8_STRING:
michael@0 1022 case SEC_ASN1_PRINTABLE_STRING:
michael@0 1023 case SEC_ASN1_VISIBLE_STRING:
michael@0 1024 case SEC_ASN1_IA5_STRING:
michael@0 1025 case SEC_ASN1_T61_STRING:
michael@0 1026 SECU_PrintString(out, i, m, level);
michael@0 1027 break;
michael@0 1028 case SEC_ASN1_GENERALIZED_TIME:
michael@0 1029 SECU_PrintGeneralizedTime(out, i, m, level);
michael@0 1030 break;
michael@0 1031 case SEC_ASN1_UTC_TIME:
michael@0 1032 SECU_PrintUTCTime(out, i, m, level);
michael@0 1033 break;
michael@0 1034 case SEC_ASN1_NULL:
michael@0 1035 SECU_Indent(out, level);
michael@0 1036 if (m && m[0])
michael@0 1037 fprintf(out, "%s: NULL\n", m);
michael@0 1038 else
michael@0 1039 fprintf(out, "NULL\n");
michael@0 1040 break;
michael@0 1041 case SEC_ASN1_SET:
michael@0 1042 case SEC_ASN1_SEQUENCE:
michael@0 1043 SECU_PrintSet(out, i, m, level);
michael@0 1044 break;
michael@0 1045 case SEC_ASN1_OCTET_STRING:
michael@0 1046 secu_PrintOctetString(out, i, m, level);
michael@0 1047 break;
michael@0 1048 case SEC_ASN1_BIT_STRING:
michael@0 1049 secu_PrintBitString(out, i, m, level);
michael@0 1050 break;
michael@0 1051 case SEC_ASN1_BMP_STRING:
michael@0 1052 secu_PrintBMPString(out, i, m, level);
michael@0 1053 break;
michael@0 1054 case SEC_ASN1_UNIVERSAL_STRING:
michael@0 1055 secu_PrintUniversalString(out, i, m, level);
michael@0 1056 break;
michael@0 1057 default:
michael@0 1058 SECU_PrintAsHex(out, i, m, level);
michael@0 1059 break;
michael@0 1060 }
michael@0 1061 }
michael@0 1062
michael@0 1063 void
michael@0 1064 SECU_PrintAny(FILE *out, const SECItem *i, const char *m, int level)
michael@0 1065 {
michael@0 1066 if ( i && i->len && i->data ) {
michael@0 1067 switch (i->data[0] & SEC_ASN1_CLASS_MASK) {
michael@0 1068 case SEC_ASN1_CONTEXT_SPECIFIC:
michael@0 1069 secu_PrintContextSpecific(out, i, m, level);
michael@0 1070 break;
michael@0 1071 case SEC_ASN1_UNIVERSAL:
michael@0 1072 secu_PrintUniversal(out, i, m, level);
michael@0 1073 break;
michael@0 1074 default:
michael@0 1075 SECU_PrintAsHex(out, i, m, level);
michael@0 1076 break;
michael@0 1077 }
michael@0 1078 }
michael@0 1079 }
michael@0 1080
michael@0 1081 static int
michael@0 1082 secu_PrintValidity(FILE *out, CERTValidity *v, char *m, int level)
michael@0 1083 {
michael@0 1084 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 1085 SECU_PrintTimeChoice(out, &v->notBefore, "Not Before", level+1);
michael@0 1086 SECU_PrintTimeChoice(out, &v->notAfter, "Not After ", level+1);
michael@0 1087 return 0;
michael@0 1088 }
michael@0 1089
michael@0 1090 /* This function does NOT expect a DER type and length. */
michael@0 1091 SECOidTag
michael@0 1092 SECU_PrintObjectID(FILE *out, const SECItem *oid, const char *m, int level)
michael@0 1093 {
michael@0 1094 SECOidData *oiddata;
michael@0 1095 char * oidString = NULL;
michael@0 1096
michael@0 1097 oiddata = SECOID_FindOID(oid);
michael@0 1098 if (oiddata != NULL) {
michael@0 1099 const char *name = oiddata->desc;
michael@0 1100 SECU_Indent(out, level);
michael@0 1101 if (m != NULL)
michael@0 1102 fprintf(out, "%s: ", m);
michael@0 1103 fprintf(out, "%s\n", name);
michael@0 1104 return oiddata->offset;
michael@0 1105 }
michael@0 1106 oidString = CERT_GetOidString(oid);
michael@0 1107 if (oidString) {
michael@0 1108 SECU_Indent(out, level);
michael@0 1109 if (m != NULL)
michael@0 1110 fprintf(out, "%s: ", m);
michael@0 1111 fprintf(out, "%s\n", oidString);
michael@0 1112 PR_smprintf_free(oidString);
michael@0 1113 return SEC_OID_UNKNOWN;
michael@0 1114 }
michael@0 1115 SECU_PrintAsHex(out, oid, m, level);
michael@0 1116 return SEC_OID_UNKNOWN;
michael@0 1117 }
michael@0 1118
michael@0 1119 typedef struct secuPBEParamsStr {
michael@0 1120 SECItem salt;
michael@0 1121 SECItem iterationCount;
michael@0 1122 SECItem keyLength;
michael@0 1123 SECAlgorithmID cipherAlg;
michael@0 1124 SECAlgorithmID kdfAlg;
michael@0 1125 } secuPBEParams;
michael@0 1126
michael@0 1127 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
michael@0 1128
michael@0 1129 /* SECOID_PKCS5_PBKDF2 */
michael@0 1130 const SEC_ASN1Template secuKDF2Params[] =
michael@0 1131 {
michael@0 1132 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(secuPBEParams) },
michael@0 1133 { SEC_ASN1_OCTET_STRING, offsetof(secuPBEParams, salt) },
michael@0 1134 { SEC_ASN1_INTEGER, offsetof(secuPBEParams, iterationCount) },
michael@0 1135 { SEC_ASN1_INTEGER, offsetof(secuPBEParams, keyLength) },
michael@0 1136 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(secuPBEParams, kdfAlg),
michael@0 1137 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
michael@0 1138 { 0 }
michael@0 1139 };
michael@0 1140
michael@0 1141 /* PKCS5v1 & PKCS12 */
michael@0 1142 const SEC_ASN1Template secuPBEParamsTemp[] =
michael@0 1143 {
michael@0 1144 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(secuPBEParams) },
michael@0 1145 { SEC_ASN1_OCTET_STRING, offsetof(secuPBEParams, salt) },
michael@0 1146 { SEC_ASN1_INTEGER, offsetof(secuPBEParams, iterationCount) },
michael@0 1147 { 0 }
michael@0 1148 };
michael@0 1149
michael@0 1150 /* SEC_OID_PKCS5_PBES2, SEC_OID_PKCS5_PBMAC1 */
michael@0 1151 const SEC_ASN1Template secuPBEV2Params[] =
michael@0 1152 {
michael@0 1153 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(secuPBEParams)},
michael@0 1154 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(secuPBEParams, kdfAlg),
michael@0 1155 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
michael@0 1156 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(secuPBEParams, cipherAlg),
michael@0 1157 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
michael@0 1158 { 0 }
michael@0 1159 };
michael@0 1160
michael@0 1161 void
michael@0 1162 secu_PrintRSAPSSParams(FILE *out, SECItem *value, char *m, int level)
michael@0 1163 {
michael@0 1164 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1165 SECStatus rv;
michael@0 1166 SECKEYRSAPSSParams param;
michael@0 1167 SECAlgorithmID maskHashAlg;
michael@0 1168
michael@0 1169 if (m) {
michael@0 1170 SECU_Indent(out, level);
michael@0 1171 fprintf (out, "%s:\n", m);
michael@0 1172 }
michael@0 1173
michael@0 1174 if (!pool) {
michael@0 1175 SECU_Indent(out, level);
michael@0 1176 fprintf(out, "Out of memory\n");
michael@0 1177 return;
michael@0 1178 }
michael@0 1179
michael@0 1180 PORT_Memset(&param, 0, sizeof param);
michael@0 1181
michael@0 1182 rv = SEC_QuickDERDecodeItem(pool, &param,
michael@0 1183 SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate),
michael@0 1184 value);
michael@0 1185 if (rv == SECSuccess) {
michael@0 1186 if (!param.hashAlg) {
michael@0 1187 SECU_Indent(out, level+1);
michael@0 1188 fprintf(out, "Hash algorithm: default, SHA-1\n");
michael@0 1189 } else {
michael@0 1190 SECU_PrintObjectID(out, &param.hashAlg->algorithm,
michael@0 1191 "Hash algorithm", level+1);
michael@0 1192 }
michael@0 1193 if (!param.maskAlg) {
michael@0 1194 SECU_Indent(out, level+1);
michael@0 1195 fprintf(out, "Mask algorithm: default, MGF1\n");
michael@0 1196 SECU_Indent(out, level+1);
michael@0 1197 fprintf(out, "Mask hash algorithm: default, SHA-1\n");
michael@0 1198 } else {
michael@0 1199 SECU_PrintObjectID(out, &param.maskAlg->algorithm,
michael@0 1200 "Mask algorithm", level+1);
michael@0 1201 rv = SEC_QuickDERDecodeItem(pool, &maskHashAlg,
michael@0 1202 SEC_ASN1_GET(SECOID_AlgorithmIDTemplate),
michael@0 1203 &param.maskAlg->parameters);
michael@0 1204 if (rv == SECSuccess) {
michael@0 1205 SECU_PrintObjectID(out, &maskHashAlg.algorithm,
michael@0 1206 "Mask hash algorithm", level+1);
michael@0 1207 } else {
michael@0 1208 SECU_Indent(out, level+1);
michael@0 1209 fprintf(out, "Invalid mask generation algorithm parameters\n");
michael@0 1210 }
michael@0 1211 }
michael@0 1212 if (!param.saltLength.data) {
michael@0 1213 SECU_Indent(out, level+1);
michael@0 1214 fprintf(out, "Salt length: default, %i (0x%2X)\n", 20, 20);
michael@0 1215 } else {
michael@0 1216 SECU_PrintInteger(out, &param.saltLength, "Salt Length", level+1);
michael@0 1217 }
michael@0 1218 } else {
michael@0 1219 SECU_Indent(out, level+1);
michael@0 1220 fprintf(out, "Invalid RSA-PSS parameters\n");
michael@0 1221 }
michael@0 1222 PORT_FreeArena(pool, PR_FALSE);
michael@0 1223 }
michael@0 1224
michael@0 1225 void
michael@0 1226 secu_PrintKDF2Params(FILE *out, SECItem *value, char *m, int level)
michael@0 1227 {
michael@0 1228 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1229 SECStatus rv;
michael@0 1230 secuPBEParams param;
michael@0 1231
michael@0 1232 if (m) {
michael@0 1233 SECU_Indent(out, level);
michael@0 1234 fprintf (out, "%s:\n", m);
michael@0 1235 }
michael@0 1236
michael@0 1237 if (!pool) {
michael@0 1238 SECU_Indent(out, level);
michael@0 1239 fprintf(out, "Out of memory\n");
michael@0 1240 return;
michael@0 1241 }
michael@0 1242
michael@0 1243 PORT_Memset(&param, 0, sizeof param);
michael@0 1244 rv = SEC_QuickDERDecodeItem(pool, &param, secuKDF2Params, value);
michael@0 1245 if (rv == SECSuccess) {
michael@0 1246 SECU_PrintAsHex(out, &param.salt, "Salt", level+1);
michael@0 1247 SECU_PrintInteger(out, &param.iterationCount, "Iteration Count",
michael@0 1248 level+1);
michael@0 1249 SECU_PrintInteger(out, &param.keyLength, "Key Length", level+1);
michael@0 1250 SECU_PrintAlgorithmID(out, &param.kdfAlg, "KDF algorithm", level+1);
michael@0 1251 }
michael@0 1252 PORT_FreeArena(pool, PR_FALSE);
michael@0 1253 }
michael@0 1254
michael@0 1255 void
michael@0 1256 secu_PrintPKCS5V2Params(FILE *out, SECItem *value, char *m, int level)
michael@0 1257 {
michael@0 1258 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1259 SECStatus rv;
michael@0 1260 secuPBEParams param;
michael@0 1261
michael@0 1262 if (m) {
michael@0 1263 SECU_Indent(out, level);
michael@0 1264 fprintf (out, "%s:\n", m);
michael@0 1265 }
michael@0 1266
michael@0 1267 if (!pool) {
michael@0 1268 SECU_Indent(out, level);
michael@0 1269 fprintf(out, "Out of memory\n");
michael@0 1270 return;
michael@0 1271 }
michael@0 1272
michael@0 1273 PORT_Memset(&param, 0, sizeof param);
michael@0 1274 rv = SEC_QuickDERDecodeItem(pool, &param, secuPBEV2Params, value);
michael@0 1275 if (rv == SECSuccess) {
michael@0 1276 SECU_PrintAlgorithmID(out, &param.kdfAlg, "KDF", level+1);
michael@0 1277 SECU_PrintAlgorithmID(out, &param.cipherAlg, "Cipher", level+1);
michael@0 1278 }
michael@0 1279 PORT_FreeArena(pool, PR_FALSE);
michael@0 1280 }
michael@0 1281
michael@0 1282 void
michael@0 1283 secu_PrintPBEParams(FILE *out, SECItem *value, char *m, int level)
michael@0 1284 {
michael@0 1285 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1286 SECStatus rv;
michael@0 1287 secuPBEParams param;
michael@0 1288
michael@0 1289 if (m) {
michael@0 1290 SECU_Indent(out, level);
michael@0 1291 fprintf (out, "%s:\n", m);
michael@0 1292 }
michael@0 1293
michael@0 1294 if (!pool) {
michael@0 1295 SECU_Indent(out, level);
michael@0 1296 fprintf(out, "Out of memory\n");
michael@0 1297 return;
michael@0 1298 }
michael@0 1299
michael@0 1300 PORT_Memset(&param, 0, sizeof(secuPBEParams));
michael@0 1301 rv = SEC_QuickDERDecodeItem(pool, &param, secuPBEParamsTemp, value);
michael@0 1302 if (rv == SECSuccess) {
michael@0 1303 SECU_PrintAsHex(out, &param.salt, "Salt", level+1);
michael@0 1304 SECU_PrintInteger(out, &param.iterationCount, "Iteration Count",
michael@0 1305 level+1);
michael@0 1306 }
michael@0 1307 PORT_FreeArena(pool, PR_FALSE);
michael@0 1308 }
michael@0 1309
michael@0 1310 /* This function does NOT expect a DER type and length. */
michael@0 1311 void
michael@0 1312 SECU_PrintAlgorithmID(FILE *out, SECAlgorithmID *a, char *m, int level)
michael@0 1313 {
michael@0 1314 SECOidTag algtag;
michael@0 1315 SECU_PrintObjectID(out, &a->algorithm, m, level);
michael@0 1316
michael@0 1317 algtag = SECOID_GetAlgorithmTag(a);
michael@0 1318 if (SEC_PKCS5IsAlgorithmPBEAlgTag(algtag)) {
michael@0 1319 switch (algtag) {
michael@0 1320 case SEC_OID_PKCS5_PBKDF2:
michael@0 1321 secu_PrintKDF2Params(out, &a->parameters, "Parameters", level+1);
michael@0 1322 break;
michael@0 1323 case SEC_OID_PKCS5_PBES2:
michael@0 1324 secu_PrintPKCS5V2Params(out, &a->parameters, "Encryption", level+1);
michael@0 1325 break;
michael@0 1326 case SEC_OID_PKCS5_PBMAC1:
michael@0 1327 secu_PrintPKCS5V2Params(out, &a->parameters, "MAC", level+1);
michael@0 1328 break;
michael@0 1329 default:
michael@0 1330 secu_PrintPBEParams(out, &a->parameters, "Parameters", level+1);
michael@0 1331 break;
michael@0 1332 }
michael@0 1333 return;
michael@0 1334 }
michael@0 1335
michael@0 1336 if (algtag == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) {
michael@0 1337 secu_PrintRSAPSSParams(out, &a->parameters, "Parameters", level+1);
michael@0 1338 return;
michael@0 1339 }
michael@0 1340
michael@0 1341 if (a->parameters.len == 0
michael@0 1342 || (a->parameters.len == 2
michael@0 1343 && PORT_Memcmp(a->parameters.data, "\005\000", 2) == 0)) {
michael@0 1344 /* No arguments or NULL argument */
michael@0 1345 } else {
michael@0 1346 /* Print args to algorithm */
michael@0 1347 SECU_PrintAsHex(out, &a->parameters, "Args", level+1);
michael@0 1348 }
michael@0 1349 }
michael@0 1350
michael@0 1351 static void
michael@0 1352 secu_PrintAttribute(FILE *out, SEC_PKCS7Attribute *attr, char *m, int level)
michael@0 1353 {
michael@0 1354 SECItem *value;
michael@0 1355 int i;
michael@0 1356 char om[100];
michael@0 1357
michael@0 1358 if (m) {
michael@0 1359 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 1360 }
michael@0 1361
michael@0 1362 /*
michael@0 1363 * Should make this smarter; look at the type field and then decode
michael@0 1364 * and print the value(s) appropriately!
michael@0 1365 */
michael@0 1366 SECU_PrintObjectID(out, &(attr->type), "Type", level+1);
michael@0 1367 if (attr->values != NULL) {
michael@0 1368 i = 0;
michael@0 1369 while ((value = attr->values[i++]) != NULL) {
michael@0 1370 sprintf(om, "Value (%d)%s", i, attr->encoded ? " (encoded)" : "");
michael@0 1371 if (attr->encoded || attr->typeTag == NULL) {
michael@0 1372 SECU_PrintAny(out, value, om, level+1);
michael@0 1373 } else {
michael@0 1374 switch (attr->typeTag->offset) {
michael@0 1375 default:
michael@0 1376 SECU_PrintAsHex(out, value, om, level+1);
michael@0 1377 break;
michael@0 1378 case SEC_OID_PKCS9_CONTENT_TYPE:
michael@0 1379 SECU_PrintObjectID(out, value, om, level+1);
michael@0 1380 break;
michael@0 1381 case SEC_OID_PKCS9_SIGNING_TIME:
michael@0 1382 SECU_PrintTimeChoice(out, value, om, level+1);
michael@0 1383 break;
michael@0 1384 }
michael@0 1385 }
michael@0 1386 }
michael@0 1387 }
michael@0 1388 }
michael@0 1389
michael@0 1390 #ifndef NSS_DISABLE_ECC
michael@0 1391 static void
michael@0 1392 secu_PrintECPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level)
michael@0 1393 {
michael@0 1394 SECItem curveOID = { siBuffer, NULL, 0};
michael@0 1395
michael@0 1396 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 1397 SECU_PrintInteger(out, &pk->u.ec.publicValue, "PublicValue", level+1);
michael@0 1398 /* For named curves, the DEREncodedParams field contains an
michael@0 1399 * ASN Object ID (0x06 is SEC_ASN1_OBJECT_ID).
michael@0 1400 */
michael@0 1401 if ((pk->u.ec.DEREncodedParams.len > 2) &&
michael@0 1402 (pk->u.ec.DEREncodedParams.data[0] == 0x06)) {
michael@0 1403 curveOID.len = pk->u.ec.DEREncodedParams.data[1];
michael@0 1404 curveOID.data = pk->u.ec.DEREncodedParams.data + 2;
michael@0 1405 SECU_PrintObjectID(out, &curveOID, "Curve", level +1);
michael@0 1406 }
michael@0 1407 }
michael@0 1408 #endif /* NSS_DISABLE_ECC */
michael@0 1409
michael@0 1410 void
michael@0 1411 SECU_PrintRSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level)
michael@0 1412 {
michael@0 1413 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 1414 SECU_PrintInteger(out, &pk->u.rsa.modulus, "Modulus", level+1);
michael@0 1415 SECU_PrintInteger(out, &pk->u.rsa.publicExponent, "Exponent", level+1);
michael@0 1416 if (pk->u.rsa.publicExponent.len == 1 &&
michael@0 1417 pk->u.rsa.publicExponent.data[0] == 1) {
michael@0 1418 SECU_Indent(out, level +1); fprintf(out, "Error: INVALID RSA KEY!\n");
michael@0 1419 }
michael@0 1420 }
michael@0 1421
michael@0 1422 void
michael@0 1423 SECU_PrintDSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level)
michael@0 1424 {
michael@0 1425 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 1426 SECU_PrintInteger(out, &pk->u.dsa.params.prime, "Prime", level+1);
michael@0 1427 SECU_PrintInteger(out, &pk->u.dsa.params.subPrime, "Subprime", level+1);
michael@0 1428 SECU_PrintInteger(out, &pk->u.dsa.params.base, "Base", level+1);
michael@0 1429 SECU_PrintInteger(out, &pk->u.dsa.publicValue, "PublicValue", level+1);
michael@0 1430 }
michael@0 1431
michael@0 1432 static void
michael@0 1433 secu_PrintSubjectPublicKeyInfo(FILE *out, PLArenaPool *arena,
michael@0 1434 CERTSubjectPublicKeyInfo *i, char *msg, int level)
michael@0 1435 {
michael@0 1436 SECKEYPublicKey *pk;
michael@0 1437
michael@0 1438 SECU_Indent(out, level); fprintf(out, "%s:\n", msg);
michael@0 1439 SECU_PrintAlgorithmID(out, &i->algorithm, "Public Key Algorithm", level+1);
michael@0 1440
michael@0 1441 pk = SECKEY_ExtractPublicKey(i);
michael@0 1442 if (pk) {
michael@0 1443 switch (pk->keyType) {
michael@0 1444 case rsaKey:
michael@0 1445 SECU_PrintRSAPublicKey(out, pk, "RSA Public Key", level +1);
michael@0 1446 break;
michael@0 1447
michael@0 1448 case dsaKey:
michael@0 1449 SECU_PrintDSAPublicKey(out, pk, "DSA Public Key", level +1);
michael@0 1450 break;
michael@0 1451
michael@0 1452 #ifndef NSS_DISABLE_ECC
michael@0 1453 case ecKey:
michael@0 1454 secu_PrintECPublicKey(out, pk, "EC Public Key", level +1);
michael@0 1455 break;
michael@0 1456 #endif
michael@0 1457
michael@0 1458 case dhKey:
michael@0 1459 case fortezzaKey:
michael@0 1460 case keaKey:
michael@0 1461 SECU_Indent(out, level);
michael@0 1462 fprintf(out, "unable to format this SPKI algorithm type\n");
michael@0 1463 goto loser;
michael@0 1464 default:
michael@0 1465 SECU_Indent(out, level);
michael@0 1466 fprintf(out, "unknown SPKI algorithm type\n");
michael@0 1467 goto loser;
michael@0 1468 }
michael@0 1469 PORT_FreeArena(pk->arena, PR_FALSE);
michael@0 1470 } else {
michael@0 1471 SECU_PrintErrMsg(out, level, "Error", "Parsing public key");
michael@0 1472 loser:
michael@0 1473 if (i->subjectPublicKey.data) {
michael@0 1474 SECU_PrintAny(out, &i->subjectPublicKey, "Raw", level);
michael@0 1475 }
michael@0 1476 }
michael@0 1477 }
michael@0 1478
michael@0 1479 static void
michael@0 1480 printStringWithoutCRLF(FILE *out, const char *str)
michael@0 1481 {
michael@0 1482 const char *c = str;
michael@0 1483 while (*c) {
michael@0 1484 if (*c != '\r' && *c != '\n') {
michael@0 1485 fputc(*c, out);
michael@0 1486 }
michael@0 1487 ++c;
michael@0 1488 }
michael@0 1489 }
michael@0 1490
michael@0 1491 int
michael@0 1492 SECU_PrintDumpDerIssuerAndSerial(FILE *out, SECItem *der, char *m,
michael@0 1493 int level)
michael@0 1494 {
michael@0 1495 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1496 CERTCertificate *c;
michael@0 1497 int rv = SEC_ERROR_NO_MEMORY;
michael@0 1498 char *derIssuerB64;
michael@0 1499 char *derSerialB64;
michael@0 1500
michael@0 1501 if (!arena)
michael@0 1502 return rv;
michael@0 1503
michael@0 1504 /* Decode certificate */
michael@0 1505 c = PORT_ArenaZNew(arena, CERTCertificate);
michael@0 1506 if (!c)
michael@0 1507 goto loser;
michael@0 1508 c->arena = arena;
michael@0 1509 rv = SEC_ASN1DecodeItem(arena, c,
michael@0 1510 SEC_ASN1_GET(CERT_CertificateTemplate), der);
michael@0 1511 if (rv) {
michael@0 1512 SECU_PrintErrMsg(out, 0, "Error", "Parsing extension");
michael@0 1513 goto loser;
michael@0 1514 }
michael@0 1515
michael@0 1516 SECU_PrintName(out, &c->subject, "Subject", 0);
michael@0 1517 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/
michael@0 1518 SECU_Newline(out);
michael@0 1519 SECU_PrintName(out, &c->issuer, "Issuer", 0);
michael@0 1520 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/
michael@0 1521 SECU_Newline(out);
michael@0 1522 SECU_PrintInteger(out, &c->serialNumber, "Serial Number", 0);
michael@0 1523
michael@0 1524 derIssuerB64 = BTOA_ConvertItemToAscii(&c->derIssuer);
michael@0 1525 derSerialB64 = BTOA_ConvertItemToAscii(&c->serialNumber);
michael@0 1526
michael@0 1527 fprintf(out, "Issuer DER Base64:\n");
michael@0 1528 if (SECU_GetWrapEnabled()) {
michael@0 1529 fprintf(out, "%s\n", derIssuerB64);
michael@0 1530 } else {
michael@0 1531 printStringWithoutCRLF(out, derIssuerB64);
michael@0 1532 fputs("\n", out);
michael@0 1533 }
michael@0 1534
michael@0 1535 fprintf(out, "Serial DER Base64:\n");
michael@0 1536 if (SECU_GetWrapEnabled()) {
michael@0 1537 fprintf(out, "%s\n", derSerialB64);
michael@0 1538 } else {
michael@0 1539 printStringWithoutCRLF(out, derSerialB64);
michael@0 1540 fputs("\n", out);
michael@0 1541 }
michael@0 1542
michael@0 1543 PORT_Free(derIssuerB64);
michael@0 1544 PORT_Free(derSerialB64);
michael@0 1545
michael@0 1546 fprintf(out, "Serial DER as C source: \n{ %d, \"", c->serialNumber.len);
michael@0 1547
michael@0 1548 {
michael@0 1549 int i;
michael@0 1550 for (i=0; i < c->serialNumber.len; ++i) {
michael@0 1551 unsigned char *chardata = (unsigned char*)(c->serialNumber.data);
michael@0 1552 unsigned char c = *(chardata + i);
michael@0 1553
michael@0 1554 fprintf(out, "\\x%02x", c);
michael@0 1555 }
michael@0 1556 fprintf(out, "\" }\n");
michael@0 1557 }
michael@0 1558
michael@0 1559 loser:
michael@0 1560 PORT_FreeArena(arena, PR_FALSE);
michael@0 1561 return rv;
michael@0 1562 }
michael@0 1563
michael@0 1564 static SECStatus
michael@0 1565 secu_PrintX509InvalidDate(FILE *out, SECItem *value, char *msg, int level)
michael@0 1566 {
michael@0 1567 SECItem decodedValue;
michael@0 1568 SECStatus rv;
michael@0 1569 PRTime invalidTime;
michael@0 1570 char *formattedTime = NULL;
michael@0 1571
michael@0 1572 decodedValue.data = NULL;
michael@0 1573 rv = SEC_ASN1DecodeItem (NULL, &decodedValue,
michael@0 1574 SEC_ASN1_GET(SEC_GeneralizedTimeTemplate),
michael@0 1575 value);
michael@0 1576 if (rv == SECSuccess) {
michael@0 1577 rv = DER_GeneralizedTimeToTime(&invalidTime, &decodedValue);
michael@0 1578 if (rv == SECSuccess) {
michael@0 1579 formattedTime = CERT_GenTime2FormattedAscii
michael@0 1580 (invalidTime, "%a %b %d %H:%M:%S %Y");
michael@0 1581 SECU_Indent(out, level +1);
michael@0 1582 fprintf (out, "%s: %s\n", msg, formattedTime);
michael@0 1583 PORT_Free (formattedTime);
michael@0 1584 }
michael@0 1585 }
michael@0 1586 PORT_Free (decodedValue.data);
michael@0 1587 return (rv);
michael@0 1588 }
michael@0 1589
michael@0 1590 static SECStatus
michael@0 1591 PrintExtKeyUsageExtension (FILE *out, SECItem *value, char *msg, int level)
michael@0 1592 {
michael@0 1593 CERTOidSequence *os;
michael@0 1594 SECItem **op;
michael@0 1595
michael@0 1596 os = CERT_DecodeOidSequence(value);
michael@0 1597 if( (CERTOidSequence *)NULL == os ) {
michael@0 1598 return SECFailure;
michael@0 1599 }
michael@0 1600
michael@0 1601 for( op = os->oids; *op; op++ ) {
michael@0 1602 SECU_PrintObjectID(out, *op, msg, level + 1);
michael@0 1603 }
michael@0 1604 CERT_DestroyOidSequence(os);
michael@0 1605 return SECSuccess;
michael@0 1606 }
michael@0 1607
michael@0 1608 static SECStatus
michael@0 1609 secu_PrintBasicConstraints(FILE *out, SECItem *value, char *msg, int level) {
michael@0 1610 CERTBasicConstraints constraints;
michael@0 1611 SECStatus rv;
michael@0 1612
michael@0 1613 SECU_Indent(out, level);
michael@0 1614 if (msg) {
michael@0 1615 fprintf(out,"%s: ",msg);
michael@0 1616 }
michael@0 1617 rv = CERT_DecodeBasicConstraintValue(&constraints,value);
michael@0 1618 if (rv == SECSuccess && constraints.isCA) {
michael@0 1619 if (constraints.pathLenConstraint >= 0) {
michael@0 1620 fprintf(out,"Is a CA with a maximum path length of %d.\n",
michael@0 1621 constraints.pathLenConstraint);
michael@0 1622 } else {
michael@0 1623 fprintf(out,"Is a CA with no maximum path length.\n");
michael@0 1624 }
michael@0 1625 } else {
michael@0 1626 fprintf(out,"Is not a CA.\n");
michael@0 1627 }
michael@0 1628 return SECSuccess;
michael@0 1629 }
michael@0 1630
michael@0 1631 static const char * const nsTypeBits[] = {
michael@0 1632 "SSL Client",
michael@0 1633 "SSL Server",
michael@0 1634 "S/MIME",
michael@0 1635 "Object Signing",
michael@0 1636 "Reserved",
michael@0 1637 "SSL CA",
michael@0 1638 "S/MIME CA",
michael@0 1639 "ObjectSigning CA"
michael@0 1640 };
michael@0 1641
michael@0 1642 /* NSCertType is merely a bit string whose bits are displayed symbolically */
michael@0 1643 static SECStatus
michael@0 1644 secu_PrintNSCertType(FILE *out, SECItem *value, char *msg, int level)
michael@0 1645 {
michael@0 1646 int unused;
michael@0 1647 int NS_Type;
michael@0 1648 int i;
michael@0 1649 int found = 0;
michael@0 1650 SECItem my = *value;
michael@0 1651
michael@0 1652 if ((my.data[0] != SEC_ASN1_BIT_STRING) ||
michael@0 1653 SECSuccess != SECU_StripTagAndLength(&my)) {
michael@0 1654 SECU_PrintAny(out, value, "Data", level);
michael@0 1655 return SECSuccess;
michael@0 1656 }
michael@0 1657
michael@0 1658 unused = (my.len == 2) ? (my.data[0] & 0x0f) : 0;
michael@0 1659 NS_Type = my.data[1] & (0xff << unused);
michael@0 1660
michael@0 1661
michael@0 1662 SECU_Indent(out, level);
michael@0 1663 if (msg) {
michael@0 1664 fprintf(out,"%s: ",msg);
michael@0 1665 } else {
michael@0 1666 fprintf(out,"Netscape Certificate Type: ");
michael@0 1667 }
michael@0 1668 for (i=0; i < 8; i++) {
michael@0 1669 if ( (0x80 >> i) & NS_Type) {
michael@0 1670 fprintf(out, "%c%s", (found ? ',' : '<'), nsTypeBits[i]);
michael@0 1671 found = 1;
michael@0 1672 }
michael@0 1673 }
michael@0 1674 fprintf(out, (found ? ">\n" : "none\n"));
michael@0 1675 return SECSuccess;
michael@0 1676 }
michael@0 1677
michael@0 1678 static const char * const usageBits[] = {
michael@0 1679 "Digital Signature", /* 0x80 */
michael@0 1680 "Non-Repudiation", /* 0x40 */
michael@0 1681 "Key Encipherment", /* 0x20 */
michael@0 1682 "Data Encipherment", /* 0x10 */
michael@0 1683 "Key Agreement", /* 0x08 */
michael@0 1684 "Certificate Signing", /* 0x04 */
michael@0 1685 "CRL Signing", /* 0x02 */
michael@0 1686 "Encipher Only", /* 0x01 */
michael@0 1687 "Decipher Only", /* 0x0080 */
michael@0 1688 NULL
michael@0 1689 };
michael@0 1690
michael@0 1691 /* X509KeyUsage is merely a bit string whose bits are displayed symbolically */
michael@0 1692 static void
michael@0 1693 secu_PrintX509KeyUsage(FILE *out, SECItem *value, char *msg, int level)
michael@0 1694 {
michael@0 1695 int unused;
michael@0 1696 int usage;
michael@0 1697 int i;
michael@0 1698 int found = 0;
michael@0 1699 SECItem my = *value;
michael@0 1700
michael@0 1701 if ((my.data[0] != SEC_ASN1_BIT_STRING) ||
michael@0 1702 SECSuccess != SECU_StripTagAndLength(&my)) {
michael@0 1703 SECU_PrintAny(out, value, "Data", level);
michael@0 1704 return;
michael@0 1705 }
michael@0 1706
michael@0 1707 unused = (my.len >= 2) ? (my.data[0] & 0x0f) : 0;
michael@0 1708 usage = (my.len == 2) ? (my.data[1] & (0xff << unused)) << 8
michael@0 1709 : (my.data[1] << 8) |
michael@0 1710 (my.data[2] & (0xff << unused));
michael@0 1711
michael@0 1712 SECU_Indent(out, level);
michael@0 1713 fprintf(out, "Usages: ");
michael@0 1714 for (i=0; usageBits[i]; i++) {
michael@0 1715 if ( (0x8000 >> i) & usage) {
michael@0 1716 if (found)
michael@0 1717 SECU_Indent(out, level + 2);
michael@0 1718 fprintf(out, "%s\n", usageBits[i]);
michael@0 1719 found = 1;
michael@0 1720 }
michael@0 1721 }
michael@0 1722 if (!found) {
michael@0 1723 fprintf(out, "(none)\n");
michael@0 1724 }
michael@0 1725 }
michael@0 1726
michael@0 1727 static void
michael@0 1728 secu_PrintIPAddress(FILE *out, SECItem *value, char *msg, int level)
michael@0 1729 {
michael@0 1730 PRStatus st;
michael@0 1731 PRNetAddr addr;
michael@0 1732 char addrBuf[80];
michael@0 1733
michael@0 1734 memset(&addr, 0, sizeof addr);
michael@0 1735 if (value->len == 4) {
michael@0 1736 addr.inet.family = PR_AF_INET;
michael@0 1737 memcpy(&addr.inet.ip, value->data, value->len);
michael@0 1738 } else if (value->len == 16) {
michael@0 1739 addr.ipv6.family = PR_AF_INET6;
michael@0 1740 memcpy(addr.ipv6.ip.pr_s6_addr, value->data, value->len);
michael@0 1741 if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped)) {
michael@0 1742 /* convert to IPv4. */
michael@0 1743 addr.inet.family = PR_AF_INET;
michael@0 1744 memcpy(&addr.inet.ip, &addr.ipv6.ip.pr_s6_addr[12], 4);
michael@0 1745 memset(&addr.inet.pad[0], 0, sizeof addr.inet.pad);
michael@0 1746 }
michael@0 1747 } else {
michael@0 1748 goto loser;
michael@0 1749 }
michael@0 1750
michael@0 1751 st = PR_NetAddrToString(&addr, addrBuf, sizeof addrBuf);
michael@0 1752 if (st == PR_SUCCESS) {
michael@0 1753 SECU_Indent(out, level);
michael@0 1754 fprintf(out, "%s: %s\n", msg, addrBuf);
michael@0 1755 } else {
michael@0 1756 loser:
michael@0 1757 SECU_PrintAsHex(out, value, msg, level);
michael@0 1758 }
michael@0 1759 }
michael@0 1760
michael@0 1761
michael@0 1762 static void
michael@0 1763 secu_PrintGeneralName(FILE *out, CERTGeneralName *gname, char *msg, int level)
michael@0 1764 {
michael@0 1765 char label[40];
michael@0 1766 if (msg && msg[0]) {
michael@0 1767 SECU_Indent(out, level++); fprintf(out, "%s: \n", msg);
michael@0 1768 }
michael@0 1769 switch (gname->type) {
michael@0 1770 case certOtherName :
michael@0 1771 SECU_PrintAny( out, &gname->name.OthName.name, "Other Name", level);
michael@0 1772 SECU_PrintObjectID(out, &gname->name.OthName.oid, "OID", level+1);
michael@0 1773 break;
michael@0 1774 case certDirectoryName :
michael@0 1775 SECU_PrintName(out, &gname->name.directoryName, "Directory Name", level);
michael@0 1776 break;
michael@0 1777 case certRFC822Name :
michael@0 1778 secu_PrintRawString( out, &gname->name.other, "RFC822 Name", level);
michael@0 1779 break;
michael@0 1780 case certDNSName :
michael@0 1781 secu_PrintRawString( out, &gname->name.other, "DNS name", level);
michael@0 1782 break;
michael@0 1783 case certURI :
michael@0 1784 secu_PrintRawString( out, &gname->name.other, "URI", level);
michael@0 1785 break;
michael@0 1786 case certIPAddress :
michael@0 1787 secu_PrintIPAddress(out, &gname->name.other, "IP Address", level);
michael@0 1788 break;
michael@0 1789 case certRegisterID :
michael@0 1790 SECU_PrintObjectID( out, &gname->name.other, "Registered ID", level);
michael@0 1791 break;
michael@0 1792 case certX400Address :
michael@0 1793 SECU_PrintAny( out, &gname->name.other, "X400 Address", level);
michael@0 1794 break;
michael@0 1795 case certEDIPartyName :
michael@0 1796 SECU_PrintAny( out, &gname->name.other, "EDI Party", level);
michael@0 1797 break;
michael@0 1798 default:
michael@0 1799 PR_snprintf(label, sizeof label, "unknown type [%d]",
michael@0 1800 (int)gname->type - 1);
michael@0 1801 SECU_PrintAsHex(out, &gname->name.other, label, level);
michael@0 1802 break;
michael@0 1803 }
michael@0 1804 }
michael@0 1805
michael@0 1806 static void
michael@0 1807 secu_PrintGeneralNames(FILE *out, CERTGeneralName *gname, char *msg, int level)
michael@0 1808 {
michael@0 1809 CERTGeneralName *name = gname;
michael@0 1810 do {
michael@0 1811 secu_PrintGeneralName(out, name, msg, level);
michael@0 1812 name = CERT_GetNextGeneralName(name);
michael@0 1813 } while (name && name != gname);
michael@0 1814 }
michael@0 1815
michael@0 1816
michael@0 1817 static void
michael@0 1818 secu_PrintAuthKeyIDExtension(FILE *out, SECItem *value, char *msg, int level)
michael@0 1819 {
michael@0 1820 CERTAuthKeyID *kid = NULL;
michael@0 1821 PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1822
michael@0 1823 if (!pool) {
michael@0 1824 SECU_PrintError("Error", "Allocating new ArenaPool");
michael@0 1825 return;
michael@0 1826 }
michael@0 1827 kid = CERT_DecodeAuthKeyID(pool, value);
michael@0 1828 if (!kid) {
michael@0 1829 SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
michael@0 1830 SECU_PrintAny(out, value, "Data", level);
michael@0 1831 } else {
michael@0 1832 int keyIDPresent = (kid->keyID.data && kid->keyID.len);
michael@0 1833 int issuerPresent = kid->authCertIssuer != NULL;
michael@0 1834 int snPresent = (kid->authCertSerialNumber.data &&
michael@0 1835 kid->authCertSerialNumber.len);
michael@0 1836
michael@0 1837 if (keyIDPresent)
michael@0 1838 SECU_PrintAsHex(out, &kid->keyID, "Key ID", level);
michael@0 1839 if (issuerPresent)
michael@0 1840 secu_PrintGeneralName(out, kid->authCertIssuer, "Issuer", level);
michael@0 1841 if (snPresent)
michael@0 1842 SECU_PrintInteger(out, &kid->authCertSerialNumber,
michael@0 1843 "Serial Number", level);
michael@0 1844 }
michael@0 1845 PORT_FreeArena(pool, PR_FALSE);
michael@0 1846 }
michael@0 1847
michael@0 1848
michael@0 1849 static void
michael@0 1850 secu_PrintAltNameExtension(FILE *out, SECItem *value, char *msg, int level)
michael@0 1851 {
michael@0 1852 CERTGeneralName * nameList;
michael@0 1853 CERTGeneralName * current;
michael@0 1854 PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1855
michael@0 1856 if (!pool) {
michael@0 1857 SECU_PrintError("Error", "Allocating new ArenaPool");
michael@0 1858 return;
michael@0 1859 }
michael@0 1860 nameList = current = CERT_DecodeAltNameExtension(pool, value);
michael@0 1861 if (!current) {
michael@0 1862 if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) {
michael@0 1863 /* Decoder found empty sequence, which is invalid. */
michael@0 1864 PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID);
michael@0 1865 }
michael@0 1866 SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
michael@0 1867 SECU_PrintAny(out, value, "Data", level);
michael@0 1868 } else {
michael@0 1869 do {
michael@0 1870 secu_PrintGeneralName(out, current, msg, level);
michael@0 1871 current = CERT_GetNextGeneralName(current);
michael@0 1872 } while (current != nameList);
michael@0 1873 }
michael@0 1874 PORT_FreeArena(pool, PR_FALSE);
michael@0 1875 }
michael@0 1876
michael@0 1877 static void
michael@0 1878 secu_PrintCRLDistPtsExtension(FILE *out, SECItem *value, char *msg, int level)
michael@0 1879 {
michael@0 1880 CERTCrlDistributionPoints * dPoints;
michael@0 1881 PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1882
michael@0 1883 if (!pool) {
michael@0 1884 SECU_PrintError("Error", "Allocating new ArenaPool");
michael@0 1885 return;
michael@0 1886 }
michael@0 1887 dPoints = CERT_DecodeCRLDistributionPoints(pool, value);
michael@0 1888 if (dPoints && dPoints->distPoints && dPoints->distPoints[0]) {
michael@0 1889 CRLDistributionPoint ** pPoints = dPoints->distPoints;
michael@0 1890 CRLDistributionPoint * pPoint;
michael@0 1891 while (NULL != (pPoint = *pPoints++)) {
michael@0 1892 SECU_Indent(out, level); fputs("Distribution point:\n", out);
michael@0 1893 if (pPoint->distPointType == generalName &&
michael@0 1894 pPoint->distPoint.fullName != NULL) {
michael@0 1895 secu_PrintGeneralNames(out, pPoint->distPoint.fullName, NULL,
michael@0 1896 level + 1);
michael@0 1897 } else if (pPoint->distPointType == relativeDistinguishedName &&
michael@0 1898 pPoint->distPoint.relativeName.avas) {
michael@0 1899 SECU_PrintRDN(out, &pPoint->distPoint.relativeName, "RDN",
michael@0 1900 level + 1);
michael@0 1901 } else if (pPoint->derDistPoint.data) {
michael@0 1902 SECU_PrintAny(out, &pPoint->derDistPoint, "Point", level + 1);
michael@0 1903 }
michael@0 1904 if (pPoint->reasons.data) {
michael@0 1905 secu_PrintDecodedBitString(out, &pPoint->reasons, "Reasons",
michael@0 1906 level + 1);
michael@0 1907 }
michael@0 1908 if (pPoint->crlIssuer) {
michael@0 1909 secu_PrintGeneralName(out, pPoint->crlIssuer, "CRL issuer",
michael@0 1910 level + 1);
michael@0 1911 }
michael@0 1912 }
michael@0 1913 } else {
michael@0 1914 SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
michael@0 1915 SECU_PrintAny(out, value, "Data", level);
michael@0 1916 }
michael@0 1917 PORT_FreeArena(pool, PR_FALSE);
michael@0 1918 }
michael@0 1919
michael@0 1920
michael@0 1921 static void
michael@0 1922 secu_PrintNameConstraintSubtree(FILE *out, CERTNameConstraint *value,
michael@0 1923 char *msg, int level)
michael@0 1924 {
michael@0 1925 CERTNameConstraint *head = value;
michael@0 1926 SECU_Indent(out, level); fprintf(out, "%s Subtree:\n", msg);
michael@0 1927 level++;
michael@0 1928 do {
michael@0 1929 secu_PrintGeneralName(out, &value->name, NULL, level);
michael@0 1930 if (value->min.data)
michael@0 1931 SECU_PrintInteger(out, &value->min, "Minimum", level+1);
michael@0 1932 if (value->max.data)
michael@0 1933 SECU_PrintInteger(out, &value->max, "Maximum", level+1);
michael@0 1934 value = CERT_GetNextNameConstraint(value);
michael@0 1935 } while (value != head);
michael@0 1936 }
michael@0 1937
michael@0 1938 static void
michael@0 1939 secu_PrintNameConstraintsExtension(FILE *out, SECItem *value, char *msg, int level)
michael@0 1940 {
michael@0 1941 CERTNameConstraints * cnstrnts;
michael@0 1942 PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1943
michael@0 1944 if (!pool) {
michael@0 1945 SECU_PrintError("Error", "Allocating new ArenaPool");
michael@0 1946 return;
michael@0 1947 }
michael@0 1948 cnstrnts = CERT_DecodeNameConstraintsExtension(pool, value);
michael@0 1949 if (!cnstrnts) {
michael@0 1950 SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
michael@0 1951 SECU_PrintAny(out, value, "Raw", level);
michael@0 1952 } else {
michael@0 1953 if (cnstrnts->permited)
michael@0 1954 secu_PrintNameConstraintSubtree(out, cnstrnts->permited,
michael@0 1955 "Permitted", level);
michael@0 1956 if (cnstrnts->excluded)
michael@0 1957 secu_PrintNameConstraintSubtree(out, cnstrnts->excluded,
michael@0 1958 "Excluded", level);
michael@0 1959 }
michael@0 1960 PORT_FreeArena(pool, PR_FALSE);
michael@0 1961 }
michael@0 1962
michael@0 1963
michael@0 1964 static void
michael@0 1965 secu_PrintAuthorityInfoAcess(FILE *out, SECItem *value, char *msg, int level)
michael@0 1966 {
michael@0 1967 CERTAuthInfoAccess **infos = NULL;
michael@0 1968 PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1969
michael@0 1970 if (!pool) {
michael@0 1971 SECU_PrintError("Error", "Allocating new ArenaPool");
michael@0 1972 return;
michael@0 1973 }
michael@0 1974 infos = CERT_DecodeAuthInfoAccessExtension(pool, value);
michael@0 1975 if (!infos) {
michael@0 1976 SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
michael@0 1977 SECU_PrintAny(out, value, "Raw", level);
michael@0 1978 } else {
michael@0 1979 CERTAuthInfoAccess *info;
michael@0 1980 while (NULL != (info = *infos++)) {
michael@0 1981 if (info->method.data) {
michael@0 1982 SECU_PrintObjectID(out, &info->method, "Method", level);
michael@0 1983 } else {
michael@0 1984 SECU_Indent(out,level);
michael@0 1985 fprintf(out, "Error: missing method\n");
michael@0 1986 }
michael@0 1987 if (info->location) {
michael@0 1988 secu_PrintGeneralName(out, info->location, "Location", level);
michael@0 1989 } else {
michael@0 1990 SECU_PrintAny(out, &info->derLocation, "Location", level);
michael@0 1991 }
michael@0 1992 }
michael@0 1993 }
michael@0 1994 PORT_FreeArena(pool, PR_FALSE);
michael@0 1995 }
michael@0 1996
michael@0 1997
michael@0 1998 void
michael@0 1999 SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions,
michael@0 2000 char *msg, int level)
michael@0 2001 {
michael@0 2002 SECOidTag oidTag;
michael@0 2003
michael@0 2004 if ( extensions ) {
michael@0 2005 if (msg && *msg) {
michael@0 2006 SECU_Indent(out, level++); fprintf(out, "%s:\n", msg);
michael@0 2007 }
michael@0 2008
michael@0 2009 while ( *extensions ) {
michael@0 2010 SECItem *tmpitem;
michael@0 2011
michael@0 2012 tmpitem = &(*extensions)->id;
michael@0 2013 SECU_PrintObjectID(out, tmpitem, "Name", level);
michael@0 2014
michael@0 2015 tmpitem = &(*extensions)->critical;
michael@0 2016 if ( tmpitem->len ) {
michael@0 2017 secu_PrintBoolean(out, tmpitem, "Critical", level);
michael@0 2018 }
michael@0 2019
michael@0 2020 oidTag = SECOID_FindOIDTag (&((*extensions)->id));
michael@0 2021 tmpitem = &((*extensions)->value);
michael@0 2022
michael@0 2023 switch (oidTag) {
michael@0 2024 case SEC_OID_X509_INVALID_DATE:
michael@0 2025 case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME:
michael@0 2026 secu_PrintX509InvalidDate(out, tmpitem, "Date", level );
michael@0 2027 break;
michael@0 2028 case SEC_OID_X509_CERTIFICATE_POLICIES:
michael@0 2029 SECU_PrintPolicy(out, tmpitem, "Data", level );
michael@0 2030 break;
michael@0 2031 case SEC_OID_NS_CERT_EXT_BASE_URL:
michael@0 2032 case SEC_OID_NS_CERT_EXT_REVOCATION_URL:
michael@0 2033 case SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL:
michael@0 2034 case SEC_OID_NS_CERT_EXT_CA_CRL_URL:
michael@0 2035 case SEC_OID_NS_CERT_EXT_CA_CERT_URL:
michael@0 2036 case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL:
michael@0 2037 case SEC_OID_NS_CERT_EXT_CA_POLICY_URL:
michael@0 2038 case SEC_OID_NS_CERT_EXT_HOMEPAGE_URL:
michael@0 2039 case SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL:
michael@0 2040 case SEC_OID_OCSP_RESPONDER:
michael@0 2041 SECU_PrintString(out,tmpitem, "URL", level);
michael@0 2042 break;
michael@0 2043 case SEC_OID_NS_CERT_EXT_COMMENT:
michael@0 2044 SECU_PrintString(out,tmpitem, "Comment", level);
michael@0 2045 break;
michael@0 2046 case SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME:
michael@0 2047 SECU_PrintString(out,tmpitem, "ServerName", level);
michael@0 2048 break;
michael@0 2049 case SEC_OID_NS_CERT_EXT_CERT_TYPE:
michael@0 2050 secu_PrintNSCertType(out,tmpitem,"Data",level);
michael@0 2051 break;
michael@0 2052 case SEC_OID_X509_BASIC_CONSTRAINTS:
michael@0 2053 secu_PrintBasicConstraints(out,tmpitem,"Data",level);
michael@0 2054 break;
michael@0 2055 case SEC_OID_X509_EXT_KEY_USAGE:
michael@0 2056 PrintExtKeyUsageExtension(out, tmpitem, NULL, level);
michael@0 2057 break;
michael@0 2058 case SEC_OID_X509_KEY_USAGE:
michael@0 2059 secu_PrintX509KeyUsage(out, tmpitem, NULL, level );
michael@0 2060 break;
michael@0 2061 case SEC_OID_X509_AUTH_KEY_ID:
michael@0 2062 secu_PrintAuthKeyIDExtension(out, tmpitem, NULL, level );
michael@0 2063 break;
michael@0 2064 case SEC_OID_X509_SUBJECT_ALT_NAME:
michael@0 2065 case SEC_OID_X509_ISSUER_ALT_NAME:
michael@0 2066 secu_PrintAltNameExtension(out, tmpitem, NULL, level );
michael@0 2067 break;
michael@0 2068 case SEC_OID_X509_CRL_DIST_POINTS:
michael@0 2069 secu_PrintCRLDistPtsExtension(out, tmpitem, NULL, level );
michael@0 2070 break;
michael@0 2071 case SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD:
michael@0 2072 SECU_PrintPrivKeyUsagePeriodExtension(out, tmpitem, NULL,
michael@0 2073 level );
michael@0 2074 break;
michael@0 2075 case SEC_OID_X509_NAME_CONSTRAINTS:
michael@0 2076 secu_PrintNameConstraintsExtension(out, tmpitem, NULL, level);
michael@0 2077 break;
michael@0 2078 case SEC_OID_X509_AUTH_INFO_ACCESS:
michael@0 2079 secu_PrintAuthorityInfoAcess(out, tmpitem, NULL, level);
michael@0 2080 break;
michael@0 2081
michael@0 2082 case SEC_OID_X509_CRL_NUMBER:
michael@0 2083 case SEC_OID_X509_REASON_CODE:
michael@0 2084
michael@0 2085 /* PKIX OIDs */
michael@0 2086 case SEC_OID_PKIX_OCSP:
michael@0 2087 case SEC_OID_PKIX_OCSP_BASIC_RESPONSE:
michael@0 2088 case SEC_OID_PKIX_OCSP_NONCE:
michael@0 2089 case SEC_OID_PKIX_OCSP_CRL:
michael@0 2090 case SEC_OID_PKIX_OCSP_RESPONSE:
michael@0 2091 case SEC_OID_PKIX_OCSP_NO_CHECK:
michael@0 2092 case SEC_OID_PKIX_OCSP_ARCHIVE_CUTOFF:
michael@0 2093 case SEC_OID_PKIX_OCSP_SERVICE_LOCATOR:
michael@0 2094 case SEC_OID_PKIX_REGCTRL_REGTOKEN:
michael@0 2095 case SEC_OID_PKIX_REGCTRL_AUTHENTICATOR:
michael@0 2096 case SEC_OID_PKIX_REGCTRL_PKIPUBINFO:
michael@0 2097 case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS:
michael@0 2098 case SEC_OID_PKIX_REGCTRL_OLD_CERT_ID:
michael@0 2099 case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY:
michael@0 2100 case SEC_OID_PKIX_REGINFO_UTF8_PAIRS:
michael@0 2101 case SEC_OID_PKIX_REGINFO_CERT_REQUEST:
michael@0 2102
michael@0 2103 /* Netscape extension OIDs. */
michael@0 2104 case SEC_OID_NS_CERT_EXT_NETSCAPE_OK:
michael@0 2105 case SEC_OID_NS_CERT_EXT_ISSUER_LOGO:
michael@0 2106 case SEC_OID_NS_CERT_EXT_SUBJECT_LOGO:
michael@0 2107 case SEC_OID_NS_CERT_EXT_ENTITY_LOGO:
michael@0 2108 case SEC_OID_NS_CERT_EXT_USER_PICTURE:
michael@0 2109
michael@0 2110 /* x.509 v3 Extensions */
michael@0 2111 case SEC_OID_X509_SUBJECT_DIRECTORY_ATTR:
michael@0 2112 case SEC_OID_X509_SUBJECT_KEY_ID:
michael@0 2113 case SEC_OID_X509_POLICY_MAPPINGS:
michael@0 2114 case SEC_OID_X509_POLICY_CONSTRAINTS:
michael@0 2115
michael@0 2116
michael@0 2117 default:
michael@0 2118 SECU_PrintAny(out, tmpitem, "Data", level);
michael@0 2119 break;
michael@0 2120 }
michael@0 2121
michael@0 2122 SECU_Newline(out);
michael@0 2123 extensions++;
michael@0 2124 }
michael@0 2125 }
michael@0 2126 }
michael@0 2127
michael@0 2128 /* An RDN is a subset of a DirectoryName, and we already know how to
michael@0 2129 * print those, so make a directory name out of the RDN, and print it.
michael@0 2130 */
michael@0 2131 void
michael@0 2132 SECU_PrintRDN(FILE *out, CERTRDN *rdn, const char *msg, int level)
michael@0 2133 {
michael@0 2134 CERTName name;
michael@0 2135 CERTRDN *rdns[2];
michael@0 2136
michael@0 2137 name.arena = NULL;
michael@0 2138 name.rdns = rdns;
michael@0 2139 rdns[0] = rdn;
michael@0 2140 rdns[1] = NULL;
michael@0 2141 SECU_PrintName(out, &name, msg, level);
michael@0 2142 }
michael@0 2143
michael@0 2144 void
michael@0 2145 SECU_PrintNameQuotesOptional(FILE *out, CERTName *name, const char *msg,
michael@0 2146 int level, PRBool quotes)
michael@0 2147 {
michael@0 2148 char *nameStr = NULL;
michael@0 2149 char *str;
michael@0 2150 SECItem my;
michael@0 2151
michael@0 2152 if (!name) {
michael@0 2153 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 2154 return;
michael@0 2155 }
michael@0 2156 if (!name->rdns || !name->rdns[0]) {
michael@0 2157 str = "(empty)";
michael@0 2158 } else {
michael@0 2159 str = nameStr = CERT_NameToAscii(name);
michael@0 2160 }
michael@0 2161 if (!str) {
michael@0 2162 str = "!Invalid AVA!";
michael@0 2163 }
michael@0 2164 my.data = (unsigned char *)str;
michael@0 2165 my.len = PORT_Strlen(str);
michael@0 2166 #if 1
michael@0 2167 secu_PrintRawStringQuotesOptional(out, &my, msg, level, quotes);
michael@0 2168 #else
michael@0 2169 SECU_Indent(out, level); fprintf(out, "%s: ", msg);
michael@0 2170 fprintf(out, str);
michael@0 2171 SECU_Newline(out);
michael@0 2172 #endif
michael@0 2173 PORT_Free(nameStr);
michael@0 2174 }
michael@0 2175
michael@0 2176 void
michael@0 2177 SECU_PrintName(FILE *out, CERTName *name, const char *msg, int level)
michael@0 2178 {
michael@0 2179 SECU_PrintNameQuotesOptional(out, name, msg, level, PR_TRUE);
michael@0 2180 }
michael@0 2181
michael@0 2182 void
michael@0 2183 printflags(char *trusts, unsigned int flags)
michael@0 2184 {
michael@0 2185 if (flags & CERTDB_VALID_CA)
michael@0 2186 if (!(flags & CERTDB_TRUSTED_CA) &&
michael@0 2187 !(flags & CERTDB_TRUSTED_CLIENT_CA))
michael@0 2188 PORT_Strcat(trusts, "c");
michael@0 2189 if (flags & CERTDB_TERMINAL_RECORD)
michael@0 2190 if (!(flags & CERTDB_TRUSTED))
michael@0 2191 PORT_Strcat(trusts, "p");
michael@0 2192 if (flags & CERTDB_TRUSTED_CA)
michael@0 2193 PORT_Strcat(trusts, "C");
michael@0 2194 if (flags & CERTDB_TRUSTED_CLIENT_CA)
michael@0 2195 PORT_Strcat(trusts, "T");
michael@0 2196 if (flags & CERTDB_TRUSTED)
michael@0 2197 PORT_Strcat(trusts, "P");
michael@0 2198 if (flags & CERTDB_USER)
michael@0 2199 PORT_Strcat(trusts, "u");
michael@0 2200 if (flags & CERTDB_SEND_WARN)
michael@0 2201 PORT_Strcat(trusts, "w");
michael@0 2202 if (flags & CERTDB_INVISIBLE_CA)
michael@0 2203 PORT_Strcat(trusts, "I");
michael@0 2204 if (flags & CERTDB_GOVT_APPROVED_CA)
michael@0 2205 PORT_Strcat(trusts, "G");
michael@0 2206 return;
michael@0 2207 }
michael@0 2208
michael@0 2209 /* callback for listing certs through pkcs11 */
michael@0 2210 SECStatus
michael@0 2211 SECU_PrintCertNickname(CERTCertListNode *node, void *data)
michael@0 2212 {
michael@0 2213 CERTCertTrust trust;
michael@0 2214 CERTCertificate* cert;
michael@0 2215 FILE *out;
michael@0 2216 char trusts[30];
michael@0 2217 char *name;
michael@0 2218
michael@0 2219 cert = node->cert;
michael@0 2220
michael@0 2221 PORT_Memset (trusts, 0, sizeof (trusts));
michael@0 2222 out = (FILE *)data;
michael@0 2223
michael@0 2224 name = node->appData;
michael@0 2225 if (!name || !name[0]) {
michael@0 2226 name = cert->nickname;
michael@0 2227 }
michael@0 2228 if (!name || !name[0]) {
michael@0 2229 name = cert->emailAddr;
michael@0 2230 }
michael@0 2231 if (!name || !name[0]) {
michael@0 2232 name = "(NULL)";
michael@0 2233 }
michael@0 2234
michael@0 2235 if (CERT_GetCertTrust(cert, &trust) == SECSuccess) {
michael@0 2236 printflags(trusts, trust.sslFlags);
michael@0 2237 PORT_Strcat(trusts, ",");
michael@0 2238 printflags(trusts, trust.emailFlags);
michael@0 2239 PORT_Strcat(trusts, ",");
michael@0 2240 printflags(trusts, trust.objectSigningFlags);
michael@0 2241 } else {
michael@0 2242 PORT_Memcpy(trusts,",,",3);
michael@0 2243 }
michael@0 2244 fprintf(out, "%-60s %-5s\n", name, trusts);
michael@0 2245
michael@0 2246 return (SECSuccess);
michael@0 2247 }
michael@0 2248
michael@0 2249 int
michael@0 2250 SECU_DecodeAndPrintExtensions(FILE *out, SECItem *any, char *m, int level)
michael@0 2251 {
michael@0 2252 CERTCertExtension **extensions = NULL;
michael@0 2253 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 2254 int rv = 0;
michael@0 2255
michael@0 2256 if (!arena)
michael@0 2257 return SEC_ERROR_NO_MEMORY;
michael@0 2258
michael@0 2259 rv = SEC_QuickDERDecodeItem(arena, &extensions,
michael@0 2260 SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate), any);
michael@0 2261 if (!rv)
michael@0 2262 SECU_PrintExtensions(out, extensions, m, level);
michael@0 2263 else
michael@0 2264 SECU_PrintAny(out, any, m, level);
michael@0 2265 PORT_FreeArena(arena, PR_FALSE);
michael@0 2266 return rv;
michael@0 2267 }
michael@0 2268
michael@0 2269 /* print a decoded SET OF or SEQUENCE OF Extensions */
michael@0 2270 int
michael@0 2271 SECU_PrintSetOfExtensions(FILE *out, SECItem **any, char *m, int level)
michael@0 2272 {
michael@0 2273 int rv = 0;
michael@0 2274 if (m && *m) {
michael@0 2275 SECU_Indent(out, level++); fprintf(out, "%s:\n", m);
michael@0 2276 }
michael@0 2277 while (any && any[0]) {
michael@0 2278 rv |= SECU_DecodeAndPrintExtensions(out, any[0], "", level);
michael@0 2279 any++;
michael@0 2280 }
michael@0 2281 return rv;
michael@0 2282 }
michael@0 2283
michael@0 2284 /* print a decoded SET OF or SEQUENCE OF "ANY" */
michael@0 2285 int
michael@0 2286 SECU_PrintSetOfAny(FILE *out, SECItem **any, char *m, int level)
michael@0 2287 {
michael@0 2288 int rv = 0;
michael@0 2289 if (m && *m) {
michael@0 2290 SECU_Indent(out, level++); fprintf(out, "%s:\n", m);
michael@0 2291 }
michael@0 2292 while (any && any[0]) {
michael@0 2293 SECU_PrintAny(out, any[0], "", level);
michael@0 2294 any++;
michael@0 2295 }
michael@0 2296 return rv;
michael@0 2297 }
michael@0 2298
michael@0 2299 int
michael@0 2300 SECU_PrintCertAttribute(FILE *out, CERTAttribute *attr, char *m, int level)
michael@0 2301 {
michael@0 2302 int rv = 0;
michael@0 2303 SECOidTag tag;
michael@0 2304 tag = SECU_PrintObjectID(out, &attr->attrType, "Attribute Type", level);
michael@0 2305 if (tag == SEC_OID_PKCS9_EXTENSION_REQUEST) {
michael@0 2306 rv = SECU_PrintSetOfExtensions(out, attr->attrValue, "Extensions", level);
michael@0 2307 } else {
michael@0 2308 rv = SECU_PrintSetOfAny(out, attr->attrValue, "Attribute Values", level);
michael@0 2309 }
michael@0 2310 return rv;
michael@0 2311 }
michael@0 2312
michael@0 2313 int
michael@0 2314 SECU_PrintCertAttributes(FILE *out, CERTAttribute **attrs, char *m, int level)
michael@0 2315 {
michael@0 2316 int rv = 0;
michael@0 2317 while (attrs[0]) {
michael@0 2318 rv |= SECU_PrintCertAttribute(out, attrs[0], m, level+1);
michael@0 2319 attrs++;
michael@0 2320 }
michael@0 2321 return rv;
michael@0 2322 }
michael@0 2323
michael@0 2324 int /* sometimes a PRErrorCode, other times a SECStatus. Sigh. */
michael@0 2325 SECU_PrintCertificateRequest(FILE *out, SECItem *der, char *m, int level)
michael@0 2326 {
michael@0 2327 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 2328 CERTCertificateRequest *cr;
michael@0 2329 int rv = SEC_ERROR_NO_MEMORY;
michael@0 2330
michael@0 2331 if (!arena)
michael@0 2332 return rv;
michael@0 2333
michael@0 2334 /* Decode certificate request */
michael@0 2335 cr = PORT_ArenaZNew(arena, CERTCertificateRequest);
michael@0 2336 if (!cr)
michael@0 2337 goto loser;
michael@0 2338 cr->arena = arena;
michael@0 2339 rv = SEC_QuickDERDecodeItem(arena, cr,
michael@0 2340 SEC_ASN1_GET(CERT_CertificateRequestTemplate), der);
michael@0 2341 if (rv)
michael@0 2342 goto loser;
michael@0 2343
michael@0 2344 /* Pretty print it out */
michael@0 2345 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 2346 SECU_PrintInteger(out, &cr->version, "Version", level+1);
michael@0 2347 SECU_PrintName(out, &cr->subject, "Subject", level+1);
michael@0 2348 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/
michael@0 2349 SECU_Newline(out);
michael@0 2350 secu_PrintSubjectPublicKeyInfo(out, arena, &cr->subjectPublicKeyInfo,
michael@0 2351 "Subject Public Key Info", level+1);
michael@0 2352 if (cr->attributes)
michael@0 2353 SECU_PrintCertAttributes(out, cr->attributes, "Attributes", level+1);
michael@0 2354 rv = 0;
michael@0 2355 loser:
michael@0 2356 PORT_FreeArena(arena, PR_FALSE);
michael@0 2357 return rv;
michael@0 2358 }
michael@0 2359
michael@0 2360 int
michael@0 2361 SECU_PrintCertificate(FILE *out, const SECItem *der, const char *m, int level)
michael@0 2362 {
michael@0 2363 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 2364 CERTCertificate *c;
michael@0 2365 int rv = SEC_ERROR_NO_MEMORY;
michael@0 2366 int iv;
michael@0 2367
michael@0 2368 if (!arena)
michael@0 2369 return rv;
michael@0 2370
michael@0 2371 /* Decode certificate */
michael@0 2372 c = PORT_ArenaZNew(arena, CERTCertificate);
michael@0 2373 if (!c)
michael@0 2374 goto loser;
michael@0 2375 c->arena = arena;
michael@0 2376 rv = SEC_ASN1DecodeItem(arena, c,
michael@0 2377 SEC_ASN1_GET(CERT_CertificateTemplate), der);
michael@0 2378 if (rv) {
michael@0 2379 SECU_Indent(out, level);
michael@0 2380 SECU_PrintErrMsg(out, level, "Error", "Parsing extension");
michael@0 2381 SECU_PrintAny(out, der, "Raw", level);
michael@0 2382 goto loser;
michael@0 2383 }
michael@0 2384 /* Pretty print it out */
michael@0 2385 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 2386 iv = c->version.len ? DER_GetInteger(&c->version) : 0; /* version is optional */
michael@0 2387 SECU_Indent(out, level+1); fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv);
michael@0 2388
michael@0 2389 SECU_PrintInteger(out, &c->serialNumber, "Serial Number", level+1);
michael@0 2390 SECU_PrintAlgorithmID(out, &c->signature, "Signature Algorithm", level+1);
michael@0 2391 SECU_PrintName(out, &c->issuer, "Issuer", level+1);
michael@0 2392 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/
michael@0 2393 SECU_Newline(out);
michael@0 2394 secu_PrintValidity(out, &c->validity, "Validity", level+1);
michael@0 2395 SECU_PrintName(out, &c->subject, "Subject", level+1);
michael@0 2396 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/
michael@0 2397 SECU_Newline(out);
michael@0 2398 secu_PrintSubjectPublicKeyInfo(out, arena, &c->subjectPublicKeyInfo,
michael@0 2399 "Subject Public Key Info", level+1);
michael@0 2400 if (c->issuerID.data)
michael@0 2401 secu_PrintDecodedBitString(out, &c->issuerID, "Issuer Unique ID", level+1);
michael@0 2402 if (c->subjectID.data)
michael@0 2403 secu_PrintDecodedBitString(out, &c->subjectID, "Subject Unique ID", level+1);
michael@0 2404 SECU_PrintExtensions(out, c->extensions, "Signed Extensions", level+1);
michael@0 2405 loser:
michael@0 2406 PORT_FreeArena(arena, PR_FALSE);
michael@0 2407 return rv;
michael@0 2408 }
michael@0 2409
michael@0 2410 int
michael@0 2411 SECU_PrintSubjectPublicKeyInfo(FILE *out, SECItem *der, char *m, int level)
michael@0 2412 {
michael@0 2413 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 2414 int rv = SEC_ERROR_NO_MEMORY;
michael@0 2415 CERTSubjectPublicKeyInfo spki;
michael@0 2416
michael@0 2417 if (!arena)
michael@0 2418 return rv;
michael@0 2419
michael@0 2420 PORT_Memset(&spki, 0, sizeof spki);
michael@0 2421 rv = SEC_ASN1DecodeItem(arena, &spki,
michael@0 2422 SEC_ASN1_GET(CERT_SubjectPublicKeyInfoTemplate),
michael@0 2423 der);
michael@0 2424 if (!rv) {
michael@0 2425 if (m && *m) {
michael@0 2426 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 2427 }
michael@0 2428 secu_PrintSubjectPublicKeyInfo(out, arena, &spki,
michael@0 2429 "Subject Public Key Info", level+1);
michael@0 2430 }
michael@0 2431
michael@0 2432 PORT_FreeArena(arena, PR_FALSE);
michael@0 2433 return rv;
michael@0 2434 }
michael@0 2435
michael@0 2436 #ifdef HAVE_EPV_TEMPLATE
michael@0 2437 int
michael@0 2438 SECU_PrintPrivateKey(FILE *out, SECItem *der, char *m, int level)
michael@0 2439 {
michael@0 2440 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 2441 SECKEYEncryptedPrivateKeyInfo key;
michael@0 2442 int rv = SEC_ERROR_NO_MEMORY;
michael@0 2443
michael@0 2444 if (!arena)
michael@0 2445 return rv;
michael@0 2446
michael@0 2447 PORT_Memset(&key, 0, sizeof(key));
michael@0 2448 rv = SEC_ASN1DecodeItem(arena, &key,
michael@0 2449 SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate), der);
michael@0 2450 if (rv)
michael@0 2451 goto loser;
michael@0 2452
michael@0 2453 /* Pretty print it out */
michael@0 2454 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 2455 SECU_PrintAlgorithmID(out, &key.algorithm, "Encryption Algorithm",
michael@0 2456 level+1);
michael@0 2457 SECU_PrintAsHex(out, &key.encryptedData, "Encrypted Data", level+1);
michael@0 2458 loser:
michael@0 2459 PORT_FreeArena(arena, PR_TRUE);
michael@0 2460 return rv;
michael@0 2461 }
michael@0 2462 #endif
michael@0 2463
michael@0 2464 int
michael@0 2465 SECU_PrintFingerprints(FILE *out, SECItem *derCert, char *m, int level)
michael@0 2466 {
michael@0 2467 unsigned char fingerprint[SHA256_LENGTH];
michael@0 2468 char *fpStr = NULL;
michael@0 2469 int err = PORT_GetError();
michael@0 2470 SECStatus rv;
michael@0 2471 SECItem fpItem;
michael@0 2472
michael@0 2473 /* Print SHA-256 fingerprint */
michael@0 2474 memset(fingerprint, 0, sizeof fingerprint);
michael@0 2475 rv = PK11_HashBuf(SEC_OID_SHA256, fingerprint, derCert->data, derCert->len);
michael@0 2476 fpItem.data = fingerprint;
michael@0 2477 fpItem.len = SHA256_LENGTH;
michael@0 2478 fpStr = CERT_Hexify(&fpItem, 1);
michael@0 2479 SECU_Indent(out, level); fprintf(out, "%s (SHA-256):", m);
michael@0 2480 if (SECU_GetWrapEnabled()) {
michael@0 2481 fprintf(out, "\n");
michael@0 2482 SECU_Indent(out, level+1);
michael@0 2483 }
michael@0 2484 else {
michael@0 2485 fprintf(out, " ");
michael@0 2486 }
michael@0 2487 fprintf(out, "%s\n", fpStr);
michael@0 2488 PORT_Free(fpStr);
michael@0 2489 fpStr = NULL;
michael@0 2490 if (rv != SECSuccess && !err)
michael@0 2491 err = PORT_GetError();
michael@0 2492
michael@0 2493 /* print SHA1 fingerprint */
michael@0 2494 memset(fingerprint, 0, sizeof fingerprint);
michael@0 2495 rv = PK11_HashBuf(SEC_OID_SHA1,fingerprint, derCert->data, derCert->len);
michael@0 2496 fpItem.data = fingerprint;
michael@0 2497 fpItem.len = SHA1_LENGTH;
michael@0 2498 fpStr = CERT_Hexify(&fpItem, 1);
michael@0 2499 SECU_Indent(out, level); fprintf(out, "%s (SHA1):", m);
michael@0 2500 if (SECU_GetWrapEnabled()) {
michael@0 2501 fprintf(out, "\n");
michael@0 2502 SECU_Indent(out, level+1);
michael@0 2503 }
michael@0 2504 else {
michael@0 2505 fprintf(out, " ");
michael@0 2506 }
michael@0 2507 fprintf(out, "%s\n", fpStr);
michael@0 2508 PORT_Free(fpStr);
michael@0 2509 if (SECU_GetWrapEnabled())
michael@0 2510 fprintf(out, "\n");
michael@0 2511
michael@0 2512 if (err)
michael@0 2513 PORT_SetError(err);
michael@0 2514 if (err || rv != SECSuccess)
michael@0 2515 return SECFailure;
michael@0 2516
michael@0 2517 return 0;
michael@0 2518 }
michael@0 2519
michael@0 2520 /*
michael@0 2521 ** PKCS7 Support
michael@0 2522 */
michael@0 2523
michael@0 2524 /* forward declaration */
michael@0 2525 static int
michael@0 2526 secu_PrintPKCS7ContentInfo(FILE *, SEC_PKCS7ContentInfo *, char *, int);
michael@0 2527
michael@0 2528 /*
michael@0 2529 ** secu_PrintPKCS7EncContent
michael@0 2530 ** Prints a SEC_PKCS7EncryptedContentInfo (without decrypting it)
michael@0 2531 */
michael@0 2532 static void
michael@0 2533 secu_PrintPKCS7EncContent(FILE *out, SEC_PKCS7EncryptedContentInfo *src,
michael@0 2534 char *m, int level)
michael@0 2535 {
michael@0 2536 if (src->contentTypeTag == NULL)
michael@0 2537 src->contentTypeTag = SECOID_FindOID(&(src->contentType));
michael@0 2538
michael@0 2539 SECU_Indent(out, level);
michael@0 2540 fprintf(out, "%s:\n", m);
michael@0 2541 SECU_Indent(out, level + 1);
michael@0 2542 fprintf(out, "Content Type: %s\n",
michael@0 2543 (src->contentTypeTag != NULL) ? src->contentTypeTag->desc
michael@0 2544 : "Unknown");
michael@0 2545 SECU_PrintAlgorithmID(out, &(src->contentEncAlg),
michael@0 2546 "Content Encryption Algorithm", level+1);
michael@0 2547 SECU_PrintAsHex(out, &(src->encContent),
michael@0 2548 "Encrypted Content", level+1);
michael@0 2549 }
michael@0 2550
michael@0 2551 /*
michael@0 2552 ** secu_PrintRecipientInfo
michael@0 2553 ** Prints a PKCS7RecipientInfo type
michael@0 2554 */
michael@0 2555 static void
michael@0 2556 secu_PrintRecipientInfo(FILE *out, SEC_PKCS7RecipientInfo *info, char *m,
michael@0 2557 int level)
michael@0 2558 {
michael@0 2559 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 2560 SECU_PrintInteger(out, &(info->version), "Version", level + 1);
michael@0 2561
michael@0 2562 SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer",
michael@0 2563 level + 1);
michael@0 2564 SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber),
michael@0 2565 "Serial Number", level + 1);
michael@0 2566
michael@0 2567 /* Parse and display encrypted key */
michael@0 2568 SECU_PrintAlgorithmID(out, &(info->keyEncAlg),
michael@0 2569 "Key Encryption Algorithm", level + 1);
michael@0 2570 SECU_PrintAsHex(out, &(info->encKey), "Encrypted Key", level + 1);
michael@0 2571 }
michael@0 2572
michael@0 2573 /*
michael@0 2574 ** secu_PrintSignerInfo
michael@0 2575 ** Prints a PKCS7SingerInfo type
michael@0 2576 */
michael@0 2577 static void
michael@0 2578 secu_PrintSignerInfo(FILE *out, SEC_PKCS7SignerInfo *info, char *m, int level)
michael@0 2579 {
michael@0 2580 SEC_PKCS7Attribute *attr;
michael@0 2581 int iv;
michael@0 2582 char om[100];
michael@0 2583
michael@0 2584 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 2585 SECU_PrintInteger(out, &(info->version), "Version", level + 1);
michael@0 2586
michael@0 2587 SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer",
michael@0 2588 level + 1);
michael@0 2589 SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber),
michael@0 2590 "Serial Number", level + 1);
michael@0 2591
michael@0 2592 SECU_PrintAlgorithmID(out, &(info->digestAlg), "Digest Algorithm",
michael@0 2593 level + 1);
michael@0 2594
michael@0 2595 if (info->authAttr != NULL) {
michael@0 2596 SECU_Indent(out, level + 1);
michael@0 2597 fprintf(out, "Authenticated Attributes:\n");
michael@0 2598 iv = 0;
michael@0 2599 while ((attr = info->authAttr[iv++]) != NULL) {
michael@0 2600 sprintf(om, "Attribute (%d)", iv);
michael@0 2601 secu_PrintAttribute(out, attr, om, level + 2);
michael@0 2602 }
michael@0 2603 }
michael@0 2604
michael@0 2605 /* Parse and display signature */
michael@0 2606 SECU_PrintAlgorithmID(out, &(info->digestEncAlg),
michael@0 2607 "Digest Encryption Algorithm", level + 1);
michael@0 2608 SECU_PrintAsHex(out, &(info->encDigest), "Encrypted Digest", level + 1);
michael@0 2609
michael@0 2610 if (info->unAuthAttr != NULL) {
michael@0 2611 SECU_Indent(out, level + 1);
michael@0 2612 fprintf(out, "Unauthenticated Attributes:\n");
michael@0 2613 iv = 0;
michael@0 2614 while ((attr = info->unAuthAttr[iv++]) != NULL) {
michael@0 2615 sprintf(om, "Attribute (%x)", iv);
michael@0 2616 secu_PrintAttribute(out, attr, om, level + 2);
michael@0 2617 }
michael@0 2618 }
michael@0 2619 }
michael@0 2620
michael@0 2621 /* callers of this function must make sure that the CERTSignedCrl
michael@0 2622 from which they are extracting the CERTCrl has been fully-decoded.
michael@0 2623 Otherwise it will not have the entries even though the CRL may have
michael@0 2624 some */
michael@0 2625
michael@0 2626 void
michael@0 2627 SECU_PrintCRLInfo(FILE *out, CERTCrl *crl, char *m, int level)
michael@0 2628 {
michael@0 2629 CERTCrlEntry *entry;
michael@0 2630 int iv;
michael@0 2631 char om[100];
michael@0 2632
michael@0 2633 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 2634 /* version is optional */
michael@0 2635 iv = crl->version.len ? DER_GetInteger(&crl->version) : 0;
michael@0 2636 SECU_Indent(out, level+1);
michael@0 2637 fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv);
michael@0 2638 SECU_PrintAlgorithmID(out, &(crl->signatureAlg), "Signature Algorithm",
michael@0 2639 level + 1);
michael@0 2640 SECU_PrintName(out, &(crl->name), "Issuer", level + 1);
michael@0 2641 SECU_PrintTimeChoice(out, &(crl->lastUpdate), "This Update", level + 1);
michael@0 2642 if (crl->nextUpdate.data && crl->nextUpdate.len) /* is optional */
michael@0 2643 SECU_PrintTimeChoice(out, &(crl->nextUpdate), "Next Update", level + 1);
michael@0 2644
michael@0 2645 if (crl->entries != NULL) {
michael@0 2646 iv = 0;
michael@0 2647 while ((entry = crl->entries[iv++]) != NULL) {
michael@0 2648 sprintf(om, "Entry %d (0x%x):\n", iv, iv);
michael@0 2649 SECU_Indent(out, level + 1); fputs(om, out);
michael@0 2650 SECU_PrintInteger(out, &(entry->serialNumber), "Serial Number",
michael@0 2651 level + 2);
michael@0 2652 SECU_PrintTimeChoice(out, &(entry->revocationDate),
michael@0 2653 "Revocation Date", level + 2);
michael@0 2654 SECU_PrintExtensions(out, entry->extensions,
michael@0 2655 "Entry Extensions", level + 2);
michael@0 2656 }
michael@0 2657 }
michael@0 2658 SECU_PrintExtensions(out, crl->extensions, "CRL Extensions", level + 1);
michael@0 2659 }
michael@0 2660
michael@0 2661 /*
michael@0 2662 ** secu_PrintPKCS7Signed
michael@0 2663 ** Pretty print a PKCS7 signed data type (up to version 1).
michael@0 2664 */
michael@0 2665 static int
michael@0 2666 secu_PrintPKCS7Signed(FILE *out, SEC_PKCS7SignedData *src,
michael@0 2667 const char *m, int level)
michael@0 2668 {
michael@0 2669 SECAlgorithmID *digAlg; /* digest algorithms */
michael@0 2670 SECItem *aCert; /* certificate */
michael@0 2671 CERTSignedCrl *aCrl; /* certificate revocation list */
michael@0 2672 SEC_PKCS7SignerInfo *sigInfo; /* signer information */
michael@0 2673 int rv, iv;
michael@0 2674 char om[100];
michael@0 2675
michael@0 2676 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 2677 SECU_PrintInteger(out, &(src->version), "Version", level + 1);
michael@0 2678
michael@0 2679 /* Parse and list digest algorithms (if any) */
michael@0 2680 if (src->digestAlgorithms != NULL) {
michael@0 2681 SECU_Indent(out, level + 1); fprintf(out, "Digest Algorithm List:\n");
michael@0 2682 iv = 0;
michael@0 2683 while ((digAlg = src->digestAlgorithms[iv++]) != NULL) {
michael@0 2684 sprintf(om, "Digest Algorithm (%x)", iv);
michael@0 2685 SECU_PrintAlgorithmID(out, digAlg, om, level + 2);
michael@0 2686 }
michael@0 2687 }
michael@0 2688
michael@0 2689 /* Now for the content */
michael@0 2690 rv = secu_PrintPKCS7ContentInfo(out, &(src->contentInfo),
michael@0 2691 "Content Information", level + 1);
michael@0 2692 if (rv != 0)
michael@0 2693 return rv;
michael@0 2694
michael@0 2695 /* Parse and list certificates (if any) */
michael@0 2696 if (src->rawCerts != NULL) {
michael@0 2697 SECU_Indent(out, level + 1); fprintf(out, "Certificate List:\n");
michael@0 2698 iv = 0;
michael@0 2699 while ((aCert = src->rawCerts[iv++]) != NULL) {
michael@0 2700 sprintf(om, "Certificate (%x)", iv);
michael@0 2701 rv = SECU_PrintSignedData(out, aCert, om, level + 2,
michael@0 2702 SECU_PrintCertificate);
michael@0 2703 if (rv)
michael@0 2704 return rv;
michael@0 2705 }
michael@0 2706 }
michael@0 2707
michael@0 2708 /* Parse and list CRL's (if any) */
michael@0 2709 if (src->crls != NULL) {
michael@0 2710 SECU_Indent(out, level + 1);
michael@0 2711 fprintf(out, "Signed Revocation Lists:\n");
michael@0 2712 iv = 0;
michael@0 2713 while ((aCrl = src->crls[iv++]) != NULL) {
michael@0 2714 sprintf(om, "Signed Revocation List (%x)", iv);
michael@0 2715 SECU_Indent(out, level + 2); fprintf(out, "%s:\n", om);
michael@0 2716 SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm,
michael@0 2717 "Signature Algorithm", level+3);
michael@0 2718 DER_ConvertBitString(&aCrl->signatureWrap.signature);
michael@0 2719 SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature",
michael@0 2720 level+3);
michael@0 2721 SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List",
michael@0 2722 level + 3);
michael@0 2723 }
michael@0 2724 }
michael@0 2725
michael@0 2726 /* Parse and list signatures (if any) */
michael@0 2727 if (src->signerInfos != NULL) {
michael@0 2728 SECU_Indent(out, level + 1);
michael@0 2729 fprintf(out, "Signer Information List:\n");
michael@0 2730 iv = 0;
michael@0 2731 while ((sigInfo = src->signerInfos[iv++]) != NULL) {
michael@0 2732 sprintf(om, "Signer Information (%x)", iv);
michael@0 2733 secu_PrintSignerInfo(out, sigInfo, om, level + 2);
michael@0 2734 }
michael@0 2735 }
michael@0 2736
michael@0 2737 return 0;
michael@0 2738 }
michael@0 2739
michael@0 2740 /*
michael@0 2741 ** secu_PrintPKCS7Enveloped
michael@0 2742 ** Pretty print a PKCS7 enveloped data type (up to version 1).
michael@0 2743 */
michael@0 2744 static void
michael@0 2745 secu_PrintPKCS7Enveloped(FILE *out, SEC_PKCS7EnvelopedData *src,
michael@0 2746 const char *m, int level)
michael@0 2747 {
michael@0 2748 SEC_PKCS7RecipientInfo *recInfo; /* pointer for signer information */
michael@0 2749 int iv;
michael@0 2750 char om[100];
michael@0 2751
michael@0 2752 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 2753 SECU_PrintInteger(out, &(src->version), "Version", level + 1);
michael@0 2754
michael@0 2755 /* Parse and list recipients (this is not optional) */
michael@0 2756 if (src->recipientInfos != NULL) {
michael@0 2757 SECU_Indent(out, level + 1);
michael@0 2758 fprintf(out, "Recipient Information List:\n");
michael@0 2759 iv = 0;
michael@0 2760 while ((recInfo = src->recipientInfos[iv++]) != NULL) {
michael@0 2761 sprintf(om, "Recipient Information (%x)", iv);
michael@0 2762 secu_PrintRecipientInfo(out, recInfo, om, level + 2);
michael@0 2763 }
michael@0 2764 }
michael@0 2765
michael@0 2766 secu_PrintPKCS7EncContent(out, &src->encContentInfo,
michael@0 2767 "Encrypted Content Information", level + 1);
michael@0 2768 }
michael@0 2769
michael@0 2770 /*
michael@0 2771 ** secu_PrintPKCS7SignedEnveloped
michael@0 2772 ** Pretty print a PKCS7 singed and enveloped data type (up to version 1).
michael@0 2773 */
michael@0 2774 static int
michael@0 2775 secu_PrintPKCS7SignedAndEnveloped(FILE *out,
michael@0 2776 SEC_PKCS7SignedAndEnvelopedData *src,
michael@0 2777 const char *m, int level)
michael@0 2778 {
michael@0 2779 SECAlgorithmID *digAlg; /* pointer for digest algorithms */
michael@0 2780 SECItem *aCert; /* pointer for certificate */
michael@0 2781 CERTSignedCrl *aCrl; /* pointer for certificate revocation list */
michael@0 2782 SEC_PKCS7SignerInfo *sigInfo; /* pointer for signer information */
michael@0 2783 SEC_PKCS7RecipientInfo *recInfo; /* pointer for recipient information */
michael@0 2784 int rv, iv;
michael@0 2785 char om[100];
michael@0 2786
michael@0 2787 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 2788 SECU_PrintInteger(out, &(src->version), "Version", level + 1);
michael@0 2789
michael@0 2790 /* Parse and list recipients (this is not optional) */
michael@0 2791 if (src->recipientInfos != NULL) {
michael@0 2792 SECU_Indent(out, level + 1);
michael@0 2793 fprintf(out, "Recipient Information List:\n");
michael@0 2794 iv = 0;
michael@0 2795 while ((recInfo = src->recipientInfos[iv++]) != NULL) {
michael@0 2796 sprintf(om, "Recipient Information (%x)", iv);
michael@0 2797 secu_PrintRecipientInfo(out, recInfo, om, level + 2);
michael@0 2798 }
michael@0 2799 }
michael@0 2800
michael@0 2801 /* Parse and list digest algorithms (if any) */
michael@0 2802 if (src->digestAlgorithms != NULL) {
michael@0 2803 SECU_Indent(out, level + 1); fprintf(out, "Digest Algorithm List:\n");
michael@0 2804 iv = 0;
michael@0 2805 while ((digAlg = src->digestAlgorithms[iv++]) != NULL) {
michael@0 2806 sprintf(om, "Digest Algorithm (%x)", iv);
michael@0 2807 SECU_PrintAlgorithmID(out, digAlg, om, level + 2);
michael@0 2808 }
michael@0 2809 }
michael@0 2810
michael@0 2811 secu_PrintPKCS7EncContent(out, &src->encContentInfo,
michael@0 2812 "Encrypted Content Information", level + 1);
michael@0 2813
michael@0 2814 /* Parse and list certificates (if any) */
michael@0 2815 if (src->rawCerts != NULL) {
michael@0 2816 SECU_Indent(out, level + 1); fprintf(out, "Certificate List:\n");
michael@0 2817 iv = 0;
michael@0 2818 while ((aCert = src->rawCerts[iv++]) != NULL) {
michael@0 2819 sprintf(om, "Certificate (%x)", iv);
michael@0 2820 rv = SECU_PrintSignedData(out, aCert, om, level + 2,
michael@0 2821 SECU_PrintCertificate);
michael@0 2822 if (rv)
michael@0 2823 return rv;
michael@0 2824 }
michael@0 2825 }
michael@0 2826
michael@0 2827 /* Parse and list CRL's (if any) */
michael@0 2828 if (src->crls != NULL) {
michael@0 2829 SECU_Indent(out, level + 1);
michael@0 2830 fprintf(out, "Signed Revocation Lists:\n");
michael@0 2831 iv = 0;
michael@0 2832 while ((aCrl = src->crls[iv++]) != NULL) {
michael@0 2833 sprintf(om, "Signed Revocation List (%x)", iv);
michael@0 2834 SECU_Indent(out, level + 2); fprintf(out, "%s:\n", om);
michael@0 2835 SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm,
michael@0 2836 "Signature Algorithm", level+3);
michael@0 2837 DER_ConvertBitString(&aCrl->signatureWrap.signature);
michael@0 2838 SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature",
michael@0 2839 level+3);
michael@0 2840 SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List",
michael@0 2841 level + 3);
michael@0 2842 }
michael@0 2843 }
michael@0 2844
michael@0 2845 /* Parse and list signatures (if any) */
michael@0 2846 if (src->signerInfos != NULL) {
michael@0 2847 SECU_Indent(out, level + 1);
michael@0 2848 fprintf(out, "Signer Information List:\n");
michael@0 2849 iv = 0;
michael@0 2850 while ((sigInfo = src->signerInfos[iv++]) != NULL) {
michael@0 2851 sprintf(om, "Signer Information (%x)", iv);
michael@0 2852 secu_PrintSignerInfo(out, sigInfo, om, level + 2);
michael@0 2853 }
michael@0 2854 }
michael@0 2855
michael@0 2856 return 0;
michael@0 2857 }
michael@0 2858
michael@0 2859 int
michael@0 2860 SECU_PrintCrl (FILE *out, SECItem *der, char *m, int level)
michael@0 2861 {
michael@0 2862 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 2863 CERTCrl *c = NULL;
michael@0 2864 int rv = SEC_ERROR_NO_MEMORY;
michael@0 2865
michael@0 2866 if (!arena)
michael@0 2867 return rv;
michael@0 2868 do {
michael@0 2869 /* Decode CRL */
michael@0 2870 c = PORT_ArenaZNew(arena, CERTCrl);
michael@0 2871 if (!c)
michael@0 2872 break;
michael@0 2873
michael@0 2874 rv = SEC_QuickDERDecodeItem(arena, c, SEC_ASN1_GET(CERT_CrlTemplate), der);
michael@0 2875 if (rv != SECSuccess)
michael@0 2876 break;
michael@0 2877 SECU_PrintCRLInfo (out, c, m, level);
michael@0 2878 } while (0);
michael@0 2879 PORT_FreeArena (arena, PR_FALSE);
michael@0 2880 return rv;
michael@0 2881 }
michael@0 2882
michael@0 2883
michael@0 2884 /*
michael@0 2885 ** secu_PrintPKCS7Encrypted
michael@0 2886 ** Pretty print a PKCS7 encrypted data type (up to version 1).
michael@0 2887 */
michael@0 2888 static void
michael@0 2889 secu_PrintPKCS7Encrypted(FILE *out, SEC_PKCS7EncryptedData *src,
michael@0 2890 const char *m, int level)
michael@0 2891 {
michael@0 2892 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 2893 SECU_PrintInteger(out, &(src->version), "Version", level + 1);
michael@0 2894
michael@0 2895 secu_PrintPKCS7EncContent(out, &src->encContentInfo,
michael@0 2896 "Encrypted Content Information", level + 1);
michael@0 2897 }
michael@0 2898
michael@0 2899 /*
michael@0 2900 ** secu_PrintPKCS7Digested
michael@0 2901 ** Pretty print a PKCS7 digested data type (up to version 1).
michael@0 2902 */
michael@0 2903 static void
michael@0 2904 secu_PrintPKCS7Digested(FILE *out, SEC_PKCS7DigestedData *src,
michael@0 2905 const char *m, int level)
michael@0 2906 {
michael@0 2907 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 2908 SECU_PrintInteger(out, &(src->version), "Version", level + 1);
michael@0 2909
michael@0 2910 SECU_PrintAlgorithmID(out, &src->digestAlg, "Digest Algorithm",
michael@0 2911 level + 1);
michael@0 2912 secu_PrintPKCS7ContentInfo(out, &src->contentInfo, "Content Information",
michael@0 2913 level + 1);
michael@0 2914 SECU_PrintAsHex(out, &src->digest, "Digest", level + 1);
michael@0 2915 }
michael@0 2916
michael@0 2917 /*
michael@0 2918 ** secu_PrintPKCS7ContentInfo
michael@0 2919 ** Takes a SEC_PKCS7ContentInfo type and sends the contents to the
michael@0 2920 ** appropriate function
michael@0 2921 */
michael@0 2922 static int
michael@0 2923 secu_PrintPKCS7ContentInfo(FILE *out, SEC_PKCS7ContentInfo *src,
michael@0 2924 char *m, int level)
michael@0 2925 {
michael@0 2926 const char *desc;
michael@0 2927 SECOidTag kind;
michael@0 2928 int rv;
michael@0 2929
michael@0 2930 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 2931 level++;
michael@0 2932
michael@0 2933 if (src->contentTypeTag == NULL)
michael@0 2934 src->contentTypeTag = SECOID_FindOID(&(src->contentType));
michael@0 2935
michael@0 2936 if (src->contentTypeTag == NULL) {
michael@0 2937 desc = "Unknown";
michael@0 2938 kind = SEC_OID_PKCS7_DATA;
michael@0 2939 } else {
michael@0 2940 desc = src->contentTypeTag->desc;
michael@0 2941 kind = src->contentTypeTag->offset;
michael@0 2942 }
michael@0 2943
michael@0 2944 if (src->content.data == NULL) {
michael@0 2945 SECU_Indent(out, level); fprintf(out, "%s:\n", desc);
michael@0 2946 level++;
michael@0 2947 SECU_Indent(out, level); fprintf(out, "<no content>\n");
michael@0 2948 return 0;
michael@0 2949 }
michael@0 2950
michael@0 2951 rv = 0;
michael@0 2952 switch (kind) {
michael@0 2953 case SEC_OID_PKCS7_SIGNED_DATA: /* Signed Data */
michael@0 2954 rv = secu_PrintPKCS7Signed(out, src->content.signedData, desc, level);
michael@0 2955 break;
michael@0 2956
michael@0 2957 case SEC_OID_PKCS7_ENVELOPED_DATA: /* Enveloped Data */
michael@0 2958 secu_PrintPKCS7Enveloped(out, src->content.envelopedData, desc, level);
michael@0 2959 break;
michael@0 2960
michael@0 2961 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: /* Signed and Enveloped */
michael@0 2962 rv = secu_PrintPKCS7SignedAndEnveloped(out,
michael@0 2963 src->content.signedAndEnvelopedData,
michael@0 2964 desc, level);
michael@0 2965 break;
michael@0 2966
michael@0 2967 case SEC_OID_PKCS7_DIGESTED_DATA: /* Digested Data */
michael@0 2968 secu_PrintPKCS7Digested(out, src->content.digestedData, desc, level);
michael@0 2969 break;
michael@0 2970
michael@0 2971 case SEC_OID_PKCS7_ENCRYPTED_DATA: /* Encrypted Data */
michael@0 2972 secu_PrintPKCS7Encrypted(out, src->content.encryptedData, desc, level);
michael@0 2973 break;
michael@0 2974
michael@0 2975 default:
michael@0 2976 SECU_PrintAsHex(out, src->content.data, desc, level);
michael@0 2977 break;
michael@0 2978 }
michael@0 2979
michael@0 2980 return rv;
michael@0 2981 }
michael@0 2982
michael@0 2983 /*
michael@0 2984 ** SECU_PrintPKCS7ContentInfo
michael@0 2985 ** Decode and print any major PKCS7 data type (up to version 1).
michael@0 2986 */
michael@0 2987 int
michael@0 2988 SECU_PrintPKCS7ContentInfo(FILE *out, SECItem *der, char *m, int level)
michael@0 2989 {
michael@0 2990 SEC_PKCS7ContentInfo *cinfo;
michael@0 2991 int rv;
michael@0 2992
michael@0 2993 cinfo = SEC_PKCS7DecodeItem(der, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
michael@0 2994 if (cinfo != NULL) {
michael@0 2995 /* Send it to recursive parsing and printing module */
michael@0 2996 rv = secu_PrintPKCS7ContentInfo(out, cinfo, m, level);
michael@0 2997 SEC_PKCS7DestroyContentInfo(cinfo);
michael@0 2998 } else {
michael@0 2999 rv = -1;
michael@0 3000 }
michael@0 3001
michael@0 3002 return rv;
michael@0 3003 }
michael@0 3004
michael@0 3005 /*
michael@0 3006 ** End of PKCS7 functions
michael@0 3007 */
michael@0 3008
michael@0 3009 void
michael@0 3010 printFlags(FILE *out, unsigned int flags, int level)
michael@0 3011 {
michael@0 3012 if ( flags & CERTDB_TERMINAL_RECORD ) {
michael@0 3013 SECU_Indent(out, level); fprintf(out, "Terminal Record\n");
michael@0 3014 }
michael@0 3015 if ( flags & CERTDB_TRUSTED ) {
michael@0 3016 SECU_Indent(out, level); fprintf(out, "Trusted\n");
michael@0 3017 }
michael@0 3018 if ( flags & CERTDB_SEND_WARN ) {
michael@0 3019 SECU_Indent(out, level); fprintf(out, "Warn When Sending\n");
michael@0 3020 }
michael@0 3021 if ( flags & CERTDB_VALID_CA ) {
michael@0 3022 SECU_Indent(out, level); fprintf(out, "Valid CA\n");
michael@0 3023 }
michael@0 3024 if ( flags & CERTDB_TRUSTED_CA ) {
michael@0 3025 SECU_Indent(out, level); fprintf(out, "Trusted CA\n");
michael@0 3026 }
michael@0 3027 if ( flags & CERTDB_NS_TRUSTED_CA ) {
michael@0 3028 SECU_Indent(out, level); fprintf(out, "Netscape Trusted CA\n");
michael@0 3029 }
michael@0 3030 if ( flags & CERTDB_USER ) {
michael@0 3031 SECU_Indent(out, level); fprintf(out, "User\n");
michael@0 3032 }
michael@0 3033 if ( flags & CERTDB_TRUSTED_CLIENT_CA ) {
michael@0 3034 SECU_Indent(out, level); fprintf(out, "Trusted Client CA\n");
michael@0 3035 }
michael@0 3036 if ( flags & CERTDB_GOVT_APPROVED_CA ) {
michael@0 3037 SECU_Indent(out, level); fprintf(out, "Step-up\n");
michael@0 3038 }
michael@0 3039 }
michael@0 3040
michael@0 3041 void
michael@0 3042 SECU_PrintTrustFlags(FILE *out, CERTCertTrust *trust, char *m, int level)
michael@0 3043 {
michael@0 3044 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 3045 SECU_Indent(out, level+1); fprintf(out, "SSL Flags:\n");
michael@0 3046 printFlags(out, trust->sslFlags, level+2);
michael@0 3047 SECU_Indent(out, level+1); fprintf(out, "Email Flags:\n");
michael@0 3048 printFlags(out, trust->emailFlags, level+2);
michael@0 3049 SECU_Indent(out, level+1); fprintf(out, "Object Signing Flags:\n");
michael@0 3050 printFlags(out, trust->objectSigningFlags, level+2);
michael@0 3051 }
michael@0 3052
michael@0 3053 int SECU_PrintDERName(FILE *out, SECItem *der, const char *m, int level)
michael@0 3054 {
michael@0 3055 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 3056 CERTName *name;
michael@0 3057 int rv = SEC_ERROR_NO_MEMORY;
michael@0 3058
michael@0 3059 if (!arena)
michael@0 3060 return rv;
michael@0 3061
michael@0 3062 name = PORT_ArenaZNew(arena, CERTName);
michael@0 3063 if (!name)
michael@0 3064 goto loser;
michael@0 3065
michael@0 3066 rv = SEC_ASN1DecodeItem(arena, name, SEC_ASN1_GET(CERT_NameTemplate), der);
michael@0 3067 if (rv)
michael@0 3068 goto loser;
michael@0 3069
michael@0 3070 SECU_PrintName(out, name, m, level);
michael@0 3071 if (!SECU_GetWrapEnabled()) /*SECU_PrintName didn't add newline*/
michael@0 3072 SECU_Newline(out);
michael@0 3073 loser:
michael@0 3074 PORT_FreeArena(arena, PR_FALSE);
michael@0 3075 return rv;
michael@0 3076 }
michael@0 3077
michael@0 3078 typedef enum {
michael@0 3079 noSignature = 0,
michael@0 3080 withSignature = 1
michael@0 3081 } SignatureOptionType;
michael@0 3082
michael@0 3083 static int
michael@0 3084 secu_PrintSignedDataSigOpt(FILE *out, SECItem *der, const char *m,
michael@0 3085 int level, SECU_PPFunc inner,
michael@0 3086 SignatureOptionType withSignature)
michael@0 3087 {
michael@0 3088 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 3089 CERTSignedData *sd;
michael@0 3090 int rv = SEC_ERROR_NO_MEMORY;
michael@0 3091
michael@0 3092 if (!arena)
michael@0 3093 return rv;
michael@0 3094
michael@0 3095 /* Strip off the signature */
michael@0 3096 sd = PORT_ArenaZNew(arena, CERTSignedData);
michael@0 3097 if (!sd)
michael@0 3098 goto loser;
michael@0 3099
michael@0 3100 rv = SEC_ASN1DecodeItem(arena, sd, SEC_ASN1_GET(CERT_SignedDataTemplate),
michael@0 3101 der);
michael@0 3102 if (rv)
michael@0 3103 goto loser;
michael@0 3104
michael@0 3105 if (m) {
michael@0 3106 SECU_Indent(out, level); fprintf(out, "%s:\n", m);
michael@0 3107 } else {
michael@0 3108 level -= 1;
michael@0 3109 }
michael@0 3110 rv = (*inner)(out, &sd->data, "Data", level+1);
michael@0 3111
michael@0 3112 if (withSignature) {
michael@0 3113 SECU_PrintAlgorithmID(out, &sd->signatureAlgorithm, "Signature Algorithm",
michael@0 3114 level+1);
michael@0 3115 DER_ConvertBitString(&sd->signature);
michael@0 3116 SECU_PrintAsHex(out, &sd->signature, "Signature", level+1);
michael@0 3117 }
michael@0 3118 SECU_PrintFingerprints(out, der, "Fingerprint", level+1);
michael@0 3119 loser:
michael@0 3120 PORT_FreeArena(arena, PR_FALSE);
michael@0 3121 return rv;
michael@0 3122 }
michael@0 3123
michael@0 3124 int SECU_PrintSignedData(FILE *out, SECItem *der, const char *m,
michael@0 3125 int level, SECU_PPFunc inner)
michael@0 3126 {
michael@0 3127 return secu_PrintSignedDataSigOpt(out, der, m, level, inner,
michael@0 3128 withSignature);
michael@0 3129 }
michael@0 3130
michael@0 3131 int SECU_PrintSignedContent(FILE *out, SECItem *der, char *m,
michael@0 3132 int level, SECU_PPFunc inner)
michael@0 3133 {
michael@0 3134 return secu_PrintSignedDataSigOpt(out, der, m, level, inner,
michael@0 3135 noSignature);
michael@0 3136 }
michael@0 3137
michael@0 3138 SECStatus
michael@0 3139 SEC_PrintCertificateAndTrust(CERTCertificate *cert,
michael@0 3140 const char *label,
michael@0 3141 CERTCertTrust *trust)
michael@0 3142 {
michael@0 3143 SECStatus rv;
michael@0 3144 SECItem data;
michael@0 3145 CERTCertTrust certTrust;
michael@0 3146
michael@0 3147 data.data = cert->derCert.data;
michael@0 3148 data.len = cert->derCert.len;
michael@0 3149
michael@0 3150 rv = SECU_PrintSignedData(stdout, &data, label, 0,
michael@0 3151 SECU_PrintCertificate);
michael@0 3152 if (rv) {
michael@0 3153 return(SECFailure);
michael@0 3154 }
michael@0 3155 if (trust) {
michael@0 3156 SECU_PrintTrustFlags(stdout, trust,
michael@0 3157 "Certificate Trust Flags", 1);
michael@0 3158 } else if (CERT_GetCertTrust(cert, &certTrust) == SECSuccess) {
michael@0 3159 SECU_PrintTrustFlags(stdout, &certTrust,
michael@0 3160 "Certificate Trust Flags", 1);
michael@0 3161 }
michael@0 3162
michael@0 3163 printf("\n");
michael@0 3164
michael@0 3165 return(SECSuccess);
michael@0 3166 }
michael@0 3167
michael@0 3168
michael@0 3169 static char *
michael@0 3170 bestCertName(CERTCertificate *cert) {
michael@0 3171 if (cert->nickname) {
michael@0 3172 return cert->nickname;
michael@0 3173 }
michael@0 3174 if (cert->emailAddr && cert->emailAddr[0]) {
michael@0 3175 return cert->emailAddr;
michael@0 3176 }
michael@0 3177 return cert->subjectName;
michael@0 3178 }
michael@0 3179
michael@0 3180 void
michael@0 3181 SECU_printCertProblemsOnDate(FILE *outfile, CERTCertDBHandle *handle,
michael@0 3182 CERTCertificate *cert, PRBool checksig,
michael@0 3183 SECCertificateUsage certUsage, void *pinArg, PRBool verbose,
michael@0 3184 PRTime datetime)
michael@0 3185 {
michael@0 3186 CERTVerifyLog log;
michael@0 3187 CERTVerifyLogNode *node;
michael@0 3188
michael@0 3189 PRErrorCode err = PORT_GetError();
michael@0 3190
michael@0 3191 log.arena = PORT_NewArena(512);
michael@0 3192 log.head = log.tail = NULL;
michael@0 3193 log.count = 0;
michael@0 3194 CERT_VerifyCertificate(handle, cert, checksig, certUsage, datetime, pinArg, &log, NULL);
michael@0 3195
michael@0 3196 SECU_displayVerifyLog(outfile, &log, verbose);
michael@0 3197
michael@0 3198 for (node = log.head; node; node = node->next) {
michael@0 3199 if (node->cert)
michael@0 3200 CERT_DestroyCertificate(node->cert);
michael@0 3201 }
michael@0 3202 PORT_FreeArena(log.arena, PR_FALSE);
michael@0 3203
michael@0 3204 PORT_SetError(err); /* restore original error code */
michael@0 3205 }
michael@0 3206
michael@0 3207 void
michael@0 3208 SECU_displayVerifyLog(FILE *outfile, CERTVerifyLog *log,
michael@0 3209 PRBool verbose)
michael@0 3210 {
michael@0 3211 CERTVerifyLogNode *node = NULL;
michael@0 3212 unsigned int depth = (unsigned int)-1;
michael@0 3213 unsigned int flags = 0;
michael@0 3214 char * errstr = NULL;
michael@0 3215
michael@0 3216 if (log->count > 0) {
michael@0 3217 fprintf(outfile,"PROBLEM WITH THE CERT CHAIN:\n");
michael@0 3218 for (node = log->head; node; node = node->next) {
michael@0 3219 if (depth != node->depth) {
michael@0 3220 depth = node->depth;
michael@0 3221 fprintf(outfile,"CERT %d. %s %s:\n", depth,
michael@0 3222 bestCertName(node->cert),
michael@0 3223 depth ? "[Certificate Authority]": "");
michael@0 3224 if (verbose) {
michael@0 3225 const char * emailAddr;
michael@0 3226 emailAddr = CERT_GetFirstEmailAddress(node->cert);
michael@0 3227 if (emailAddr) {
michael@0 3228 fprintf(outfile,"Email Address(es): ");
michael@0 3229 do {
michael@0 3230 fprintf(outfile, "%s\n", emailAddr);
michael@0 3231 emailAddr = CERT_GetNextEmailAddress(node->cert,
michael@0 3232 emailAddr);
michael@0 3233 } while (emailAddr);
michael@0 3234 }
michael@0 3235 }
michael@0 3236 }
michael@0 3237 fprintf(outfile, " ERROR %ld: %s\n", node->error,
michael@0 3238 SECU_Strerror(node->error));
michael@0 3239 errstr = NULL;
michael@0 3240 switch (node->error) {
michael@0 3241 case SEC_ERROR_INADEQUATE_KEY_USAGE:
michael@0 3242 flags = (unsigned int)node->arg;
michael@0 3243 switch (flags) {
michael@0 3244 case KU_DIGITAL_SIGNATURE:
michael@0 3245 errstr = "Cert cannot sign.";
michael@0 3246 break;
michael@0 3247 case KU_KEY_ENCIPHERMENT:
michael@0 3248 errstr = "Cert cannot encrypt.";
michael@0 3249 break;
michael@0 3250 case KU_KEY_CERT_SIGN:
michael@0 3251 errstr = "Cert cannot sign other certs.";
michael@0 3252 break;
michael@0 3253 default:
michael@0 3254 errstr = "[unknown usage].";
michael@0 3255 break;
michael@0 3256 }
michael@0 3257 case SEC_ERROR_INADEQUATE_CERT_TYPE:
michael@0 3258 flags = (unsigned int)node->arg;
michael@0 3259 switch (flags) {
michael@0 3260 case NS_CERT_TYPE_SSL_CLIENT:
michael@0 3261 case NS_CERT_TYPE_SSL_SERVER:
michael@0 3262 errstr = "Cert cannot be used for SSL.";
michael@0 3263 break;
michael@0 3264 case NS_CERT_TYPE_SSL_CA:
michael@0 3265 errstr = "Cert cannot be used as an SSL CA.";
michael@0 3266 break;
michael@0 3267 case NS_CERT_TYPE_EMAIL:
michael@0 3268 errstr = "Cert cannot be used for SMIME.";
michael@0 3269 break;
michael@0 3270 case NS_CERT_TYPE_EMAIL_CA:
michael@0 3271 errstr = "Cert cannot be used as an SMIME CA.";
michael@0 3272 break;
michael@0 3273 case NS_CERT_TYPE_OBJECT_SIGNING:
michael@0 3274 errstr = "Cert cannot be used for object signing.";
michael@0 3275 break;
michael@0 3276 case NS_CERT_TYPE_OBJECT_SIGNING_CA:
michael@0 3277 errstr = "Cert cannot be used as an object signing CA.";
michael@0 3278 break;
michael@0 3279 default:
michael@0 3280 errstr = "[unknown usage].";
michael@0 3281 break;
michael@0 3282 }
michael@0 3283 case SEC_ERROR_UNKNOWN_ISSUER:
michael@0 3284 case SEC_ERROR_UNTRUSTED_ISSUER:
michael@0 3285 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
michael@0 3286 errstr = node->cert->issuerName;
michael@0 3287 break;
michael@0 3288 default:
michael@0 3289 break;
michael@0 3290 }
michael@0 3291 if (errstr) {
michael@0 3292 fprintf(stderr," %s\n",errstr);
michael@0 3293 }
michael@0 3294 }
michael@0 3295 }
michael@0 3296 }
michael@0 3297
michael@0 3298 void
michael@0 3299 SECU_printCertProblems(FILE *outfile, CERTCertDBHandle *handle,
michael@0 3300 CERTCertificate *cert, PRBool checksig,
michael@0 3301 SECCertificateUsage certUsage, void *pinArg, PRBool verbose)
michael@0 3302 {
michael@0 3303 SECU_printCertProblemsOnDate(outfile, handle, cert, checksig,
michael@0 3304 certUsage, pinArg, verbose, PR_Now());
michael@0 3305 }
michael@0 3306
michael@0 3307 SECStatus
michael@0 3308 SECU_StoreCRL(PK11SlotInfo *slot, SECItem *derCrl, PRFileDesc *outFile,
michael@0 3309 PRBool ascii, char *url)
michael@0 3310 {
michael@0 3311 PORT_Assert(derCrl != NULL);
michael@0 3312 if (!derCrl) {
michael@0 3313 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 3314 return SECFailure;
michael@0 3315 }
michael@0 3316
michael@0 3317 if (outFile != NULL) {
michael@0 3318 if (ascii) {
michael@0 3319 PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CRL_HEADER,
michael@0 3320 BTOA_DataToAscii(derCrl->data, derCrl->len),
michael@0 3321 NS_CRL_TRAILER);
michael@0 3322 } else {
michael@0 3323 if (PR_Write(outFile, derCrl->data, derCrl->len) != derCrl->len) {
michael@0 3324 return SECFailure;
michael@0 3325 }
michael@0 3326 }
michael@0 3327 }
michael@0 3328 if (slot) {
michael@0 3329 CERTSignedCrl *newCrl = PK11_ImportCRL(slot, derCrl, url,
michael@0 3330 SEC_CRL_TYPE, NULL, 0, NULL, 0);
michael@0 3331 if (newCrl != NULL) {
michael@0 3332 SEC_DestroyCrl(newCrl);
michael@0 3333 return SECSuccess;
michael@0 3334 }
michael@0 3335 return SECFailure;
michael@0 3336 }
michael@0 3337 if (!outFile && !slot) {
michael@0 3338 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 3339 return SECFailure;
michael@0 3340 }
michael@0 3341 return SECSuccess;
michael@0 3342 }
michael@0 3343
michael@0 3344 SECStatus
michael@0 3345 SECU_SignAndEncodeCRL(CERTCertificate *issuer, CERTSignedCrl *signCrl,
michael@0 3346 SECOidTag hashAlgTag, SignAndEncodeFuncExitStat *resCode)
michael@0 3347 {
michael@0 3348 SECItem der;
michael@0 3349 SECKEYPrivateKey *caPrivateKey = NULL;
michael@0 3350 SECStatus rv;
michael@0 3351 PLArenaPool *arena;
michael@0 3352 SECOidTag algID;
michael@0 3353 void *dummy;
michael@0 3354
michael@0 3355 PORT_Assert(issuer != NULL && signCrl != NULL);
michael@0 3356 if (!issuer || !signCrl) {
michael@0 3357 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 3358 return SECFailure;
michael@0 3359 }
michael@0 3360
michael@0 3361 arena = signCrl->arena;
michael@0 3362
michael@0 3363 caPrivateKey = PK11_FindKeyByAnyCert(issuer, NULL);
michael@0 3364 if (caPrivateKey == NULL) {
michael@0 3365 *resCode = noKeyFound;
michael@0 3366 return SECFailure;
michael@0 3367 }
michael@0 3368
michael@0 3369 algID = SEC_GetSignatureAlgorithmOidTag(caPrivateKey->keyType, hashAlgTag);
michael@0 3370 if (algID == SEC_OID_UNKNOWN) {
michael@0 3371 *resCode = noSignatureMatch;
michael@0 3372 rv = SECFailure;
michael@0 3373 goto done;
michael@0 3374 }
michael@0 3375
michael@0 3376 if (!signCrl->crl.signatureAlg.parameters.data) {
michael@0 3377 rv = SECOID_SetAlgorithmID(arena, &signCrl->crl.signatureAlg, algID, 0);
michael@0 3378 if (rv != SECSuccess) {
michael@0 3379 *resCode = failToEncode;
michael@0 3380 goto done;
michael@0 3381 }
michael@0 3382 }
michael@0 3383
michael@0 3384 der.len = 0;
michael@0 3385 der.data = NULL;
michael@0 3386 dummy = SEC_ASN1EncodeItem(arena, &der, &signCrl->crl,
michael@0 3387 SEC_ASN1_GET(CERT_CrlTemplate));
michael@0 3388 if (!dummy) {
michael@0 3389 *resCode = failToEncode;
michael@0 3390 rv = SECFailure;
michael@0 3391 goto done;
michael@0 3392 }
michael@0 3393
michael@0 3394 rv = SECU_DerSignDataCRL(arena, &signCrl->signatureWrap,
michael@0 3395 der.data, der.len, caPrivateKey, algID);
michael@0 3396 if (rv != SECSuccess) {
michael@0 3397 *resCode = failToSign;
michael@0 3398 goto done;
michael@0 3399 }
michael@0 3400
michael@0 3401 signCrl->derCrl = PORT_ArenaZNew(arena, SECItem);
michael@0 3402 if (signCrl->derCrl == NULL) {
michael@0 3403 *resCode = noMem;
michael@0 3404 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 3405 rv = SECFailure;
michael@0 3406 goto done;
michael@0 3407 }
michael@0 3408
michael@0 3409 signCrl->derCrl->len = 0;
michael@0 3410 signCrl->derCrl->data = NULL;
michael@0 3411 dummy = SEC_ASN1EncodeItem (arena, signCrl->derCrl, signCrl,
michael@0 3412 SEC_ASN1_GET(CERT_SignedCrlTemplate));
michael@0 3413 if (!dummy) {
michael@0 3414 *resCode = failToEncode;
michael@0 3415 rv = SECFailure;
michael@0 3416 goto done;
michael@0 3417 }
michael@0 3418
michael@0 3419 done:
michael@0 3420 if (caPrivateKey) {
michael@0 3421 SECKEY_DestroyPrivateKey(caPrivateKey);
michael@0 3422 }
michael@0 3423 return rv;
michael@0 3424 }
michael@0 3425
michael@0 3426
michael@0 3427
michael@0 3428 SECStatus
michael@0 3429 SECU_CopyCRL(PLArenaPool *destArena, CERTCrl *destCrl, CERTCrl *srcCrl)
michael@0 3430 {
michael@0 3431 void *dummy;
michael@0 3432 SECStatus rv = SECSuccess;
michael@0 3433 SECItem der;
michael@0 3434
michael@0 3435 PORT_Assert(destArena && srcCrl && destCrl);
michael@0 3436 if (!destArena || !srcCrl || !destCrl) {
michael@0 3437 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 3438 return SECFailure;
michael@0 3439 }
michael@0 3440
michael@0 3441 der.len = 0;
michael@0 3442 der.data = NULL;
michael@0 3443 dummy = SEC_ASN1EncodeItem (destArena, &der, srcCrl,
michael@0 3444 SEC_ASN1_GET(CERT_CrlTemplate));
michael@0 3445 if (!dummy) {
michael@0 3446 return SECFailure;
michael@0 3447 }
michael@0 3448
michael@0 3449 rv = SEC_QuickDERDecodeItem(destArena, destCrl,
michael@0 3450 SEC_ASN1_GET(CERT_CrlTemplate), &der);
michael@0 3451 if (rv != SECSuccess) {
michael@0 3452 return SECFailure;
michael@0 3453 }
michael@0 3454
michael@0 3455 destCrl->arena = destArena;
michael@0 3456
michael@0 3457 return rv;
michael@0 3458 }
michael@0 3459
michael@0 3460 SECStatus
michael@0 3461 SECU_DerSignDataCRL(PLArenaPool *arena, CERTSignedData *sd,
michael@0 3462 unsigned char *buf, int len, SECKEYPrivateKey *pk,
michael@0 3463 SECOidTag algID)
michael@0 3464 {
michael@0 3465 SECItem it;
michael@0 3466 SECStatus rv;
michael@0 3467
michael@0 3468 it.data = 0;
michael@0 3469
michael@0 3470 /* XXX We should probably have some asserts here to make sure the key type
michael@0 3471 * and algID match
michael@0 3472 */
michael@0 3473
michael@0 3474 /* Sign input buffer */
michael@0 3475 rv = SEC_SignData(&it, buf, len, pk, algID);
michael@0 3476 if (rv) goto loser;
michael@0 3477
michael@0 3478 /* Fill out SignedData object */
michael@0 3479 PORT_Memset(sd, 0, sizeof(*sd));
michael@0 3480 sd->data.data = buf;
michael@0 3481 sd->data.len = len;
michael@0 3482 sd->signature.data = it.data;
michael@0 3483 sd->signature.len = it.len << 3; /* convert to bit string */
michael@0 3484 rv = SECOID_SetAlgorithmID(arena, &sd->signatureAlgorithm, algID, 0);
michael@0 3485 if (rv) goto loser;
michael@0 3486
michael@0 3487 return rv;
michael@0 3488
michael@0 3489 loser:
michael@0 3490 PORT_Free(it.data);
michael@0 3491 return rv;
michael@0 3492 }
michael@0 3493
michael@0 3494 #if 0
michael@0 3495
michael@0 3496 /* we need access to the private function cert_FindExtension for this code to work */
michael@0 3497
michael@0 3498 CERTAuthKeyID *
michael@0 3499 SECU_FindCRLAuthKeyIDExten (PLArenaPool *arena, CERTSignedCrl *scrl)
michael@0 3500 {
michael@0 3501 SECItem encodedExtenValue;
michael@0 3502 SECStatus rv;
michael@0 3503 CERTAuthKeyID *ret;
michael@0 3504 CERTCrl* crl;
michael@0 3505
michael@0 3506 if (!scrl) {
michael@0 3507 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 3508 return NULL;
michael@0 3509 }
michael@0 3510
michael@0 3511 crl = &scrl->crl;
michael@0 3512
michael@0 3513 encodedExtenValue.data = NULL;
michael@0 3514 encodedExtenValue.len = 0;
michael@0 3515
michael@0 3516 rv = cert_FindExtension(crl->extensions, SEC_OID_X509_AUTH_KEY_ID,
michael@0 3517 &encodedExtenValue);
michael@0 3518 if ( rv != SECSuccess ) {
michael@0 3519 return (NULL);
michael@0 3520 }
michael@0 3521
michael@0 3522 ret = CERT_DecodeAuthKeyID (arena, &encodedExtenValue);
michael@0 3523
michael@0 3524 PORT_Free(encodedExtenValue.data);
michael@0 3525 encodedExtenValue.data = NULL;
michael@0 3526
michael@0 3527 return(ret);
michael@0 3528 }
michael@0 3529
michael@0 3530 #endif
michael@0 3531
michael@0 3532 /*
michael@0 3533 * Find the issuer of a Crl. Use the authorityKeyID if it exists.
michael@0 3534 */
michael@0 3535 CERTCertificate *
michael@0 3536 SECU_FindCrlIssuer(CERTCertDBHandle *dbhandle, SECItem* subject,
michael@0 3537 CERTAuthKeyID* authorityKeyID, PRTime validTime)
michael@0 3538 {
michael@0 3539 CERTCertificate *issuerCert = NULL;
michael@0 3540 CERTCertList *certList = NULL;
michael@0 3541 CERTCertTrust trust;
michael@0 3542
michael@0 3543 if (!subject) {
michael@0 3544 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 3545 return NULL;
michael@0 3546 }
michael@0 3547
michael@0 3548 certList =
michael@0 3549 CERT_CreateSubjectCertList(NULL, dbhandle, subject,
michael@0 3550 validTime, PR_TRUE);
michael@0 3551 if (certList) {
michael@0 3552 CERTCertListNode *node = CERT_LIST_HEAD(certList);
michael@0 3553
michael@0 3554 /* XXX and authoritykeyid in the future */
michael@0 3555 while ( ! CERT_LIST_END(node, certList) ) {
michael@0 3556 CERTCertificate *cert = node->cert;
michael@0 3557 /* check cert CERTCertTrust data is allocated, check cert
michael@0 3558 usage extension, check that cert has pkey in db. Select
michael@0 3559 the first (newest) user cert */
michael@0 3560 if (CERT_GetCertTrust(cert, &trust) == SECSuccess &&
michael@0 3561 CERT_CheckCertUsage(cert, KU_CRL_SIGN) == SECSuccess &&
michael@0 3562 CERT_IsUserCert(cert)) {
michael@0 3563
michael@0 3564 issuerCert = CERT_DupCertificate(cert);
michael@0 3565 break;
michael@0 3566 }
michael@0 3567 node = CERT_LIST_NEXT(node);
michael@0 3568 }
michael@0 3569 CERT_DestroyCertList(certList);
michael@0 3570 }
michael@0 3571 return(issuerCert);
michael@0 3572 }
michael@0 3573
michael@0 3574
michael@0 3575 /* Encodes and adds extensions to the CRL or CRL entries. */
michael@0 3576 SECStatus
michael@0 3577 SECU_EncodeAndAddExtensionValue(PLArenaPool *arena, void *extHandle,
michael@0 3578 void *value, PRBool criticality, int extenType,
michael@0 3579 EXTEN_EXT_VALUE_ENCODER EncodeValueFn)
michael@0 3580 {
michael@0 3581 SECItem encodedValue;
michael@0 3582 SECStatus rv;
michael@0 3583
michael@0 3584 encodedValue.data = NULL;
michael@0 3585 encodedValue.len = 0;
michael@0 3586 do {
michael@0 3587 rv = (*EncodeValueFn)(arena, value, &encodedValue);
michael@0 3588 if (rv != SECSuccess)
michael@0 3589 break;
michael@0 3590
michael@0 3591 rv = CERT_AddExtension(extHandle, extenType, &encodedValue,
michael@0 3592 criticality, PR_TRUE);
michael@0 3593 if (rv != SECSuccess)
michael@0 3594 break;
michael@0 3595 } while (0);
michael@0 3596
michael@0 3597 return (rv);
michael@0 3598 }
michael@0 3599
michael@0 3600 CERTCertificate*
michael@0 3601 SECU_FindCertByNicknameOrFilename(CERTCertDBHandle *handle,
michael@0 3602 char *name, PRBool ascii,
michael@0 3603 void *pwarg)
michael@0 3604 {
michael@0 3605 CERTCertificate *the_cert;
michael@0 3606 the_cert = CERT_FindCertByNicknameOrEmailAddr(handle, name);
michael@0 3607 if (the_cert) {
michael@0 3608 return the_cert;
michael@0 3609 }
michael@0 3610 the_cert = PK11_FindCertFromNickname(name, pwarg);
michael@0 3611 if (!the_cert) {
michael@0 3612 /* Don't have a cert with name "name" in the DB. Try to
michael@0 3613 * open a file with such name and get the cert from there.*/
michael@0 3614 SECStatus rv;
michael@0 3615 SECItem item = {0, NULL, 0};
michael@0 3616 PRFileDesc* fd = PR_Open(name, PR_RDONLY, 0777);
michael@0 3617 if (!fd) {
michael@0 3618 return NULL;
michael@0 3619 }
michael@0 3620 rv = SECU_ReadDERFromFile(&item, fd, ascii, PR_FALSE);
michael@0 3621 PR_Close(fd);
michael@0 3622 if (rv != SECSuccess || !item.len) {
michael@0 3623 PORT_Free(item.data);
michael@0 3624 return NULL;
michael@0 3625 }
michael@0 3626 the_cert = CERT_NewTempCertificate(handle, &item,
michael@0 3627 NULL /* nickname */,
michael@0 3628 PR_FALSE /* isPerm */,
michael@0 3629 PR_TRUE /* copyDER */);
michael@0 3630 PORT_Free(item.data);
michael@0 3631 }
michael@0 3632 return the_cert;
michael@0 3633 }
michael@0 3634
michael@0 3635 /* Convert a SSL/TLS protocol version string into the respective numeric value
michael@0 3636 * defined by the SSL_LIBRARY_VERSION_* constants,
michael@0 3637 * while accepting a flexible set of case-insensitive identifiers.
michael@0 3638 *
michael@0 3639 * Caller must specify bufLen, allowing the function to operate on substrings.
michael@0 3640 */
michael@0 3641 static SECStatus
michael@0 3642 SECU_GetSSLVersionFromName(const char *buf, size_t bufLen, PRUint16 *version)
michael@0 3643 {
michael@0 3644 if (!buf || !version) {
michael@0 3645 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 3646 return SECFailure;
michael@0 3647 }
michael@0 3648
michael@0 3649 if (!PL_strncasecmp(buf, "ssl2", bufLen)) {
michael@0 3650 *version = SSL_LIBRARY_VERSION_2;
michael@0 3651 return SECSuccess;
michael@0 3652 }
michael@0 3653 if (!PL_strncasecmp(buf, "ssl3", bufLen)) {
michael@0 3654 *version = SSL_LIBRARY_VERSION_3_0;
michael@0 3655 return SECSuccess;
michael@0 3656 }
michael@0 3657 if (!PL_strncasecmp(buf, "tls1.0", bufLen)) {
michael@0 3658 *version = SSL_LIBRARY_VERSION_TLS_1_0;
michael@0 3659 return SECSuccess;
michael@0 3660 }
michael@0 3661 if (!PL_strncasecmp(buf, "tls1.1", bufLen)) {
michael@0 3662 *version = SSL_LIBRARY_VERSION_TLS_1_1;
michael@0 3663 return SECSuccess;
michael@0 3664 }
michael@0 3665 if (!PL_strncasecmp(buf, "tls1.2", bufLen)) {
michael@0 3666 *version = SSL_LIBRARY_VERSION_TLS_1_2;
michael@0 3667 return SECSuccess;
michael@0 3668 }
michael@0 3669 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 3670 return SECFailure;
michael@0 3671 }
michael@0 3672
michael@0 3673 SECStatus
michael@0 3674 SECU_ParseSSLVersionRangeString(const char *input,
michael@0 3675 const SSLVersionRange defaultVersionRange,
michael@0 3676 const PRBool defaultEnableSSL2,
michael@0 3677 SSLVersionRange *vrange, PRBool *enableSSL2)
michael@0 3678 {
michael@0 3679 const char *colonPos;
michael@0 3680 size_t colonIndex;
michael@0 3681 const char *maxStr;
michael@0 3682
michael@0 3683 if (!input || !vrange || !enableSSL2) {
michael@0 3684 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 3685 return SECFailure;
michael@0 3686 }
michael@0 3687
michael@0 3688 if (!strcmp(input, ":")) {
michael@0 3689 /* special value, use default */
michael@0 3690 *enableSSL2 = defaultEnableSSL2;
michael@0 3691 *vrange = defaultVersionRange;
michael@0 3692 return SECSuccess;
michael@0 3693 }
michael@0 3694
michael@0 3695 colonPos = strchr(input, ':');
michael@0 3696 if (!colonPos) {
michael@0 3697 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 3698 return SECFailure;
michael@0 3699 }
michael@0 3700
michael@0 3701 colonIndex = colonPos - input;
michael@0 3702 maxStr = colonPos + 1;
michael@0 3703
michael@0 3704 if (!colonIndex) {
michael@0 3705 /* colon was first character, min version is empty */
michael@0 3706 *enableSSL2 = defaultEnableSSL2;
michael@0 3707 vrange->min = defaultVersionRange.min;
michael@0 3708 } else {
michael@0 3709 PRUint16 version;
michael@0 3710 /* colonIndex is equivalent to the length of the min version substring */
michael@0 3711 if (SECU_GetSSLVersionFromName(input, colonIndex, &version) != SECSuccess) {
michael@0 3712 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 3713 return SECFailure;
michael@0 3714 }
michael@0 3715
michael@0 3716 if (version == SSL_LIBRARY_VERSION_2) {
michael@0 3717 *enableSSL2 = PR_TRUE;
michael@0 3718 vrange->min = defaultVersionRange.min;
michael@0 3719 } else {
michael@0 3720 *enableSSL2 = PR_FALSE;
michael@0 3721 vrange->min = version;
michael@0 3722 }
michael@0 3723 }
michael@0 3724
michael@0 3725 if (!*maxStr) {
michael@0 3726 vrange->max = defaultVersionRange.max;
michael@0 3727 } else {
michael@0 3728 PRUint16 version;
michael@0 3729 /* if max version is empty, then maxStr points to the string terminator */
michael@0 3730 if (SECU_GetSSLVersionFromName(maxStr, strlen(maxStr), &version)
michael@0 3731 != SECSuccess) {
michael@0 3732 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 3733 return SECFailure;
michael@0 3734 }
michael@0 3735
michael@0 3736 if (version == SSL_LIBRARY_VERSION_2) {
michael@0 3737 /* consistency checking, require that min allows enableSSL2, too */
michael@0 3738 if (!*enableSSL2) {
michael@0 3739 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 3740 return SECFailure;
michael@0 3741 }
michael@0 3742 /* we use 0 because SSL_LIBRARY_VERSION_NONE is private: */
michael@0 3743 vrange->min = 0;
michael@0 3744 vrange->max = 0;
michael@0 3745 } else {
michael@0 3746 vrange->max = version;
michael@0 3747 }
michael@0 3748 }
michael@0 3749
michael@0 3750 return SECSuccess;
michael@0 3751 }

mercurial