Coverage Report

Created: 2026-02-18 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/certhigh/certhtml.c
Line
Count
Source
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
/*
6
 * certhtml.c --- convert a cert to html
7
 */
8
9
#include "seccomon.h"
10
#include "secitem.h"
11
#include "sechash.h"
12
#include "cert.h"
13
#include "keyhi.h"
14
#include "secder.h"
15
#include "prprf.h"
16
#include "secport.h"
17
#include "secasn1.h"
18
#include "pk11func.h"
19
20
static char *hex = "0123456789ABCDEF";
21
22
/*
23
** Convert a der-encoded integer to a hex printable string form
24
*/
25
char *
26
CERT_Hexify(SECItem *i, int do_colon)
27
0
{
28
0
    unsigned char *cp, *end;
29
0
    char *rv, *o;
30
31
0
    if (!i->len) {
32
0
        return PORT_Strdup("00");
33
0
    }
34
35
0
    rv = o = (char *)PORT_Alloc(i->len * 3);
36
0
    if (!rv)
37
0
        return rv;
38
39
0
    cp = i->data;
40
0
    end = cp + i->len;
41
0
    while (cp < end) {
42
0
        unsigned char ch = *cp++;
43
0
        *o++ = hex[(ch >> 4) & 0xf];
44
0
        *o++ = hex[ch & 0xf];
45
0
        if (cp != end) {
46
0
            if (do_colon) {
47
0
                *o++ = ':';
48
0
            }
49
0
        }
50
0
    }
51
0
    *o = 0; /* Null terminate the string */
52
0
    return rv;
53
0
}
54
55
2.55k
#define BREAK "<br>"
56
9.50k
#define BREAKLEN 4
57
42
#define COMMA ", "
58
680
#define COMMALEN 2
59
60
1.39k
#define MAX_OUS 20
61
897
#define MAX_DC MAX_OUS
62
63
char *
64
CERT_FormatName(CERTName *name)
65
2.55k
{
66
2.55k
    CERTRDN **rdns;
67
2.55k
    CERTRDN *rdn;
68
2.55k
    CERTAVA **avas;
69
2.55k
    CERTAVA *ava;
70
2.55k
    char *buf = 0;
71
2.55k
    char *tmpbuf = 0;
72
2.55k
    SECItem *cn = 0;
73
2.55k
    SECItem *email = 0;
74
2.55k
    SECItem *org = 0;
75
2.55k
    SECItem *loc = 0;
76
2.55k
    SECItem *state = 0;
77
2.55k
    SECItem *country = 0;
78
2.55k
    SECItem *dq = 0;
79
80
2.55k
    unsigned len = 0;
81
2.55k
    int tag;
82
2.55k
    int i;
83
2.55k
    int ou_count = 0;
84
2.55k
    int dc_count = 0;
85
2.55k
    PRBool first;
86
2.55k
    SECItem *orgunit[MAX_OUS];
87
2.55k
    SECItem *dc[MAX_DC];
88
89
    /* Loop over name components and gather the interesting ones */
90
2.55k
    rdns = name->rdns;
91
27.7k
    while ((rdn = *rdns++) != 0) {
92
25.3k
        avas = rdn->avas;
93
63.8k
        while ((ava = *avas++) != 0) {
94
38.6k
            tag = CERT_GetAVATag(ava);
95
38.6k
            switch (tag) {
96
491
                case SEC_OID_AVA_COMMON_NAME:
97
491
                    if (cn) {
98
399
                        break;
99
399
                    }
100
92
                    cn = CERT_DecodeAVAValue(&ava->value);
101
92
                    if (!cn) {
102
2
                        goto loser;
103
2
                    }
104
90
                    len += cn->len;
105
                    // cn will always have BREAK after it
106
90
                    len += BREAKLEN;
107
90
                    break;
108
2.28k
                case SEC_OID_AVA_COUNTRY_NAME:
109
2.28k
                    if (country) {
110
1.85k
                        break;
111
1.85k
                    }
112
424
                    country = CERT_DecodeAVAValue(&ava->value);
113
424
                    if (!country) {
114
136
                        goto loser;
115
136
                    }
116
288
                    len += country->len;
117
                    // country may have COMMA after it (if we over-count len,
118
                    // that's fine - we'll just allocate a buffer larger than we
119
                    // need)
120
288
                    len += COMMALEN;
121
288
                    break;
122
1.06k
                case SEC_OID_AVA_LOCALITY:
123
1.06k
                    if (loc) {
124
774
                        break;
125
774
                    }
126
292
                    loc = CERT_DecodeAVAValue(&ava->value);
127
292
                    if (!loc) {
128
5
                        goto loser;
129
5
                    }
130
287
                    len += loc->len;
131
                    // loc may have COMMA after it
132
287
                    len += COMMALEN;
133
287
                    break;
134
226
                case SEC_OID_AVA_STATE_OR_PROVINCE:
135
226
                    if (state) {
136
204
                        break;
137
204
                    }
138
22
                    state = CERT_DecodeAVAValue(&ava->value);
139
22
                    if (!state) {
140
1
                        goto loser;
141
1
                    }
142
21
                    len += state->len;
143
                    // state currently won't have COMMA after it, but this is a
144
                    // (probably vain) attempt to future-proof this code
145
21
                    len += COMMALEN;
146
21
                    break;
147
6.00k
                case SEC_OID_AVA_ORGANIZATION_NAME:
148
6.00k
                    if (org) {
149
5.40k
                        break;
150
5.40k
                    }
151
596
                    org = CERT_DecodeAVAValue(&ava->value);
152
596
                    if (!org) {
153
23
                        goto loser;
154
23
                    }
155
573
                    len += org->len;
156
                    // org will have BREAK after it
157
573
                    len += BREAKLEN;
158
573
                    break;
159
204
                case SEC_OID_AVA_DN_QUALIFIER:
160
204
                    if (dq) {
161
194
                        break;
162
194
                    }
163
10
                    dq = CERT_DecodeAVAValue(&ava->value);
164
10
                    if (!dq) {
165
1
                        goto loser;
166
1
                    }
167
9
                    len += dq->len;
168
                    // dq will have BREAK after it
169
9
                    len += BREAKLEN;
170
9
                    break;
171
500
                case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME:
172
500
                    if (ou_count < MAX_OUS) {
173
306
                        orgunit[ou_count] = CERT_DecodeAVAValue(&ava->value);
174
306
                        if (!orgunit[ou_count]) {
175
1
                            goto loser;
176
1
                        }
177
305
                        len += orgunit[ou_count++]->len;
178
                        // each ou will have BREAK after it
179
305
                        len += BREAKLEN;
180
305
                    }
181
499
                    break;
182
897
                case SEC_OID_AVA_DC:
183
897
                    if (dc_count < MAX_DC) {
184
693
                        dc[dc_count] = CERT_DecodeAVAValue(&ava->value);
185
693
                        if (!dc[dc_count]) {
186
13
                            goto loser;
187
13
                        }
188
680
                        len += dc[dc_count++]->len;
189
                        // each dc will have BREAK after it
190
680
                        len += BREAKLEN;
191
680
                    }
192
884
                    break;
193
22.3k
                case SEC_OID_PKCS9_EMAIL_ADDRESS:
194
22.5k
                case SEC_OID_RFC1274_MAIL:
195
22.5k
                    if (email) {
196
22.1k
                        break;
197
22.1k
                    }
198
389
                    email = CERT_DecodeAVAValue(&ava->value);
199
389
                    if (!email) {
200
9
                        goto loser;
201
9
                    }
202
380
                    len += email->len;
203
                    // email will have BREAK after it
204
380
                    len += BREAKLEN;
205
380
                    break;
206
4.49k
                default:
207
4.49k
                    break;
208
38.6k
            }
209
38.6k
        }
210
25.3k
    }
211
212
    // there may be a final BREAK
213
2.36k
    len += BREAKLEN;
214
215
    /* allocate buffer */
216
2.36k
    buf = (char *)PORT_Alloc(len);
217
2.36k
    if (!buf) {
218
0
        goto loser;
219
0
    }
220
221
2.36k
    tmpbuf = buf;
222
223
2.36k
    if (cn) {
224
90
        PORT_Memcpy(tmpbuf, cn->data, cn->len);
225
90
        tmpbuf += cn->len;
226
90
        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
227
90
        tmpbuf += BREAKLEN;
228
90
    }
229
2.36k
    if (email) {
230
367
        PORT_Memcpy(tmpbuf, email->data, email->len);
231
367
        tmpbuf += (email->len);
232
367
        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
233
367
        tmpbuf += BREAKLEN;
234
367
    }
235
2.66k
    for (i = ou_count - 1; i >= 0; i--) {
236
301
        PORT_Memcpy(tmpbuf, orgunit[i]->data, orgunit[i]->len);
237
301
        tmpbuf += (orgunit[i]->len);
238
301
        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
239
301
        tmpbuf += BREAKLEN;
240
301
    }
241
2.36k
    if (dq) {
242
9
        PORT_Memcpy(tmpbuf, dq->data, dq->len);
243
9
        tmpbuf += (dq->len);
244
9
        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
245
9
        tmpbuf += BREAKLEN;
246
9
    }
247
2.36k
    if (org) {
248
571
        PORT_Memcpy(tmpbuf, org->data, org->len);
249
571
        tmpbuf += (org->len);
250
571
        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
251
571
        tmpbuf += BREAKLEN;
252
571
    }
253
3.04k
    for (i = dc_count - 1; i >= 0; i--) {
254
675
        PORT_Memcpy(tmpbuf, dc[i]->data, dc[i]->len);
255
675
        tmpbuf += (dc[i]->len);
256
675
        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
257
675
        tmpbuf += BREAKLEN;
258
675
    }
259
2.36k
    first = PR_TRUE;
260
2.36k
    if (loc) {
261
283
        PORT_Memcpy(tmpbuf, loc->data, loc->len);
262
283
        tmpbuf += (loc->len);
263
283
        first = PR_FALSE;
264
283
    }
265
2.36k
    if (state) {
266
16
        if (!first) {
267
6
            PORT_Memcpy(tmpbuf, COMMA, COMMALEN);
268
6
            tmpbuf += COMMALEN;
269
6
        }
270
16
        PORT_Memcpy(tmpbuf, state->data, state->len);
271
16
        tmpbuf += (state->len);
272
16
        first = PR_FALSE;
273
16
    }
274
2.36k
    if (country) {
275
282
        if (!first) {
276
36
            PORT_Memcpy(tmpbuf, COMMA, COMMALEN);
277
36
            tmpbuf += COMMALEN;
278
36
        }
279
282
        PORT_Memcpy(tmpbuf, country->data, country->len);
280
282
        tmpbuf += (country->len);
281
282
        first = PR_FALSE;
282
282
    }
283
2.36k
    if (!first) {
284
539
        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
285
539
        tmpbuf += BREAKLEN;
286
539
    }
287
288
2.36k
    *tmpbuf = 0;
289
290
/* fall through and clean */
291
2.55k
loser:
292
2.55k
    if (cn) {
293
90
        SECITEM_FreeItem(cn, PR_TRUE);
294
90
    }
295
2.55k
    if (email) {
296
380
        SECITEM_FreeItem(email, PR_TRUE);
297
380
    }
298
2.86k
    for (i = ou_count - 1; i >= 0; i--) {
299
305
        SECITEM_FreeItem(orgunit[i], PR_TRUE);
300
305
    }
301
2.55k
    if (dq) {
302
9
        SECITEM_FreeItem(dq, PR_TRUE);
303
9
    }
304
2.55k
    if (org) {
305
573
        SECITEM_FreeItem(org, PR_TRUE);
306
573
    }
307
3.23k
    for (i = dc_count - 1; i >= 0; i--) {
308
680
        SECITEM_FreeItem(dc[i], PR_TRUE);
309
680
    }
310
2.55k
    if (loc) {
311
287
        SECITEM_FreeItem(loc, PR_TRUE);
312
287
    }
313
2.55k
    if (state) {
314
21
        SECITEM_FreeItem(state, PR_TRUE);
315
21
    }
316
2.55k
    if (country) {
317
288
        SECITEM_FreeItem(country, PR_TRUE);
318
288
    }
319
320
2.55k
    return (buf);
321
2.36k
}