Coverage Report

Created: 2025-06-24 06:49

/src/nss/lib/certhigh/certhtml.c
Line
Count
Source (jump to first uncovered line)
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.51k
#define BREAKLEN 4
57
29
#define COMMA ", "
58
656
#define COMMALEN 2
59
60
1.36k
#define MAX_OUS 20
61
850
#define MAX_DC MAX_OUS
62
63
char *
64
CERT_FormatName(CERTName *name)
65
2.57k
{
66
2.57k
    CERTRDN **rdns;
67
2.57k
    CERTRDN *rdn;
68
2.57k
    CERTAVA **avas;
69
2.57k
    CERTAVA *ava;
70
2.57k
    char *buf = 0;
71
2.57k
    char *tmpbuf = 0;
72
2.57k
    SECItem *cn = 0;
73
2.57k
    SECItem *email = 0;
74
2.57k
    SECItem *org = 0;
75
2.57k
    SECItem *loc = 0;
76
2.57k
    SECItem *state = 0;
77
2.57k
    SECItem *country = 0;
78
2.57k
    SECItem *dq = 0;
79
80
2.57k
    unsigned len = 0;
81
2.57k
    int tag;
82
2.57k
    int i;
83
2.57k
    int ou_count = 0;
84
2.57k
    int dc_count = 0;
85
2.57k
    PRBool first;
86
2.57k
    SECItem *orgunit[MAX_OUS];
87
2.57k
    SECItem *dc[MAX_DC];
88
89
    /* Loop over name components and gather the interesting ones */
90
2.57k
    rdns = name->rdns;
91
25.5k
    while ((rdn = *rdns++) != 0) {
92
23.1k
        avas = rdn->avas;
93
61.6k
        while ((ava = *avas++) != 0) {
94
38.6k
            tag = CERT_GetAVATag(ava);
95
38.6k
            switch (tag) {
96
543
                case SEC_OID_AVA_COMMON_NAME:
97
543
                    if (cn) {
98
436
                        break;
99
436
                    }
100
107
                    cn = CERT_DecodeAVAValue(&ava->value);
101
107
                    if (!cn) {
102
1
                        goto loser;
103
1
                    }
104
106
                    len += cn->len;
105
                    // cn will always have BREAK after it
106
106
                    len += BREAKLEN;
107
106
                    break;
108
2.48k
                case SEC_OID_AVA_COUNTRY_NAME:
109
2.48k
                    if (country) {
110
2.07k
                        break;
111
2.07k
                    }
112
407
                    country = CERT_DecodeAVAValue(&ava->value);
113
407
                    if (!country) {
114
126
                        goto loser;
115
126
                    }
116
281
                    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
281
                    len += COMMALEN;
121
281
                    break;
122
2.03k
                case SEC_OID_AVA_LOCALITY:
123
2.03k
                    if (loc) {
124
1.72k
                        break;
125
1.72k
                    }
126
304
                    loc = CERT_DecodeAVAValue(&ava->value);
127
304
                    if (!loc) {
128
8
                        goto loser;
129
8
                    }
130
296
                    len += loc->len;
131
                    // loc may have COMMA after it
132
296
                    len += COMMALEN;
133
296
                    break;
134
216
                case SEC_OID_AVA_STATE_OR_PROVINCE:
135
216
                    if (state) {
136
194
                        break;
137
194
                    }
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
8.13k
                case SEC_OID_AVA_ORGANIZATION_NAME:
148
8.13k
                    if (org) {
149
7.52k
                        break;
150
7.52k
                    }
151
611
                    org = CERT_DecodeAVAValue(&ava->value);
152
611
                    if (!org) {
153
25
                        goto loser;
154
25
                    }
155
586
                    len += org->len;
156
                    // org will have BREAK after it
157
586
                    len += BREAKLEN;
158
586
                    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
516
                case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME:
172
516
                    if (ou_count < MAX_OUS) {
173
318
                        orgunit[ou_count] = CERT_DecodeAVAValue(&ava->value);
174
318
                        if (!orgunit[ou_count]) {
175
1
                            goto loser;
176
1
                        }
177
317
                        len += orgunit[ou_count++]->len;
178
                        // each ou will have BREAK after it
179
317
                        len += BREAKLEN;
180
317
                    }
181
515
                    break;
182
850
                case SEC_OID_AVA_DC:
183
850
                    if (dc_count < MAX_DC) {
184
650
                        dc[dc_count] = CERT_DecodeAVAValue(&ava->value);
185
650
                        if (!dc[dc_count]) {
186
6
                            goto loser;
187
6
                        }
188
644
                        len += dc[dc_count++]->len;
189
                        // each dc will have BREAK after it
190
644
                        len += BREAKLEN;
191
644
                    }
192
844
                    break;
193
18.9k
                case SEC_OID_PKCS9_EMAIL_ADDRESS:
194
19.1k
                case SEC_OID_RFC1274_MAIL:
195
19.1k
                    if (email) {
196
18.7k
                        break;
197
18.7k
                    }
198
371
                    email = CERT_DecodeAVAValue(&ava->value);
199
371
                    if (!email) {
200
9
                        goto loser;
201
9
                    }
202
362
                    len += email->len;
203
                    // email will have BREAK after it
204
362
                    len += BREAKLEN;
205
362
                    break;
206
4.53k
                default:
207
4.53k
                    break;
208
38.6k
            }
209
38.6k
        }
210
23.1k
    }
211
212
    // there may be a final BREAK
213
2.39k
    len += BREAKLEN;
214
215
    /* allocate buffer */
216
2.39k
    buf = (char *)PORT_Alloc(len);
217
2.39k
    if (!buf) {
218
0
        goto loser;
219
0
    }
220
221
2.39k
    tmpbuf = buf;
222
223
2.39k
    if (cn) {
224
106
        PORT_Memcpy(tmpbuf, cn->data, cn->len);
225
106
        tmpbuf += cn->len;
226
106
        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
227
106
        tmpbuf += BREAKLEN;
228
106
    }
229
2.39k
    if (email) {
230
349
        PORT_Memcpy(tmpbuf, email->data, email->len);
231
349
        tmpbuf += (email->len);
232
349
        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
233
349
        tmpbuf += BREAKLEN;
234
349
    }
235
2.70k
    for (i = ou_count - 1; i >= 0; i--) {
236
312
        PORT_Memcpy(tmpbuf, orgunit[i]->data, orgunit[i]->len);
237
312
        tmpbuf += (orgunit[i]->len);
238
312
        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
239
312
        tmpbuf += BREAKLEN;
240
312
    }
241
2.39k
    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.39k
    if (org) {
248
581
        PORT_Memcpy(tmpbuf, org->data, org->len);
249
581
        tmpbuf += (org->len);
250
581
        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
251
581
        tmpbuf += BREAKLEN;
252
581
    }
253
3.03k
    for (i = dc_count - 1; i >= 0; i--) {
254
638
        PORT_Memcpy(tmpbuf, dc[i]->data, dc[i]->len);
255
638
        tmpbuf += (dc[i]->len);
256
638
        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
257
638
        tmpbuf += BREAKLEN;
258
638
    }
259
2.39k
    first = PR_TRUE;
260
2.39k
    if (loc) {
261
291
        PORT_Memcpy(tmpbuf, loc->data, loc->len);
262
291
        tmpbuf += (loc->len);
263
291
        first = PR_FALSE;
264
291
    }
265
2.39k
    if (state) {
266
15
        if (!first) {
267
5
            PORT_Memcpy(tmpbuf, COMMA, COMMALEN);
268
5
            tmpbuf += COMMALEN;
269
5
        }
270
15
        PORT_Memcpy(tmpbuf, state->data, state->len);
271
15
        tmpbuf += (state->len);
272
15
        first = PR_FALSE;
273
15
    }
274
2.39k
    if (country) {
275
279
        if (!first) {
276
24
            PORT_Memcpy(tmpbuf, COMMA, COMMALEN);
277
24
            tmpbuf += COMMALEN;
278
24
        }
279
279
        PORT_Memcpy(tmpbuf, country->data, country->len);
280
279
        tmpbuf += (country->len);
281
279
        first = PR_FALSE;
282
279
    }
283
2.39k
    if (!first) {
284
556
        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
285
556
        tmpbuf += BREAKLEN;
286
556
    }
287
288
2.39k
    *tmpbuf = 0;
289
290
/* fall through and clean */
291
2.57k
loser:
292
2.57k
    if (cn) {
293
106
        SECITEM_FreeItem(cn, PR_TRUE);
294
106
    }
295
2.57k
    if (email) {
296
362
        SECITEM_FreeItem(email, PR_TRUE);
297
362
    }
298
2.88k
    for (i = ou_count - 1; i >= 0; i--) {
299
317
        SECITEM_FreeItem(orgunit[i], PR_TRUE);
300
317
    }
301
2.57k
    if (dq) {
302
9
        SECITEM_FreeItem(dq, PR_TRUE);
303
9
    }
304
2.57k
    if (org) {
305
586
        SECITEM_FreeItem(org, PR_TRUE);
306
586
    }
307
3.21k
    for (i = dc_count - 1; i >= 0; i--) {
308
644
        SECITEM_FreeItem(dc[i], PR_TRUE);
309
644
    }
310
2.57k
    if (loc) {
311
296
        SECITEM_FreeItem(loc, PR_TRUE);
312
296
    }
313
2.57k
    if (state) {
314
21
        SECITEM_FreeItem(state, PR_TRUE);
315
21
    }
316
2.57k
    if (country) {
317
281
        SECITEM_FreeItem(country, PR_TRUE);
318
281
    }
319
320
2.57k
    return (buf);
321
2.39k
}