1 diff --git a/ssl/ssl.h b/ssl/ssl.h
2 index 80717db..e9f5fb0 100644
5 @@ -191,6 +191,9 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
6 #define SSL_ENABLE_FALLBACK_SCSV 28 /* Send fallback SCSV in
9 +/* Request Signed Certificate Timestamps via TLS extension (client) */
10 +#define SSL_ENABLE_SIGNED_CERT_TIMESTAMPS 29
12 #ifdef SSL_DEPRECATED_FUNCTION
13 /* Old deprecated function names */
14 SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRBool on);
15 @@ -493,6 +496,23 @@ SSL_IMPORT CERTCertList *SSL_PeerCertificateChain(PRFileDesc *fd);
17 SSL_IMPORT const SECItemArray * SSL_PeerStapledOCSPResponses(PRFileDesc *fd);
19 +/* SSL_PeerSignedCertTimestamps returns the signed_certificate_timestamp
20 + * extension data provided by the TLS server. The return value is a pointer
21 + * to an internal SECItem that contains the returned response (as a serialized
22 + * SignedCertificateTimestampList, see RFC 6962). The returned pointer is only
23 + * valid until the callback function that calls SSL_PeerSignedCertTimestamps
24 + * (e.g. the authenticate certificate hook, or the handshake callback) returns.
26 + * If no Signed Certificate Timestamps were given by the server then the result
27 + * will be empty. If there was an error, then the result will be NULL.
29 + * You must set the SSL_ENABLE_SIGNED_CERT_TIMESTAMPS option to indicate support
30 + * for Signed Certificate Timestamps to a server.
32 + * libssl does not do any parsing or validation of the response itself.
34 +SSL_IMPORT const SECItem * SSL_PeerSignedCertTimestamps(PRFileDesc *fd);
36 /* SSL_SetStapledOCSPResponses stores an array of one or multiple OCSP responses
37 * in the fd's data, which may be sent as part of a server side cert_status
38 * handshake message. Parameter |responses| is for the server certificate of
39 diff --git a/ssl/ssl3con.c b/ssl/ssl3con.c
40 index 708a4c7..3421e0b 100644
43 @@ -6737,10 +6737,22 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
44 sid->u.ssl3.sessionIDLength = sidBytes.len;
45 PORT_Memcpy(sid->u.ssl3.sessionID, sidBytes.data, sidBytes.len);
47 + /* Copy Signed Certificate Timestamps, if any. */
48 + if (ss->xtnData.signedCertTimestamps.data) {
49 + rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.signedCertTimestamps,
50 + &ss->xtnData.signedCertTimestamps);
51 + if (rv != SECSuccess)
55 ss->ssl3.hs.isResuming = PR_FALSE;
56 ss->ssl3.hs.ws = wait_server_cert;
59 + /* Clean up the temporary pointer to the handshake buffer. */
60 + ss->xtnData.signedCertTimestamps.data = NULL;
61 + ss->xtnData.signedCertTimestamps.len = 0;
63 /* If we will need a ChannelID key then we make the callback now. This
64 * allows the handshake to be restarted cleanly if the callback returns
66 @@ -6766,6 +6778,9 @@ alert_loser:
67 (void)SSL3_SendAlert(ss, alert_fatal, desc);
70 + /* Clean up the temporary pointer to the handshake buffer. */
71 + ss->xtnData.signedCertTimestamps.data = NULL;
72 + ss->xtnData.signedCertTimestamps.len = 0;
73 errCode = ssl_MapLowLevelError(errCode);
76 diff --git a/ssl/ssl3ext.c b/ssl/ssl3ext.c
77 index b6ed17d..6c120ff 100644
80 @@ -85,6 +85,12 @@ static PRInt32 ssl3_ClientSendSigAlgsXtn(sslSocket *ss, PRBool append,
82 static SECStatus ssl3_ServerHandleSigAlgsXtn(sslSocket *ss, PRUint16 ex_type,
84 +static PRInt32 ssl3_ClientSendSignedCertTimestampXtn(sslSocket *ss,
87 +static SECStatus ssl3_ClientHandleSignedCertTimestampXtn(sslSocket *ss,
91 static PRInt32 ssl3_ClientSendDraftVersionXtn(sslSocket *ss, PRBool append,
93 @@ -270,6 +276,8 @@ static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = {
94 { ssl_use_srtp_xtn, &ssl3_HandleUseSRTPXtn },
95 { ssl_channel_id_xtn, &ssl3_ClientHandleChannelIDXtn },
96 { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn },
97 + { ssl_signed_certificate_timestamp_xtn,
98 + &ssl3_ClientHandleSignedCertTimestampXtn },
102 @@ -298,6 +306,8 @@ ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = {
103 { ssl_use_srtp_xtn, &ssl3_SendUseSRTPXtn },
104 { ssl_channel_id_xtn, &ssl3_ClientSendChannelIDXtn },
105 { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn },
106 + { ssl_signed_certificate_timestamp_xtn,
107 + &ssl3_ClientSendSignedCertTimestampXtn },
108 { ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn },
109 { ssl_tls13_draft_version_xtn, &ssl3_ClientSendDraftVersionXtn },
110 /* any extra entries will appear as { 0, NULL } */
111 @@ -2582,3 +2592,64 @@ loser:
115 +/* ssl3_ClientSendSignedCertTimestampXtn sends the signed_certificate_timestamp
116 + * extension for TLS ClientHellos. */
118 +ssl3_ClientSendSignedCertTimestampXtn(sslSocket *ss, PRBool append,
121 + PRInt32 extension_length = 2 /* extension_type */ +
122 + 2 /* length(extension_data) */;
124 + /* Only send the extension if processing is enabled. */
125 + if (!ss->opt.enableSignedCertTimestamps)
128 + if (append && maxBytes >= extension_length) {
130 + /* extension_type */
131 + rv = ssl3_AppendHandshakeNumber(ss,
132 + ssl_signed_certificate_timestamp_xtn,
134 + if (rv != SECSuccess)
137 + rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
138 + if (rv != SECSuccess)
140 + ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
141 + ssl_signed_certificate_timestamp_xtn;
142 + } else if (maxBytes < extension_length) {
147 + return extension_length;
153 +ssl3_ClientHandleSignedCertTimestampXtn(sslSocket *ss, PRUint16 ex_type,
156 + /* We do not yet know whether we'll be resuming a session or creating
157 + * a new one, so we keep a pointer to the data in the TLSExtensionData
158 + * structure. This pointer is only valid in the scope of
159 + * ssl3_HandleServerHello, and, if not resuming a session, the data is
160 + * copied once a new session structure has been set up.
161 + * All parsing is currently left to the application and we accept
162 + * everything, including empty data.
164 + SECItem *scts = &ss->xtnData.signedCertTimestamps;
165 + PORT_Assert(!scts->data && !scts->len);
168 + /* Empty extension data: RFC 6962 mandates non-empty contents. */
172 + /* Keep track of negotiated extensions. */
173 + ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
176 diff --git a/ssl/sslimpl.h b/ssl/sslimpl.h
177 index 62f822a..2f61a46 100644
180 @@ -339,6 +339,7 @@ typedef struct sslOptionsStr {
181 unsigned int enableALPN : 1; /* 27 */
182 unsigned int reuseServerECDHEKey : 1; /* 28 */
183 unsigned int enableFallbackSCSV : 1; /* 29 */
184 + unsigned int enableSignedCertTimestamps : 1; /* 30 */
187 typedef enum { sslHandshakingUndetermined = 0,
188 @@ -721,6 +722,11 @@ struct sslSessionIDStr {
189 * resumption handshake to the original handshake. */
190 SECItem originalHandshakeHash;
192 + /* Signed certificate timestamps received in a TLS extension.
193 + ** (used only in client).
195 + SECItem signedCertTimestamps;
197 /* This lock is lazily initialized by CacheSID when a sid is first
198 * cached. Before then, there is no need to lock anything because
199 * the sid isn't being shared by anything.
200 @@ -829,6 +835,18 @@ struct TLSExtensionDataStr {
201 * is beyond ssl3_HandleClientHello function. */
203 PRUint32 sniNameArrSize;
205 + /* Signed Certificate Timestamps extracted from the TLS extension.
207 + * This container holds a temporary pointer to the extension data,
208 + * until a session structure (the sec.ci.sid of an sslSocket) is setup
209 + * that can hold a permanent copy of the data
210 + * (in sec.ci.sid.u.ssl3.signedCertTimestamps).
211 + * The data pointed to by this structure is neither explicitly allocated
212 + * nor copied: the pointer points to the handshake message buffer and is
213 + * only valid in the scope of ssl3_HandleServerHello.
215 + SECItem signedCertTimestamps;
218 typedef SECStatus (*sslRestartTarget)(sslSocket *);
219 diff --git a/ssl/sslnonce.c b/ssl/sslnonce.c
220 index c45849d..cefdda6 100644
223 @@ -131,6 +131,9 @@ ssl_DestroySID(sslSessionID *sid)
224 if (sid->u.ssl3.originalHandshakeHash.data) {
225 SECITEM_FreeItem(&sid->u.ssl3.originalHandshakeHash, PR_FALSE);
227 + if (sid->u.ssl3.signedCertTimestamps.data) {
228 + SECITEM_FreeItem(&sid->u.ssl3.signedCertTimestamps, PR_FALSE);
231 if (sid->u.ssl3.lock) {
232 PR_DestroyRWLock(sid->u.ssl3.lock);
233 diff --git a/ssl/sslsock.c b/ssl/sslsock.c
234 index 0d12273..80f4e67 100644
237 @@ -89,7 +89,8 @@ static sslOptions ssl_defaults = {
238 PR_TRUE, /* enableNPN */
239 PR_FALSE, /* enableALPN */
240 PR_TRUE, /* reuseServerECDHEKey */
241 - PR_FALSE /* enableFallbackSCSV */
242 + PR_FALSE, /* enableFallbackSCSV */
243 + PR_FALSE, /* enableSignedCertTimestamps */
247 @@ -807,6 +808,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on)
248 ss->opt.enableFallbackSCSV = on;
251 + case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS:
252 + ss->opt.enableSignedCertTimestamps = on;
256 PORT_SetError(SEC_ERROR_INVALID_ARGS);
258 @@ -882,6 +887,9 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn)
259 case SSL_REUSE_SERVER_ECDHE_KEY:
260 on = ss->opt.reuseServerECDHEKey; break;
261 case SSL_ENABLE_FALLBACK_SCSV: on = ss->opt.enableFallbackSCSV; break;
262 + case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS:
263 + on = ss->opt.enableSignedCertTimestamps;
267 PORT_SetError(SEC_ERROR_INVALID_ARGS);
268 @@ -951,6 +959,9 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn)
269 case SSL_ENABLE_FALLBACK_SCSV:
270 on = ssl_defaults.enableFallbackSCSV;
272 + case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS:
273 + on = ssl_defaults.enableSignedCertTimestamps;
277 PORT_SetError(SEC_ERROR_INVALID_ARGS);
278 @@ -1134,6 +1145,10 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on)
279 ssl_defaults.enableFallbackSCSV = on;
282 + case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS:
283 + ssl_defaults.enableSignedCertTimestamps = on;
287 PORT_SetError(SEC_ERROR_INVALID_ARGS);
289 @@ -1963,6 +1978,29 @@ SSL_PeerStapledOCSPResponses(PRFileDesc *fd)
290 return &ss->sec.ci.sid->peerCertStatus;
294 +SSL_PeerSignedCertTimestamps(PRFileDesc *fd)
296 + sslSocket *ss = ssl_FindSocket(fd);
299 + SSL_DBG(("%d: SSL[%d]: bad socket in SSL_PeerSignedCertTimestamps",
300 + SSL_GETPID(), fd));
304 + if (!ss->sec.ci.sid) {
305 + PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
309 + if (ss->sec.ci.sid->version < SSL_LIBRARY_VERSION_3_0) {
310 + PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2);
313 + return &ss->sec.ci.sid->u.ssl3.signedCertTimestamps;
317 SSL_HandshakeResumedSession(PRFileDesc *fd, PRBool *handshake_resumed) {
318 sslSocket *ss = ssl_FindSocket(fd);
319 diff --git a/ssl/sslt.h b/ssl/sslt.h
320 index fe0ad07..c36b8c7 100644
323 @@ -202,6 +202,7 @@ typedef enum {
324 ssl_signature_algorithms_xtn = 13,
325 ssl_use_srtp_xtn = 14,
326 ssl_app_layer_protocol_xtn = 16,
327 + ssl_signed_certificate_timestamp_xtn = 18, /* RFC 6962 */
328 ssl_padding_xtn = 21,
329 ssl_session_ticket_xtn = 35,
330 ssl_next_proto_nego_xtn = 13172,
331 @@ -210,6 +211,6 @@ typedef enum {
332 ssl_tls13_draft_version_xtn = 0xff02 /* experimental number */
335 -#define SSL_MAX_EXTENSIONS 12 /* doesn't include ssl_padding_xtn. */
336 +#define SSL_MAX_EXTENSIONS 13 /* doesn't include ssl_padding_xtn. */
338 #endif /* __sslt_h_ */