/src/boringssl/ssl/ssl_asn1.cc
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
2 | | * All rights reserved. |
3 | | * |
4 | | * This package is an SSL implementation written |
5 | | * by Eric Young (eay@cryptsoft.com). |
6 | | * The implementation was written so as to conform with Netscapes SSL. |
7 | | * |
8 | | * This library is free for commercial and non-commercial use as long as |
9 | | * the following conditions are aheared to. The following conditions |
10 | | * apply to all code found in this distribution, be it the RC4, RSA, |
11 | | * lhash, DES, etc., code; not just the SSL code. The SSL documentation |
12 | | * included with this distribution is covered by the same copyright terms |
13 | | * except that the holder is Tim Hudson (tjh@cryptsoft.com). |
14 | | * |
15 | | * Copyright remains Eric Young's, and as such any Copyright notices in |
16 | | * the code are not to be removed. |
17 | | * If this package is used in a product, Eric Young should be given attribution |
18 | | * as the author of the parts of the library used. |
19 | | * This can be in the form of a textual message at program startup or |
20 | | * in documentation (online or textual) provided with the package. |
21 | | * |
22 | | * Redistribution and use in source and binary forms, with or without |
23 | | * modification, are permitted provided that the following conditions |
24 | | * are met: |
25 | | * 1. Redistributions of source code must retain the copyright |
26 | | * notice, this list of conditions and the following disclaimer. |
27 | | * 2. Redistributions in binary form must reproduce the above copyright |
28 | | * notice, this list of conditions and the following disclaimer in the |
29 | | * documentation and/or other materials provided with the distribution. |
30 | | * 3. All advertising materials mentioning features or use of this software |
31 | | * must display the following acknowledgement: |
32 | | * "This product includes cryptographic software written by |
33 | | * Eric Young (eay@cryptsoft.com)" |
34 | | * The word 'cryptographic' can be left out if the rouines from the library |
35 | | * being used are not cryptographic related :-). |
36 | | * 4. If you include any Windows specific code (or a derivative thereof) from |
37 | | * the apps directory (application code) you must include an acknowledgement: |
38 | | * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" |
39 | | * |
40 | | * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND |
41 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
42 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
43 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
44 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
45 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
46 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
47 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
48 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
49 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
50 | | * SUCH DAMAGE. |
51 | | * |
52 | | * The licence and distribution terms for any publically available version or |
53 | | * derivative of this code cannot be changed. i.e. this code cannot simply be |
54 | | * copied and put under another distribution licence |
55 | | * [including the GNU Public Licence.] |
56 | | */ |
57 | | /* ==================================================================== |
58 | | * Copyright 2005 Nokia. All rights reserved. |
59 | | * |
60 | | * The portions of the attached software ("Contribution") is developed by |
61 | | * Nokia Corporation and is licensed pursuant to the OpenSSL open source |
62 | | * license. |
63 | | * |
64 | | * The Contribution, originally written by Mika Kousa and Pasi Eronen of |
65 | | * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites |
66 | | * support (see RFC 4279) to OpenSSL. |
67 | | * |
68 | | * No patent licenses or other rights except those expressly stated in |
69 | | * the OpenSSL open source license shall be deemed granted or received |
70 | | * expressly, by implication, estoppel, or otherwise. |
71 | | * |
72 | | * No assurances are provided by Nokia that the Contribution does not |
73 | | * infringe the patent or other intellectual property rights of any third |
74 | | * party or that the license provides you with all the necessary rights |
75 | | * to make use of the Contribution. |
76 | | * |
77 | | * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN |
78 | | * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA |
79 | | * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY |
80 | | * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR |
81 | | * OTHERWISE. */ |
82 | | |
83 | | #include <openssl/ssl.h> |
84 | | |
85 | | #include <limits.h> |
86 | | #include <string.h> |
87 | | |
88 | | #include <utility> |
89 | | |
90 | | #include <openssl/bytestring.h> |
91 | | #include <openssl/err.h> |
92 | | #include <openssl/mem.h> |
93 | | #include <openssl/x509.h> |
94 | | |
95 | | #include "../crypto/internal.h" |
96 | | #include "internal.h" |
97 | | |
98 | | |
99 | | BSSL_NAMESPACE_BEGIN |
100 | | |
101 | | // An SSL_SESSION is serialized as the following ASN.1 structure: |
102 | | // |
103 | | // SSLSession ::= SEQUENCE { |
104 | | // version INTEGER (1), -- session structure version |
105 | | // sslVersion INTEGER, -- protocol version number |
106 | | // cipher OCTET STRING, -- two bytes long |
107 | | // sessionID OCTET STRING, |
108 | | // secret OCTET STRING, |
109 | | // time [1] INTEGER, -- seconds since UNIX epoch |
110 | | // timeout [2] INTEGER, -- in seconds |
111 | | // peer [3] Certificate OPTIONAL, |
112 | | // sessionIDContext [4] OCTET STRING OPTIONAL, |
113 | | // verifyResult [5] INTEGER OPTIONAL, -- one of X509_V_* codes |
114 | | // pskIdentity [8] OCTET STRING OPTIONAL, |
115 | | // ticketLifetimeHint [9] INTEGER OPTIONAL, -- client-only |
116 | | // ticket [10] OCTET STRING OPTIONAL, -- client-only |
117 | | // peerSHA256 [13] OCTET STRING OPTIONAL, |
118 | | // originalHandshakeHash [14] OCTET STRING OPTIONAL, |
119 | | // signedCertTimestampList [15] OCTET STRING OPTIONAL, |
120 | | // -- contents of SCT extension |
121 | | // ocspResponse [16] OCTET STRING OPTIONAL, |
122 | | // -- stapled OCSP response from the server |
123 | | // extendedMasterSecret [17] BOOLEAN OPTIONAL, |
124 | | // groupID [18] INTEGER OPTIONAL, |
125 | | // certChain [19] SEQUENCE OF Certificate OPTIONAL, |
126 | | // ticketAgeAdd [21] OCTET STRING OPTIONAL, |
127 | | // isServer [22] BOOLEAN DEFAULT TRUE, |
128 | | // peerSignatureAlgorithm [23] INTEGER OPTIONAL, |
129 | | // ticketMaxEarlyData [24] INTEGER OPTIONAL, |
130 | | // authTimeout [25] INTEGER OPTIONAL, -- defaults to timeout |
131 | | // earlyALPN [26] OCTET STRING OPTIONAL, |
132 | | // isQuic [27] BOOLEAN OPTIONAL, |
133 | | // quicEarlyDataHash [28] OCTET STRING OPTIONAL, |
134 | | // localALPS [29] OCTET STRING OPTIONAL, |
135 | | // peerALPS [30] OCTET STRING OPTIONAL, |
136 | | // -- Either both or none of localALPS and peerALPS must be present. If both |
137 | | // -- are present, earlyALPN must be present and non-empty. |
138 | | // } |
139 | | // |
140 | | // Note: historically this serialization has included other optional |
141 | | // fields. Their presence is currently treated as a parse error, except for |
142 | | // hostName, which is ignored. |
143 | | // |
144 | | // keyArg [0] IMPLICIT OCTET STRING OPTIONAL, |
145 | | // hostName [6] OCTET STRING OPTIONAL, |
146 | | // pskIdentityHint [7] OCTET STRING OPTIONAL, |
147 | | // compressionMethod [11] OCTET STRING OPTIONAL, |
148 | | // srpUsername [12] OCTET STRING OPTIONAL, |
149 | | // ticketFlags [20] INTEGER OPTIONAL, |
150 | | |
151 | | static const unsigned kVersion = 1; |
152 | | |
153 | | static const CBS_ASN1_TAG kTimeTag = |
154 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1; |
155 | | static const CBS_ASN1_TAG kTimeoutTag = |
156 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 2; |
157 | | static const CBS_ASN1_TAG kPeerTag = |
158 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 3; |
159 | | static const CBS_ASN1_TAG kSessionIDContextTag = |
160 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 4; |
161 | | static const CBS_ASN1_TAG kVerifyResultTag = |
162 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 5; |
163 | | static const CBS_ASN1_TAG kHostNameTag = |
164 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 6; |
165 | | static const CBS_ASN1_TAG kPSKIdentityTag = |
166 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 8; |
167 | | static const CBS_ASN1_TAG kTicketLifetimeHintTag = |
168 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 9; |
169 | | static const CBS_ASN1_TAG kTicketTag = |
170 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 10; |
171 | | static const CBS_ASN1_TAG kPeerSHA256Tag = |
172 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 13; |
173 | | static const CBS_ASN1_TAG kOriginalHandshakeHashTag = |
174 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 14; |
175 | | static const CBS_ASN1_TAG kSignedCertTimestampListTag = |
176 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 15; |
177 | | static const CBS_ASN1_TAG kOCSPResponseTag = |
178 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 16; |
179 | | static const CBS_ASN1_TAG kExtendedMasterSecretTag = |
180 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 17; |
181 | | static const CBS_ASN1_TAG kGroupIDTag = |
182 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 18; |
183 | | static const CBS_ASN1_TAG kCertChainTag = |
184 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 19; |
185 | | static const CBS_ASN1_TAG kTicketAgeAddTag = |
186 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 21; |
187 | | static const CBS_ASN1_TAG kIsServerTag = |
188 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 22; |
189 | | static const CBS_ASN1_TAG kPeerSignatureAlgorithmTag = |
190 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 23; |
191 | | static const CBS_ASN1_TAG kTicketMaxEarlyDataTag = |
192 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 24; |
193 | | static const CBS_ASN1_TAG kAuthTimeoutTag = |
194 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 25; |
195 | | static const CBS_ASN1_TAG kEarlyALPNTag = |
196 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 26; |
197 | | static const CBS_ASN1_TAG kIsQuicTag = |
198 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 27; |
199 | | static const CBS_ASN1_TAG kQuicEarlyDataContextTag = |
200 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 28; |
201 | | static const CBS_ASN1_TAG kLocalALPSTag = |
202 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 29; |
203 | | static const CBS_ASN1_TAG kPeerALPSTag = |
204 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 30; |
205 | | |
206 | | static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, CBB *cbb, |
207 | 0 | int for_ticket) { |
208 | 0 | if (in == NULL || in->cipher == NULL) { |
209 | 0 | return 0; |
210 | 0 | } |
211 | | |
212 | 0 | CBB session, child, child2; |
213 | 0 | if (!CBB_add_asn1(cbb, &session, CBS_ASN1_SEQUENCE) || |
214 | 0 | !CBB_add_asn1_uint64(&session, kVersion) || |
215 | 0 | !CBB_add_asn1_uint64(&session, in->ssl_version) || |
216 | 0 | !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) || |
217 | 0 | !CBB_add_u16(&child, (uint16_t)(in->cipher->id & 0xffff)) || |
218 | | // The session ID is irrelevant for a session ticket. |
219 | 0 | !CBB_add_asn1_octet_string(&session, in->session_id, |
220 | 0 | for_ticket ? 0 : in->session_id_length) || |
221 | 0 | !CBB_add_asn1_octet_string(&session, in->secret, in->secret_length) || |
222 | 0 | !CBB_add_asn1(&session, &child, kTimeTag) || |
223 | 0 | !CBB_add_asn1_uint64(&child, in->time) || |
224 | 0 | !CBB_add_asn1(&session, &child, kTimeoutTag) || |
225 | 0 | !CBB_add_asn1_uint64(&child, in->timeout)) { |
226 | 0 | return 0; |
227 | 0 | } |
228 | | |
229 | | // The peer certificate is only serialized if the SHA-256 isn't |
230 | | // serialized instead. |
231 | 0 | if (sk_CRYPTO_BUFFER_num(in->certs.get()) > 0 && !in->peer_sha256_valid) { |
232 | 0 | const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(in->certs.get(), 0); |
233 | 0 | if (!CBB_add_asn1(&session, &child, kPeerTag) || |
234 | 0 | !CBB_add_bytes(&child, CRYPTO_BUFFER_data(buffer), |
235 | 0 | CRYPTO_BUFFER_len(buffer))) { |
236 | 0 | return 0; |
237 | 0 | } |
238 | 0 | } |
239 | | |
240 | | // Although it is OPTIONAL and usually empty, OpenSSL has |
241 | | // historically always encoded the sid_ctx. |
242 | 0 | if (!CBB_add_asn1(&session, &child, kSessionIDContextTag) || |
243 | 0 | !CBB_add_asn1_octet_string(&child, in->sid_ctx, in->sid_ctx_length)) { |
244 | 0 | return 0; |
245 | 0 | } |
246 | | |
247 | 0 | if (in->verify_result != X509_V_OK) { |
248 | 0 | if (!CBB_add_asn1(&session, &child, kVerifyResultTag) || |
249 | 0 | !CBB_add_asn1_uint64(&child, in->verify_result)) { |
250 | 0 | return 0; |
251 | 0 | } |
252 | 0 | } |
253 | | |
254 | 0 | if (in->psk_identity) { |
255 | 0 | if (!CBB_add_asn1(&session, &child, kPSKIdentityTag) || |
256 | 0 | !CBB_add_asn1_octet_string(&child, |
257 | 0 | (const uint8_t *)in->psk_identity.get(), |
258 | 0 | strlen(in->psk_identity.get()))) { |
259 | 0 | return 0; |
260 | 0 | } |
261 | 0 | } |
262 | | |
263 | 0 | if (in->ticket_lifetime_hint > 0) { |
264 | 0 | if (!CBB_add_asn1(&session, &child, kTicketLifetimeHintTag) || |
265 | 0 | !CBB_add_asn1_uint64(&child, in->ticket_lifetime_hint)) { |
266 | 0 | return 0; |
267 | 0 | } |
268 | 0 | } |
269 | | |
270 | 0 | if (!in->ticket.empty() && !for_ticket) { |
271 | 0 | if (!CBB_add_asn1(&session, &child, kTicketTag) || |
272 | 0 | !CBB_add_asn1_octet_string(&child, in->ticket.data(), |
273 | 0 | in->ticket.size())) { |
274 | 0 | return 0; |
275 | 0 | } |
276 | 0 | } |
277 | | |
278 | 0 | if (in->peer_sha256_valid) { |
279 | 0 | if (!CBB_add_asn1(&session, &child, kPeerSHA256Tag) || |
280 | 0 | !CBB_add_asn1_octet_string(&child, in->peer_sha256, |
281 | 0 | sizeof(in->peer_sha256))) { |
282 | 0 | return 0; |
283 | 0 | } |
284 | 0 | } |
285 | | |
286 | 0 | if (in->original_handshake_hash_len > 0) { |
287 | 0 | if (!CBB_add_asn1(&session, &child, kOriginalHandshakeHashTag) || |
288 | 0 | !CBB_add_asn1_octet_string(&child, in->original_handshake_hash, |
289 | 0 | in->original_handshake_hash_len)) { |
290 | 0 | return 0; |
291 | 0 | } |
292 | 0 | } |
293 | | |
294 | 0 | if (in->signed_cert_timestamp_list != nullptr) { |
295 | 0 | if (!CBB_add_asn1(&session, &child, kSignedCertTimestampListTag) || |
296 | 0 | !CBB_add_asn1_octet_string( |
297 | 0 | &child, CRYPTO_BUFFER_data(in->signed_cert_timestamp_list.get()), |
298 | 0 | CRYPTO_BUFFER_len(in->signed_cert_timestamp_list.get()))) { |
299 | 0 | return 0; |
300 | 0 | } |
301 | 0 | } |
302 | | |
303 | 0 | if (in->ocsp_response != nullptr) { |
304 | 0 | if (!CBB_add_asn1(&session, &child, kOCSPResponseTag) || |
305 | 0 | !CBB_add_asn1_octet_string( |
306 | 0 | &child, CRYPTO_BUFFER_data(in->ocsp_response.get()), |
307 | 0 | CRYPTO_BUFFER_len(in->ocsp_response.get()))) { |
308 | 0 | return 0; |
309 | 0 | } |
310 | 0 | } |
311 | | |
312 | 0 | if (in->extended_master_secret) { |
313 | 0 | if (!CBB_add_asn1(&session, &child, kExtendedMasterSecretTag) || |
314 | 0 | !CBB_add_asn1_bool(&child, true)) { |
315 | 0 | return 0; |
316 | 0 | } |
317 | 0 | } |
318 | | |
319 | 0 | if (in->group_id > 0 && |
320 | 0 | (!CBB_add_asn1(&session, &child, kGroupIDTag) || |
321 | 0 | !CBB_add_asn1_uint64(&child, in->group_id))) { |
322 | 0 | return 0; |
323 | 0 | } |
324 | | |
325 | | // The certificate chain is only serialized if the leaf's SHA-256 isn't |
326 | | // serialized instead. |
327 | 0 | if (in->certs != NULL && |
328 | 0 | !in->peer_sha256_valid && |
329 | 0 | sk_CRYPTO_BUFFER_num(in->certs.get()) >= 2) { |
330 | 0 | if (!CBB_add_asn1(&session, &child, kCertChainTag)) { |
331 | 0 | return 0; |
332 | 0 | } |
333 | 0 | for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(in->certs.get()); i++) { |
334 | 0 | const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(in->certs.get(), i); |
335 | 0 | if (!CBB_add_bytes(&child, CRYPTO_BUFFER_data(buffer), |
336 | 0 | CRYPTO_BUFFER_len(buffer))) { |
337 | 0 | return 0; |
338 | 0 | } |
339 | 0 | } |
340 | 0 | } |
341 | | |
342 | 0 | if (in->ticket_age_add_valid) { |
343 | 0 | if (!CBB_add_asn1(&session, &child, kTicketAgeAddTag) || |
344 | 0 | !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || |
345 | 0 | !CBB_add_u32(&child2, in->ticket_age_add)) { |
346 | 0 | return 0; |
347 | 0 | } |
348 | 0 | } |
349 | | |
350 | 0 | if (!in->is_server) { |
351 | 0 | if (!CBB_add_asn1(&session, &child, kIsServerTag) || |
352 | 0 | !CBB_add_asn1_bool(&child, false)) { |
353 | 0 | return 0; |
354 | 0 | } |
355 | 0 | } |
356 | | |
357 | 0 | if (in->peer_signature_algorithm != 0 && |
358 | 0 | (!CBB_add_asn1(&session, &child, kPeerSignatureAlgorithmTag) || |
359 | 0 | !CBB_add_asn1_uint64(&child, in->peer_signature_algorithm))) { |
360 | 0 | return 0; |
361 | 0 | } |
362 | | |
363 | 0 | if (in->ticket_max_early_data != 0 && |
364 | 0 | (!CBB_add_asn1(&session, &child, kTicketMaxEarlyDataTag) || |
365 | 0 | !CBB_add_asn1_uint64(&child, in->ticket_max_early_data))) { |
366 | 0 | return 0; |
367 | 0 | } |
368 | | |
369 | 0 | if (in->timeout != in->auth_timeout && |
370 | 0 | (!CBB_add_asn1(&session, &child, kAuthTimeoutTag) || |
371 | 0 | !CBB_add_asn1_uint64(&child, in->auth_timeout))) { |
372 | 0 | return 0; |
373 | 0 | } |
374 | | |
375 | 0 | if (!in->early_alpn.empty()) { |
376 | 0 | if (!CBB_add_asn1(&session, &child, kEarlyALPNTag) || |
377 | 0 | !CBB_add_asn1_octet_string(&child, in->early_alpn.data(), |
378 | 0 | in->early_alpn.size())) { |
379 | 0 | return 0; |
380 | 0 | } |
381 | 0 | } |
382 | | |
383 | 0 | if (in->is_quic) { |
384 | 0 | if (!CBB_add_asn1(&session, &child, kIsQuicTag) || |
385 | 0 | !CBB_add_asn1_bool(&child, true)) { |
386 | 0 | return 0; |
387 | 0 | } |
388 | 0 | } |
389 | | |
390 | 0 | if (!in->quic_early_data_context.empty()) { |
391 | 0 | if (!CBB_add_asn1(&session, &child, kQuicEarlyDataContextTag) || |
392 | 0 | !CBB_add_asn1_octet_string(&child, in->quic_early_data_context.data(), |
393 | 0 | in->quic_early_data_context.size())) { |
394 | 0 | return 0; |
395 | 0 | } |
396 | 0 | } |
397 | | |
398 | 0 | if (in->has_application_settings) { |
399 | 0 | if (!CBB_add_asn1(&session, &child, kLocalALPSTag) || |
400 | 0 | !CBB_add_asn1_octet_string(&child, |
401 | 0 | in->local_application_settings.data(), |
402 | 0 | in->local_application_settings.size()) || |
403 | 0 | !CBB_add_asn1(&session, &child, kPeerALPSTag) || |
404 | 0 | !CBB_add_asn1_octet_string(&child, in->peer_application_settings.data(), |
405 | 0 | in->peer_application_settings.size())) { |
406 | 0 | return 0; |
407 | 0 | } |
408 | 0 | } |
409 | | |
410 | 0 | return CBB_flush(cbb); |
411 | 0 | } |
412 | | |
413 | | // SSL_SESSION_parse_string gets an optional ASN.1 OCTET STRING explicitly |
414 | | // tagged with |tag| from |cbs| and saves it in |*out|. If the element was not |
415 | | // found, it sets |*out| to NULL. It returns one on success, whether or not the |
416 | | // element was found, and zero on decode error. |
417 | | static int SSL_SESSION_parse_string(CBS *cbs, UniquePtr<char> *out, |
418 | 8.06k | CBS_ASN1_TAG tag) { |
419 | 8.06k | CBS value; |
420 | 8.06k | int present; |
421 | 8.06k | if (!CBS_get_optional_asn1_octet_string(cbs, &value, &present, tag)) { |
422 | 3 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
423 | 3 | return 0; |
424 | 3 | } |
425 | 8.05k | if (present) { |
426 | 416 | if (CBS_contains_zero_byte(&value)) { |
427 | 1 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
428 | 1 | return 0; |
429 | 1 | } |
430 | 415 | char *raw = nullptr; |
431 | 415 | if (!CBS_strdup(&value, &raw)) { |
432 | 0 | return 0; |
433 | 0 | } |
434 | 415 | out->reset(raw); |
435 | 7.64k | } else { |
436 | 7.64k | out->reset(); |
437 | 7.64k | } |
438 | 8.05k | return 1; |
439 | 8.05k | } |
440 | | |
441 | | // SSL_SESSION_parse_octet_string gets an optional ASN.1 OCTET STRING explicitly |
442 | | // tagged with |tag| from |cbs| and stows it in |*out|. It returns one on |
443 | | // success, whether or not the element was found, and zero on decode error. |
444 | | static bool SSL_SESSION_parse_octet_string(CBS *cbs, Array<uint8_t> *out, |
445 | 23.7k | CBS_ASN1_TAG tag) { |
446 | 23.7k | CBS value; |
447 | 23.7k | if (!CBS_get_optional_asn1_octet_string(cbs, &value, NULL, tag)) { |
448 | 24 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
449 | 24 | return false; |
450 | 24 | } |
451 | 23.7k | return out->CopyFrom(value); |
452 | 23.7k | } |
453 | | |
454 | | static int SSL_SESSION_parse_crypto_buffer(CBS *cbs, |
455 | | UniquePtr<CRYPTO_BUFFER> *out, |
456 | | CBS_ASN1_TAG tag, |
457 | 16.0k | CRYPTO_BUFFER_POOL *pool) { |
458 | 16.0k | if (!CBS_peek_asn1_tag(cbs, tag)) { |
459 | 15.5k | return 1; |
460 | 15.5k | } |
461 | | |
462 | 538 | CBS child, value; |
463 | 538 | if (!CBS_get_asn1(cbs, &child, tag) || |
464 | 538 | !CBS_get_asn1(&child, &value, CBS_ASN1_OCTETSTRING) || |
465 | 538 | CBS_len(&child) != 0) { |
466 | 5 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
467 | 5 | return 0; |
468 | 5 | } |
469 | 533 | out->reset(CRYPTO_BUFFER_new_from_CBS(&value, pool)); |
470 | 533 | if (*out == nullptr) { |
471 | 0 | return 0; |
472 | 0 | } |
473 | 533 | return 1; |
474 | 533 | } |
475 | | |
476 | | // SSL_SESSION_parse_bounded_octet_string parses an optional ASN.1 OCTET STRING |
477 | | // explicitly tagged with |tag| of size at most |max_out|. |
478 | | static int SSL_SESSION_parse_bounded_octet_string(CBS *cbs, uint8_t *out, |
479 | | uint8_t *out_len, |
480 | | uint8_t max_out, |
481 | 16.1k | CBS_ASN1_TAG tag) { |
482 | 16.1k | CBS value; |
483 | 16.1k | if (!CBS_get_optional_asn1_octet_string(cbs, &value, NULL, tag) || |
484 | 16.1k | CBS_len(&value) > max_out) { |
485 | 6 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
486 | 6 | return 0; |
487 | 6 | } |
488 | 16.1k | OPENSSL_memcpy(out, CBS_data(&value), CBS_len(&value)); |
489 | 16.1k | *out_len = static_cast<uint8_t>(CBS_len(&value)); |
490 | 16.1k | return 1; |
491 | 16.1k | } |
492 | | |
493 | | static int SSL_SESSION_parse_long(CBS *cbs, long *out, CBS_ASN1_TAG tag, |
494 | 8.07k | long default_value) { |
495 | 8.07k | uint64_t value; |
496 | 8.07k | if (!CBS_get_optional_asn1_uint64(cbs, &value, tag, |
497 | 8.07k | (uint64_t)default_value) || |
498 | 8.07k | value > LONG_MAX) { |
499 | 17 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
500 | 17 | return 0; |
501 | 17 | } |
502 | 8.06k | *out = (long)value; |
503 | 8.06k | return 1; |
504 | 8.07k | } |
505 | | |
506 | | static int SSL_SESSION_parse_u32(CBS *cbs, uint32_t *out, CBS_ASN1_TAG tag, |
507 | 23.8k | uint32_t default_value) { |
508 | 23.8k | uint64_t value; |
509 | 23.8k | if (!CBS_get_optional_asn1_uint64(cbs, &value, tag, |
510 | 23.8k | (uint64_t)default_value) || |
511 | 23.8k | value > 0xffffffff) { |
512 | 40 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
513 | 40 | return 0; |
514 | 40 | } |
515 | 23.8k | *out = (uint32_t)value; |
516 | 23.8k | return 1; |
517 | 23.8k | } |
518 | | |
519 | | static int SSL_SESSION_parse_u16(CBS *cbs, uint16_t *out, CBS_ASN1_TAG tag, |
520 | 15.9k | uint16_t default_value) { |
521 | 15.9k | uint64_t value; |
522 | 15.9k | if (!CBS_get_optional_asn1_uint64(cbs, &value, tag, |
523 | 15.9k | (uint64_t)default_value) || |
524 | 15.9k | value > 0xffff) { |
525 | 66 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
526 | 66 | return 0; |
527 | 66 | } |
528 | 15.9k | *out = (uint16_t)value; |
529 | 15.9k | return 1; |
530 | 15.9k | } |
531 | | |
532 | | UniquePtr<SSL_SESSION> SSL_SESSION_parse(CBS *cbs, |
533 | | const SSL_X509_METHOD *x509_method, |
534 | 8.69k | CRYPTO_BUFFER_POOL *pool) { |
535 | 8.69k | UniquePtr<SSL_SESSION> ret = ssl_session_new(x509_method); |
536 | 8.69k | if (!ret) { |
537 | 0 | return nullptr; |
538 | 0 | } |
539 | | |
540 | 8.69k | CBS session; |
541 | 8.69k | uint64_t version, ssl_version; |
542 | 8.69k | uint16_t unused; |
543 | 8.69k | if (!CBS_get_asn1(cbs, &session, CBS_ASN1_SEQUENCE) || |
544 | 8.69k | !CBS_get_asn1_uint64(&session, &version) || |
545 | 8.69k | version != kVersion || |
546 | 8.69k | !CBS_get_asn1_uint64(&session, &ssl_version) || |
547 | | // Require sessions have versions valid in either TLS or DTLS. The session |
548 | | // will not be used by the handshake if not applicable, but, for |
549 | | // simplicity, never parse a session that does not pass |
550 | | // |ssl_protocol_version_from_wire|. |
551 | 8.69k | ssl_version > UINT16_MAX || |
552 | 8.69k | !ssl_protocol_version_from_wire(&unused, ssl_version)) { |
553 | 491 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
554 | 491 | return nullptr; |
555 | 491 | } |
556 | 8.20k | ret->ssl_version = ssl_version; |
557 | | |
558 | 8.20k | CBS cipher; |
559 | 8.20k | uint16_t cipher_value; |
560 | 8.20k | if (!CBS_get_asn1(&session, &cipher, CBS_ASN1_OCTETSTRING) || |
561 | 8.20k | !CBS_get_u16(&cipher, &cipher_value) || |
562 | 8.20k | CBS_len(&cipher) != 0) { |
563 | 12 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
564 | 12 | return nullptr; |
565 | 12 | } |
566 | 8.18k | ret->cipher = SSL_get_cipher_by_value(cipher_value); |
567 | 8.18k | if (ret->cipher == NULL) { |
568 | 20 | OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_CIPHER); |
569 | 20 | return nullptr; |
570 | 20 | } |
571 | | |
572 | 8.16k | CBS session_id, secret; |
573 | 8.16k | if (!CBS_get_asn1(&session, &session_id, CBS_ASN1_OCTETSTRING) || |
574 | 8.16k | CBS_len(&session_id) > SSL3_MAX_SSL_SESSION_ID_LENGTH || |
575 | 8.16k | !CBS_get_asn1(&session, &secret, CBS_ASN1_OCTETSTRING) || |
576 | 8.16k | CBS_len(&secret) > SSL_MAX_MASTER_KEY_LENGTH) { |
577 | 10 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
578 | 10 | return nullptr; |
579 | 10 | } |
580 | 8.15k | OPENSSL_memcpy(ret->session_id, CBS_data(&session_id), CBS_len(&session_id)); |
581 | 8.15k | static_assert(SSL3_MAX_SSL_SESSION_ID_LENGTH <= UINT8_MAX, |
582 | 8.15k | "max session ID is too large"); |
583 | 8.15k | ret->session_id_length = static_cast<uint8_t>(CBS_len(&session_id)); |
584 | 8.15k | OPENSSL_memcpy(ret->secret, CBS_data(&secret), CBS_len(&secret)); |
585 | 8.15k | static_assert(SSL_MAX_MASTER_KEY_LENGTH <= UINT8_MAX, |
586 | 8.15k | "max secret is too large"); |
587 | 8.15k | ret->secret_length = static_cast<uint8_t>(CBS_len(&secret)); |
588 | | |
589 | 8.15k | CBS child; |
590 | 8.15k | uint64_t timeout; |
591 | 8.15k | if (!CBS_get_asn1(&session, &child, kTimeTag) || |
592 | 8.15k | !CBS_get_asn1_uint64(&child, &ret->time) || |
593 | 8.15k | !CBS_get_asn1(&session, &child, kTimeoutTag) || |
594 | 8.15k | !CBS_get_asn1_uint64(&child, &timeout) || |
595 | 8.15k | timeout > UINT32_MAX) { |
596 | 74 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
597 | 74 | return nullptr; |
598 | 74 | } |
599 | | |
600 | 8.08k | ret->timeout = (uint32_t)timeout; |
601 | | |
602 | 8.08k | CBS peer; |
603 | 8.08k | int has_peer; |
604 | 8.08k | if (!CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag) || |
605 | 8.08k | (has_peer && CBS_len(&peer) == 0)) { |
606 | 2 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
607 | 2 | return nullptr; |
608 | 2 | } |
609 | | // |peer| is processed with the certificate chain. |
610 | | |
611 | 8.08k | if (!SSL_SESSION_parse_bounded_octet_string( |
612 | 8.08k | &session, ret->sid_ctx, &ret->sid_ctx_length, sizeof(ret->sid_ctx), |
613 | 8.08k | kSessionIDContextTag) || |
614 | 8.08k | !SSL_SESSION_parse_long(&session, &ret->verify_result, kVerifyResultTag, |
615 | 8.07k | X509_V_OK)) { |
616 | 21 | return nullptr; |
617 | 21 | } |
618 | | |
619 | | // Skip the historical hostName field. |
620 | 8.06k | CBS unused_hostname; |
621 | 8.06k | if (!CBS_get_optional_asn1(&session, &unused_hostname, nullptr, |
622 | 8.06k | kHostNameTag)) { |
623 | 1 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
624 | 1 | return nullptr; |
625 | 1 | } |
626 | | |
627 | 8.06k | if (!SSL_SESSION_parse_string(&session, &ret->psk_identity, |
628 | 8.06k | kPSKIdentityTag) || |
629 | 8.06k | !SSL_SESSION_parse_u32(&session, &ret->ticket_lifetime_hint, |
630 | 8.05k | kTicketLifetimeHintTag, 0) || |
631 | 8.06k | !SSL_SESSION_parse_octet_string(&session, &ret->ticket, kTicketTag)) { |
632 | 11 | return nullptr; |
633 | 11 | } |
634 | | |
635 | 8.05k | if (CBS_peek_asn1_tag(&session, kPeerSHA256Tag)) { |
636 | 32 | CBS peer_sha256; |
637 | 32 | if (!CBS_get_asn1(&session, &child, kPeerSHA256Tag) || |
638 | 32 | !CBS_get_asn1(&child, &peer_sha256, CBS_ASN1_OCTETSTRING) || |
639 | 32 | CBS_len(&peer_sha256) != sizeof(ret->peer_sha256) || |
640 | 32 | CBS_len(&child) != 0) { |
641 | 6 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
642 | 6 | return nullptr; |
643 | 6 | } |
644 | 26 | OPENSSL_memcpy(ret->peer_sha256, CBS_data(&peer_sha256), |
645 | 26 | sizeof(ret->peer_sha256)); |
646 | 26 | ret->peer_sha256_valid = true; |
647 | 8.01k | } else { |
648 | 8.01k | ret->peer_sha256_valid = false; |
649 | 8.01k | } |
650 | | |
651 | 8.04k | if (!SSL_SESSION_parse_bounded_octet_string( |
652 | 8.04k | &session, ret->original_handshake_hash, |
653 | 8.04k | &ret->original_handshake_hash_len, |
654 | 8.04k | sizeof(ret->original_handshake_hash), kOriginalHandshakeHashTag) || |
655 | 8.04k | !SSL_SESSION_parse_crypto_buffer(&session, |
656 | 8.04k | &ret->signed_cert_timestamp_list, |
657 | 8.04k | kSignedCertTimestampListTag, pool) || |
658 | 8.04k | !SSL_SESSION_parse_crypto_buffer(&session, &ret->ocsp_response, |
659 | 8.03k | kOCSPResponseTag, pool)) { |
660 | 7 | return nullptr; |
661 | 7 | } |
662 | | |
663 | 8.03k | int extended_master_secret; |
664 | 8.03k | if (!CBS_get_optional_asn1_bool(&session, &extended_master_secret, |
665 | 8.03k | kExtendedMasterSecretTag, |
666 | 8.03k | 0 /* default to false */)) { |
667 | 24 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
668 | 24 | return nullptr; |
669 | 24 | } |
670 | 8.01k | ret->extended_master_secret = !!extended_master_secret; |
671 | | |
672 | 8.01k | if (!SSL_SESSION_parse_u16(&session, &ret->group_id, kGroupIDTag, 0)) { |
673 | 3 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
674 | 3 | return nullptr; |
675 | 3 | } |
676 | | |
677 | 8.01k | CBS cert_chain; |
678 | 8.01k | CBS_init(&cert_chain, NULL, 0); |
679 | 8.01k | int has_cert_chain; |
680 | 8.01k | if (!CBS_get_optional_asn1(&session, &cert_chain, &has_cert_chain, |
681 | 8.01k | kCertChainTag) || |
682 | 8.01k | (has_cert_chain && CBS_len(&cert_chain) == 0)) { |
683 | 2 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
684 | 2 | return nullptr; |
685 | 2 | } |
686 | 8.00k | if (has_cert_chain && !has_peer) { |
687 | 1 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
688 | 1 | return nullptr; |
689 | 1 | } |
690 | 8.00k | if (has_peer || has_cert_chain) { |
691 | 4.36k | ret->certs.reset(sk_CRYPTO_BUFFER_new_null()); |
692 | 4.36k | if (ret->certs == nullptr) { |
693 | 0 | return nullptr; |
694 | 0 | } |
695 | | |
696 | 4.36k | if (has_peer) { |
697 | 4.36k | UniquePtr<CRYPTO_BUFFER> buffer(CRYPTO_BUFFER_new_from_CBS(&peer, pool)); |
698 | 4.36k | if (!buffer || |
699 | 4.36k | !PushToStack(ret->certs.get(), std::move(buffer))) { |
700 | 0 | return nullptr; |
701 | 0 | } |
702 | 4.36k | } |
703 | | |
704 | 5.35k | while (CBS_len(&cert_chain) > 0) { |
705 | 1.00k | CBS cert; |
706 | 1.00k | if (!CBS_get_any_asn1_element(&cert_chain, &cert, NULL, NULL) || |
707 | 1.00k | CBS_len(&cert) == 0) { |
708 | 11 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
709 | 11 | return nullptr; |
710 | 11 | } |
711 | | |
712 | 991 | UniquePtr<CRYPTO_BUFFER> buffer(CRYPTO_BUFFER_new_from_CBS(&cert, pool)); |
713 | 991 | if (buffer == nullptr || |
714 | 991 | !PushToStack(ret->certs.get(), std::move(buffer))) { |
715 | 0 | return nullptr; |
716 | 0 | } |
717 | 991 | } |
718 | 4.36k | } |
719 | | |
720 | 7.99k | CBS age_add; |
721 | 7.99k | int age_add_present; |
722 | 7.99k | if (!CBS_get_optional_asn1_octet_string(&session, &age_add, &age_add_present, |
723 | 7.99k | kTicketAgeAddTag) || |
724 | 7.99k | (age_add_present && |
725 | 7.99k | !CBS_get_u32(&age_add, &ret->ticket_age_add)) || |
726 | 7.99k | CBS_len(&age_add) != 0) { |
727 | 3 | return nullptr; |
728 | 3 | } |
729 | 7.99k | ret->ticket_age_add_valid = age_add_present != 0; |
730 | | |
731 | 7.99k | int is_server; |
732 | 7.99k | if (!CBS_get_optional_asn1_bool(&session, &is_server, kIsServerTag, |
733 | 7.99k | 1 /* default to true */)) { |
734 | 28 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
735 | 28 | return nullptr; |
736 | 28 | } |
737 | | /* TODO: in time we can include |is_server| for servers too, then we can |
738 | | enforce that client and server sessions are never mixed up. */ |
739 | | |
740 | 7.96k | ret->is_server = is_server; |
741 | | |
742 | 7.96k | int is_quic; |
743 | 7.96k | if (!SSL_SESSION_parse_u16(&session, &ret->peer_signature_algorithm, |
744 | 7.96k | kPeerSignatureAlgorithmTag, 0) || |
745 | 7.96k | !SSL_SESSION_parse_u32(&session, &ret->ticket_max_early_data, |
746 | 7.90k | kTicketMaxEarlyDataTag, 0) || |
747 | 7.96k | !SSL_SESSION_parse_u32(&session, &ret->auth_timeout, kAuthTimeoutTag, |
748 | 7.89k | ret->timeout) || |
749 | 7.96k | !SSL_SESSION_parse_octet_string(&session, &ret->early_alpn, |
750 | 7.86k | kEarlyALPNTag) || |
751 | 7.96k | !CBS_get_optional_asn1_bool(&session, &is_quic, kIsQuicTag, |
752 | 7.84k | /*default_value=*/false) || |
753 | 7.96k | !SSL_SESSION_parse_octet_string(&session, &ret->quic_early_data_context, |
754 | 7.82k | kQuicEarlyDataContextTag)) { |
755 | 148 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
756 | 148 | return nullptr; |
757 | 148 | } |
758 | | |
759 | 7.81k | CBS settings; |
760 | 7.81k | int has_local_alps, has_peer_alps; |
761 | 7.81k | if (!CBS_get_optional_asn1_octet_string(&session, &settings, &has_local_alps, |
762 | 7.81k | kLocalALPSTag) || |
763 | 7.81k | !ret->local_application_settings.CopyFrom(settings) || |
764 | 7.81k | !CBS_get_optional_asn1_octet_string(&session, &settings, &has_peer_alps, |
765 | 7.81k | kPeerALPSTag) || |
766 | 7.81k | !ret->peer_application_settings.CopyFrom(settings) || |
767 | 7.81k | CBS_len(&session) != 0) { |
768 | 291 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
769 | 291 | return nullptr; |
770 | 291 | } |
771 | 7.52k | ret->is_quic = is_quic; |
772 | | |
773 | | // The two ALPS values and ALPN must be consistent. |
774 | 7.52k | if (has_local_alps != has_peer_alps || |
775 | 7.52k | (has_local_alps && ret->early_alpn.empty())) { |
776 | 2 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
777 | 2 | return nullptr; |
778 | 2 | } |
779 | 7.52k | ret->has_application_settings = has_local_alps; |
780 | | |
781 | 7.52k | if (!x509_method->session_cache_objects(ret.get())) { |
782 | 484 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
783 | 484 | return nullptr; |
784 | 484 | } |
785 | | |
786 | 7.04k | return ret; |
787 | 7.52k | } |
788 | | |
789 | 0 | bool ssl_session_serialize(const SSL_SESSION *in, CBB *cbb) { |
790 | 0 | return SSL_SESSION_to_bytes_full(in, cbb, 0); |
791 | 0 | } |
792 | | |
793 | | BSSL_NAMESPACE_END |
794 | | |
795 | | using namespace bssl; |
796 | | |
797 | | int SSL_SESSION_to_bytes(const SSL_SESSION *in, uint8_t **out_data, |
798 | 0 | size_t *out_len) { |
799 | 0 | if (in->not_resumable) { |
800 | | // If the caller has an unresumable session, e.g. if |SSL_get_session| were |
801 | | // called on a TLS 1.3 or False Started connection, serialize with a |
802 | | // placeholder value so it is not accidentally deserialized into a resumable |
803 | | // one. |
804 | 0 | static const char kNotResumableSession[] = "NOT RESUMABLE"; |
805 | |
|
806 | 0 | *out_len = strlen(kNotResumableSession); |
807 | 0 | *out_data = (uint8_t *)OPENSSL_memdup(kNotResumableSession, *out_len); |
808 | 0 | if (*out_data == NULL) { |
809 | 0 | return 0; |
810 | 0 | } |
811 | | |
812 | 0 | return 1; |
813 | 0 | } |
814 | | |
815 | 0 | ScopedCBB cbb; |
816 | 0 | if (!CBB_init(cbb.get(), 256) || |
817 | 0 | !SSL_SESSION_to_bytes_full(in, cbb.get(), 0) || |
818 | 0 | !CBB_finish(cbb.get(), out_data, out_len)) { |
819 | 0 | return 0; |
820 | 0 | } |
821 | | |
822 | 0 | return 1; |
823 | 0 | } |
824 | | |
825 | | int SSL_SESSION_to_bytes_for_ticket(const SSL_SESSION *in, uint8_t **out_data, |
826 | 0 | size_t *out_len) { |
827 | 0 | ScopedCBB cbb; |
828 | 0 | if (!CBB_init(cbb.get(), 256) || |
829 | 0 | !SSL_SESSION_to_bytes_full(in, cbb.get(), 1) || |
830 | 0 | !CBB_finish(cbb.get(), out_data, out_len)) { |
831 | 0 | return 0; |
832 | 0 | } |
833 | | |
834 | 0 | return 1; |
835 | 0 | } |
836 | | |
837 | 0 | int i2d_SSL_SESSION(SSL_SESSION *in, uint8_t **pp) { |
838 | 0 | uint8_t *out; |
839 | 0 | size_t len; |
840 | |
|
841 | 0 | if (!SSL_SESSION_to_bytes(in, &out, &len)) { |
842 | 0 | return -1; |
843 | 0 | } |
844 | | |
845 | 0 | if (len > INT_MAX) { |
846 | 0 | OPENSSL_free(out); |
847 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); |
848 | 0 | return -1; |
849 | 0 | } |
850 | | |
851 | 0 | if (pp) { |
852 | 0 | OPENSSL_memcpy(*pp, out, len); |
853 | 0 | *pp += len; |
854 | 0 | } |
855 | 0 | OPENSSL_free(out); |
856 | |
|
857 | 0 | return len; |
858 | 0 | } |
859 | | |
860 | | SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, size_t in_len, |
861 | 8.69k | const SSL_CTX *ctx) { |
862 | 8.69k | CBS cbs; |
863 | 8.69k | CBS_init(&cbs, in, in_len); |
864 | 8.69k | UniquePtr<SSL_SESSION> ret = |
865 | 8.69k | SSL_SESSION_parse(&cbs, ctx->x509_method, ctx->pool); |
866 | 8.69k | if (!ret) { |
867 | 1.65k | return NULL; |
868 | 1.65k | } |
869 | 7.04k | if (CBS_len(&cbs) != 0) { |
870 | 12 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); |
871 | 12 | return NULL; |
872 | 12 | } |
873 | 7.02k | return ret.release(); |
874 | 7.04k | } |