Coverage Report

Created: 2026-07-07 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/ssl/sslcon.c
Line
Count
Source
1
/*
2
 * Basic SSL handshake functions.
3
 *
4
 * This Source Code Form is subject to the terms of the Mozilla Public
5
 * License, v. 2.0. If a copy of the MPL was not distributed with this
6
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8
#include "nssrenam.h"
9
#include "cert.h"
10
#include "secitem.h"
11
#include "sechash.h"
12
#include "cryptohi.h" /* for SGN_ funcs */
13
#include "keyhi.h"    /* for SECKEY_ high level functions. */
14
#include "ssl.h"
15
#include "sslimpl.h"
16
#include "sslproto.h"
17
#include "ssl3prot.h"
18
#include "sslerr.h"
19
#include "pk11func.h"
20
#include "prinit.h"
21
22
/*
23
** Put a string tag in the library so that we can examine an executable
24
** and see what kind of security it supports.
25
*/
26
const char *ssl_version = "SECURITY_VERSION:"
27
                          " +us"
28
                          " +export"
29
#ifdef TRACE
30
                          " +trace"
31
#endif
32
#ifdef DEBUG
33
                          " +debug"
34
#endif
35
    ;
36
37
/***********************************************************************
38
 * Gathers in and handles records/messages until either the handshake is
39
 * complete or application data is available.
40
 *
41
 * Called from ssl_Do1stHandshake() via function pointer ss->handshake.
42
 * Caller must hold handshake lock.
43
 * This function acquires and releases the RecvBufLock.
44
 *
45
 * returns SECSuccess for success.
46
 * returns SECFailure on error, setting PR_WOULD_BLOCK_ERROR if only blocked.
47
 *
48
 * The gather functions called by ssl_GatherRecord1stHandshake are expected
49
 *  to return values interpreted as follows:
50
 *  1 : the function completed without error.
51
 *  0 : the function read EOF.
52
 * -1 : read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error.
53
 *
54
 * This code is similar to, and easily confused with, DoRecv() in sslsecur.c
55
 *
56
 * This function is called from ssl_Do1stHandshake().
57
 * The following functions put ssl_GatherRecord1stHandshake into ss->handshake:
58
 *  ssl_BeginClientHandshake
59
 *  ssl3_RestartHandshakeAfterCertReq
60
 *  ssl3_RestartHandshakeAfterServerCert
61
 *  ssl_BeginServerHandshake
62
 */
63
SECStatus
64
ssl_GatherRecord1stHandshake(sslSocket *ss)
65
65.4k
{
66
65.4k
    int rv;
67
68
65.4k
    PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss));
69
70
65.4k
    ssl_GetRecvBufLock(ss);
71
72
    /* Wait for handshake to complete, or application data to arrive.  */
73
65.4k
    rv = ssl3_GatherCompleteHandshake(ss, 0);
74
65.4k
    SSL_TRC(10, ("%d: SSL[%d]: handshake gathering, rv=%d",
75
65.4k
                 SSL_GETPID(), ss->fd, rv));
76
77
65.4k
    ssl_ReleaseRecvBufLock(ss);
78
79
65.4k
    if (rv <= 0) {
80
60.6k
        if (rv == 0) {
81
            /* EOF. Loser  */
82
28.6k
            PORT_SetError(PR_END_OF_FILE_ERROR);
83
28.6k
        }
84
60.6k
        if (PORT_GetError() == PR_WOULD_BLOCK_ERROR) {
85
4.86k
            SSL_TRC(10, ("%d: SSL[%d]: handshake blocked (need %d)",
86
4.86k
                         SSL_GETPID(), ss->fd, ss->gs.remainder));
87
4.86k
        }
88
60.6k
        return SECFailure; /* rv is < 0 here. */
89
60.6k
    }
90
91
4.73k
    ss->handshake = NULL;
92
4.73k
    return SECSuccess;
93
65.4k
}
94
95
/* This function is called at the beginning of a handshake to ensure that at
96
 * least one SSL/TLS version is enabled. */
97
static SECStatus
98
ssl_CheckConfigSanity(sslSocket *ss)
99
62.7k
{
100
62.7k
    if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange)) {
101
0
        SSL_DBG(("%d: SSL[%d]: Can't handshake! all versions disabled.",
102
0
                 SSL_GETPID(), ss->fd));
103
0
        PORT_SetError(SSL_ERROR_SSL_DISABLED);
104
0
        return SECFailure;
105
0
    }
106
62.7k
    return SECSuccess;
107
62.7k
}
108
109
/* Sends out the initial client Hello message on the connection.
110
 * Acquires and releases the socket's xmitBufLock.
111
 */
112
SECStatus
113
ssl_BeginClientHandshake(sslSocket *ss)
114
31.8k
{
115
31.8k
    sslSessionID *sid = NULL;
116
31.8k
    SECStatus rv;
117
118
31.8k
    PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss));
119
120
31.8k
    ss->sec.isServer = PR_FALSE;
121
122
31.8k
    rv = ssl_CheckConfigSanity(ss);
123
31.8k
    if (rv != SECSuccess)
124
0
        goto loser;
125
126
    /* Get peer name of server */
127
31.8k
    rv = ssl_GetPeerInfo(ss);
128
31.8k
    if (rv < 0) {
129
#ifdef HPUX11
130
        /*
131
         * On some HP-UX B.11.00 systems, getpeername() occasionally
132
         * fails with ENOTCONN after a successful completion of
133
         * non-blocking connect.  I found that if we do a write()
134
         * and then retry getpeername(), it will work.
135
         */
136
        if (PR_GetError() == PR_NOT_CONNECTED_ERROR) {
137
            char dummy;
138
            (void)PR_Write(ss->fd->lower, &dummy, 0);
139
            rv = ssl_GetPeerInfo(ss);
140
            if (rv < 0) {
141
                goto loser;
142
            }
143
        }
144
#else
145
0
        goto loser;
146
0
#endif
147
0
    }
148
149
31.8k
    SSL_TRC(3, ("%d: SSL[%d]: sending client-hello", SSL_GETPID(), ss->fd));
150
151
    /* If there's an sid set from an external cache, use it. */
152
31.8k
    if (ss->sec.ci.sid && ss->sec.ci.sid->cached == in_external_cache) {
153
0
        sid = ss->sec.ci.sid;
154
0
        SSL_TRC(3, ("%d: SSL[%d]: using external token", SSL_GETPID(), ss->fd));
155
31.8k
    } else if (!ss->opt.noCache) {
156
        /* Try to find server in our session-id cache */
157
16.4k
        sid = ssl_LookupSID(ssl_Time(ss), &ss->sec.ci.peer,
158
16.4k
                            ss->sec.ci.port, ss->peerID, ss->url);
159
16.4k
    }
160
161
31.8k
    if (sid) {
162
0
        if (sid->version >= ss->vrange.min && sid->version <= ss->vrange.max) {
163
0
            PORT_Assert(!ss->sec.localCert);
164
0
            ss->sec.localCert = CERT_DupCertificate(sid->localCert);
165
0
        } else {
166
0
            ssl_UncacheSessionID(ss);
167
0
            if (ss->sec.ci.sid == sid) {
168
                /* sid aliases ss->sec.ci.sid (external cache); clear it so
169
                 * the socket cannot hold a dangling pointer if the
170
                 * ssl3_NewSessionID allocation below fails. */
171
0
                ss->sec.ci.sid = NULL;
172
0
            }
173
0
            ssl_FreeSID(sid);
174
0
            sid = NULL;
175
0
        }
176
0
    }
177
31.8k
    if (!sid) {
178
31.8k
        sid = ssl3_NewSessionID(ss, PR_FALSE);
179
31.8k
        if (!sid) {
180
0
            goto loser;
181
0
        }
182
        /* This session is a dummy, which we don't want to resume. */
183
31.8k
        sid->u.ssl3.keys.resumable = PR_FALSE;
184
31.8k
    }
185
31.8k
    ss->sec.ci.sid = sid;
186
187
31.8k
    ss->gs.state = GS_INIT;
188
31.8k
    ss->handshake = ssl_GatherRecord1stHandshake;
189
190
    /* ssl3_SendClientHello will override this if it succeeds. */
191
31.8k
    ss->version = SSL_LIBRARY_VERSION_3_0;
192
193
31.8k
    ssl_GetSSL3HandshakeLock(ss);
194
31.8k
    ssl_GetXmitBufLock(ss);
195
31.8k
    rv = ssl3_SendClientHello(ss, client_hello_initial);
196
31.8k
    ssl_ReleaseXmitBufLock(ss);
197
31.8k
    ssl_ReleaseSSL3HandshakeLock(ss);
198
199
31.8k
    return rv;
200
201
0
loser:
202
0
    return SECFailure;
203
31.8k
}
204
205
SECStatus
206
ssl_BeginServerHandshake(sslSocket *ss)
207
30.8k
{
208
30.8k
    SECStatus rv;
209
210
30.8k
    ss->sec.isServer = PR_TRUE;
211
30.8k
    ss->ssl3.hs.ws = wait_client_hello;
212
213
30.8k
    rv = ssl_CheckConfigSanity(ss);
214
30.8k
    if (rv != SECSuccess)
215
0
        goto loser;
216
217
30.8k
    ss->handshake = ssl_GatherRecord1stHandshake;
218
30.8k
    return SECSuccess;
219
220
0
loser:
221
0
    return SECFailure;
222
30.8k
}
223
224
/* This function doesn't really belong in this file.
225
** It's here to keep AIX compilers from optimizing it away,
226
** and not including it in the DSO.
227
*/
228
229
#include "nss.h"
230
extern const char __nss_ssl_version[];
231
232
PRBool
233
NSSSSL_VersionCheck(const char *importedVersion)
234
0
{
235
0
#define NSS_VERSION_VARIABLE __nss_ssl_version
236
0
#include "verref.h"
237
238
    /*
239
     * This is the secret handshake algorithm.
240
     *
241
     * This release has a simple version compatibility
242
     * check algorithm.  This release is not backward
243
     * compatible with previous major releases.  It is
244
     * not compatible with future major, minor, or
245
     * patch releases.
246
     */
247
0
    return NSS_VersionCheck(importedVersion);
248
0
}
249
250
const char *
251
NSSSSL_GetVersion(void)
252
0
{
253
0
    return NSS_VERSION;
254
0
}