Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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(¶m, 0, sizeof param); |
michael@0 | 1181 | |
michael@0 | 1182 | rv = SEC_QuickDERDecodeItem(pool, ¶m, |
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, ¶m.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, ¶m.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 | ¶m.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, ¶m.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(¶m, 0, sizeof param); |
michael@0 | 1244 | rv = SEC_QuickDERDecodeItem(pool, ¶m, secuKDF2Params, value); |
michael@0 | 1245 | if (rv == SECSuccess) { |
michael@0 | 1246 | SECU_PrintAsHex(out, ¶m.salt, "Salt", level+1); |
michael@0 | 1247 | SECU_PrintInteger(out, ¶m.iterationCount, "Iteration Count", |
michael@0 | 1248 | level+1); |
michael@0 | 1249 | SECU_PrintInteger(out, ¶m.keyLength, "Key Length", level+1); |
michael@0 | 1250 | SECU_PrintAlgorithmID(out, ¶m.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(¶m, 0, sizeof param); |
michael@0 | 1274 | rv = SEC_QuickDERDecodeItem(pool, ¶m, secuPBEV2Params, value); |
michael@0 | 1275 | if (rv == SECSuccess) { |
michael@0 | 1276 | SECU_PrintAlgorithmID(out, ¶m.kdfAlg, "KDF", level+1); |
michael@0 | 1277 | SECU_PrintAlgorithmID(out, ¶m.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(¶m, 0, sizeof(secuPBEParams)); |
michael@0 | 1301 | rv = SEC_QuickDERDecodeItem(pool, ¶m, secuPBEParamsTemp, value); |
michael@0 | 1302 | if (rv == SECSuccess) { |
michael@0 | 1303 | SECU_PrintAsHex(out, ¶m.salt, "Salt", level+1); |
michael@0 | 1304 | SECU_PrintInteger(out, ¶m.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 | } |