/
secutil.c
3894 lines (3455 loc) · 114 KB
1
2
3
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
6
7
8
9
10
11
12
13
14
/*
** secutil.c - various functions used by security stuff
**
*/
#include "prtypes.h"
#include "prtime.h"
#include "prlong.h"
#include "prerror.h"
#include "prprf.h"
#include "plgetopt.h"
15
#include "prenv.h"
16
#include "prnetdb.h"
17
18
#include "cryptohi.h"
19
20
#include "secutil.h"
#include "secpkcs7.h"
21
#include "secpkcs5.h"
22
#include <stdarg.h>
23
#include <sys/stat.h>
24
#include <errno.h>
25
26
27
28
29
30
31
32
33
34
#ifdef XP_UNIX
#include <unistd.h>
#endif
/* for SEC_TraverseNames */
#include "cert.h"
#include "certt.h"
#include "certdb.h"
35
#include "secmod.h"
36
37
38
#include "pk11func.h"
#include "secoid.h"
39
static char consoleName[] = {
40
41
#ifdef XP_UNIX
"/dev/tty"
42
43
44
#else
#ifdef XP_OS2
"\\DEV\\CON"
45
46
47
#else
"CON:"
#endif
48
#endif
49
50
};
51
52
#include "nssutil.h"
#include "ssl.h"
53
#include "sslproto.h"
54
55
56
static PRBool utf8DisplayEnabled = PR_FALSE;
57
58
59
60
/* The minimum password/pin length (in Unicode characters) in FIPS mode,
* defined in lib/softoken/pkcs11i.h. */
#define FIPS_MIN_PIN 7
61
62
63
64
65
66
67
68
69
70
71
void
SECU_EnableUtf8Display(PRBool enable)
{
utf8DisplayEnabled = enable;
}
PRBool
SECU_GetUtf8DisplayEnabled(void)
{
return utf8DisplayEnabled;
}
72
73
74
75
76
static void
secu_ClearPassword(char *p)
{
if (p) {
77
78
PORT_Memset(p, 0, PORT_Strlen(p));
PORT_Free(p);
79
80
81
82
83
84
85
86
87
88
89
90
91
}
}
char *
SECU_GetPasswordString(void *arg, char *prompt)
{
#ifndef _WINDOWS
char *p = NULL;
FILE *input, *output;
/* open terminal */
input = fopen(consoleName, "r");
if (input == NULL) {
92
93
fprintf(stderr, "Error opening input terminal for read\n");
return NULL;
94
95
96
97
}
output = fopen(consoleName, "w");
if (output == NULL) {
98
99
100
fprintf(stderr, "Error opening output terminal for write\n");
fclose(input);
return NULL;
101
102
}
103
p = SEC_GetPassword(input, output, prompt, SEC_BlindCheckPassword);
104
105
106
107
108
109
110
111
112
113
114
115
fclose(input);
fclose(output);
return p;
#else
/* Win32 version of above. opening the console may fail
on windows95, and certainly isn't necessary.. */
char *p = NULL;
116
p = SEC_GetPassword(stdin, stdout, prompt, SEC_BlindCheckPassword);
117
118
119
120
121
122
return p;
#endif
}
/*
123
* p a s s w o r d _ h a r d c o d e
124
125
*
* A function to use the password passed in the -f(pwfile) argument
126
* of the command line.
127
128
129
130
131
132
* After use once, null it out otherwise PKCS11 calls us forever.?
*
*/
char *
SECU_FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg)
{
133
char *phrases, *phrase;
134
135
136
PRFileDesc *fd;
PRInt32 nb;
char *pwFile = arg;
137
int i;
138
const long maxPwdFileSize = 4096;
139
char *tokenName = NULL;
140
int tokenLen = 0;
141
142
if (!pwFile)
143
return 0;
144
145
if (retry) {
146
return 0; /* no good retrying - the files contents will be the same */
147
148
149
150
151
152
153
}
phrases = PORT_ZAlloc(maxPwdFileSize);
if (!phrases) {
return 0; /* out of memory */
}
154
155
156
fd = PR_Open(pwFile, PR_RDONLY, 0);
if (!fd) {
157
fprintf(stderr, "No password file \"%s\" exists.\n", pwFile);
158
PORT_Free(phrases);
159
return NULL;
160
161
}
162
nb = PR_Read(fd, phrases, maxPwdFileSize);
163
164
PR_Close(fd);
165
166
if (nb == 0) {
167
fprintf(stderr, "password file contains no data\n");
168
169
170
171
172
173
174
175
176
PORT_Free(phrases);
return NULL;
}
if (slot) {
tokenName = PK11_GetTokenName(slot);
if (tokenName) {
tokenLen = PORT_Strlen(tokenName);
}
177
}
178
i = 0;
179
do {
180
181
182
183
int startphrase = i;
int phraseLen;
/* handle the Windows EOL case */
184
185
while (phrases[i] != '\r' && phrases[i] != '\n' && i < nb)
i++;
186
187
188
/* terminate passphrase */
phrases[i++] = '\0';
/* clean up any EOL before the start of the next passphrase */
189
while ((i < nb) && (phrases[i] == '\r' || phrases[i] == '\n')) {
190
191
192
193
194
195
phrases[i++] = '\0';
}
/* now analyze the current passphrase */
phrase = &phrases[startphrase];
if (!tokenName)
break;
196
197
if (PORT_Strncmp(phrase, tokenName, tokenLen))
continue;
198
phraseLen = PORT_Strlen(phrase);
199
200
201
202
203
if (phraseLen < (tokenLen + 1))
continue;
if (phrase[tokenLen] != ':')
continue;
phrase = &phrase[tokenLen + 1];
204
205
break;
206
} while (i < nb);
207
208
phrase = PORT_Strdup((char *)phrase);
209
210
PORT_Free(phrases);
return phrase;
211
212
213
}
char *
214
SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg)
215
216
{
char prompt[255];
217
secuPWData *pwdata = (secuPWData *)arg;
218
secuPWData pwnull = { PW_NONE, 0 };
219
secuPWData pwxtrn = { PW_EXTERNAL, "external" };
220
221
if (pwdata == NULL)
222
pwdata = &pwnull;
223
224
if (PK11_ProtectedAuthenticationPath(slot)) {
225
pwdata = &pwxtrn;
226
}
227
if (retry && pwdata->source != PW_NONE) {
228
229
PR_fprintf(PR_STDERR, "Incorrect password/PIN entered.\n");
return NULL;
230
231
232
}
switch (pwdata->source) {
233
234
235
236
237
case PW_NONE:
sprintf(prompt, "Enter Password or Pin for \"%s\":",
PK11_GetTokenName(slot));
return SECU_GetPasswordString(NULL, prompt);
case PW_FROMFILE:
238
return SECU_FilePasswd(slot, retry, pwdata->data);
239
240
241
242
243
244
245
246
247
248
case PW_EXTERNAL:
sprintf(prompt,
"Press Enter, then enter PIN for \"%s\" on external device.\n",
PK11_GetTokenName(slot));
(void)SECU_GetPasswordString(NULL, prompt);
/* Fall Through */
case PW_PLAINTEXT:
return PL_strdup(pwdata->data);
default:
break;
249
250
}
251
PR_fprintf(PR_STDERR, "Password check failed: No password found.\n");
252
253
254
return NULL;
}
255
char *
256
257
258
259
260
261
262
secu_InitSlotPassword(PK11SlotInfo *slot, PRBool retry, void *arg)
{
char *p0 = NULL;
char *p1 = NULL;
FILE *input, *output;
secuPWData *pwdata = arg;
263
if (pwdata->source == PW_FROMFILE) {
264
265
return SECU_FilePasswd(slot, retry, pwdata->data);
}
266
if (pwdata->source == PW_PLAINTEXT) {
267
return PL_strdup(pwdata->data);
268
}
269
270
271
/* PW_NONE - get it from tty */
/* open terminal */
272
#ifdef _WINDOWS
273
input = stdin;
274
#else
275
input = fopen(consoleName, "r");
276
#endif
277
if (input == NULL) {
278
279
PR_fprintf(PR_STDERR, "Error opening input terminal for read\n");
return NULL;
280
281
}
282
/* we have no password, so initialize database with one */
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
if (PK11_IsFIPS()) {
PR_fprintf(PR_STDERR,
"Enter a password which will be used to encrypt your keys.\n"
"The password should be at least %d characters long,\n"
"and should consist of at least three character classes.\n"
"The available character classes are: digits (0-9), ASCII\n"
"lowercase letters, ASCII uppercase letters, ASCII\n"
"non-alphanumeric characters, and non-ASCII characters.\n\n"
"If an ASCII uppercase letter appears at the beginning of\n"
"the password, it is not counted toward its character class.\n"
"Similarly, if a digit appears at the end of the password,\n"
"it is not counted toward its character class.\n\n",
FIPS_MIN_PIN);
} else {
PR_fprintf(PR_STDERR,
"Enter a password which will be used to encrypt your keys.\n"
"The password should be at least 8 characters long,\n"
"and should contain at least one non-alphabetic character.\n\n");
}
302
303
304
output = fopen(consoleName, "w");
if (output == NULL) {
305
PR_fprintf(PR_STDERR, "Error opening output terminal for write\n");
306
#ifndef _WINDOWS
307
fclose(input);
308
#endif
309
return NULL;
310
311
312
}
for (;;) {
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
if (p0)
PORT_Free(p0);
p0 = SEC_GetPassword(input, output, "Enter new password: ",
SEC_BlindCheckPassword);
if (p1)
PORT_Free(p1);
p1 = SEC_GetPassword(input, output, "Re-enter password: ",
SEC_BlindCheckPassword);
if (p0 && p1 && !PORT_Strcmp(p0, p1)) {
break;
}
PR_fprintf(PR_STDERR, "Passwords do not match. Try again.\n");
}
328
329
/* clear out the duplicate password string */
secu_ClearPassword(p1);
330
331
332
333
334
335
336
337
338
fclose(input);
fclose(output);
return p0;
}
SECStatus
SECU_ChangePW(PK11SlotInfo *slot, char *passwd, char *pwFile)
339
340
341
342
343
344
{
return SECU_ChangePW2(slot, passwd, 0, pwFile, 0);
}
SECStatus
SECU_ChangePW2(PK11SlotInfo *slot, char *oldPass, char *newPass,
345
char *oldPwFile, char *newPwFile)
346
347
348
349
350
{
SECStatus rv;
secuPWData pwdata, newpwdata;
char *oldpw = NULL, *newpw = NULL;
351
if (oldPass) {
352
353
pwdata.source = PW_PLAINTEXT;
pwdata.data = oldPass;
354
} else if (oldPwFile) {
355
356
pwdata.source = PW_FROMFILE;
pwdata.data = oldPwFile;
357
} else {
358
359
pwdata.source = PW_NONE;
pwdata.data = NULL;
360
361
}
362
if (newPass) {
363
364
newpwdata.source = PW_PLAINTEXT;
newpwdata.data = newPass;
365
} else if (newPwFile) {
366
367
newpwdata.source = PW_FROMFILE;
newpwdata.data = newPwFile;
368
} else {
369
370
newpwdata.source = PW_NONE;
newpwdata.data = NULL;
371
372
}
373
if (PK11_NeedUserInit(slot)) {
374
375
376
newpw = secu_InitSlotPassword(slot, PR_FALSE, &pwdata);
rv = PK11_InitPin(slot, (char *)NULL, newpw);
goto done;
377
378
379
}
for (;;) {
380
381
382
383
384
385
386
387
388
389
oldpw = SECU_GetModulePassword(slot, PR_FALSE, &pwdata);
if (PK11_CheckUserPassword(slot, oldpw) != SECSuccess) {
if (pwdata.source == PW_NONE) {
PR_fprintf(PR_STDERR, "Invalid password. Try again.\n");
} else {
PR_fprintf(PR_STDERR, "Invalid password.\n");
PORT_Memset(oldpw, 0, PL_strlen(oldpw));
PORT_Free(oldpw);
rv = SECFailure;
390
goto done;
391
392
393
}
} else
break;
394
395
PORT_Free(oldpw);
396
397
398
399
}
newpw = secu_InitSlotPassword(slot, PR_FALSE, &newpwdata);
400
401
rv = PK11_ChangePW(slot, oldpw, newpw);
if (rv != SECSuccess) {
402
PR_fprintf(PR_STDERR, "Failed to change password.\n");
403
404
} else {
PR_fprintf(PR_STDOUT, "Password changed successfully.\n");
405
406
407
408
409
410
}
PORT_Memset(oldpw, 0, PL_strlen(oldpw));
PORT_Free(oldpw);
done:
411
412
413
414
415
if (newpw) {
PORT_Memset(newpw, 0, PL_strlen(newpw));
PORT_Free(newpw);
}
return rv;
416
417
418
419
420
421
422
423
424
425
426
427
428
429
}
struct matchobj {
SECItem index;
char *nname;
PRBool found;
};
char *
SECU_DefaultSSLDir(void)
{
char *dir;
static char sslDir[1000];
430
dir = PR_GetEnvSecure("SSL_DIR");
431
if (!dir)
432
return NULL;
433
434
if (strlen(dir) >= PR_ARRAY_SIZE(sslDir)) {
435
return NULL;
436
}
437
438
sprintf(sslDir, "%s", dir);
439
440
if (sslDir[strlen(sslDir) - 1] == '/')
sslDir[strlen(sslDir) - 1] = 0;
441
442
443
444
445
446
447
448
449
return sslDir;
}
char *
SECU_AppendFilenameToDir(char *dir, char *filename)
{
static char path[1000];
450
451
if (dir[strlen(dir) - 1] == '/')
sprintf(path, "%s%s", dir, filename);
452
else
453
sprintf(path, "%s/%s", dir, filename);
454
455
456
457
return path;
}
char *
458
SECU_ConfigDirectory(const char *base)
459
460
461
462
463
464
{
static PRBool initted = PR_FALSE;
const char *dir = ".netscape";
char *home;
static char buf[1000];
465
466
if (initted)
return buf;
467
468
if (base == NULL || *base == 0) {
469
470
471
home = PR_GetEnvSecure("HOME");
if (!home)
home = "";
472
473
474
475
476
if (*home && home[strlen(home) - 1] == '/')
sprintf(buf, "%.900s%s", home, dir);
else
sprintf(buf, "%.900s/%s", home, dir);
477
} else {
478
479
480
sprintf(buf, "%.900s", base);
if (buf[strlen(buf) - 1] == '/')
buf[strlen(buf) - 1] = 0;
481
482
483
484
485
486
487
}
initted = PR_TRUE;
return buf;
}
SECStatus
488
SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii,
489
PRBool warnOnPrivateKeyInAsciiFile)
490
491
492
{
SECStatus rv;
if (ascii) {
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
/* First convert ascii to binary */
SECItem filedata;
char *asc, *body;
/* Read in ascii data */
rv = SECU_FileToItem(&filedata, inFile);
if (rv != SECSuccess)
return rv;
asc = (char *)filedata.data;
if (!asc) {
fprintf(stderr, "unable to read data from input file\n");
return SECFailure;
}
if (warnOnPrivateKeyInAsciiFile && strstr(asc, "PRIVATE KEY")) {
fprintf(stderr, "Warning: ignoring private key. Consider to use "
"pk12util.\n");
}
/* check for headers and trailers and remove them */
if ((body = strstr(asc, "-----BEGIN")) != NULL) {
char *trailer = NULL;
asc = body;
body = PORT_Strchr(body, '\n');
if (!body)
body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */
if (body)
trailer = strstr(++body, "-----END");
if (trailer != NULL) {
*trailer = '\0';
} else {
fprintf(stderr, "input has header but no trailer\n");
PORT_Free(filedata.data);
return SECFailure;
}
} else {
/* need one additional byte for zero terminator */
rv = SECITEM_ReallocItemV2(NULL, &filedata, filedata.len + 1);
if (rv != SECSuccess) {
PORT_Free(filedata.data);
return rv;
}
body = (char *)filedata.data;
body[filedata.len - 1] = '\0';
}
/* Convert to binary */
rv = ATOB_ConvertAsciiToItem(der, body);
if (rv != SECSuccess) {
fprintf(stderr, "error converting ascii to binary (%s)\n",
SECU_Strerror(PORT_GetError()));
PORT_Free(filedata.data);
return SECFailure;
}
PORT_Free(filedata.data);
549
} else {
550
551
552
553
554
555
556
/* Read in binary der */
rv = SECU_FileToItem(der, inFile);
if (rv != SECSuccess) {
fprintf(stderr, "error converting der (%s)\n",
SECU_Strerror(PORT_GetError()));
return SECFailure;
}
557
558
559
560
}
return SECSuccess;
}
561
#define INDENT_MULT 4
562
563
564
565
566
567
568
569
570
571
572
573
574
575
SECStatus
SECU_StripTagAndLength(SECItem *i)
{
unsigned int start;
if (!i || !i->data || i->len < 2) { /* must be at least tag and length */
return SECFailure;
}
start = ((i->data[1] & 0x80) ? (i->data[1] & 0x7f) + 2 : 2);
if (i->len < start) {
return SECFailure;
}
i->data += start;
576
i->len -= start;
577
578
579
580
return SECSuccess;
}
static void
581
582
secu_PrintRawStringQuotesOptional(FILE *out, SECItem *si, const char *m,
int level, PRBool quotes)
583
{
584
585
int column;
unsigned int i;
586
587
588
589
590
591
if (m) {
SECU_Indent(out, level);
fprintf(out, "%s: ", m);
column = (level * INDENT_MULT) + strlen(m) + 2;
level++;
592
} else {
593
594
SECU_Indent(out, level);
column = level * INDENT_MULT;
595
}
596
if (quotes) {
597
598
fprintf(out, "\"");
column++;
599
}
600
601
for (i = 0; i < si->len; i++) {
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
unsigned char val = si->data[i];
unsigned char c;
if (SECU_GetWrapEnabled() && column > 76) {
SECU_Newline(out);
SECU_Indent(out, level);
column = level * INDENT_MULT;
}
if (utf8DisplayEnabled) {
if (val < 32)
c = '.';
else
c = val;
} else {
c = printable[val];
}
fprintf(out, "%c", c);
column++;
620
}
621
622
if (quotes) {
623
624
fprintf(out, "\"");
column++;
625
}
626
if (SECU_GetWrapEnabled() &&
627
628
(column != level * INDENT_MULT || column > 76)) {
SECU_Newline(out);
629
630
631
}
}
632
633
634
static void
secu_PrintRawString(FILE *out, SECItem *si, const char *m, int level)
{
635
secu_PrintRawStringQuotesOptional(out, si, m, level, PR_TRUE);
636
637
}
638
void
639
SECU_PrintString(FILE *out, const SECItem *si, const char *m, int level)
640
641
642
643
{
SECItem my = *si;
if (SECSuccess != SECU_StripTagAndLength(&my) || !my.len)
644
return;
645
secu_PrintRawString(out, &my, m, level);
646
647
}
648
/* print an unencoded boolean */
649
static void
650
secu_PrintBoolean(FILE *out, SECItem *i, const char *m, int level)
651
652
{
int val = 0;
653
654
655
if (i->data && i->len) {
val = i->data[0];
656
657
}
658
if (!m) {
659
m = "Boolean";
660
}
661
SECU_Indent(out, level);
662
fprintf(out, "%s: %s\n", m, (val ? "True" : "False"));
663
664
665
666
667
668
669
670
}
/*
* Format and print "time". If the tag message "m" is not NULL,
* do indent formatting based on "level" and add a newline afterward;
* otherwise just print the formatted time string only.
*/
static void
671
secu_PrintTime(FILE *out, const PRTime time, const char *m, int level)
672
{
673
PRExplodedTime printableTime;
674
675
676
677
678
char *timeString;
/* Convert to local time */
PR_ExplodeTime(time, PR_GMTParameters, &printableTime);
679
timeString = PORT_Alloc(256);
680
if (timeString == NULL)
681
return;
682
683
if (m != NULL) {
684
685
SECU_Indent(out, level);
fprintf(out, "%s: ", m);
686
687
}
688
if (PR_FormatTime(timeString, 256, "%a %b %d %H:%M:%S %Y", &printableTime)) {
689
fputs(timeString, out);
690
}
691
692
if (m != NULL)
693
fprintf(out, "\n");
694
695
696
697
698
699
700
701
702
703
PORT_Free(timeString);
}
/*
* Format and print the UTC Time "t". If the tag message "m" is not NULL,
* do indent formatting based on "level" and add a newline afterward;
* otherwise just print the formatted time string only.
*/
void
704
SECU_PrintUTCTime(FILE *out, const SECItem *t, const char *m, int level)
705
{
706
PRTime time;
707
708
709
710
SECStatus rv;
rv = DER_UTCTimeToTime(&time, t);
if (rv != SECSuccess)
711
return;
712
713
714
715
716
717
718
719
720
721
secu_PrintTime(out, time, m, level);
}
/*
* Format and print the Generalized Time "t". If the tag message "m"
* is not NULL, * do indent formatting based on "level" and add a newline
* afterward; otherwise just print the formatted time string only.
*/
void
722
SECU_PrintGeneralizedTime(FILE *out, const SECItem *t, const char *m, int level)
723
{
724
PRTime time;
725
726
727
728
SECStatus rv;
rv = DER_GeneralizedTimeToTime(&time, t);
if (rv != SECSuccess)
729
return;
730
731
732
733
secu_PrintTime(out, time, m, level);
}
734
735
736
737
738
739
/*
* Format and print the UTC or Generalized Time "t". If the tag message
* "m" is not NULL, do indent formatting based on "level" and add a newline
* afterward; otherwise just print the formatted time string only.
*/
void
740
SECU_PrintTimeChoice(FILE *out, const SECItem *t, const char *m, int level)
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
{
switch (t->type) {
case siUTCTime:
SECU_PrintUTCTime(out, t, m, level);
break;
case siGeneralizedTime:
SECU_PrintGeneralizedTime(out, t, m, level);
break;
default:
PORT_Assert(0);
break;
}
}
757
/* This prints a SET or SEQUENCE */
758
759
static void
SECU_PrintSet(FILE *out, const SECItem *t, const char *m, int level)
760
{
761
762
763
764
int type = t->data[0] & SEC_ASN1_TAGNUM_MASK;
int constructed = t->data[0] & SEC_ASN1_CONSTRUCTED;
const char *label;
SECItem my = *t;
765
766
if (!constructed) {
767
SECU_PrintAsHex(out, t, m, level);
768
769
770
return;
}
if (SECSuccess != SECU_StripTagAndLength(&my))
771
return;
772
773
774
SECU_Indent(out, level);
if (m) {
775
fprintf(out, "%s: ", m);
776
}
777
778
if (type == SEC_ASN1_SET)
779
label = "Set ";
780
else if (type == SEC_ASN1_SEQUENCE)
781
label = "Sequence ";
782
else
783
784
label = "";
fprintf(out, "%s{\n", label); /* } */
785
786
while (my.len >= 2) {
787
SECItem tmp = my;
788
789
if (tmp.data[1] & 0x80) {
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
unsigned int i;
unsigned int lenlen = tmp.data[1] & 0x7f;
if (lenlen > sizeof tmp.len)
break;
tmp.len = 0;
for (i = 0; i < lenlen; i++) {
tmp.len = (tmp.len << 8) | tmp.data[2 + i];
}
tmp.len += lenlen + 2;
} else {
tmp.len = tmp.data[1] + 2;
}
if (tmp.len > my.len) {
tmp.len = my.len;
}
my.data += tmp.len;
my.len -= tmp.len;
SECU_PrintAny(out, &tmp, NULL, level + 1);
}
SECU_Indent(out, level);
fprintf(out, /* { */ "}\n");
811
}
812
813
static void
814
secu_PrintContextSpecific(FILE *out, const SECItem *i, const char *m, int level)
815
{
816
int type = i->data[0] & SEC_ASN1_TAGNUM_MASK;
817
int constructed = i->data[0] & SEC_ASN1_CONSTRUCTED;
818
SECItem tmp;
819
820
if (constructed) {
821
822
823
824
825
826
827
828
829
830
char *m2;
if (!m)
m2 = PR_smprintf("[%d]", type);
else
m2 = PR_smprintf("%s: [%d]", m, type);
if (m2) {
SECU_PrintSet(out, i, m2, level);
PR_smprintf_free(m2);
}
return;
831
}
832
833
834
SECU_Indent(out, level);
if (m) {
835
fprintf(out, "%s: ", m);
836
}
837
fprintf(out, "[%d]\n", type);
838
839
840
tmp = *i;
if (SECSuccess == SECU_StripTagAndLength(&tmp))
841
SECU_PrintAsHex(out, &tmp, m, level + 1);
842
843
}
844
static void
845
secu_PrintOctetString(FILE *out, const SECItem *i, const char *m, int level)
846
{
847
848
SECItem tmp = *i;
if (SECSuccess == SECU_StripTagAndLength(&tmp))
849
SECU_PrintAsHex(out, &tmp, m, level);
850
851
852
}
static void
853
secu_PrintBitString(FILE *out, const SECItem *i, const char *m, int level)
854
855
{
int unused_bits;
856
857
858
SECItem tmp = *i;
if (SECSuccess != SECU_StripTagAndLength(&tmp) || tmp.len < 2)
859
return;
860
861
862
unused_bits = *tmp.data++;
tmp.len--;
863
864
865
SECU_PrintAsHex(out, &tmp, m, level);
if (unused_bits) {
866
867
SECU_Indent(out, level + 1);
fprintf(out, "(%d least significant bits unused)\n", unused_bits);
868
869
870
}
}
871
872
/* in a decoded bit string, the len member is a bit length. */
static void
873
secu_PrintDecodedBitString(FILE *out, const SECItem *i, const char *m, int level)
874
875
876
877
878
879
880
881
882
{
int unused_bits;
SECItem tmp = *i;
unused_bits = (tmp.len & 0x7) ? 8 - (tmp.len & 7) : 0;
DER_ConvertBitString(&tmp); /* convert length to byte length */
SECU_PrintAsHex(out, &tmp, m, level);
if (unused_bits) {
883
884
SECU_Indent(out, level + 1);
fprintf(out, "(%d least significant bits unused)\n", unused_bits);
885
886
887
}
}
888
889
/* Print a DER encoded Boolean */
void
890
SECU_PrintEncodedBoolean(FILE *out, const SECItem *i, const char *m, int level)
891
{
892
SECItem my = *i;
893
if (SECSuccess == SECU_StripTagAndLength(&my))
894
secu_PrintBoolean(out, &my, m, level);
895
896
897
898
}
/* Print a DER encoded integer */
void
899
SECU_PrintEncodedInteger(FILE *out, const SECItem *i, const char *m, int level)
900
{
901
SECItem my = *i;
902
if (SECSuccess == SECU_StripTagAndLength(&my))
903
SECU_PrintInteger(out, &my, m, level);
904
905
906
907
}
/* Print a DER encoded OID */
void
908
SECU_PrintEncodedObjectID(FILE *out, const SECItem *i, const char *m, int level)
909
{
910
SECItem my = *i;
911
if (SECSuccess == SECU_StripTagAndLength(&my))
912
SECU_PrintObjectID(out, &my, m, level);
913
914
}
915
static void
916
secu_PrintBMPString(FILE *out, const SECItem *i, const char *m, int level)
917
{
918
919
920
921
922
unsigned char *s;
unsigned char *d;
int len;
SECItem tmp = { 0, 0, 0 };
SECItem my = *i;
923
924
if (SECSuccess != SECU_StripTagAndLength(&my))
925
926
927
goto loser;
if (my.len % 2)
goto loser;
928
929
930
len = (int)(my.len / 2);
tmp.data = (unsigned char *)PORT_Alloc(len);
if (!tmp.data)
931
goto loser;
932
tmp.len = len;
933
934
935
936
937
938
for (s = my.data, d = tmp.data; len > 0; len--) {
PRUint32 bmpChar = (s[0] << 8) | s[1];
s += 2;
if (!isprint(bmpChar))
goto loser;
*d++ = (unsigned char)bmpChar;
939
940
941
942
943
944
945
946
}
secu_PrintRawString(out, &tmp, m, level);
PORT_Free(tmp.data);
return;
loser:
SECU_PrintAsHex(out, i, m, level);
if (tmp.data)
947
PORT_Free(tmp.data);
948
949
950
}
static void
951
secu_PrintUniversalString(FILE *out, const SECItem *i, const char *m, int level)
952
{
953
954
955
956
957
unsigned char *s;
unsigned char *d;
int len;
SECItem tmp = { 0, 0, 0 };
SECItem my = *i;
958
959
if (SECSuccess != SECU_StripTagAndLength(&my))
960
961
962
goto loser;
if (my.len % 4)
goto loser;
963
964
965
len = (int)(my.len / 4);
tmp.data = (unsigned char *)PORT_Alloc(len);
if (!tmp.data)
966
goto loser;
967
tmp.len = len;
968
969
970
for (s = my.data, d = tmp.data; len > 0; len--) {
PRUint32 bmpChar = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
s += 4;
971
if (!isprint(bmpChar & 0xFF))
972
973
goto loser;
*d++ = (unsigned char)bmpChar;
974
975
976
977
978
979
980
981
}
secu_PrintRawString(out, &tmp, m, level);
PORT_Free(tmp.data);
return;
loser:
SECU_PrintAsHex(out, i, m, level);
if (tmp.data)
982
PORT_Free(tmp.data);
983
984
}
985
static void
986
secu_PrintUniversal(FILE *out, const SECItem *i, const char *m, int level)
987
{
988
989
990
991
992
993
994
995
996
997
998
999
1000
switch (i->data[0] & SEC_ASN1_TAGNUM_MASK) {
case SEC_ASN1_ENUMERATED:
case SEC_ASN1_INTEGER:
SECU_PrintEncodedInteger(out, i, m, level);
break;
case SEC_ASN1_OBJECT_ID:
SECU_PrintEncodedObjectID(out, i, m, level);
break;
case SEC_ASN1_BOOLEAN:
SECU_PrintEncodedBoolean(out, i, m, level);
break;
case SEC_ASN1_UTF8_STRING:
case SEC_ASN1_PRINTABLE_STRING: