Coverage Report

Created: 2025-09-17 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/ssl/sslauth.c
Line
Count
Source
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
#include "cert.h"
6
#include "secitem.h"
7
#include "ssl.h"
8
#include "sslimpl.h"
9
#include "sslproto.h"
10
#include "pk11func.h"
11
#include "ocsp.h"
12
13
/* NEED LOCKS IN HERE.  */
14
CERTCertificate *
15
SSL_PeerCertificate(PRFileDesc *fd)
16
0
{
17
0
    sslSocket *ss;
18
19
0
    ss = ssl_FindSocket(fd);
20
0
    if (!ss) {
21
0
        SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificate",
22
0
                 SSL_GETPID(), fd));
23
0
        return 0;
24
0
    }
25
0
    if (ss->opt.useSecurity && ss->sec.peerCert) {
26
0
        return CERT_DupCertificate(ss->sec.peerCert);
27
0
    }
28
0
    return 0;
29
0
}
30
31
/* NEED LOCKS IN HERE.  */
32
SECStatus
33
SSLExp_PeerCertificateChainDER(PRFileDesc *fd, SECItemArray **out)
34
0
{
35
0
    sslSocket *ss;
36
0
    ssl3CertNode *cur;
37
0
    SECItemArray *chain;
38
0
    unsigned int count;
39
0
    unsigned int index;
40
0
    SECStatus rv;
41
42
0
    ss = ssl_FindSocket(fd);
43
0
    if (!ss) {
44
0
        SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificateChainDER",
45
0
                 SSL_GETPID(), fd));
46
0
        return SECFailure;
47
0
    }
48
0
    if (!ss->opt.useSecurity || !ss->sec.peerCert) {
49
0
        PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
50
0
        return SECFailure;
51
0
    }
52
53
0
    count = 1; // for ss->sec.peerCert
54
0
    for (cur = ss->ssl3.peerCertChain; cur; cur = cur->next) {
55
0
        ++count;
56
0
    }
57
58
0
    chain = SECITEM_AllocArray(NULL, NULL, count);
59
0
    if (chain == NULL) {
60
0
        return SECFailure; /* error code set in SECITEM_AllocArray */
61
0
    }
62
63
0
    index = 0;
64
0
    rv = SECITEM_CopyItem(NULL, &chain->items[index++], &ss->sec.peerCert->derCert);
65
0
    if (rv != SECSuccess) {
66
0
        goto loser; /* error code set in SECITEM_CopyItem */
67
0
    }
68
69
0
    for (cur = ss->ssl3.peerCertChain; cur; cur = cur->next) {
70
0
        rv = SECITEM_CopyItem(NULL, &chain->items[index++], cur->derCert);
71
0
        if (rv != SECSuccess) {
72
0
            goto loser; /* error code set in SECITEM_CopyItem */
73
0
        }
74
0
    }
75
76
0
    *out = chain;
77
0
    return SECSuccess;
78
79
0
loser:
80
0
    SECITEM_FreeArray(chain, PR_TRUE);
81
0
    return SECFailure;
82
0
}
83
84
/* NEED LOCKS IN HERE.  */
85
CERTCertList *
86
SSL_PeerCertificateChain(PRFileDesc *fd)
87
73.1k
{
88
73.1k
    sslSocket *ss;
89
73.1k
    CERTCertList *chain = NULL;
90
73.1k
    CERTCertificate *cert;
91
73.1k
    ssl3CertNode *cur;
92
93
73.1k
    ss = ssl_FindSocket(fd);
94
73.1k
    if (!ss) {
95
0
        SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificateChain",
96
0
                 SSL_GETPID(), fd));
97
0
        return NULL;
98
0
    }
99
73.1k
    if (!ss->opt.useSecurity || !ss->sec.peerCert) {
100
0
        PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
101
0
        return NULL;
102
0
    }
103
73.1k
    chain = CERT_NewCertList();
104
73.1k
    if (!chain) {
105
0
        return NULL;
106
0
    }
107
73.1k
    cert = CERT_DupCertificate(ss->sec.peerCert);
108
73.1k
    if (CERT_AddCertToListTail(chain, cert) != SECSuccess) {
109
0
        goto loser;
110
0
    }
111
77.0k
    for (cur = ss->ssl3.peerCertChain; cur; cur = cur->next) {
112
4.42k
        cert = CERT_NewTempCertificate(ss->dbHandle, cur->derCert,
113
4.42k
                                       NULL, PR_FALSE, PR_TRUE);
114
4.42k
        if (!cert || CERT_AddCertToListTail(chain, cert) != SECSuccess) {
115
463
            goto loser;
116
463
        }
117
4.42k
    }
118
72.6k
    return chain;
119
120
463
loser:
121
463
    CERT_DestroyCertList(chain);
122
463
    return NULL;
123
73.1k
}
124
125
/* NEED LOCKS IN HERE.  */
126
CERTCertificate *
127
SSL_LocalCertificate(PRFileDesc *fd)
128
0
{
129
0
    sslSocket *ss;
130
131
0
    ss = ssl_FindSocket(fd);
132
0
    if (!ss) {
133
0
        SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificate",
134
0
                 SSL_GETPID(), fd));
135
0
        return NULL;
136
0
    }
137
0
    if (ss->opt.useSecurity) {
138
0
        if (ss->sec.localCert) {
139
0
            return CERT_DupCertificate(ss->sec.localCert);
140
0
        }
141
0
        if (ss->sec.ci.sid && ss->sec.ci.sid->localCert) {
142
0
            return CERT_DupCertificate(ss->sec.ci.sid->localCert);
143
0
        }
144
0
    }
145
0
    return NULL;
146
0
}
147
148
/* NEED LOCKS IN HERE.  */
149
SECStatus
150
SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1,
151
                   char **ip, char **sp)
152
0
{
153
0
    sslSocket *ss;
154
155
0
    ss = ssl_FindSocket(fd);
156
0
    if (!ss) {
157
0
        SSL_DBG(("%d: SSL[%d]: bad socket in SecurityStatus",
158
0
                 SSL_GETPID(), fd));
159
0
        return SECFailure;
160
0
    }
161
162
0
    if (cp)
163
0
        *cp = 0;
164
0
    if (kp0)
165
0
        *kp0 = 0;
166
0
    if (kp1)
167
0
        *kp1 = 0;
168
0
    if (ip)
169
0
        *ip = 0;
170
0
    if (sp)
171
0
        *sp = 0;
172
0
    if (op) {
173
0
        *op = SSL_SECURITY_STATUS_OFF;
174
0
    }
175
176
0
    if (ss->opt.useSecurity && ss->enoughFirstHsDone) {
177
0
        const ssl3BulkCipherDef *bulkCipherDef;
178
0
        PRBool isDes = PR_FALSE;
179
180
0
        bulkCipherDef = ssl_GetBulkCipherDef(ss->ssl3.hs.suite_def);
181
0
        if (cp) {
182
0
            *cp = PORT_Strdup(bulkCipherDef->short_name);
183
0
        }
184
0
        if (PORT_Strstr(bulkCipherDef->short_name, "DES")) {
185
0
            isDes = PR_TRUE;
186
0
        }
187
188
0
        if (kp0) {
189
0
            *kp0 = bulkCipherDef->key_size * 8;
190
0
            if (isDes)
191
0
                *kp0 = (*kp0 * 7) / 8;
192
0
        }
193
0
        if (kp1) {
194
0
            *kp1 = bulkCipherDef->secret_key_size * 8;
195
0
            if (isDes)
196
0
                *kp1 = (*kp1 * 7) / 8;
197
0
        }
198
0
        if (op) {
199
0
            if (bulkCipherDef->key_size == 0) {
200
0
                *op = SSL_SECURITY_STATUS_OFF;
201
0
            } else if (bulkCipherDef->secret_key_size * 8 < 90) {
202
0
                *op = SSL_SECURITY_STATUS_ON_LOW;
203
0
            } else {
204
0
                *op = SSL_SECURITY_STATUS_ON_HIGH;
205
0
            }
206
0
        }
207
208
0
        if (ip || sp) {
209
0
            CERTCertificate *cert;
210
211
0
            cert = ss->sec.peerCert;
212
0
            if (cert) {
213
0
                if (ip) {
214
0
                    *ip = CERT_NameToAscii(&cert->issuer);
215
0
                }
216
0
                if (sp) {
217
0
                    *sp = CERT_NameToAscii(&cert->subject);
218
0
                }
219
0
            } else {
220
0
                if (ip) {
221
0
                    *ip = PORT_Strdup("no certificate");
222
0
                }
223
0
                if (sp) {
224
0
                    *sp = PORT_Strdup("no certificate");
225
0
                }
226
0
            }
227
0
        }
228
0
    }
229
230
0
    return SECSuccess;
231
0
}
232
233
/************************************************************************/
234
235
/* NEED LOCKS IN HERE.  */
236
SECStatus
237
SSL_AuthCertificateHook(PRFileDesc *s, SSLAuthCertificate func, void *arg)
238
64.1k
{
239
64.1k
    sslSocket *ss;
240
241
64.1k
    ss = ssl_FindSocket(s);
242
64.1k
    if (!ss) {
243
0
        SSL_DBG(("%d: SSL[%d]: bad socket in AuthCertificateHook",
244
0
                 SSL_GETPID(), s));
245
0
        return SECFailure;
246
0
    }
247
248
64.1k
    ss->authCertificate = func;
249
64.1k
    ss->authCertificateArg = arg;
250
251
64.1k
    return SECSuccess;
252
64.1k
}
253
254
/* NEED LOCKS IN HERE.  */
255
SECStatus
256
SSL_GetClientAuthDataHook(PRFileDesc *s, SSLGetClientAuthData func,
257
                          void *arg)
258
0
{
259
0
    sslSocket *ss;
260
261
0
    ss = ssl_FindSocket(s);
262
0
    if (!ss) {
263
0
        SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook",
264
0
                 SSL_GETPID(), s));
265
0
        return SECFailure;
266
0
    }
267
268
0
    ss->getClientAuthData = func;
269
0
    ss->getClientAuthDataArg = arg;
270
0
    return SECSuccess;
271
0
}
272
273
/* NEED LOCKS IN HERE.  */
274
SECStatus
275
SSL_SetPKCS11PinArg(PRFileDesc *s, void *arg)
276
0
{
277
0
    sslSocket *ss;
278
279
0
    ss = ssl_FindSocket(s);
280
0
    if (!ss) {
281
0
        SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook",
282
0
                 SSL_GETPID(), s));
283
0
        return SECFailure;
284
0
    }
285
286
0
    ss->pkcs11PinArg = arg;
287
0
    return SECSuccess;
288
0
}
289
290
/* This is the "default" authCert callback function.  It is called when a
291
 * certificate message is received from the peer and the local application
292
 * has not registered an authCert callback function.
293
 */
294
SECStatus
295
SSL_AuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
296
0
{
297
0
    SECStatus rv;
298
0
    CERTCertDBHandle *handle;
299
0
    sslSocket *ss;
300
0
    SECCertUsage certUsage;
301
0
    const char *hostname = NULL;
302
0
    SECItemArray *certStatusArray;
303
304
0
    ss = ssl_FindSocket(fd);
305
0
    PORT_Assert(ss != NULL);
306
0
    if (!ss) {
307
0
        return SECFailure;
308
0
    }
309
310
0
    handle = (CERTCertDBHandle *)arg;
311
0
    certStatusArray = &ss->sec.ci.sid->peerCertStatus;
312
313
0
    PRTime now = ssl_Time(ss);
314
0
    if (certStatusArray->len) {
315
0
        PORT_SetError(0);
316
0
        if (CERT_CacheOCSPResponseFromSideChannel(handle, ss->sec.peerCert, now,
317
0
                                                  &certStatusArray->items[0],
318
0
                                                  ss->pkcs11PinArg) !=
319
0
            SECSuccess) {
320
0
            PORT_Assert(PR_GetError() != 0);
321
0
        }
322
0
    }
323
324
    /* this may seem backwards, but isn't. */
325
0
    certUsage = isServer ? certUsageSSLClient : certUsageSSLServer;
326
327
    /* Calling SSL_PeerCertificateChain here ensures that all certs from the
328
     * peer's presented chain are in the database for path finding.
329
     */
330
0
    CERTCertList *peerChain = SSL_PeerCertificateChain(fd);
331
332
0
    rv = CERT_VerifyCert(handle, ss->sec.peerCert, checkSig, certUsage,
333
0
                         now, ss->pkcs11PinArg, NULL);
334
335
0
    CERT_DestroyCertList(peerChain);
336
337
0
    if (rv != SECSuccess || isServer)
338
0
        return rv;
339
340
    /* cert is OK.  This is the client side of an SSL connection.
341
     * Now check the name field in the cert against the desired hostname.
342
     * NB: This is our only defense against Man-In-The-Middle (MITM) attacks!
343
     */
344
0
    hostname = ss->url;
345
0
    if (hostname && hostname[0])
346
0
        rv = CERT_VerifyCertName(ss->sec.peerCert, hostname);
347
0
    else
348
0
        rv = SECFailure;
349
0
    if (rv != SECSuccess)
350
0
        PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
351
352
0
    return rv;
353
0
}