• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "ssl.h"
5 #include "sslimpl.h"
6 #include "sslproto.h"
7 
8 static const char *
ssl_GetCompressionMethodName(SSLCompressionMethod compression)9 ssl_GetCompressionMethodName(SSLCompressionMethod compression)
10 {
11     switch (compression) {
12     case ssl_compression_null:
13 	return "NULL";
14 #ifdef NSS_ENABLE_ZLIB
15     case ssl_compression_deflate:
16 	return "DEFLATE";
17 #endif
18     default:
19 	return "???";
20     }
21 }
22 
23 SECStatus
SSL_GetChannelInfo(PRFileDesc * fd,SSLChannelInfo * info,PRUintn len)24 SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
25 {
26     sslSocket *      ss;
27     SSLChannelInfo   inf;
28     sslSessionID *   sid;
29 
30     if (!info || len < sizeof inf.length) {
31 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
32 	return SECFailure;
33     }
34 
35     ss = ssl_FindSocket(fd);
36     if (!ss) {
37 	SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetChannelInfo",
38 		 SSL_GETPID(), fd));
39 	return SECFailure;
40     }
41 
42     memset(&inf, 0, sizeof inf);
43     inf.length = PR_MIN(sizeof inf, len);
44 
45     if (ss->opt.useSecurity && ss->enoughFirstHsDone) {
46         sid = ss->sec.ci.sid;
47 	inf.protocolVersion  = ss->version;
48 	inf.authKeyBits      = ss->sec.authKeyBits;
49 	inf.keaKeyBits       = ss->sec.keaKeyBits;
50 	if (ss->version < SSL_LIBRARY_VERSION_3_0) { /* SSL2 */
51 	    inf.cipherSuite           = ss->sec.cipherType | 0xff00;
52 	    inf.compressionMethod     = ssl_compression_null;
53 	    inf.compressionMethodName = "N/A";
54 	} else if (ss->ssl3.initialized) { 	/* SSL3 and TLS */
55 	    ssl_GetSpecReadLock(ss);
56 	    /* XXX  The cipher suite should be in the specs and this
57 	     * function should get it from cwSpec rather than from the "hs".
58 	     * See bug 275744 comment 69 and bug 766137.
59 	     */
60 	    inf.cipherSuite           = ss->ssl3.hs.cipher_suite;
61 	    inf.compressionMethod     = ss->ssl3.cwSpec->compression_method;
62 	    ssl_ReleaseSpecReadLock(ss);
63 	    inf.compressionMethodName =
64 		ssl_GetCompressionMethodName(inf.compressionMethod);
65 	}
66 	if (sid) {
67 	    inf.creationTime   = sid->creationTime;
68 	    inf.lastAccessTime = sid->lastAccessTime;
69 	    inf.expirationTime = sid->expirationTime;
70 	    if (ss->version < SSL_LIBRARY_VERSION_3_0) { /* SSL2 */
71 	        inf.sessionIDLength = SSL2_SESSIONID_BYTES;
72 		memcpy(inf.sessionID, sid->u.ssl2.sessionID,
73 		       SSL2_SESSIONID_BYTES);
74 	    } else {
75 		unsigned int sidLen = sid->u.ssl3.sessionIDLength;
76 	        sidLen = PR_MIN(sidLen, sizeof inf.sessionID);
77 	        inf.sessionIDLength = sidLen;
78 		memcpy(inf.sessionID, sid->u.ssl3.sessionID, sidLen);
79 	    }
80 	}
81     }
82 
83     memcpy(info, &inf, inf.length);
84 
85     return SECSuccess;
86 }
87 
88 
89 #define CS(x) x, #x
90 #define CK(x) x | 0xff00, #x
91 
92 #define S_DSA   "DSA", ssl_auth_dsa
93 #define S_RSA	"RSA", ssl_auth_rsa
94 #define S_KEA   "KEA", ssl_auth_kea
95 #define S_ECDSA "ECDSA", ssl_auth_ecdsa
96 
97 #define K_DHE	"DHE", kt_dh
98 #define K_RSA	"RSA", kt_rsa
99 #define K_KEA	"KEA", kt_kea
100 #define K_ECDH	"ECDH", kt_ecdh
101 #define K_ECDHE	"ECDHE", kt_ecdh
102 
103 #define C_SEED 	"SEED", calg_seed
104 #define C_CAMELLIA "CAMELLIA", calg_camellia
105 #define C_AES	"AES", calg_aes
106 #define C_RC4	"RC4", calg_rc4
107 #define C_RC2	"RC2", calg_rc2
108 #define C_DES	"DES", calg_des
109 #define C_3DES	"3DES", calg_3des
110 #define C_NULL  "NULL", calg_null
111 #define C_SJ 	"SKIPJACK", calg_sj
112 #define C_AESGCM "AES-GCM", calg_aes_gcm
113 #define C_CHACHA20 "CHACHA20POLY1305", calg_chacha20
114 
115 #define B_256	256, 256, 256
116 #define B_128	128, 128, 128
117 #define B_3DES  192, 156, 112
118 #define B_SJ     96,  80,  80
119 #define B_DES    64,  56,  56
120 #define B_56    128,  56,  56
121 #define B_40    128,  40,  40
122 #define B_0  	  0,   0,   0
123 
124 #define M_AEAD_128 "AEAD", ssl_mac_aead, 128
125 #define M_SHA256 "SHA256", ssl_hmac_sha256, 256
126 #define M_SHA	"SHA1", ssl_mac_sha, 160
127 #define M_MD5	"MD5",  ssl_mac_md5, 128
128 #define M_NULL	"NULL", ssl_mac_null,  0
129 
130 static const SSLCipherSuiteInfo suiteInfo[] = {
131 /* <------ Cipher suite --------------------> <auth> <KEA>  <bulk cipher> <MAC> <FIPS> */
132 {0,CS(TLS_RSA_WITH_AES_128_GCM_SHA256),       S_RSA, K_RSA, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0, },
133 
134 {0,CS(TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_256, M_SHA, 0, 0, 0, },
135 {0,CS(TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_256, M_SHA, 0, 0, 0, },
136 {0,CS(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256),   S_RSA, K_DHE, C_AES, B_256, M_SHA256, 1, 0, 0, },
137 {0,CS(TLS_DHE_RSA_WITH_AES_256_CBC_SHA),      S_RSA, K_DHE, C_AES, B_256, M_SHA, 1, 0, 0, },
138 {0,CS(TLS_DHE_DSS_WITH_AES_256_CBC_SHA),      S_DSA, K_DHE, C_AES, B_256, M_SHA, 1, 0, 0, },
139 {0,CS(TLS_RSA_WITH_CAMELLIA_256_CBC_SHA),     S_RSA, K_RSA, C_CAMELLIA, B_256, M_SHA, 0, 0, 0, },
140 {0,CS(TLS_RSA_WITH_AES_256_CBC_SHA256),       S_RSA, K_RSA, C_AES, B_256, M_SHA256, 1, 0, 0, },
141 {0,CS(TLS_RSA_WITH_AES_256_CBC_SHA),          S_RSA, K_RSA, C_AES, B_256, M_SHA, 1, 0, 0, },
142 
143 {0,CS(TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_128, M_SHA, 0, 0, 0, },
144 {0,CS(TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_128, M_SHA, 0, 0, 0, },
145 {0,CS(TLS_DHE_DSS_WITH_RC4_128_SHA),          S_DSA, K_DHE, C_RC4, B_128, M_SHA, 0, 0, 0, },
146 {0,CS(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256),   S_RSA, K_DHE, C_AES, B_128, M_SHA256, 1, 0, 0, },
147 {0,CS(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256),   S_RSA, K_DHE, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0, },
148 {0,CS(TLS_DHE_RSA_WITH_AES_128_CBC_SHA),      S_RSA, K_DHE, C_AES, B_128, M_SHA, 1, 0, 0, },
149 {0,CS(TLS_DHE_DSS_WITH_AES_128_CBC_SHA),      S_DSA, K_DHE, C_AES, B_128, M_SHA, 1, 0, 0, },
150 {0,CS(TLS_RSA_WITH_SEED_CBC_SHA),             S_RSA, K_RSA, C_SEED,B_128, M_SHA, 1, 0, 0, },
151 {0,CS(TLS_RSA_WITH_CAMELLIA_128_CBC_SHA),     S_RSA, K_RSA, C_CAMELLIA, B_128, M_SHA, 0, 0, 0, },
152 {0,CS(SSL_RSA_WITH_RC4_128_SHA),              S_RSA, K_RSA, C_RC4, B_128, M_SHA, 0, 0, 0, },
153 {0,CS(SSL_RSA_WITH_RC4_128_MD5),              S_RSA, K_RSA, C_RC4, B_128, M_MD5, 0, 0, 0, },
154 {0,CS(TLS_RSA_WITH_AES_128_CBC_SHA256),       S_RSA, K_RSA, C_AES, B_128, M_SHA256, 1, 0, 0, },
155 {0,CS(TLS_RSA_WITH_AES_128_CBC_SHA),          S_RSA, K_RSA, C_AES, B_128, M_SHA, 1, 0, 0, },
156 
157 {0,CS(SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA),     S_RSA, K_DHE, C_3DES,B_3DES,M_SHA, 1, 0, 0, },
158 {0,CS(SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA),     S_DSA, K_DHE, C_3DES,B_3DES,M_SHA, 1, 0, 0, },
159 {0,CS(SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA),    S_RSA, K_RSA, C_3DES,B_3DES,M_SHA, 1, 0, 1, },
160 {0,CS(SSL_RSA_WITH_3DES_EDE_CBC_SHA),         S_RSA, K_RSA, C_3DES,B_3DES,M_SHA, 1, 0, 0, },
161 
162 {0,CS(SSL_DHE_RSA_WITH_DES_CBC_SHA),          S_RSA, K_DHE, C_DES, B_DES, M_SHA, 0, 0, 0, },
163 {0,CS(SSL_DHE_DSS_WITH_DES_CBC_SHA),          S_DSA, K_DHE, C_DES, B_DES, M_SHA, 0, 0, 0, },
164 {0,CS(SSL_RSA_FIPS_WITH_DES_CBC_SHA),         S_RSA, K_RSA, C_DES, B_DES, M_SHA, 0, 0, 1, },
165 {0,CS(SSL_RSA_WITH_DES_CBC_SHA),              S_RSA, K_RSA, C_DES, B_DES, M_SHA, 0, 0, 0, },
166 
167 {0,CS(TLS_RSA_EXPORT1024_WITH_RC4_56_SHA),    S_RSA, K_RSA, C_RC4, B_56,  M_SHA, 0, 1, 0, },
168 {0,CS(TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA),   S_RSA, K_RSA, C_DES, B_DES, M_SHA, 0, 1, 0, },
169 {0,CS(SSL_RSA_EXPORT_WITH_RC4_40_MD5),        S_RSA, K_RSA, C_RC4, B_40,  M_MD5, 0, 1, 0, },
170 {0,CS(SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5),    S_RSA, K_RSA, C_RC2, B_40,  M_MD5, 0, 1, 0, },
171 {0,CS(TLS_RSA_WITH_NULL_SHA256),              S_RSA, K_RSA, C_NULL,B_0,   M_SHA256, 0, 1, 0, },
172 {0,CS(SSL_RSA_WITH_NULL_SHA),                 S_RSA, K_RSA, C_NULL,B_0,   M_SHA, 0, 1, 0, },
173 {0,CS(SSL_RSA_WITH_NULL_MD5),                 S_RSA, K_RSA, C_NULL,B_0,   M_MD5, 0, 1, 0, },
174 
175 #ifdef NSS_ENABLE_ECC
176 /* ECC cipher suites */
177 {0,CS(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0, },
178 {0,CS(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), S_ECDSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0, },
179 
180 {0,CS(TLS_ECDH_ECDSA_WITH_NULL_SHA),          S_ECDSA, K_ECDH, C_NULL, B_0, M_SHA, 0, 0, 0, },
181 {0,CS(TLS_ECDH_ECDSA_WITH_RC4_128_SHA),       S_ECDSA, K_ECDH, C_RC4, B_128, M_SHA, 0, 0, 0, },
182 {0,CS(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA),  S_ECDSA, K_ECDH, C_3DES, B_3DES, M_SHA, 1, 0, 0, },
183 {0,CS(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA),   S_ECDSA, K_ECDH, C_AES, B_128, M_SHA, 1, 0, 0, },
184 {0,CS(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA),   S_ECDSA, K_ECDH, C_AES, B_256, M_SHA, 1, 0, 0, },
185 
186 {0,CS(TLS_ECDHE_ECDSA_WITH_NULL_SHA),         S_ECDSA, K_ECDHE, C_NULL, B_0, M_SHA, 0, 0, 0, },
187 {0,CS(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA),      S_ECDSA, K_ECDHE, C_RC4, B_128, M_SHA, 0, 0, 0, },
188 {0,CS(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDHE, C_3DES, B_3DES, M_SHA, 1, 0, 0, },
189 {0,CS(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA),  S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA, 1, 0, 0, },
190 {0,CS(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA256, 1, 0, 0, },
191 {0,CS(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA),  S_ECDSA, K_ECDHE, C_AES, B_256, M_SHA, 1, 0, 0, },
192 {0,CS(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305),S_ECDSA,K_ECDHE,C_CHACHA20,B_256,M_AEAD_128,0, 0, 0, },
193 
194 {0,CS(TLS_ECDH_RSA_WITH_NULL_SHA),            S_RSA, K_ECDH, C_NULL, B_0, M_SHA, 0, 0, 0, },
195 {0,CS(TLS_ECDH_RSA_WITH_RC4_128_SHA),         S_RSA, K_ECDH, C_RC4, B_128, M_SHA, 0, 0, 0, },
196 {0,CS(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA),    S_RSA, K_ECDH, C_3DES, B_3DES, M_SHA, 1, 0, 0, },
197 {0,CS(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA),     S_RSA, K_ECDH, C_AES, B_128, M_SHA, 1, 0, 0, },
198 {0,CS(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA),     S_RSA, K_ECDH, C_AES, B_256, M_SHA, 1, 0, 0, },
199 {0,CS(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305),  S_RSA,K_ECDHE,C_CHACHA20,B_256,M_AEAD_128, 0, 0, 0, },
200 
201 {0,CS(TLS_ECDHE_RSA_WITH_NULL_SHA),           S_RSA, K_ECDHE, C_NULL, B_0, M_SHA, 0, 0, 0, },
202 {0,CS(TLS_ECDHE_RSA_WITH_RC4_128_SHA),        S_RSA, K_ECDHE, C_RC4, B_128, M_SHA, 0, 0, 0, },
203 {0,CS(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA),   S_RSA, K_ECDHE, C_3DES, B_3DES, M_SHA, 1, 0, 0, },
204 {0,CS(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA),    S_RSA, K_ECDHE, C_AES, B_128, M_SHA, 1, 0, 0, },
205 {0,CS(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_ECDHE, C_AES, B_128, M_SHA256, 1, 0, 0, },
206 {0,CS(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA),    S_RSA, K_ECDHE, C_AES, B_256, M_SHA, 1, 0, 0, },
207 #endif /* NSS_ENABLE_ECC */
208 
209 /* SSL 2 table */
210 {0,CK(SSL_CK_RC4_128_WITH_MD5),               S_RSA, K_RSA, C_RC4, B_128, M_MD5, 0, 0, 0, },
211 {0,CK(SSL_CK_RC2_128_CBC_WITH_MD5),           S_RSA, K_RSA, C_RC2, B_128, M_MD5, 0, 0, 0, },
212 {0,CK(SSL_CK_DES_192_EDE3_CBC_WITH_MD5),      S_RSA, K_RSA, C_3DES,B_3DES,M_MD5, 0, 0, 0, },
213 {0,CK(SSL_CK_DES_64_CBC_WITH_MD5),            S_RSA, K_RSA, C_DES, B_DES, M_MD5, 0, 0, 0, },
214 {0,CK(SSL_CK_RC4_128_EXPORT40_WITH_MD5),      S_RSA, K_RSA, C_RC4, B_40,  M_MD5, 0, 1, 0, },
215 {0,CK(SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5),  S_RSA, K_RSA, C_RC2, B_40,  M_MD5, 0, 1, 0, }
216 };
217 
218 #define NUM_SUITEINFOS ((sizeof suiteInfo) / (sizeof suiteInfo[0]))
219 
220 
SSL_GetCipherSuiteInfo(PRUint16 cipherSuite,SSLCipherSuiteInfo * info,PRUintn len)221 SECStatus SSL_GetCipherSuiteInfo(PRUint16 cipherSuite,
222                                  SSLCipherSuiteInfo *info, PRUintn len)
223 {
224     unsigned int i;
225 
226     len = PR_MIN(len, sizeof suiteInfo[0]);
227     if (!info || len < sizeof suiteInfo[0].length) {
228 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
229     	return SECFailure;
230     }
231     for (i = 0; i < NUM_SUITEINFOS; i++) {
232     	if (suiteInfo[i].cipherSuite == cipherSuite) {
233 	    memcpy(info, &suiteInfo[i], len);
234 	    info->length = len;
235 	    return SECSuccess;
236 	}
237     }
238     PORT_SetError(SEC_ERROR_INVALID_ARGS);
239     return SECFailure;
240 }
241 
242 /* This function might be a candidate to be public.
243  * Disables all export ciphers in the default set of enabled ciphers.
244  */
245 SECStatus
SSL_DisableDefaultExportCipherSuites(void)246 SSL_DisableDefaultExportCipherSuites(void)
247 {
248     const SSLCipherSuiteInfo * pInfo = suiteInfo;
249     unsigned int i;
250     SECStatus rv;
251 
252     for (i = 0; i < NUM_SUITEINFOS; ++i, ++pInfo) {
253     	if (pInfo->isExportable) {
254 	    rv = SSL_CipherPrefSetDefault(pInfo->cipherSuite, PR_FALSE);
255 	    PORT_Assert(rv == SECSuccess);
256 	}
257     }
258     return SECSuccess;
259 }
260 
261 /* This function might be a candidate to be public,
262  * except that it takes an sslSocket pointer as an argument.
263  * A Public version would take a PRFileDesc pointer.
264  * Disables all export ciphers in the default set of enabled ciphers.
265  */
266 SECStatus
SSL_DisableExportCipherSuites(PRFileDesc * fd)267 SSL_DisableExportCipherSuites(PRFileDesc * fd)
268 {
269     const SSLCipherSuiteInfo * pInfo = suiteInfo;
270     unsigned int i;
271     SECStatus rv;
272 
273     for (i = 0; i < NUM_SUITEINFOS; ++i, ++pInfo) {
274     	if (pInfo->isExportable) {
275 	    rv = SSL_CipherPrefSet(fd, pInfo->cipherSuite, PR_FALSE);
276 	    PORT_Assert(rv == SECSuccess);
277 	}
278     }
279     return SECSuccess;
280 }
281 
282 /* Tells us if the named suite is exportable
283  * returns false for unknown suites.
284  */
285 PRBool
SSL_IsExportCipherSuite(PRUint16 cipherSuite)286 SSL_IsExportCipherSuite(PRUint16 cipherSuite)
287 {
288     unsigned int i;
289     for (i = 0; i < NUM_SUITEINFOS; i++) {
290     	if (suiteInfo[i].cipherSuite == cipherSuite) {
291 	    return (PRBool)(suiteInfo[i].isExportable);
292 	}
293     }
294     return PR_FALSE;
295 }
296 
297 SECItem*
SSL_GetNegotiatedHostInfo(PRFileDesc * fd)298 SSL_GetNegotiatedHostInfo(PRFileDesc *fd)
299 {
300     SECItem *sniName = NULL;
301     sslSocket *ss;
302     char *name = NULL;
303 
304     ss = ssl_FindSocket(fd);
305     if (!ss) {
306 	SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetNegotiatedHostInfo",
307 		 SSL_GETPID(), fd));
308 	return NULL;
309     }
310 
311     if (ss->sec.isServer) {
312         if (ss->version > SSL_LIBRARY_VERSION_3_0 &&
313             ss->ssl3.initialized) { /* TLS */
314             SECItem *crsName;
315             ssl_GetSpecReadLock(ss); /*********************************/
316             crsName = &ss->ssl3.cwSpec->srvVirtName;
317             if (crsName->data) {
318                 sniName = SECITEM_DupItem(crsName);
319             }
320             ssl_ReleaseSpecReadLock(ss); /*----------------------------*/
321         }
322         return sniName;
323     }
324     name = SSL_RevealURL(fd);
325     if (name) {
326         sniName = PORT_ZNew(SECItem);
327         if (!sniName) {
328             PORT_Free(name);
329             return NULL;
330         }
331         sniName->data = (void*)name;
332         sniName->len  = PORT_Strlen(name);
333     }
334     return sniName;
335 }
336 
337 SECStatus
SSL_ExportKeyingMaterial(PRFileDesc * fd,const char * label,unsigned int labelLen,PRBool hasContext,const unsigned char * context,unsigned int contextLen,unsigned char * out,unsigned int outLen)338 SSL_ExportKeyingMaterial(PRFileDesc *fd,
339                          const char *label, unsigned int labelLen,
340                          PRBool hasContext,
341                          const unsigned char *context, unsigned int contextLen,
342                          unsigned char *out, unsigned int outLen)
343 {
344     sslSocket *ss;
345     unsigned char *val = NULL;
346     unsigned int valLen, i;
347     SECStatus rv = SECFailure;
348 
349     ss = ssl_FindSocket(fd);
350     if (!ss) {
351 	SSL_DBG(("%d: SSL[%d]: bad socket in ExportKeyingMaterial",
352 		 SSL_GETPID(), fd));
353 	return SECFailure;
354     }
355 
356     ssl_GetRecvBufLock(ss);
357     ssl_GetSSL3HandshakeLock(ss);
358 
359     if (ss->version < SSL_LIBRARY_VERSION_3_1_TLS) {
360 	PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION);
361 	ssl_ReleaseSSL3HandshakeLock(ss);
362 	ssl_ReleaseRecvBufLock(ss);
363 	return SECFailure;
364     }
365 
366     /* construct PRF arguments */
367     valLen = SSL3_RANDOM_LENGTH * 2;
368     if (hasContext) {
369 	valLen += 2 /* PRUint16 length */ + contextLen;
370     }
371     val = PORT_Alloc(valLen);
372     if (!val) {
373 	ssl_ReleaseSSL3HandshakeLock(ss);
374 	ssl_ReleaseRecvBufLock(ss);
375 	return SECFailure;
376     }
377     i = 0;
378 
379     PORT_Memcpy(val + i, &ss->ssl3.hs.client_random.rand, SSL3_RANDOM_LENGTH);
380     i += SSL3_RANDOM_LENGTH;
381     PORT_Memcpy(val + i, &ss->ssl3.hs.server_random.rand, SSL3_RANDOM_LENGTH);
382     i += SSL3_RANDOM_LENGTH;
383 
384     if (hasContext) {
385 	val[i++] = contextLen >> 8;
386 	val[i++] = contextLen;
387 	PORT_Memcpy(val + i, context, contextLen);
388 	i += contextLen;
389     }
390     PORT_Assert(i == valLen);
391 
392     /* Allow TLS keying material to be exported sooner, when the master
393      * secret is available and we have sent ChangeCipherSpec.
394      */
395     ssl_GetSpecReadLock(ss);
396     if (!ss->ssl3.cwSpec->master_secret && !ss->ssl3.cwSpec->msItem.len) {
397 	PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED);
398 	rv = SECFailure;
399     } else {
400 	rv = ssl3_TLSPRFWithMasterSecret(ss->ssl3.cwSpec, label, labelLen, val,
401 					 valLen, out, outLen);
402     }
403     ssl_ReleaseSpecReadLock(ss);
404     ssl_ReleaseSSL3HandshakeLock(ss);
405     ssl_ReleaseRecvBufLock(ss);
406 
407     PORT_ZFree(val, valLen);
408     return rv;
409 }
410